From cf5b87f82e9d120bd33f5a285fc691d0e9747b30 Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Wed, 23 Nov 2022 12:28:44 +0400 Subject: [PATCH 01/25] SubGhz: add protocol Nice_Flo 20bit (#1983) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- lib/subghz/protocols/nice_flo.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/subghz/protocols/nice_flo.c b/lib/subghz/protocols/nice_flo.c index ecd866a7..a57d5f4d 100644 --- a/lib/subghz/protocols/nice_flo.c +++ b/lib/subghz/protocols/nice_flo.c @@ -138,9 +138,9 @@ bool subghz_protocol_encoder_nice_flo_deserialize(void* context, FlipperFormat* FURI_LOG_E(TAG, "Deserialize error"); break; } - if((instance->generic.data_count_bit != - subghz_protocol_nice_flo_const.min_count_bit_for_found) && - (instance->generic.data_count_bit != + if((instance->generic.data_count_bit < + subghz_protocol_nice_flo_const.min_count_bit_for_found) || + (instance->generic.data_count_bit > 2 * subghz_protocol_nice_flo_const.min_count_bit_for_found)) { FURI_LOG_E(TAG, "Wrong number of bits in key"); break; @@ -297,9 +297,9 @@ bool subghz_protocol_decoder_nice_flo_deserialize(void* context, FlipperFormat* if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { break; } - if((instance->generic.data_count_bit != - subghz_protocol_nice_flo_const.min_count_bit_for_found) && - (instance->generic.data_count_bit != + if((instance->generic.data_count_bit < + subghz_protocol_nice_flo_const.min_count_bit_for_found) || + (instance->generic.data_count_bit > 2 * subghz_protocol_nice_flo_const.min_count_bit_for_found)) { FURI_LOG_E(TAG, "Wrong number of bits in key"); break; From 00fcd9cfcd9eae7ea97cbe94504ac852cc63a519 Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Wed, 23 Nov 2022 13:29:30 +0400 Subject: [PATCH 02/25] [FL-2976] SubGhz: add protocol "Ansonic" (#2000) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * SubGhz: add protocol "Ansonic" * SubGhz: fix encoder "Ansonic" * SubGhz: add unit_test "Ansonic" * SubGhz: fix flag * SubGhz: protocol "Ansonic" fix timing Co-authored-by: あく --- .../debug/unit_tests/subghz/subghz_test.c | 17 +- assets/unit_tests/subghz/ansonic.sub | 7 + assets/unit_tests/subghz/ansonic_raw.sub | 11 + assets/unit_tests/subghz/test_random_raw.sub | 21 ++ lib/subghz/protocols/ansonic.c | 346 ++++++++++++++++++ lib/subghz/protocols/ansonic.h | 107 ++++++ lib/subghz/protocols/protocol_items.c | 2 +- lib/subghz/protocols/protocol_items.h | 1 + 8 files changed, 510 insertions(+), 2 deletions(-) create mode 100644 assets/unit_tests/subghz/ansonic.sub create mode 100644 assets/unit_tests/subghz/ansonic_raw.sub create mode 100644 lib/subghz/protocols/ansonic.c create mode 100644 lib/subghz/protocols/ansonic.h diff --git a/applications/debug/unit_tests/subghz/subghz_test.c b/applications/debug/unit_tests/subghz/subghz_test.c index dbe03d88..3052448b 100644 --- a/applications/debug/unit_tests/subghz/subghz_test.c +++ b/applications/debug/unit_tests/subghz/subghz_test.c @@ -13,7 +13,7 @@ #define CAME_ATOMO_DIR_NAME EXT_PATH("subghz/assets/came_atomo") #define NICE_FLOR_S_DIR_NAME EXT_PATH("subghz/assets/nice_flor_s") #define TEST_RANDOM_DIR_NAME EXT_PATH("unit_tests/subghz/test_random_raw.sub") -#define TEST_RANDOM_COUNT_PARSE 232 +#define TEST_RANDOM_COUNT_PARSE 244 #define TEST_TIMEOUT 10000 static SubGhzEnvironment* environment_handler; @@ -437,6 +437,13 @@ MU_TEST(subghz_decoder_clemsa_test) { "Test decoder " SUBGHZ_PROTOCOL_CLEMSA_NAME " error\r\n"); } +MU_TEST(subghz_decoder_ansonic_test) { + mu_assert( + subghz_decoder_test( + EXT_PATH("unit_tests/subghz/ansonic_raw.sub"), SUBGHZ_PROTOCOL_ANSONIC_NAME), + "Test decoder " SUBGHZ_PROTOCOL_ANSONIC_NAME " error\r\n"); +} + //test encoders MU_TEST(subghz_encoder_princeton_test) { mu_assert( @@ -558,6 +565,12 @@ MU_TEST(subghz_encoder_clemsa_test) { "Test encoder " SUBGHZ_PROTOCOL_CLEMSA_NAME " error\r\n"); } +MU_TEST(subghz_encoder_ansonic_test) { + mu_assert( + subghz_encoder_test(EXT_PATH("unit_tests/subghz/ansonic.sub")), + "Test encoder " SUBGHZ_PROTOCOL_ANSONIC_NAME " error\r\n"); +} + MU_TEST(subghz_random_test) { mu_assert(subghz_decode_random_test(TEST_RANDOM_DIR_NAME), "Random test error\r\n"); } @@ -598,6 +611,7 @@ MU_TEST_SUITE(subghz) { MU_RUN_TEST(subghz_decoder_magellan_test); MU_RUN_TEST(subghz_decoder_intertechno_v3_test); MU_RUN_TEST(subghz_decoder_clemsa_test); + MU_RUN_TEST(subghz_decoder_ansonic_test); MU_RUN_TEST(subghz_encoder_princeton_test); MU_RUN_TEST(subghz_encoder_came_test); @@ -619,6 +633,7 @@ MU_TEST_SUITE(subghz) { MU_RUN_TEST(subghz_encoder_magellan_test); MU_RUN_TEST(subghz_encoder_intertechno_v3_test); MU_RUN_TEST(subghz_encoder_clemsa_test); + MU_RUN_TEST(subghz_encoder_ansonic_test); MU_RUN_TEST(subghz_random_test); subghz_test_deinit(); diff --git a/assets/unit_tests/subghz/ansonic.sub b/assets/unit_tests/subghz/ansonic.sub new file mode 100644 index 00000000..a7219b12 --- /dev/null +++ b/assets/unit_tests/subghz/ansonic.sub @@ -0,0 +1,7 @@ +Filetype: Flipper SubGhz Key File +Version: 1 +Frequency: 433920000 +Preset: FuriHalSubGhzPresetOok650Async +Protocol: Ansonic +Bit: 12 +Key: 00 00 00 00 00 00 05 5A diff --git a/assets/unit_tests/subghz/ansonic_raw.sub b/assets/unit_tests/subghz/ansonic_raw.sub new file mode 100644 index 00000000..6d4c78eb --- /dev/null +++ b/assets/unit_tests/subghz/ansonic_raw.sub @@ -0,0 +1,11 @@ +Filetype: Flipper SubGhz RAW File +Version: 1 +Frequency: 433920000 +Preset: FuriHalSubGhzPresetOok650Async +Protocol: RAW +RAW_Data: 57 -144 401 -86 173 -202 143 -258 133 -88 257 -144 287 -58 402 -56 259 -230 259 -86 85 -96 95 -174 286 -162 57 -230 253 -400 229 -88 536 -58 85 -72 167 -110 263 -72 229 -58 85 -86 87 -262 119 -288 163 -210 321 -320 186 -140 261 -96 143 -456 117 -216 143 -246 239 -102 121 -72 71 -191 167 -263 191 -96 239 -80 57 -116 143 -118 167 -168 215 -288 191 -106 287 -114 517 -88 113 -394 173 -70 215 -100 661 -86 201 -114 259 -58 287 -86 57 -202 399 -200 57 -288 229 -144 115 -1425 83 -142 173 -86 459 -112 223 -144 201 -116 143 -114 196 -17422 287 -614 1075 -1132 533 -560 1125 -1112 561 -530 1133 -1088 585 -512 1129 -1104 563 -1102 571 -1072 591 -524 1137 -538 1115 -19392 589 -522 1139 -1090 569 -520 1137 -1100 587 -520 1135 -1092 569 -514 1155 -1076 599 -1062 585 -1086 585 -532 1125 -528 1145 -19396 581 -504 1155 -1064 619 -506 1145 -1080 595 -508 1149 -1062 587 -536 1129 -1088 585 -1090 589 -1062 587 -510 1177 -506 1149 -19394 587 -524 1147 -1076 597 -512 1129 -1072 617 -498 1159 -1066 599 -514 1147 -1076 595 -1060 613 -1060 589 -506 1179 -510 1155 -19378 605 -514 1129 -1098 601 -488 1177 -1062 583 -510 1161 -1072 587 -516 1169 -1058 587 -1082 589 -1076 593 -532 1121 -536 1127 -19444 549 -542 1129 -1092 601 -510 1147 -1098 581 -506 1123 -1100 585 -510 1147 -1106 591 -1060 597 -1060 595 -510 1151 -534 1157 -19390 593 -512 1163 -1064 597 -510 1173 -1042 617 -510 1159 -1056 579 -556 1133 -1054 609 -1060 607 -1078 585 -528 1147 -516 1135 -19444 559 -534 1165 -1052 605 -510 1149 -1062 599 -520 1173 -1054 591 -540 1111 -1116 573 -1088 593 -1042 615 -534 1117 -536 1129 -19436 569 -530 1157 -1052 605 -504 1177 -1062 591 -536 1113 -1114 589 -514 1125 -1112 563 -1084 587 -1080 589 -536 1123 -532 1165 -19392 599 -524 1143 -1080 595 -540 1125 -1090 563 -534 1149 -1084 567 -534 1147 -1092 587 -1086 585 -1064 565 -558 1123 -532 1143 -19450 549 -556 1121 -1086 585 -534 1137 -1094 583 -516 1133 -1114 563 -536 1123 -1108 573 -1082 597 -1078 565 -532 1143 -524 1135 -19464 561 -528 1149 -1066 613 -508 1151 -1076 587 -532 1125 -1076 609 -506 1175 -1076 563 -1106 563 -1084 591 -534 1157 -484 1179 -19414 589 -528 1131 -1096 587 -520 1163 -1080 563 -550 1121 -1098 555 -562 1117 -1082 575 -1112 563 -1104 559 -558 1121 -530 1149 -19442 591 -498 1175 -1066 585 -534 1121 -1114 565 -540 1115 -1096 585 -538 1123 -1110 559 -1086 585 -1084 589 -530 1125 -558 1121 -19454 563 -542 1163 -1044 585 -558 1131 -1092 571 -536 1133 -1088 587 -518 1149 -1086 601 -1058 587 -1080 611 -510 +RAW_Data: 1125 -536 1145 -19444 567 -542 1151 -1086 581 -534 1133 -1084 583 -530 1141 -1090 587 -516 1121 -1114 591 -1062 595 -1092 567 -538 1131 -536 1145 -19448 589 -516 1143 -1076 591 -540 1115 -1090 591 -538 1115 -1096 597 -512 1155 -1078 581 -1082 585 -1104 559 -530 1153 -516 1147 -19438 589 -526 1157 -1056 609 -534 1137 -1078 585 -532 1149 -1076 585 -536 1123 -1104 587 -1062 597 -1082 587 -536 1121 -554 1121 -19464 555 -560 1123 -1104 563 -542 1131 -1096 565 -536 1143 -1060 621 -492 1175 -1078 571 -1100 577 -1092 591 -494 1167 -538 1117 -19452 593 -538 1133 -1074 603 -510 1157 -1062 595 -548 1115 -1102 573 -538 1139 -1094 567 -1094 583 -1092 567 -536 1127 -560 1113 -19478 563 -534 1151 -1084 569 -534 1135 -1116 565 -534 1135 -1084 583 -532 1155 -1060 587 -1084 589 -1084 581 -536 1125 -546 1141 -19460 577 -536 1123 -1102 565 -554 1119 -1096 593 -520 1133 -1108 563 -546 1131 -1088 569 -1094 573 -1100 583 -526 1147 -540 1123 -19466 587 -530 1129 -1100 587 -510 1143 -1084 609 -510 1131 -1110 567 -542 1121 -1102 567 -1110 563 -1106 567 -532 1149 -518 1145 -19458 573 -534 1147 -1082 575 -556 1149 -1048 589 -532 1157 -1088 565 -536 1129 -1088 589 -1106 563 -1086 587 -536 1129 -548 1147 -4298 103 -56 87 -344 87 -258 85 -278 215 -70 77 -344 279 -56 87 -56 197 -198 143 -288 362 -86 605 -144 57 -268 95 -114 143 -144 173 -144 143 -402 57 -202 259 -391 652 -340 427 -230 173 -356 97 -144 111 -246 219 -96 191 -114 173 -288 115 -56 109 -106 199 -106 73 -130 57 -172 85 -260 373 -56 629 -200 690 -230 273 -120 85 -460 85 -314 77 -78 111 -88 401 -116 171 -312 71 -500 81 -224 229 -88 257 -370 181 -172 200 -116 535 -174 113 -294 213 -359 445 -144 258 -114 115 -202 675 -509 239 -432 373 -538 85 -58 113 -86 761 -104 113 -318 443 -70 143 -144 647 -204 111 -334 87 -114 115 -144 113 -188 177 -144 199 -260 143 -86 87 -622 57 -116 171 -58 139 -222 55 -346 315 -76 345 -114 139 -171 195 -52 53 -98 119 -144 143 -244 95 -72 95 -96 167 -302 253 -186 307 -444 287 -449 115 -172 57 -172 316 -202 85 -370 697 -116 57 -144 171 -202 259 -114 85 -144 87 -315 85 -58 201 -116 171 -272 121 -358 171 -403 113 -86 115 -202 489 -229 115 -392 95 -116 171 -140 93 -102 143 -543 245 -358 215 -120 387 -288 171 -202 221 -202 115 -748 57 -316 143 -260 143 -288 115 -316 115 -58 85 -288 143 -460 485 -96 71 -104 199 -96 199 -202 143 -86 201 -116 85 -230 211 -288 115 -605 365 -126 53 -172 +RAW_Data: 317 -144 57 -486 53 -282 115 -585 97 -72 229 -174 257 -440 225 -86 173 -518 243 -167 95 -259 137 -96 694 -58 227 -80 279 -287 71 -72 301 -72 121 -106 51 -84 57 -58 199 -260 143 -288 219 -174 113 -681 115 -172 403 -58 113 -116 113 -432 171 -202 55 -108 95 -212 113 -72 527 -166 95 -212 195 -108 603 -142 239 -296 173 -346 373 -287 53 -80 79 -72 95 -238 95 -312 167 -618 143 -288 95 -72 95 -72 141 -210 55 -258 143 -328 305 -58 87 -86 315 -116 195 -218 85 -290 285 -220 215 -189 201 -58 57 -645 119 -96 71 -144 119 -406 143 -72 191 -72 631 -268 344 -56 115 -260 315 -140 455 -518 57 -58 171 -144 488 -86 219 -232 257 -144 85 -174 171 -260 115 -56 87 -166 197 -58 83 -56 85 -288 113 -410 115 -172 163 -202 113 -58 201 -144 201 -86 143 -264 167 -212 113 -116 139 -72 181 -287 343 -430 201 -260 201 -462 143 -192 301 -230 191 -454 187 -144 315 -164 143 -477 165 -58 201 -114 143 -490 115 -86 201 -58 113 -88 85 -58 203 -198 375 -86 171 -346 95 -88 257 -170 81 -56 143 -172 335 -230 173 -202 133 -471 187 -264 215 -86 115 -198 159 -72 179 -112 195 -116 449 -216 93 -96 167 -216 71 -216 71 -166 235 -86 447 -102 101 -226 195 -213 71 -144 215 -144 215 -261 241 -136 269 -142 263 -311 215 -172 201 -144 265 -168 71 -404 259 -86 85 -230 115 -650 143 -202 749 -512 248 -316 201 -154 71 -96 95 -360 105 -56 57 -432 95 -288 95 -286 95 -96 166 -144 93 -144 167 -150 904 -162 95 -526 287 -244 95 -240 383 -120 167 -394 430 -854 95 -72 143 -194 227 -120 167 -264 405 -144 143 -72 143 -72 141 -120 187 -86 143 -164 170 -96 143 -58 143 -86 402 -166 153 -120 95 -96 69 -96 71 -359 404 -338 71 -225 93 -74 97 -54 161 -114 319 -288 113 -116 459 -202 115 -114 115 -116 143 -86 57 -56 87 -114 85 -375 113 -58 311 -240 203 -288 95 -72 119 -383 213 -384 115 -86 171 -58 53 -104 401 -58 115 -86 373 -116 143 -144 161 -216 406 -72 263 -96 215 -72 95 -94 167 -96 191 -240 95 -94 214 -120 403 -116 200 -114 57 -172 220 -120 137 -364 334 -392 115 -260 199 -116 373 -188 95 -110 143 -172 87 -114 172 -230 57 -316 201 -56 249 -485 171 -202 87 -86 85 -144 345 -86 171 -58 259 -58 295 -120 95 -120 71 -192 635 -118 167 -96 375 -72 119 -120 261 -144 167 -96 95 -96 923 -215 71 -433 71 -477 +RAW_Data: 191 -240 85 -72 637 -408 213 -510 261 -168 143 -126 79 -106 167 -72 117 -218 251 -168 119 -96 215 -182 191 -238 517 -116 201 -144 255 -154 97 -94 215 -72 95 -120 71 -288 261 -106 434 -96 606 -232 229 -432 85 -174 343 -58 329 -156 55 -116 259 -144 488 -56 307 -339 115 -202 334 -88 113 -86 57 -174 143 -144 401 -376 85 -240 267 -82 95 -216 137 -158 85 -144 143 -58 221 -308 295 -114 87 -114 301 -120 358 -517 71 -262 191 -144 57 -140 165 -407 53 -262 217 -120 238 -358 119 -357 71 -72 119 -96 428 -72 95 -72 167 -72 93 -240 335 -96 357 -240 173 -230 143 -114 87 -200 143 -232 287 -150 97 -288 71 -72 93 -288 115 -58 143 -230 109 -264 71 -72 119 -72 238 -242 97 -78 163 -86 115 -518 79 -560 205 -449 969 -144 507 -86 231 -114 345 -58 979 -110 85 -288 287 -404 229 -202 57 -274 233 -86 115 -202 632 -230 85 -312 369 -392 460 -450 75 -280 85 -202 201 -86 229 -174 143 -144 233 -528 115 -212 127 -202 287 -172 403 -172 139 -128 165 -138 261 -392 143 -480 142 -189 291 -80 53 -283 167 -140 113 -1008 191 -144 119 -120 71 -193 241 -462 201 -58 143 -344 539 -316 113 -174 85 -116 113 -250 239 -168 405 -168 239 -158 85 -144 115 -86 57 -86 341 -144 171 -202 85 -202 115 -114 719 -88 55 -318 257 -56 254 -86 171 -116 459 -174 171 -329 95 -134 85 -314 431 -306 77 -316 401 -86 173 -404 281 -1073 488 -94 217 -78 101 -98 214 -120 215 -340 403 -535 143 -564 115 -116 199 -58 85 -174 315 -58 335 -136 55 -260 143 -144 229 -460 143 -58 143 -144 171 -202 115 -374 291 -130 339 -82 143 -58 171 -58 201 -86 85 -174 1022 -56 85 -82 255 -240 103 -202 431 -278 95 -216 119 -72 71 -96 71 -559 57 -144 171 -88 113 -86 231 -414 131 -192 237 -360 95 -168 145 -168 213 -120 167 -96 143 -110 57 -86 259 -56 87 -777 295 -96 57 -86 173 -86 171 -404 143 -172 231 -200 57 -441 55 -58 173 -56 87 -86 171 -72 287 -72 119 -262 119 -144 71 -72 121 -310 71 -302 113 -54 193 -80 307 -58 257 -232 143 -56 143 -116 219 -72 695 -70 71 -460 85 -232 719 -363 57 -402 604 -230 287 -138 83 -172 259 -58 171 -174 55 -88 489 -114 143 -116 171 -116 143 -58 199 -144 145 -343 374 -186 235 -140 77 -86 143 -202 143 -144 113 -144 143 -58 732 -96 263 -264 71 -206 95 -168 215 -144 271 -80 139 -88 85 -414 75 -100 +RAW_Data: 285 -96 627 -362 53 -84 201 -374 113 -202 115 -202 421 -316 85 -58 139 -224 87 -86 229 -58 243 -178 267 -288 95 -336 171 -96 213 -288 71 -405 95 -96 95 -384 95 -72 213 -72 95 -96 95 -272 87 -1083 85 -58 113 -88 257 -116 143 -292 175 -318 95 -120 95 -144 95 -72 71 -216 368 -116 373 -172 115 -58 85 -116 143 -86 85 -144 201 -86 201 -202 257 -144 201 -174 113 -144 115 -144 257 -202 585 -364 173 -138 287 -422 431 -86 85 -96 869 -186 95 -52 115 -86 115 -58 55 -276 365 -86 85 -489 171 -140 577 -106 718 -144 391 -232 195 -82 143 -172 109 -120 167 -96 280 -216 145 -240 215 -186 163 -96 141 -172 159 -603 257 -108 629 -192 119 -80 87 -172 57 -144 286 -86 57 -230 344 -58 113 -537 75 -96 537 -86 403 -196 167 -264 119 -238 119 -120 167 -96 95 -478 95 -120 167 -216 1085 -96 358 -72 263 -72 69 -120 143 -96 71 -96 191 -362 55 -144 57 -260 113 -58 85 -174 55 -88 257 -86 231 -194 55 -58 115 -56 55 -339 55 -58 374 -172 139 -82 419 -98 119 -261 71 -72 71 -240 713 -86 143 -218 295 -72 53 -56 431 -58 317 -144 161 -144 373 -144 173 -144 57 -114 85 -116 195 -72 708 -172 115 -86 191 -96 506 -120 71 -174 85 -58 363 -114 317 -230 316 -200 87 -114 57 -230 115 -315 173 -280 694 -212 453 -256 143 -202 113 -540 352 -116 257 -116 457 -56 109 -58 143 -230 259 -144 259 -525 119 -408 247 -112 389 -72 431 -96 137 -236 97 -474 201 -298 71 -82 55 -116 55 -112 199 -174 191 -86 143 -144 115 -114 317 -86 85 -230 87 -114 259 -84 107 -130 143 -94 153 -86 135 -94 215 -72 239 -94 435 -96 263 -142 166 -334 87 -194 179 -96 115 -284 135 -56 57 -144 463 -204 143 -316 201 -58 403 -86 141 -288 85 -202 139 -397 171 -174 305 -202 85 -144 373 -253 161 -492 181 -191 95 -216 315 -191 71 -166 97 -126 337 -96 71 -96 189 -168 295 -84 197 -86 259 -345 137 -144 167 -796 115 -344 455 -72 119 -96 119 -550 209 -88 85 -86 143 -340 167 -260 143 -537 85 -226 51 -537 57 -260 315 -461 51 -84 199 -358 383 -96 143 -257 115 -86 173 -86 201 -144 143 -316 85 -86 479 -88 85 -72 71 -104 115 -116 267 -72 137 -144 143 -116 85 -86 373 -288 115 -200 87 -114 259 -114 259 -462 143 -144 171 -86 57 -58 137 -144 57 -634 343 -72 205 -86 143 -258 57 -232 113 -230 461 -58 185 -74 537 -86 +RAW_Data: 535 -142 57 -58 55 -116 115 -432 85 -172 259 -192 167 -120 117 -72 119 -240 334 -72 71 -267 285 -144 119 -374 85 -88 85 -114 143 -202 229 -58 143 -202 115 -202 171 -86 71 -144 87 -56 173 -373 143 -116 113 -462 169 -80 215 -148 115 -336 85 -230 163 -432 85 -374 639 -174 85 -58 57 -82 295 -352 269 -532 414 -322 95 -287 263 -268 115 -56 259 -76 85 -282 401 -305 516 -114 115 -202 171 -86 451 -110 85 -346 201 -274 149 -202 85 -364 366 -258 57 -114 259 -172 142 -144 85 -116 85 -480 171 -144 57 -352 115 -116 535 -404 315 -202 163 -158 517 -316 215 -98 85 -346 85 -144 87 -86 257 -82 167 -58 85 -116 113 -894 233 -186 77 -266 147 -72 71 -82 57 -86 171 -58 57 -86 201 -364 143 -202 115 -114 85 -88 113 -86 87 -230 57 -76 613 -72 85 -96 209 -346 458 -58 547 -490 201 -315 315 -116 75 -168 359 -335 95 -384 93 -120 71 -312 251 -366 233 -96 189 -240 263 -192 271 -58 115 -58 229 -346 459 -174 113 -144 173 -144 218 -224 57 -116 215 -72 103 -202 513 -210 433 -116 113 -174 650 -273 147 -450 375 -86 115 -172 536 -84 85 -230 85 -58 195 -468 287 -110 551 -214 167 -311 213 -250 85 -58 85 -355 113 -230 115 -144 117 -288 195 -202 57 -376 123 -144 236 -168 553 -284 119 -72 143 -188 161 -120 93 -312 335 -58 55 -260 105 -244 143 -120 381 -268 173 -268 635 -168 453 -318 71 -167 71 -406 191 -172 215 -408 119 -144 93 -120 97 -130 143 -192 308 -122 147 -550 313 -96 139 -162 167 -96 431 -80 83 -112 201 -86 287 -86 229 -116 57 -288 113 -174 143 -116 113 -144 115 -518 57 -230 57 -172 231 -86 113 -314 183 -144 119 -72 165 -446 81 -86 135 -190 143 -96 71 -72 411 -96 143 -120 69 -216 349 -72 95 -96 517 -646 163 -86 113 -116 171 -116 143 -116 113 -287 259 -114 517 -168 141 -116 105 -72 95 -96 311 -118 159 -310 191 -54 143 -258 115 -450 219 -54 339 -372 239 -72 167 -174 113 -58 57 -144 259 -172 143 -336 113 -174 85 -230 83 -668 85 -202 113 -144 57 -116 373 -316 719 -288 115 -58 75 -120 139 -144 229 -144 57 -144 171 -192 391 -202 403 -58 315 -188 259 -56 115 -144 85 -404 57 -58 105 -102 429 -406 81 -172 57 -144 287 -230 287 -220 317 -458 283 -58 113 -86 269 -72 281 -58 85 -202 113 -52 421 -58 229 -480 259 -58 143 -660 155 -638 123 -86 57 -86 143 -346 143 -144 57 -144 \ No newline at end of file diff --git a/assets/unit_tests/subghz/test_random_raw.sub b/assets/unit_tests/subghz/test_random_raw.sub index 928838d3..a6a3c986 100644 --- a/assets/unit_tests/subghz/test_random_raw.sub +++ b/assets/unit_tests/subghz/test_random_raw.sub @@ -145,3 +145,24 @@ RAW_Data: -66 133 -66 97 -166 561 -100 895 -132 1323 -66 10873 -3752 99 -722 229 RAW_Data: -5434 65 -298 133 -132 131 -68 231 -200 661 -132 9517 -424 97 -1456 99 -1694 393 -100 131 -560 131 -196 197 -298 65 -428 229 -196 297 -266 131 -166 2435 -66 10161 -11230 65 -1320 131 -298 265 -532 231 -200 1291 -68 631 -66 12645 -4048 133 -66 67 -132 167 -266 163 -66 397 -132 197 -132 299 -98 197 -198 2903 -66 2361 -66 9627 -3588 197 -332 165 -68 331 -68 197 -132 99 -100 663 -66 363 -230 231 -166 131 -100 201 -298 163 -132 133 -202 363 -300 397 -102 263 -100 165 -66 1221 -66 1479 -132 165 -98 229 -12976 263 -66 363 -134 231 -66 629 -132 327 -100 97 -130 99 -164 227 -64 297 -132 397 -164 425 -198 97 -198 99 -66 365 -164 199 -102 97 -66 1817 -13524 231 -134 16907 -4086 233 -630 65 -396 201 -66 165 -198 67 -198 99 -664 2117 -166 12473 -446 2649 -440 2661 -420 2651 -422 2681 -418 2703 -400 365 -2724 387 -2696 2695 -414 357 -2704 2707 -386 389 -2700 2687 -392 405 -2706 2695 -402 363 -21268 2707 -388 377 -2706 2691 -404 2699 -382 2717 -382 2707 -378 2693 -416 2687 -396 363 -2736 355 -2748 2659 -416 365 -2708 2715 -388 377 -2708 2697 -404 363 -2730 2673 -420 355 -21268 2655 -460 319 -2766 2663 -448 2631 -436 2665 -418 2683 -410 2681 -416 2701 -386 383 -2700 375 -2744 2669 -416 353 -2730 2685 -416 357 -2708 2721 -380 369 -2724 2697 -382 385 -21260 2701 -418 353 -2720 2673 -418 2675 -408 2693 -384 2715 -386 2717 -386 2691 -404 363 -2732 387 -2702 2669 -412 359 -2736 2699 -380 381 -2728 2675 -416 381 -2720 2675 -414 347 -21280 2685 -390 377 -2724 2689 -416 2673 -408 2705 -382 2695 -410 2689 -414 2661 -418 385 -2704 369 -2704 2693 -416 375 -2726 2661 -420 355 -2728 2711 -388 375 -2702 2691 -410 363 -21252 2659 -488 287 -2794 2651 -448 2629 -436 2671 -416 2695 -416 2663 -406 2699 -384 383 -2730 367 -2702 2695 -418 385 -2702 2685 -412 349 -2744 2693 -366 389 -2714 2693 -394 381 -21266 2685 -418 363 -2730 2683 -382 2693 -418 2675 -410 2699 -384 2719 -382 2707 -380 359 -2734 387 -2704 2709 -380 361 -2732 2699 -418 357 -2728 2667 -416 383 -2696 2709 -380 391 -21228 2685 -458 307 -2800 2647 -412 2659 -432 2667 -416 2695 -416 2675 -406 2675 -416 383 -2700 361 -2730 2687 -414 375 -2696 2701 -420 353 -2720 2711 -382 367 -2728 2675 -416 385 -21222 2735 -386 355 -2744 2687 -396 2679 -418 2701 -386 2705 -382 2681 -410 2697 -384 385 -2736 365 -2704 2715 -384 377 -2696 2697 -416 349 -2722 2707 -386 379 -2732 2671 -410 361 -21258 2681 -464 297 -2796 2629 -456 2655 -420 2661 -448 2663 -404 2695 -382 2715 -380 371 -2740 355 -2744 2679 -384 391 -2728 2675 -388 379 RAW_Data: -2728 2695 -414 357 -2704 2705 -418 357 -21262 2673 -416 383 -2696 2709 -380 2703 -384 2699 -418 2671 -408 2695 -382 2713 -386 379 -2730 357 -2732 2695 -384 383 -2730 2679 -416 357 -2708 2701 -410 349 -2736 2697 -382 385 -21252 2669 -478 289 -2790 2647 -426 2651 -444 2653 -430 2659 -418 2695 -414 2681 -402 349 -2738 383 -2722 2677 -414 347 -2744 2691 -382 369 -2730 2691 -384 383 -2734 2679 -414 347 -21264 2705 -386 379 -2736 2667 -410 2695 -382 2715 -380 2709 -420 2665 -392 2713 -382 383 -2730 365 -2728 2665 -418 383 -2696 2693 -418 357 -2710 2711 -380 375 -2718 2701 -416 357 -21238 2677 -484 311 -2766 2635 -444 2657 -420 2663 -422 2695 -416 2667 -428 2675 -396 363 -73890 133 -98 131 -132 129 -658 99 -66 853 -100 63 -100 361 -98 1589 -66 1231 -132 65 -100 297 -198 65 -132 265 -66 9857 -4672 165 -1030 97 -1394 65 -200 2687 -68 6873 -8336 99 -1156 97 -66 163 -232 163 -262 197 -132 295 -132 263 -166 953 -100 263 -130 393 -164 295 -64 329 -66 393 -164 823 -130 165 -66 6133 -8436 165 -164 265 -266 65 -362 197 -696 3181 -132 363 -98 65 -166 131 -66 399 -132 663 -396 329 -66 7335 -7578 497 -230 627 -264 99 -366 99 -132 131 -134 265 -498 163 -100 1323 -66 265 -66 1129 -100 399 -132 365 -100 795 -68 397 -98 597 -364 297 -132 361 -132 265 -132 8591 -4740 65 -100 131 -166 199 -1088 97 -296 99 -528 131 -98 661 -66 401 -198 1157 -166 361 -164 495 -100 165 -66 297 -100 1423 -66 3067 -5658 67 -6406 197 -1092 65 -530 659 -68 265 -100 991 -68 231 -230 297 -66 327 -66 131 -132 659 -134 131 -100 1183 -132 263 -98 621 -66 2075 -6976 65 -5138 67 -132 129 -664 67 -132 165 -100 331 -466 231 -68 467 -98 563 -66 231 -100 531 -66 465 -66 1023 -166 297 -134 3409 -12290 67 -164 99 -532 133 -166 263 -66 231 -66 721 -64 131 -68 959 -134 495 -100 299 -98 497 -98 365 -100 397 -232 297 -98 531 -66 3029 -12216 265 -132 99 -364 199 -234 131 -66 431 -166 333 -166 397 -132 327 -100 395 -66 197 -132 395 -66 527 -98 295 -100 97 -98 789 -132 363 -132 297 -200 2815 -4914 65 -6620 65 -462 65 -134 297 -66 497 -264 231 -198 2773 -134 365 -100 831 -166 131 -100 297 -132 861 -132 299 -100 561 -66 1381 -6946 65 -5516 231 -266 97 -1362 1093 -68 1621 -134 165 -332 297 -98 361 -228 97 -132 797 -98 3487 -13224 229 -164 65 -132 913 -66 1123 -98 527 -134 929 -98 723 -100 12259 -270 165 -132 67 -132 165 -1326 99 -98 65 -1194 431 -66 695 -66 733 -134 197 RAW_Data: -134 10801 -166 67 -6130 133 -198 231 -334 365 -98 229 -132 165 -68 231 -166 14501 -524 65 -328 131 -498 129 -1288 65 -494 163 -64 165 -66 527 -132 131 -132 1019 -198 129 -166 393 -198 65 -164 6411 -66 3255 -10642 65 -1320 165 -164 493 -492 559 -264 2555 -66 695 -66 1657 -164 855 -66 4001 -10526 97 -596 133 -298 67 -264 65 -300 65 -100 263 -166 231 -134 99 -100 2703 -68 13643 -4922 297 -100 65 -232 133 -198 331 -300 231 -66 331 -100 12047 -3872 97 -196 65 -494 329 -66 65 -890 97 -98 229 -164 195 -596 797 -66 861 -132 65 -66 231 -100 565 -66 65 -66 1297 -132 265 -66 363 -134 265 -364 297 -164 299 -134 297 -134 495 -98 11309 -3790 131 -1380 65 -758 65 -164 129 -460 65 -360 199 -100 563 -68 497 -198 363 -266 263 -100 165 -66 697 -66 1933 -13594 65 -762 1223 -132 1119 -196 361 -134 131 -100 793 -166 695 -68 231 -68 463 -66 11727 -4204 363 -264 131 -132 133 -1124 97 -100 163 -100 327 -100 331 -198 397 -66 397 -100 395 -100 163 -66 197 -564 1059 -7962 65 -100 65 -198 129 -362 99 -394 197 -296 495 -100 1357 -68 459 -66 593 -66 265 -68 301 -132 465 -66 231 -200 397 -66 397 -232 199 -298 12077 -4350 231 -796 363 -198 133 -264 65 -1132 597 -332 3295 -100 755 -98 231 -164 97 -264 459 -166 759 -164 3265 -12138 99 -232 99 -1228 1025 -100 393 -66 531 -132 693 -132 1063 -66 427 -64 297 -294 229 -98 9723 -5404 67 -466 99 -796 267 -98 201 -100 167 -264 461 -98 1415 -66 861 -66 267 -66 331 -134 1663 -66 2089 -7012 65 -100 101 -4804 431 -728 99 -100 65 -100 995 -134 165 -66 929 -100 65 -66 927 -100 1093 -168 99 -100 497 -66 665 -200 6517 -8312 165 -66 129 -66 559 -166 99 -430 65 -398 67 -66 593 -198 459 -132 261 -132 263 -130 723 -66 459 -100 325 -166 67 -198 559 -66 493 -66 11475 -3896 99 -266 99 -66 197 -1092 129 -198 361 -166 163 -98 263 -196 759 -100 265 -100 365 -630 4635 -12748 65 -1712 461 -100 497 -66 395 -98 265 -98 229 -164 529 -132 297 -66 565 -132 987 -132 8665 -2820 2265 -450 313 -2774 2643 -442 325 -2772 2665 -416 359 -2734 2667 -386 379 -21274 2657 -474 293 -2810 2619 -466 2613 -476 2629 -452 2663 -388 2683 -418 2705 -400 365 -2722 387 -2700 2697 -380 361 -2732 2691 -418 361 -2732 2667 -416 383 -2698 2697 -416 357 -21238 2715 -384 383 -2732 2685 -416 2667 -416 2695 -398 2671 -418 2687 -390 2713 -382 383 -2730 365 -2728 2661 -416 379 -2716 2685 -384 379 -2720 2703 -378 401 -2718 2671 +RAW_Data: 889 -130 325 -64 457 -560 165 -68 199 -170 67 -66 265 -132 133 -666 67 -166 431 -66 201 -98 297 -100 595 -66 199 -134 65 -100 795 -132 99 -168 501 -200 331 -132 265 -102 265 -134 423 -98 521 -226 65 -166 431 -134 99 -100 133 -464 195 -326 623 -100 673 -98 321 -200 65 -136 369 -166 65 -68 97 -166 165 -334 265 -102 231 -166 101 -170 65 -170 265 -136 931 -100 133 -134 563 -66 333 -100 427 -66 163 -390 231 -66 193 -130 461 -166 557 -100 99 -198 263 -100 197 -294 231 -232 299 -134 199 -170 267 -134 631 -98 235 -100 499 -68 463 -100 65 -134 335 -170 273 -134 297 -100 67 -66 197 -166 67 -134 301 -168 537 -470 99 -134 433 -132 199 -192 261 -100 523 -164 459 -132 259 -332 359 -64 227 -96 131 -132 687 -132 363 -136 329 -434 99 -334 133 -100 401 -132 233 -700 233 -170 337 -66 371 -68 233 -202 531 -266 731 -66 465 -100 167 -100 133 -232 335 -166 239 -102 367 -232 231 -100 167 -134 201 -136 301 -168 199 -300 231 -98 237 -134 233 -102 329 -132 261 -134 199 -66 265 -136 99 -170 167 -134 199 -166 167 -136 367 -298 197 -200 99 -166 469 -136 439 -66 303 -134 295 -100 433 -134 899 -266 363 -132 197 -160 555 -324 129 -96 97 -128 257 -132 97 -394 257 -98 195 -166 459 -332 395 -132 633 -134 301 -100 131 -332 169 -168 395 -166 263 -540 783 -100 287 -130 295 -96 225 -296 133 -98 99 -100 461 -164 545 -130 99 -66 301 -68 265 -100 235 -134 235 -70 333 -102 497 -66 233 -364 301 -170 103 -66 165 -336 733 -200 133 -100 263 -102 65 -136 465 -200 1035 -198 165 -170 67 -302 631 -100 429 -332 65 -128 129 -130 159 -128 159 -66 161 -96 325 -164 261 -100 197 -162 65 -96 99 -130 65 -102 333 -100 199 -98 389 -330 129 -128 229 -66 425 -366 229 -64 261 -100 227 -96 227 -526 301 -200 97 -66 699 -334 67 -100 399 -198 787 -98 297 -134 429 -100 3245 -64 527 -98 131 -526 633 -68 133 -302 1459 -164 971 -102 237 -136 1439 -266 1131 -66 599 -200 303 -332 325 -130 389 -166 371 -66 333 -102 65 -100 233 -234 327 -266 233 -166 297 -100 225 -130 163 -336 99 -596 199 -330 131 -66 331 -338 263 -358 197 -168 877 -66 227 -96 63 -130 263 -162 225 -290 197 -198 357 -132 297 -262 165 -456 227 -98 399 -296 95 -132 99 -98 457 -200 199 -168 535 -100 567 -134 327 -130 193 -130 683 -102 101 -132 233 -170 943 -166 827 -66 267 -102 503 -68 1325 -164 +RAW_Data: 1607 -68 233 -166 1167 -70 531 -134 335 -168 131 -66 299 -402 899 -66 461 -66 457 -98 953 -98 165 -66 293 -230 881 -64 393 -166 589 -66 289 -66 1093 -204 333 -98 2745 -132 2019 -170 925 -68 269 -102 1469 -136 2301 -68 1355 -100 527 -66 975 -68 1445 -98 2397 -100 1733 -66 703 -100 995 -100 135 -136 235 -202 167 -134 2071 -166 339 -170 201 -268 129 -66 465 -66 365 -100 197 -164 129 -98 161 -96 423 -66 675 -66 1543 -136 567 -200 767 -202 65 -100 1401 -66 623 -136 567 -234 67 -236 197 -194 97 -66 263 -66 1827 -392 1893 -98 165 -268 133 -132 231 -162 225 -98 695 -198 563 -100 301 -332 267 -102 341 -66 99 -132 1299 -130 525 -68 161 -96 357 -98 353 -100 131 -100 131 -98 163 -132 323 -100 535 -66 1323 -130 133 -66 235 -134 1497 -132 387 -98 129 -162 2623 -134 163 -68 167 -66 959 -232 495 -68 131 -134 867 -134 865 -66 333 -98 305 -134 231 -98 765 -198 397 -432 165 -66 165 -366 265 -102 541 -100 261 -162 331 -134 457 -66 491 -196 97 -266 193 -262 65 -166 231 -266 497 -360 263 -98 587 -164 259 -98 231 -66 359 -100 267 -102 271 -168 97 -262 63 -66 261 -130 227 -130 295 -164 65 -66 265 -200 597 -134 267 -170 603 -100 97 -466 231 -264 97 -168 99 -66 65 -200 199 -100 267 -404 303 -102 201 -204 235 -134 131 -198 335 -298 327 -130 291 -164 63 -162 295 -262 197 -130 95 -130 195 -96 159 -130 161 -66 231 -100 165 -66 199 -134 363 -66 267 -168 165 -168 167 -100 165 -530 363 -432 99 -232 65 -132 395 -328 229 -98 197 -132 161 -96 191 -292 197 -204 133 -100 399 -166 531 -332 235 -168 99 -66 325 -158 553 -132 129 -226 231 -134 99 -462 129 -64 289 -100 193 -66 355 -164 291 -198 131 -298 197 -198 373 -268 335 -234 427 -68 199 -132 267 -232 131 -66 783 -326 63 -162 161 -130 227 -66 259 -562 233 -464 303 -102 201 -334 301 -134 297 -198 229 -66 127 -166 99 -100 197 -198 571 -66 457 -134 361 -424 131 -328 163 -98 63 -100 505 -102 201 -1094 229 -164 65 -230 789 -236 2505 -166 201 -170 163 -64 1139 -66 927 -100 295 -198 723 -100 365 -66 459 -196 3033 -272 199 -66 499 -202 1319 -232 295 -298 131 -362 97 -164 129 -132 65 -98 197 -130 129 -98 261 -130 97 -98 229 -96 425 -66 227 -166 483 -66 163 -326 567 -68 235 -68 67 -66 167 -66 235 -330 425 -164 63 -66 427 -102 167 -66 669 -132 429 -200 65 -102 133 -100 197 -368 +RAW_Data: 65 -134 2481 -228 65 -130 229 -228 763 -136 603 -166 1619 -98 1763 -102 837 -166 321 -66 951 -130 2067 -66 259 -132 1835 -66 437 -102 701 -66 565 -68 363 -70 1113 -66 1989 -164 257 -128 351 -162 1055 -232 265 -170 309 -200 435 -166 833 -102 2467 -132 595 -66 773 -166 1615 -98 131 -96 485 -64 517 -166 197 -68 1231 -68 403 -100 263 -134 233 -100 503 -100 333 -266 729 -66 199 -100 369 -68 1239 -100 197 -68 299 -170 337 -100 825 -132 163 -66 4205 -64 161 -100 635 -66 907 -66 1017 -166 1709 -100 201 -266 657 -68 463 -166 331 -164 293 -64 259 -162 129 -262 597 -134 701 -136 67 -168 235 -136 303 -170 1417 -66 263 -98 857 -100 659 -166 97 -100 2497 -64 2495 -98 719 -128 227 -130 2217 -164 623 -264 719 -134 329 -98 1371 -100 553 -294 165 -66 1163 -100 329 -196 649 -200 1123 -68 263 -100 593 -266 333 -102 1133 -136 131 -132 603 -200 1819 -66 489 -66 563 -266 1113 -230 165 -66 423 -68 335 -100 101 -100 1073 -132 897 -100 101 -100 499 -134 173 -138 763 -238 371 -130 403 -166 203 -102 271 -136 269 -166 99 -168 263 -96 425 -66 331 -234 133 -400 231 -132 453 -66 459 -164 199 -68 237 -132 163 -198 161 -196 265 -132 65 -64 195 -130 357 -164 663 -68 167 -600 131 -98 133 -304 203 -134 433 -98 261 -130 199 -100 237 -100 229 -326 99 -98 331 -132 99 -294 165 -66 303 -134 99 -232 133 -136 99 -68 267 -198 233 -138 67 -166 367 -100 333 -168 267 -200 369 -266 135 -404 1939 -132 231 -160 161 -64 293 -98 331 -132 339 -104 135 -100 197 -430 263 -202 233 -64 195 -162 129 -64 227 -298 265 -68 697 -66 301 -68 231 -300 131 -368 769 -234 265 -98 195 -324 97 -752 229 -126 355 -98 257 -98 287 -64 427 -132 295 -262 197 -170 369 -102 267 -100 169 -68 201 -102 2551 -136 635 -134 639 -134 99 -132 197 -200 371 -66 731 -132 199 -138 733 -304 433 -68 729 -440 197 -68 99 -102 165 -266 261 -164 491 -296 489 -194 257 -164 133 -134 237 -68 335 -98 227 -130 229 -98 295 -98 231 -202 267 -236 233 -136 331 -130 195 -128 261 -430 261 -162 97 -224 99 -130 193 -96 197 -162 229 -396 97 -98 227 -364 267 -100 99 -100 233 -236 697 -164 227 -196 63 -98 327 -230 325 -66 129 -196 95 -98 195 -130 325 -430 131 -194 129 -454 161 -196 235 -68 433 -134 667 -164 355 -236 101 -98 2143 -134 1827 -198 63 -198 65 -64 2859 -64 619 -66 97 -130 3157 -66 679 -194 1491 -98 +RAW_Data: 951 -64 393 -100 955 -132 4715 -100 131 -66 199 -204 1541 -66 929 -130 1347 -166 665 -132 233 -132 67 -102 433 -100 595 -228 997 -66 505 -68 133 -98 231 -68 571 -134 1371 -232 231 -270 135 -102 97 -66 867 -100 269 -68 967 -100 1649 -66 65 -66 951 -68 65 -202 363 -200 779 -102 1449 -294 419 -130 361 -230 1079 -164 163 -260 893 -102 333 -100 533 -166 467 -100 135 -66 135 -202 369 -100 199 -100 269 -134 301 -166 229 -66 101 -134 199 -134 1293 -64 779 -62 831 -66 1243 -68 267 -102 197 -100 395 -98 455 -64 621 -132 877 -98 199 -100 2101 -134 503 -100 2035 -134 735 -236 475 -136 237 -132 133 -134 1229 -100 133 -66 167 -68 2655 -100 1807 -100 1095 -264 825 -98 163 -66 491 -98 161 -128 953 -100 773 -100 131 -66 67 -134 457 -130 63 -64 389 -98 715 -66 425 -300 97 -100 1515 -66 303 -68 99 -98 721 -64 887 -132 65 -132 165 -66 635 -68 2801 -66 1561 -100 751 -98 129 -64 725 -136 201 -100 333 -204 573 -104 1745 -134 99 -66 129 -64 595 -134 167 -102 337 -134 567 -134 1131 -138 1207 -100 269 -68 135 -100 1143 -134 2139 -68 1701 -162 991 -596 431 -66 99 -132 657 -66 391 -320 357 -260 259 -98 429 -66 163 -228 65 -130 227 -66 261 -166 99 -98 131 -366 199 -134 463 -102 201 -98 231 -102 639 -238 301 -568 169 -610 265 -102 841 -198 297 -100 335 -132 263 -266 265 -68 469 -134 267 -68 933 -298 333 -298 729 -168 135 -136 437 -132 1137 -134 199 -68 265 -132 463 -166 129 -130 227 -98 297 -98 65 -132 97 -202 199 -232 305 -66 165 -198 365 -66 99 -98 299 -170 65 -136 301 -232 99 -564 133 -132 233 -170 99 -102 131 -134 65 -204 101 -98 297 -98 167 -762 233 -298 99 -326 395 -66 299 -132 369 -504 333 -98 483 -200 457 -164 63 -164 329 -162 65 -622 231 -268 131 -132 133 -134 131 -134 131 -66 99 -100 231 -66 167 -336 165 -98 197 -100 97 -264 321 -98 521 -132 163 -130 129 -294 297 -134 101 -102 265 -168 497 -68 197 -68 499 -134 269 -398 267 -130 203 -302 65 -498 271 -136 465 -292 131 -294 163 -198 329 -96 129 -98 193 -130 391 -330 165 -134 167 -170 297 -102 133 -136 135 -366 199 -132 423 -132 395 -168 65 -166 401 -98 229 -98 329 -98 99 -130 129 -228 261 -160 127 -426 389 -162 193 -132 131 -100 231 -168 67 -304 201 -68 765 -132 161 -162 193 -64 195 -64 295 -130 787 -98 419 -528 429 -66 363 -134 131 -100 133 -200 331 -98 +RAW_Data: 431 -66 1167 -68 937 -68 1003 -66 99 -132 941 -134 65 -66 365 -274 165 -236 367 -96 557 -134 675 -66 261 -164 127 -96 391 -164 161 -98 391 -292 163 -98 519 -196 165 -98 523 -66 195 -160 3343 -66 661 -100 2589 -136 307 -100 629 -136 639 -100 133 -168 405 -100 267 -66 465 -132 1171 -64 749 -64 165 -98 983 -100 163 -202 537 -66 327 -100 669 -100 401 -236 2885 -164 439 -134 97 -426 1931 -66 1385 -98 715 -98 519 -66 289 -162 97 -360 297 -166 163 -66 289 -66 555 -334 167 -230 429 -102 267 -132 943 -136 401 -68 929 -130 193 -68 467 -198 335 -66 963 -100 597 -132 197 -260 523 -232 1115 -102 1935 -66 1395 -134 305 -100 99 -66 199 -66 1071 -66 2357 -66 367 -498 769 -234 163 -130 191 -64 1211 -200 133 -102 201 -100 561 -366 361 -98 195 -100 537 -64 165 -196 1041 -332 133 -102 441 -230 4217 -66 1033 -66 167 -66 933 -100 565 -66 331 -164 673 -104 441 -66 533 -66 2095 -164 525 -66 297 -170 965 -198 421 -100 663 -832 65 -100 331 -164 231 -166 135 -168 237 -466 761 -134 891 -196 791 -198 257 -160 161 -98 293 -66 1081 -98 229 -130 327 -66 1301 -200 331 -166 101 -66 461 -100 2619 -132 1663 -98 1609 -134 499 -332 165 -370 67 -264 97 -96 259 -98 701 -402 197 -128 527 -236 233 -102 167 -134 303 -134 99 -166 299 -132 165 -200 467 -68 305 -168 207 -102 465 -102 729 -136 101 -374 327 -96 259 -98 467 -202 65 -66 673 -98 335 -404 135 -66 339 -204 99 -366 233 -68 365 -166 133 -102 867 -198 163 -162 163 -294 463 -332 165 -68 269 -268 331 -100 131 -166 299 -132 231 -400 263 -164 131 -266 267 -264 367 -66 371 -134 229 -104 267 -232 67 -466 265 -100 101 -100 165 -200 65 -200 301 -66 199 -168 233 -98 267 -66 67 -134 261 -196 261 -234 427 -294 65 -194 193 -66 259 -132 849 -96 63 -198 167 -294 95 -98 361 -164 261 -196 131 -132 437 -100 597 -262 327 -162 295 -98 295 -164 259 -196 425 -230 321 -66 195 -66 261 -496 99 -200 529 -132 133 -966 133 -132 165 -66 63 -128 491 -402 65 -262 299 -66 299 -202 265 -100 99 -668 97 -134 65 -100 101 -66 65 -266 691 -66 431 -166 167 -134 199 -370 899 -134 99 -100 1093 -166 163 -166 399 -98 327 -100 99 -168 135 -200 133 -202 429 -98 65 -98 197 -556 65 -66 97 -326 331 -166 333 -200 135 -100 235 -234 265 -98 65 -68 135 -66 335 -66 133 -298 99 -66 233 -164 435 -232 97 -132 97 -392 +RAW_Data: 99 -198 819 -66 1235 -98 321 -132 1091 -66 1307 -98 3059 -164 3305 -64 227 -98 591 -98 129 -66 229 -98 2143 -98 939 -68 563 -100 361 -232 945 -164 257 -96 229 -230 387 -64 195 -130 981 -294 587 -162 193 -98 1337 -66 293 -98 2665 -66 297 -98 647 -66 459 -132 491 -164 489 -96 595 -66 899 -66 837 -64 1151 -196 259 -98 357 -164 891 -132 1359 -134 197 -98 97 -98 261 -64 229 -96 461 -136 693 -100 201 -98 865 -66 599 -100 517 -132 709 -66 293 -298 655 -66 197 -130 129 -66 197 -98 4291 -66 673 -66 667 -132 1473 -132 133 -104 99 -66 163 -168 333 -134 1743 -132 1097 -132 99 -68 167 -602 1323 -352 99 -166 753 -98 423 -98 97 -66 1317 -228 1309 -98 1849 -66 1939 -132 601 -100 665 -100 1875 -66 695 -132 425 -66 425 -66 263 -134 165 -134 99 -98 829 -66 601 -166 131 -102 565 -66 301 -100 1099 -100 601 -138 533 -66 667 -234 561 -66 99 -68 2741 -98 199 -100 531 -168 101 -434 1027 -68 431 -66 403 -132 99 -98 565 -132 135 -100 399 -166 271 -236 233 -166 197 -366 99 -66 99 -168 503 -66 199 -170 207 -100 673 -368 99 -66 263 -168 133 -98 397 -268 337 -66 131 -132 231 -132 501 -134 99 -168 567 -138 103 -136 267 -298 231 -134 197 -160 321 -332 231 -98 131 -164 257 -64 163 -328 395 -66 331 -202 65 -168 133 -68 167 -100 233 -102 335 -66 197 -326 1101 -132 589 -100 811 -132 399 -136 269 -102 497 -66 559 -100 129 -98 855 -68 637 -102 65 -200 875 -68 233 -166 167 -66 529 -202 235 -102 231 -66 1237 -66 733 -98 1723 -132 101 -100 297 -66 829 -232 197 -100 367 -134 169 -166 167 -434 633 -100 235 -200 131 -134 233 -100 131 -100 331 -134 495 -432 65 -528 161 -130 295 -132 337 -136 133 -166 165 -100 269 -240 201 -336 133 -166 165 -238 199 -202 431 -434 99 -134 501 -166 231 -96 559 -202 167 -66 717 -98 987 -198 65 -64 163 -64 227 -98 555 -164 199 -64 361 -66 163 -98 129 -162 97 -130 161 -460 197 -230 681 -98 197 -98 329 -100 267 -266 291 -264 65 -100 329 -100 459 -200 363 -98 165 -134 231 -134 301 -134 231 -302 99 -132 101 -134 267 -136 233 -68 393 -422 163 -166 361 -166 99 -134 365 -134 133 -336 401 -66 495 -132 401 -168 133 -402 501 -136 1093 -862 165 -132 293 -300 289 -66 131 -164 391 -134 99 -360 359 -130 323 -200 423 -98 195 -162 295 -132 161 -98 129 -782 131 -426 227 -64 259 -166 63 -160 323 -98 261 -230 +RAW_Data: 231 -66 921 -66 355 -64 1019 -98 227 -258 163 -66 597 -232 1313 -132 163 -404 467 -236 901 -164 483 -98 195 -96 489 -134 103 -238 169 -66 67 -68 299 -100 497 -68 65 -134 1635 -304 1153 -100 539 -168 265 -200 499 -166 535 -100 397 -168 931 -100 131 -66 631 -134 897 -270 1233 -100 65 -132 131 -334 663 -66 163 -66 131 -132 705 -98 571 -200 433 -100 237 -234 229 -132 1627 -66 569 -100 715 -66 1863 -272 265 -68 301 -98 465 -68 97 -134 99 -66 395 -136 1405 -66 529 -132 63 -196 579 -132 413 -260 129 -136 101 -166 1201 -134 833 -134 393 -66 335 -172 201 -68 1027 -96 753 -64 815 -66 97 -64 1341 -132 289 -160 127 -66 99 -228 1083 -96 163 -66 259 -64 159 -98 2409 -168 767 -200 367 -66 1675 -66 1067 -98 3407 -200 99 -66 1403 -166 99 -134 439 -200 329 -136 599 -66 637 -66 835 -66 1099 -98 99 -66 463 -166 165 -100 461 -164 3037 -66 655 -66 97 -98 229 -130 355 -132 1443 -66 527 -98 881 -98 229 -162 127 -96 583 -64 65 -162 489 -166 885 -194 257 -98 1539 -66 293 -166 229 -132 655 -98 757 -49522 271 -758 689 -1264 737 -670 293 -1152 811 -1144 341 -664 773 -678 327 -1118 807 -1144 835 -1146 781 -1126 873 -1096 347 -622 877 -624 321 -1106 843 -1098 871 -1098 843 -1106 379 -610 841 -584 381 -1122 365 -602 845 -1116 837 -610 381 -1056 889 -1078 383 -614 827 -1110 877 -592 353 -1108 845 -1120 839 -1120 347 -602 849 -1110 865 -612 361 -1072 869 -1114 351 -618 861 -618 343 -1090 853 -1106 387 -618 797 -674 347 -1084 389 -574 867 -584 381 -1114 841 -1102 845 -1116 839 -1112 843 -1098 875 -1086 383 -584 865 -588 375 -1100 861 -1112 851 -1084 853 -1108 847 -1106 381 -584 857 -610 383 -1080 357 -602 871 -602 385 -1084 383 -616 823 -610 373 -1086 381 -590 871 -1084 839 -628 353 -1102 875 -1100 349 -9404 875 -1060 871 -1086 887 -1088 879 -1058 863 -1086 855 -1132 845 -1078 871 -1076 857 -1098 881 -1082 861 -1088 843 -1120 853 -1074 879 -1074 879 -1068 889 -614 341 -1090 387 -616 863 -624 345 -1088 391 -590 857 -612 385 -1058 393 -596 843 -1088 889 -1078 879 -578 387 -1082 875 -1076 415 -550 881 -1070 877 -592 391 -1114 821 -1104 373 -620 821 -624 361 -1072 903 -1086 855 -1092 843 -1086 905 -1054 387 -614 863 -618 347 -1088 853 -1114 845 -1090 867 -1070 381 -610 885 -584 385 -1052 407 -578 877 -1052 899 -600 389 -1048 907 -1074 383 -586 877 -1072 877 -594 359 -1076 875 -1082 891 -1088 363 -616 855 -1084 857 -592 381 -1088 883 -1086 385 -572 +RAW_Data: 889 -624 353 -1082 853 -1096 379 -594 853 -624 353 -1092 417 -582 847 -612 385 -1076 847 -1080 883 -1052 913 -1044 907 -1076 849 -1088 383 -602 867 -616 361 -1068 901 -1072 865 -1104 831 -1080 879 -1098 397 -586 855 -626 355 -1084 381 -592 873 -616 351 -1084 385 -624 821 -620 359 -1086 387 -584 883 -1086 877 -592 355 -1106 853 -1086 387 -69570 97 -100 99 -2620 131 -636 333 -102 235 -236 67 -68 363 -66 201 -100 567 -102 267 -164 101 -134 65 -68 197 -68 297 -166 671 -100 469 -336 165 -100 201 -66 169 -230 169 -204 329 -624 67 -98 265 -232 193 -168 299 -100 235 -138 101 -370 165 -294 333 -622 231 -130 129 -130 353 -132 195 -162 359 -164 67 -68 333 -100 133 -688 235 -236 497 -198 293 -98 129 -296 293 -164 229 -128 229 -132 193 -400 165 -66 163 -98 361 -164 355 -196 587 -164 131 -98 263 -554 99 -130 129 -130 191 -464 99 -132 67 -100 167 -604 329 -66 199 -68 133 -102 163 -66 2971 -132 785 -66 329 -96 323 -100 201 -136 301 -66 1959 -166 867 -134 467 -66 297 -100 835 -100 753 -166 165 -64 67 -370 335 -66 559 -232 165 -334 65 -162 129 -354 163 -64 131 -134 265 -300 263 -132 267 -296 327 -198 99 -132 535 -132 469 -866 231 -860 99 -232 503 -134 99 -198 233 -134 267 -200 97 -358 297 -164 259 -98 227 -166 135 -66 323 -100 97 -294 131 -164 129 -98 295 -96 129 -426 299 -100 67 -102 623 -100 163 -194 127 -360 563 -134 199 -428 493 -98 229 -130 257 -64 165 -100 131 -98 163 -692 357 -64 161 -98 321 -64 389 -230 65 -692 227 -130 261 -132 231 -162 287 -298 97 -460 393 -130 301 -168 331 -100 269 -202 101 -134 201 -102 99 -132 199 -204 235 -664 65 -562 133 -328 463 -100 291 -194 159 -162 227 -98 293 -328 165 -128 227 -574 535 -332 197 -168 65 -300 131 -66 389 -1078 131 -64 259 -64 223 -98 257 -164 63 -328 433 -134 65 -602 131 -68 333 -136 369 -66 297 -264 427 -66 97 -130 429 -102 133 -136 203 -240 167 -236 329 -526 67 -132 133 -168 331 -360 65 -66 331 -296 267 -134 469 -132 595 -230 661 -662 299 -100 265 -200 203 -168 801 -100 133 -68 399 -132 99 -100 161 -390 65 -298 65 -98 261 -130 161 -128 257 -66 67 -134 621 -98 227 -328 99 -230 129 -294 193 -96 195 -318 425 -526 129 -196 163 -162 65 -132 293 -130 63 -66 325 -128 63 -130 293 -66 199 -200 269 -206 133 -198 325 -98 163 -100 97 -98 261 -164 67 -98 167 -430 131 -494 131 -164 +RAW_Data: 97 -98 861 -66 1199 -166 231 -100 651 -166 197 -104 439 -98 131 -64 493 -98 883 -96 99 -98 3327 -66 131 -264 733 -134 2133 -166 131 -102 303 -136 535 -134 701 -98 355 -228 131 -202 99 -134 99 -100 791 -166 169 -202 671 -100 741 -100 263 -66 165 -68 935 -132 197 -198 673 -100 605 -66 1457 -98 1195 -166 2347 -134 505 -100 1469 -66 391 -100 229 -100 1171 -98 939 -100 459 -170 369 -134 231 -162 127 -98 95 -66 195 -98 195 -66 299 -100 331 -98 65 -232 369 -132 201 -68 167 -166 1481 -102 501 -160 1257 -66 2307 -64 623 -164 2079 -66 1101 -98 423 -64 659 -68 431 -136 99 -100 435 -130 167 -168 835 -200 135 -104 133 -100 503 -68 1437 -232 821 -132 357 -96 463 -66 263 -64 683 -132 165 -96 655 -166 3939 -100 1169 -132 2443 -98 197 -132 425 -234 233 -162 1043 -66 197 -100 2793 -134 167 -104 675 -100 197 -134 1367 -102 763 -132 265 -230 133 -102 365 -100 167 -66 1069 -66 837 -100 295 -160 97 -64 129 -132 617 -164 197 -100 133 -136 337 -172 133 -66 557 -98 951 -66 263 -130 587 -66 729 -196 335 -166 933 -432 369 -100 199 -296 225 -98 355 -66 129 -64 557 -98 289 -66 355 -128 193 -162 267 -134 299 -98 165 -170 303 -640 1031 -134 99 -66 135 -68 771 -166 171 -104 201 -134 131 -68 635 -428 661 -292 749 -430 1161 -100 905 -98 65 -98 657 -262 2837 -132 67 -66 265 -132 631 -66 1037 -296 97 -98 1703 -302 367 -100 505 -232 497 -362 333 -134 591 -100 755 -232 67 -130 587 -66 231 -168 65 -332 99 -66 267 -232 393 -134 65 -132 131 -428 133 -200 165 -202 199 -168 165 -102 269 -100 333 -852 201 -134 233 -202 65 -200 563 -768 265 -136 169 -102 169 -598 333 -202 267 -134 267 -328 163 -130 625 -500 199 -200 99 -270 65 -134 65 -198 65 -100 99 -596 493 -66 99 -66 331 -232 103 -136 373 -168 831 -170 65 -672 163 -102 133 -136 331 -100 333 -234 101 -100 99 -200 99 -100 201 -302 199 -600 301 -202 135 -134 705 -166 435 -530 97 -198 131 -198 195 -66 163 -392 293 -66 295 -370 229 -198 65 -100 405 -134 165 -134 133 -170 337 -236 205 -274 267 -134 329 -132 195 -132 503 -132 133 -136 133 -334 197 -196 299 -168 101 -100 233 -100 439 -134 301 -332 331 -298 433 -406 433 -68 167 -100 203 -100 101 -102 99 -328 397 -234 205 -168 133 -364 63 -202 397 -198 95 -394 267 -134 569 -66 201 -102 133 -136 101 -102 99 -132 99 -196 197 -498 197 -102 135 -170 +RAW_Data: 331 -164 63 -162 1267 -66 163 -130 129 -66 725 -164 231 -64 853 -66 101 -134 199 -102 99 -68 365 -66 357 -130 815 -64 357 -98 97 -98 97 -66 65 -466 231 -172 3749 -66 849 -130 917 -64 327 -64 1013 -98 555 -332 795 -100 571 -132 769 -132 401 -134 1297 -134 377 -138 435 -100 401 -100 667 -100 1761 -66 667 -66 1533 -236 233 -98 885 -130 457 -66 999 -66 165 -66 833 -134 695 -166 501 -66 499 -200 329 -64 197 -134 441 -100 2099 -98 491 -134 197 -130 2225 -132 65 -100 689 -64 193 -160 159 -96 195 -98 323 -164 259 -98 535 -472 771 -66 665 -270 665 -66 595 -266 2191 -64 643 -98 1287 -98 741 -100 233 -200 569 -194 261 -68 637 -100 97 -66 491 -158 395 -138 1017 -66 627 -262 559 -64 327 -98 263 -134 99 -102 201 -102 337 -66 167 -68 679 -100 471 -134 195 -66 133 -202 693 -96 197 -98 391 -164 99 -98 3883 -194 461 -100 237 -168 1891 -68 301 -68 969 -166 1439 -294 551 -130 389 -98 99 -196 167 -102 505 -66 569 -234 901 -98 407 -136 469 -66 769 -98 769 -166 1263 -266 297 -98 1701 -200 203 -168 329 -232 65 -100 329 -164 803 -100 135 -200 233 -166 135 -272 265 -134 197 -100 133 -134 539 -232 197 -396 165 -366 263 -68 233 -102 365 -132 233 -100 135 -266 199 -234 167 -232 97 -524 127 -128 389 -98 305 -364 261 -130 257 -162 589 -464 361 -66 229 -134 161 -100 203 -432 265 -66 199 -66 199 -366 229 -236 99 -134 99 -100 131 -168 133 -100 131 -236 267 -132 297 -264 291 -132 167 -234 65 -100 199 -66 333 -730 237 -440 365 -102 99 -100 99 -132 99 -100 1429 -134 427 -100 97 -100 131 -164 799 -170 1077 -100 431 -66 133 -168 737 -134 197 -230 65 -102 803 -132 491 -98 429 -198 471 -134 365 -66 299 -236 65 -66 2837 -102 399 -64 585 -64 523 -196 97 -98 295 -196 555 -160 261 -500 299 -396 333 -236 133 -68 327 -100 199 -204 699 -66 701 -100 65 -164 65 -370 195 -196 97 -66 193 -130 129 -360 195 -130 231 -96 291 -64 455 -228 293 -196 291 -162 97 -194 621 -130 847 -66 395 -66 161 -128 193 -130 293 -98 231 -170 67 -134 297 -360 167 -266 263 -526 263 -132 229 -98 191 -160 159 -100 721 -234 101 -100 99 -130 259 -258 265 -632 687 -164 133 -134 631 -100 199 -102 165 -560 299 -200 265 -332 431 -870 99 -266 503 -364 135 -66 269 -68 499 -100 265 -102 263 -102 569 -234 719 -132 99 -196 419 -262 163 -688 95 -66 165 -128 95 -66 +RAW_Data: 295 -98 987 -196 517 -100 489 -66 355 -132 563 -198 867 -134 1413 -134 541 -134 767 -100 193 -98 1799 -102 467 -134 299 -96 323 -66 261 -100 259 -66 229 -96 851 -66 369 -266 469 -66 101 -98 163 -136 267 -432 859 -130 523 -66 197 -134 1027 -132 227 -194 393 -98 807 -166 235 -100 133 -66 165 -102 133 -136 371 -162 1411 -132 865 -200 471 -100 133 -68 299 -66 633 -98 329 -234 401 -98 1505 -132 133 -134 331 -262 163 -66 261 -98 289 -64 201 -68 1055 -96 391 -66 951 -298 265 -202 297 -66 401 -68 131 -100 1733 -98 941 -66 803 -98 847 -64 3701 -100 721 -160 357 -166 1799 -66 329 -100 99 -102 363 -198 167 -136 197 -66 567 -66 199 -236 1247 -166 2455 -68 1107 -200 235 -100 2355 -130 913 -98 877 -98 163 -196 97 -66 427 -100 801 -134 867 -98 263 -68 441 -134 561 -98 1671 -134 865 -68 935 -132 163 -102 975 -66 1343 -132 1339 -134 369 -100 1107 -66 1167 -168 631 -232 835 -66 1027 -132 333 -166 265 -98 1207 -98 223 -98 455 -64 2095 -134 933 -136 233 -68 335 -136 305 -100 1737 -66 427 -100 263 -130 323 -66 227 -66 717 -100 265 -100 65 -128 355 -66 367 -132 95 -230 229 -100 131 -64 493 -132 291 -396 393 -130 259 -196 227 -288 397 -68 229 -430 99 -302 237 -700 65 -66 65 -100 133 -200 101 -336 133 -166 237 -202 67 -302 67 -68 333 -132 263 -102 267 -296 163 -166 233 -168 363 -64 295 -298 537 -166 431 -200 431 -166 63 -258 363 -164 563 -234 199 -68 299 -100 325 -754 295 -196 65 -98 165 -132 301 -134 131 -134 97 -68 405 -68 233 -134 271 -134 67 -168 101 -136 133 -366 99 -132 67 -132 265 -200 233 -100 201 -136 101 -66 263 -132 129 -66 293 -582 263 -132 1103 -134 203 -168 97 -66 197 -264 131 -168 133 -132 65 -134 199 -134 101 -100 131 -436 99 -232 97 -398 231 -362 65 -202 301 -396 297 -98 199 -134 265 -164 101 -168 267 -102 405 -170 99 -102 397 -132 97 -98 295 -98 1179 -100 135 -136 131 -134 765 -134 465 -168 439 -232 403 -100 65 -134 931 -100 169 -136 237 -68 231 -234 199 -68 401 -134 541 -166 429 -166 1607 -368 533 -66 363 -66 133 -134 433 -166 297 -238 201 -100 201 -170 199 -134 273 -136 99 -134 167 -238 133 -66 265 -134 165 -132 165 -132 97 -228 723 -198 415 -64 491 -298 257 -66 231 -192 225 -96 227 -98 193 -96 521 -198 65 -66 231 -166 163 -98 465 -66 133 -132 195 -130 225 -162 521 -130 63 -66 199 -228 +RAW_Data: 817 -162 449 -160 719 -198 469 -68 133 -68 1101 -132 593 -230 1105 -100 131 -134 231 -66 329 -196 685 -96 557 -68 1263 -68 101 -68 397 -100 65 -66 625 -66 97 -132 1099 -66 493 -66 757 -98 1151 -66 303 -134 1901 -66 99 -100 665 -262 991 -98 791 -66 1925 -168 865 -232 835 -98 505 -102 99 -100 535 -100 169 -134 427 -132 863 -68 167 -134 975 -100 133 -268 1339 -100 1453 -66 1445 -162 195 -64 3623 -66 237 -68 1063 -308 1449 -98 1111 -132 167 -102 855 -270 199 -134 297 -134 267 -168 863 -234 637 -66 567 -230 99 -200 3325 -198 845 -66 289 -66 131 -66 815 -130 1093 -100 167 -100 429 -98 1703 -166 195 -64 971 -98 163 -192 195 -168 439 -132 329 -132 67 -134 67 -134 1591 -168 407 -100 867 -68 399 -134 661 -100 663 -66 237 -136 395 -232 131 -66 695 -100 627 -264 913 -66 1083 -98 287 -66 199 -132 335 -100 1031 -68 99 -100 3815 -98 165 -66 129 -98 163 -128 563 -98 779 -96 223 -64 161 -164 2025 -66 1741 -172 101 -136 203 -102 665 -100 475 -64 167 -100 637 -98 997 -170 1207 -136 233 -166 233 -168 635 -132 199 -100 235 -270 199 -98 131 -102 169 -170 293 -98 323 -164 427 -334 233 -168 267 -68 369 -100 263 -368 101 -66 665 -98 265 -100 133 -100 99 -168 133 -66 133 -132 133 -66 269 -134 435 -68 267 -136 271 -500 163 -100 163 -166 355 -132 97 -98 323 -194 63 -688 463 -130 97 -396 65 -100 357 -194 461 -98 161 -130 223 -162 165 -352 461 -300 267 -166 233 -464 329 -100 293 -362 163 -228 289 -66 229 -66 195 -162 325 -66 261 -98 127 -424 299 -302 367 -68 265 -272 429 -98 161 -98 393 -296 65 -130 161 -196 261 -66 473 -234 97 -98 263 -160 323 -98 67 -132 697 -298 99 -134 233 -202 97 -134 301 -200 307 -100 101 -134 865 -166 231 -202 233 -100 301 -170 169 -102 169 -200 65 -98 595 -166 231 -234 661 -66 473 -334 165 -304 365 -266 97 -502 363 -134 133 -236 65 -100 99 -134 99 -170 235 -66 333 -100 195 -100 133 -300 133 -102 301 -304 65 -100 99 -100 131 -202 135 -134 65 -200 363 -66 263 -498 67 -68 295 -194 321 -368 435 -100 97 -664 99 -100 569 -66 133 -66 67 -134 199 -136 101 -68 301 -68 405 -198 133 -132 581 -132 165 -98 159 -98 197 -66 229 -130 131 -294 133 -96 423 -100 427 -300 357 -132 291 -64 95 -194 455 -98 263 -100 359 -196 65 -162 227 -162 157 -96 157 -230 589 -132 325 -134 535 -66 267 -100 135 -302 +RAW_Data: 131 -134 599 -166 393 -98 369 -236 197 -100 401 -232 569 -134 135 -70 337 -134 101 -136 135 -100 1895 -66 401 -170 503 -66 1633 -66 601 -66 355 -96 683 -100 729 -68 133 -132 433 -68 569 -100 133 -68 201 -132 835 -100 465 -68 527 -98 193 -200 1129 -166 535 -100 199 -98 259 -132 227 -64 1597 -98 261 -192 753 -100 911 -66 667 -298 131 -100 263 -66 1051 -230 787 -66 935 -66 233 -98 885 -236 431 -66 197 -162 521 -68 167 -196 263 -96 589 -98 517 -66 1439 -64 777 -66 3219 -132 679 -134 205 -68 507 -198 749 -200 199 -168 167 -100 133 -134 201 -68 731 -66 495 -198 737 -66 237 -68 135 -100 167 -234 1535 -68 873 -66 373 -66 67 -232 297 -68 65 -66 1095 -68 327 -130 63 -132 1715 -66 2261 -100 321 -132 197 -164 457 -232 1291 -132 405 -68 1001 -68 1133 -272 471 -66 99 -134 1403 -68 167 -68 1091 -336 933 -134 1207 -132 265 -68 267 -66 99 -366 265 -66 1469 -258 367 -168 429 -132 129 -66 491 -132 343 -100 65 -100 263 -136 199 -164 273 -204 791 -100 901 -66 167 -98 165 -64 559 -132 619 -132 1087 -128 2283 -398 1467 -164 259 -130 1927 -130 421 -98 1085 -66 705 -68 1843 -168 875 -170 203 -136 341 -640 199 -66 133 -554 161 -196 63 -66 521 -292 163 -160 95 -158 127 -192 197 -100 587 -130 397 -662 261 -66 193 -130 259 -66 361 -64 459 -98 197 -560 655 -130 389 -66 1135 -100 133 -130 131 -98 1011 -100 561 -66 685 -164 457 -132 2469 -200 609 -66 665 -66 67 -132 327 -200 1657 -134 919 -132 651 -100 327 -230 191 -130 263 -358 95 -130 549 -98 99 -68 299 -100 461 -132 99 -472 165 -134 99 -66 99 -132 399 -102 169 -102 697 -166 233 -132 333 -632 197 -164 865 -266 101 -68 533 -166 299 -100 163 -228 259 -66 327 -200 65 -66 229 -100 363 -230 197 -336 165 -102 893 -300 65 -132 231 -370 265 -230 99 -98 229 -518 199 -100 401 -724 225 -98 63 -96 231 -64 291 -292 65 -98 131 -98 159 -158 127 -194 161 -292 65 -98 133 -66 297 -66 303 -168 97 -168 231 -234 269 -532 135 -168 99 -168 301 -528 99 -506 199 -368 399 -132 329 -372 99 -68 133 -264 197 -100 201 -200 67 -134 131 -270 133 -134 133 -198 327 -200 65 -100 331 -262 161 -166 469 -534 167 -738 131 -100 367 -232 101 -100 265 -604 65 -170 99 -166 299 -102 169 -132 99 -398 229 -330 197 -166 335 -366 97 -98 131 -200 269 -100 199 -168 131 -134 537 -98 265 -100 335 -236 99 -366 +RAW_Data: 459 -100 453 -130 419 -130 519 -96 63 -130 2077 -66 767 -64 127 -134 1961 -296 529 -202 637 -134 527 -100 201 -68 633 -66 163 -360 1029 -68 765 -100 867 -66 503 -100 131 -66 841 -98 165 -68 237 -66 509 -100 501 -302 235 -66 99 -164 227 -130 551 -196 327 -66 1571 -132 99 -68 867 -66 163 -96 161 -130 129 -130 549 -130 487 -166 1801 -66 229 -66 197 -232 325 -66 425 -198 131 -64 295 -166 735 -66 533 -98 227 -130 129 -262 425 -100 263 -66 129 -132 97 -168 971 -170 405 -68 199 -134 475 -202 297 -98 1445 -98 395 -196 161 -66 225 -134 1803 -100 473 -102 1499 -66 199 -100 701 -132 165 -68 133 -102 303 -98 735 -102 805 -100 827 -100 235 -100 65 -266 637 -68 693 -66 1383 -228 819 -66 233 -304 435 -198 203 -136 1135 -270 1709 -64 227 -64 581 -134 505 -66 2203 -64 293 -64 753 -66 551 -132 747 -64 1303 -64 463 -66 229 -102 1877 -266 871 -166 1357 -64 819 -66 465 -198 693 -68 165 -64 95 -128 3785 -132 1465 -100 299 -102 329 -164 595 -134 1029 -66 299 -168 1263 -166 331 -68 967 -100 101 -102 603 -260 165 -132 467 -66 233 -66 235 -102 475 -100 135 -68 301 -134 297 -98 131 -102 269 -466 99 -134 237 -166 135 -168 203 -102 265 -68 503 -66 233 -66 637 -134 101 -200 199 -166 293 -554 361 -328 367 -264 533 -238 167 -68 135 -170 99 -300 591 -298 133 -236 299 -66 231 -368 263 -232 435 -136 133 -102 133 -200 133 -134 163 -134 167 -168 299 -66 265 -100 133 -240 135 -132 263 -170 269 -200 501 -396 263 -98 227 -132 129 -292 427 -66 165 -102 627 -602 99 -66 301 -168 199 -100 563 -330 165 -134 233 -136 65 -332 499 -100 131 -232 325 -96 65 -132 195 -98 393 -624 323 -68 133 -98 195 -162 231 -100 263 -132 231 -102 133 -236 99 -236 231 -166 65 -102 133 -268 101 -102 299 -136 267 -164 493 -64 229 -258 291 -326 263 -198 391 -134 167 -202 365 -594 133 -102 201 -134 503 -396 429 -204 169 -400 197 -170 267 -132 403 -466 297 -98 469 -234 395 -132 233 -100 165 -100 165 -66 197 -68 297 -166 501 -134 133 -100 65 -166 631 -68 297 -134 199 -100 165 -68 299 -266 133 -66 165 -100 231 -490 557 -134 371 -164 299 -170 733 -164 239 -334 335 -66 299 -300 199 -170 103 -100 233 -102 641 -168 65 -100 995 -66 265 -160 259 -130 129 -226 425 -100 355 -726 97 -688 99 -66 233 -266 299 -942 167 -102 167 -166 65 -100 367 -136 99 -134 199 -134 267 -164 +RAW_Data: 67 -68 233 -66 899 -66 163 -96 485 -98 355 -130 943 -100 235 -168 499 -104 1367 -98 297 -100 635 -68 1169 -100 67 -134 835 -264 959 -164 129 -98 419 -196 589 -66 421 -66 1717 -100 133 -100 265 -134 227 -356 455 -166 163 -66 1055 -100 1455 -134 463 -98 2191 -132 295 -132 335 -66 709 -64 619 -98 959 -68 835 -170 603 -134 1033 -134 635 -168 759 -232 397 -198 397 -164 1267 -166 257 -198 1295 -100 239 -104 563 -204 335 -198 203 -68 901 -68 1255 -134 1697 -66 793 -66 1691 -68 201 -100 765 -66 165 -132 131 -230 131 -66 917 -66 335 -338 231 -170 827 -98 199 -136 301 -196 65 -98 199 -200 765 -134 403 -98 333 -68 1691 -132 2565 -64 569 -170 1255 -264 65 -132 1243 -132 2527 -66 259 -66 1739 -100 1309 -198 167 -238 337 -66 131 -68 1973 -362 299 -100 1387 -96 129 -164 423 -230 3875 -96 4283 -98 165 -98 515 -134 469 -68 171 -102 1163 -100 65 -298 461 -66 367 -136 205 -168 371 -98 491 -164 161 -262 1093 -100 299 -100 269 -334 1205 -98 63 -98 261 -64 457 -98 +RAW_Data: 57 -144 401 -86 173 -202 143 -258 133 -88 257 -144 287 -58 402 -56 259 -230 259 -86 85 -96 95 -174 286 -162 57 -230 253 -400 229 -88 536 -58 85 -72 167 -110 263 -72 229 -58 85 -86 87 -262 119 -288 163 -210 321 -320 186 -140 261 -96 143 -456 117 -216 143 -246 239 -102 121 -72 71 -191 167 -263 191 -96 239 -80 57 -116 143 -118 167 -168 215 -288 191 -106 287 -114 517 -88 113 -394 173 -70 215 -100 661 -86 201 -114 259 -58 287 -86 57 -202 399 -200 57 -288 229 -144 115 -1425 83 -142 173 -86 459 -112 223 -144 201 -116 143 -114 196 -17422 287 -614 1075 -1132 533 -560 1125 -1112 561 -530 1133 -1088 585 -512 1129 -1104 563 -1102 571 -1072 591 -524 1137 -538 1115 -19392 589 -522 1139 -1090 569 -520 1137 -1100 587 -520 1135 -1092 569 -514 1155 -1076 599 -1062 585 -1086 585 -532 1125 -528 1145 -19396 581 -504 1155 -1064 619 -506 1145 -1080 595 -508 1149 -1062 587 -536 1129 -1088 585 -1090 589 -1062 587 -510 1177 -506 1149 -19394 587 -524 1147 -1076 597 -512 1129 -1072 617 -498 1159 -1066 599 -514 1147 -1076 595 -1060 613 -1060 589 -506 1179 -510 1155 -19378 605 -514 1129 -1098 601 -488 1177 -1062 583 -510 1161 -1072 587 -516 1169 -1058 587 -1082 589 -1076 593 -532 1121 -536 1127 -19444 549 -542 1129 -1092 601 -510 1147 -1098 581 -506 1123 -1100 585 -510 1147 -1106 591 -1060 597 -1060 595 -510 1151 -534 1157 -19390 593 -512 1163 -1064 597 -510 1173 -1042 617 -510 1159 -1056 579 -556 1133 -1054 609 -1060 607 -1078 585 -528 1147 -516 1135 -19444 559 -534 1165 -1052 605 -510 1149 -1062 599 -520 1173 -1054 591 -540 1111 -1116 573 -1088 593 -1042 615 -534 1117 -536 1129 -19436 569 -530 1157 -1052 605 -504 1177 -1062 591 -536 1113 -1114 589 -514 1125 -1112 563 -1084 587 -1080 589 -536 1123 -532 1165 -19392 599 -524 1143 -1080 595 -540 1125 -1090 563 -534 1149 -1084 567 -534 1147 -1092 587 -1086 585 -1064 565 -558 1123 -532 1143 -19450 549 -556 1121 -1086 585 -534 1137 -1094 583 -516 1133 -1114 563 -536 1123 -1108 573 -1082 597 -1078 565 -532 1143 -524 1135 -19464 561 -528 1149 -1066 613 -508 1151 -1076 587 -532 1125 -1076 609 -506 1175 -1076 563 -1106 563 -1084 591 -534 1157 -484 1179 -19414 589 -528 1131 -1096 587 -520 1163 -1080 563 -550 1121 -1098 555 -562 1117 -1082 575 -1112 563 -1104 559 -558 1121 -530 1149 -19442 591 -498 1175 -1066 585 -534 1121 -1114 565 -540 1115 -1096 585 -538 1123 -1110 559 -1086 585 -1084 589 -530 1125 -558 1121 -19454 563 -542 1163 -1044 585 -558 1131 -1092 571 -536 1133 -1088 587 -518 1149 -1086 601 -1058 587 -1080 611 -510 +RAW_Data: 1125 -536 1145 -19444 567 -542 1151 -1086 581 -534 1133 -1084 583 -530 1141 -1090 587 -516 1121 -1114 591 -1062 595 -1092 567 -538 1131 -536 1145 -19448 589 -516 1143 -1076 591 -540 1115 -1090 591 -538 1115 -1096 597 -512 1155 -1078 581 -1082 585 -1104 559 -530 1153 -516 1147 -19438 589 -526 1157 -1056 609 -534 1137 -1078 585 -532 1149 -1076 585 -536 1123 -1104 587 -1062 597 -1082 587 -536 1121 -554 1121 -19464 555 -560 1123 -1104 563 -542 1131 -1096 565 -536 1143 -1060 621 -492 1175 -1078 571 -1100 577 -1092 591 -494 1167 -538 1117 -19452 593 -538 1133 -1074 603 -510 1157 -1062 595 -548 1115 -1102 573 -538 1139 -1094 567 -1094 583 -1092 567 -536 1127 -560 1113 -19478 563 -534 1151 -1084 569 -534 1135 -1116 565 -534 1135 -1084 583 -532 1155 -1060 587 -1084 589 -1084 581 -536 1125 -546 1141 -19460 577 -536 1123 -1102 565 -554 1119 -1096 593 -520 1133 -1108 563 -546 1131 -1088 569 -1094 573 -1100 583 -526 1147 -540 1123 -19466 587 -530 1129 -1100 587 -510 1143 -1084 609 -510 1131 -1110 567 -542 1121 -1102 567 -1110 563 -1106 567 -532 1149 -518 1145 -19458 573 -534 1147 -1082 575 -556 1149 -1048 589 -532 1157 -1088 565 -536 1129 -1088 589 -1106 563 -1086 587 -536 1129 -548 1147 -4298 103 -56 87 -344 87 -258 85 -278 215 -70 77 -344 279 -56 87 -56 197 -198 143 -288 362 -86 605 -144 57 -268 95 -114 143 -144 173 -144 143 -402 57 -202 259 -391 652 -340 427 -230 173 -356 97 -144 111 -246 219 -96 191 -114 173 -288 115 -56 109 -106 199 -106 73 -130 57 -172 85 -260 373 -56 629 -200 690 -230 273 -120 85 -460 85 -314 77 -78 111 -88 401 -116 171 -312 71 -500 81 -224 229 -88 257 -370 181 -172 200 -116 535 -174 113 -294 213 -359 445 -144 258 -114 115 -202 675 -509 239 -432 373 -538 85 -58 113 -86 761 -104 113 -318 443 -70 143 -144 647 -204 111 -334 87 -114 115 -144 113 -188 177 -144 199 -260 143 -86 87 -622 57 -116 171 -58 139 -222 55 -346 315 -76 345 -114 139 -171 195 -52 53 -98 119 -144 143 -244 95 -72 95 -96 167 -302 253 -186 307 -444 287 -449 115 -172 57 -172 316 -202 85 -370 697 -116 57 -144 171 -202 259 -114 85 -144 87 -315 85 -58 201 -116 171 -272 121 -358 171 -403 113 -86 115 -202 489 -229 115 -392 95 -116 171 -140 93 -102 143 -543 245 -358 215 -120 387 -288 171 -202 221 -202 115 -748 57 -316 143 -260 143 -288 115 -316 115 -58 85 -288 143 -460 485 -96 71 -104 199 -96 199 -202 143 -86 201 -116 85 -230 211 -288 115 -605 365 -126 53 -172 +RAW_Data: 317 -144 57 -486 53 -282 115 -585 97 -72 229 -174 257 -440 225 -86 173 -518 243 -167 95 -259 137 -96 694 -58 227 -80 279 -287 71 -72 301 -72 121 -106 51 -84 57 -58 199 -260 143 -288 219 -174 113 -681 115 -172 403 -58 113 -116 113 -432 171 -202 55 -108 95 -212 113 -72 527 -166 95 -212 195 -108 603 -142 239 -296 173 -346 373 -287 53 -80 79 -72 95 -238 95 -312 167 -618 143 -288 95 -72 95 -72 141 -210 55 -258 143 -328 305 -58 87 -86 315 -116 195 -218 85 -290 285 -220 215 -189 201 -58 57 -645 119 -96 71 -144 119 -406 143 -72 191 -72 631 -268 344 -56 115 -260 315 -140 455 -518 57 -58 171 -144 488 -86 219 -232 257 -144 85 -174 171 -260 115 -56 87 -166 197 -58 83 -56 85 -288 113 -410 115 -172 163 -202 113 -58 201 -144 201 -86 143 -264 167 -212 113 -116 139 -72 181 -287 343 -430 201 -260 201 -462 143 -192 301 -230 191 -454 187 -144 315 -164 143 -477 165 -58 201 -114 143 -490 115 -86 201 -58 113 -88 85 -58 203 -198 375 -86 171 -346 95 -88 257 -170 81 -56 143 -172 335 -230 173 -202 133 -471 187 -264 215 -86 115 -198 159 -72 179 -112 195 -116 449 -216 93 -96 167 -216 71 -216 71 -166 235 -86 447 -102 101 -226 195 -213 71 -144 215 -144 215 -261 241 -136 269 -142 263 -311 215 -172 201 -144 265 -168 71 -404 259 -86 85 -230 115 -650 143 -202 749 -512 248 -316 201 -154 71 -96 95 -360 105 -56 57 -432 95 -288 95 -286 95 -96 166 -144 93 -144 167 -150 904 -162 95 -526 287 -244 95 -240 383 -120 167 -394 430 -854 95 -72 143 -194 227 -120 167 -264 405 -144 143 -72 143 -72 141 -120 187 -86 143 -164 170 -96 143 -58 143 -86 402 -166 153 -120 95 -96 69 -96 71 -359 404 -338 71 -225 93 -74 97 -54 161 -114 319 -288 113 -116 459 -202 115 -114 115 -116 143 -86 57 -56 87 -114 85 -375 113 -58 311 -240 203 -288 95 -72 119 -383 213 -384 115 -86 171 -58 53 -104 401 -58 115 -86 373 -116 143 -144 161 -216 406 -72 263 -96 215 -72 95 -94 167 -96 191 -240 95 -94 214 -120 403 -116 200 -114 57 -172 220 -120 137 -364 334 -392 115 -260 199 -116 373 -188 95 -110 143 -172 87 -114 172 -230 57 -316 201 -56 249 -485 171 -202 87 -86 85 -144 345 -86 171 -58 259 -58 295 -120 95 -120 71 -192 635 -118 167 -96 375 -72 119 -120 261 -144 167 -96 95 -96 923 -215 71 -433 71 -477 +RAW_Data: 191 -240 85 -72 637 -408 213 -510 261 -168 143 -126 79 -106 167 -72 117 -218 251 -168 119 -96 215 -182 191 -238 517 -116 201 -144 255 -154 97 -94 215 -72 95 -120 71 -288 261 -106 434 -96 606 -232 229 -432 85 -174 343 -58 329 -156 55 -116 259 -144 488 -56 307 -339 115 -202 334 -88 113 -86 57 -174 143 -144 401 -376 85 -240 267 -82 95 -216 137 -158 85 -144 143 -58 221 -308 295 -114 87 -114 301 -120 358 -517 71 -262 191 -144 57 -140 165 -407 53 -262 217 -120 238 -358 119 -357 71 -72 119 -96 428 -72 95 -72 167 -72 93 -240 335 -96 357 -240 173 -230 143 -114 87 -200 143 -232 287 -150 97 -288 71 -72 93 -288 115 -58 143 -230 109 -264 71 -72 119 -72 238 -242 97 -78 163 -86 115 -518 79 -560 205 -449 969 -144 507 -86 231 -114 345 -58 979 -110 85 -288 287 -404 229 -202 57 -274 233 -86 115 -202 632 -230 85 -312 369 -392 460 -450 75 -280 85 -202 201 -86 229 -174 143 -144 233 -528 115 -212 127 -202 287 -172 403 -172 139 -128 165 -138 261 -392 143 -480 142 -189 291 -80 53 -283 167 -140 113 -1008 191 -144 119 -120 71 -193 241 -462 201 -58 143 -344 539 -316 113 -174 85 -116 113 -250 239 -168 405 -168 239 -158 85 -144 115 -86 57 -86 341 -144 171 -202 85 -202 115 -114 719 -88 55 -318 257 -56 254 -86 171 -116 459 -174 171 -329 95 -134 85 -314 431 -306 77 -316 401 -86 173 -404 281 -1073 488 -94 217 -78 101 -98 214 -120 215 -340 403 -535 143 -564 115 -116 199 -58 85 -174 315 -58 335 -136 55 -260 143 -144 229 -460 143 -58 143 -144 171 -202 115 -374 291 -130 339 -82 143 -58 171 -58 201 -86 85 -174 1022 -56 85 -82 255 -240 103 -202 431 -278 95 -216 119 -72 71 -96 71 -559 57 -144 171 -88 113 -86 231 -414 131 -192 237 -360 95 -168 145 -168 213 -120 167 -96 143 -110 57 -86 259 -56 87 -777 295 -96 57 -86 173 -86 171 -404 143 -172 231 -200 57 -441 55 -58 173 -56 87 -86 171 -72 287 -72 119 -262 119 -144 71 -72 121 -310 71 -302 113 -54 193 -80 307 -58 257 -232 143 -56 143 -116 219 -72 695 -70 71 -460 85 -232 719 -363 57 -402 604 -230 287 -138 83 -172 259 -58 171 -174 55 -88 489 -114 143 -116 171 -116 143 -58 199 -144 145 -343 374 -186 235 -140 77 -86 143 -202 143 -144 113 -144 143 -58 732 -96 263 -264 71 -206 95 -168 215 -144 271 -80 139 -88 85 -414 75 -100 +RAW_Data: 285 -96 627 -362 53 -84 201 -374 113 -202 115 -202 421 -316 85 -58 139 -224 87 -86 229 -58 243 -178 267 -288 95 -336 171 -96 213 -288 71 -405 95 -96 95 -384 95 -72 213 -72 95 -96 95 -272 87 -1083 85 -58 113 -88 257 -116 143 -292 175 -318 95 -120 95 -144 95 -72 71 -216 368 -116 373 -172 115 -58 85 -116 143 -86 85 -144 201 -86 201 -202 257 -144 201 -174 113 -144 115 -144 257 -202 585 -364 173 -138 287 -422 431 -86 85 -96 869 -186 95 -52 115 -86 115 -58 55 -276 365 -86 85 -489 171 -140 577 -106 718 -144 391 -232 195 -82 143 -172 109 -120 167 -96 280 -216 145 -240 215 -186 163 -96 141 -172 159 -603 257 -108 629 -192 119 -80 87 -172 57 -144 286 -86 57 -230 344 -58 113 -537 75 -96 537 -86 403 -196 167 -264 119 -238 119 -120 167 -96 95 -478 95 -120 167 -216 1085 -96 358 -72 263 -72 69 -120 143 -96 71 -96 191 -362 55 -144 57 -260 113 -58 85 -174 55 -88 257 -86 231 -194 55 -58 115 -56 55 -339 55 -58 374 -172 139 -82 419 -98 119 -261 71 -72 71 -240 713 -86 143 -218 295 -72 53 -56 431 -58 317 -144 161 -144 373 -144 173 -144 57 -114 85 -116 195 -72 708 -172 115 -86 191 -96 506 -120 71 -174 85 -58 363 -114 317 -230 316 -200 87 -114 57 -230 115 -315 173 -280 694 -212 453 -256 143 -202 113 -540 352 -116 257 -116 457 -56 109 -58 143 -230 259 -144 259 -525 119 -408 247 -112 389 -72 431 -96 137 -236 97 -474 201 -298 71 -82 55 -116 55 -112 199 -174 191 -86 143 -144 115 -114 317 -86 85 -230 87 -114 259 -84 107 -130 143 -94 153 -86 135 -94 215 -72 239 -94 435 -96 263 -142 166 -334 87 -194 179 -96 115 -284 135 -56 57 -144 463 -204 143 -316 201 -58 403 -86 141 -288 85 -202 139 -397 171 -174 305 -202 85 -144 373 -253 161 -492 181 -191 95 -216 315 -191 71 -166 97 -126 337 -96 71 -96 189 -168 295 -84 197 -86 259 -345 137 -144 167 -796 115 -344 455 -72 119 -96 119 -550 209 -88 85 -86 143 -340 167 -260 143 -537 85 -226 51 -537 57 -260 315 -461 51 -84 199 -358 383 -96 143 -257 115 -86 173 -86 201 -144 143 -316 85 -86 479 -88 85 -72 71 -104 115 -116 267 -72 137 -144 143 -116 85 -86 373 -288 115 -200 87 -114 259 -114 259 -462 143 -144 171 -86 57 -58 137 -144 57 -634 343 -72 205 -86 143 -258 57 -232 113 -230 461 -58 185 -74 537 -86 +RAW_Data: 535 -142 57 -58 55 -116 115 -432 85 -172 259 -192 167 -120 117 -72 119 -240 334 -72 71 -267 285 -144 119 -374 85 -88 85 -114 143 -202 229 -58 143 -202 115 -202 171 -86 71 -144 87 -56 173 -373 143 -116 113 -462 169 -80 215 -148 115 -336 85 -230 163 -432 85 -374 639 -174 85 -58 57 -82 295 -352 269 -532 414 -322 95 -287 263 -268 115 -56 259 -76 85 -282 401 -305 516 -114 115 -202 171 -86 451 -110 85 -346 201 -274 149 -202 85 -364 366 -258 57 -114 259 -172 142 -144 85 -116 85 -480 171 -144 57 -352 115 -116 535 -404 315 -202 163 -158 517 -316 215 -98 85 -346 85 -144 87 -86 257 -82 167 -58 85 -116 113 -894 233 -186 77 -266 147 -72 71 -82 57 -86 171 -58 57 -86 201 -364 143 -202 115 -114 85 -88 113 -86 87 -230 57 -76 613 -72 85 -96 209 -346 458 -58 547 -490 201 -315 315 -116 75 -168 359 -335 95 -384 93 -120 71 -312 251 -366 233 -96 189 -240 263 -192 271 -58 115 -58 229 -346 459 -174 113 -144 173 -144 218 -224 57 -116 215 -72 103 -202 513 -210 433 -116 113 -174 650 -273 147 -450 375 -86 115 -172 536 -84 85 -230 85 -58 195 -468 287 -110 551 -214 167 -311 213 -250 85 -58 85 -355 113 -230 115 -144 117 -288 195 -202 57 -376 123 -144 236 -168 553 -284 119 -72 143 -188 161 -120 93 -312 335 -58 55 -260 105 -244 143 -120 381 -268 173 -268 635 -168 453 -318 71 -167 71 -406 191 -172 215 -408 119 -144 93 -120 97 -130 143 -192 308 -122 147 -550 313 -96 139 -162 167 -96 431 -80 83 -112 201 -86 287 -86 229 -116 57 -288 113 -174 143 -116 113 -144 115 -518 57 -230 57 -172 231 -86 113 -314 183 -144 119 -72 165 -446 81 -86 135 -190 143 -96 71 -72 411 -96 143 -120 69 -216 349 -72 95 -96 517 -646 163 -86 113 -116 171 -116 143 -116 113 -287 259 -114 517 -168 141 -116 105 -72 95 -96 311 -118 159 -310 191 -54 143 -258 115 -450 219 -54 339 -372 239 -72 167 -174 113 -58 57 -144 259 -172 143 -336 113 -174 85 -230 83 -668 85 -202 113 -144 57 -116 373 -316 719 -288 115 -58 75 -120 139 -144 229 -144 57 -144 171 -192 391 -202 403 -58 315 -188 259 -56 115 -144 85 -404 57 -58 105 -102 429 -406 81 -172 57 -144 287 -230 287 -220 317 -458 283 -58 113 -86 269 -72 281 -58 85 -202 113 -52 421 -58 229 -480 259 -58 143 -660 155 -638 123 -86 57 -86 143 -346 143 -144 57 -144 \ No newline at end of file diff --git a/lib/subghz/protocols/ansonic.c b/lib/subghz/protocols/ansonic.c new file mode 100644 index 00000000..81b196e3 --- /dev/null +++ b/lib/subghz/protocols/ansonic.c @@ -0,0 +1,346 @@ +#include "ansonic.h" +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/encoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" + +#define TAG "SubGhzProtocolAnsonic" + +#define DIP_PATTERN "%c%c%c%c%c%c%c%c%c%c" +#define CNT_TO_DIP(dip) \ + (dip & 0x0800 ? '1' : '0'), (dip & 0x0400 ? '1' : '0'), (dip & 0x0200 ? '1' : '0'), \ + (dip & 0x0100 ? '1' : '0'), (dip & 0x0080 ? '1' : '0'), (dip & 0x0040 ? '1' : '0'), \ + (dip & 0x0020 ? '1' : '0'), (dip & 0x0010 ? '1' : '0'), (dip & 0x0001 ? '1' : '0'), \ + (dip & 0x0008 ? '1' : '0') + +static const SubGhzBlockConst subghz_protocol_ansonic_const = { + .te_short = 555, + .te_long = 1111, + .te_delta = 120, + .min_count_bit_for_found = 12, +}; + +struct SubGhzProtocolDecoderAnsonic { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + SubGhzBlockGeneric generic; +}; + +struct SubGhzProtocolEncoderAnsonic { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + SubGhzBlockGeneric generic; +}; + +typedef enum { + AnsonicDecoderStepReset = 0, + AnsonicDecoderStepFoundStartBit, + AnsonicDecoderStepSaveDuration, + AnsonicDecoderStepCheckDuration, +} AnsonicDecoderStep; + +const SubGhzProtocolDecoder subghz_protocol_ansonic_decoder = { + .alloc = subghz_protocol_decoder_ansonic_alloc, + .free = subghz_protocol_decoder_ansonic_free, + + .feed = subghz_protocol_decoder_ansonic_feed, + .reset = subghz_protocol_decoder_ansonic_reset, + + .get_hash_data = subghz_protocol_decoder_ansonic_get_hash_data, + .serialize = subghz_protocol_decoder_ansonic_serialize, + .deserialize = subghz_protocol_decoder_ansonic_deserialize, + .get_string = subghz_protocol_decoder_ansonic_get_string, +}; + +const SubGhzProtocolEncoder subghz_protocol_ansonic_encoder = { + .alloc = subghz_protocol_encoder_ansonic_alloc, + .free = subghz_protocol_encoder_ansonic_free, + + .deserialize = subghz_protocol_encoder_ansonic_deserialize, + .stop = subghz_protocol_encoder_ansonic_stop, + .yield = subghz_protocol_encoder_ansonic_yield, +}; + +const SubGhzProtocol subghz_protocol_ansonic = { + .name = SUBGHZ_PROTOCOL_ANSONIC_NAME, + .type = SubGhzProtocolTypeStatic, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_FM | + SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | + SubGhzProtocolFlag_Send, + + .decoder = &subghz_protocol_ansonic_decoder, + .encoder = &subghz_protocol_ansonic_encoder, +}; + +void* subghz_protocol_encoder_ansonic_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolEncoderAnsonic* instance = malloc(sizeof(SubGhzProtocolEncoderAnsonic)); + + instance->base.protocol = &subghz_protocol_ansonic; + instance->generic.protocol_name = instance->base.protocol->name; + + instance->encoder.repeat = 10; + instance->encoder.size_upload = 52; + instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); + instance->encoder.is_running = false; + return instance; +} + +void subghz_protocol_encoder_ansonic_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderAnsonic* instance = context; + free(instance->encoder.upload); + free(instance); +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderAnsonic instance + * @return true On success + */ +static bool subghz_protocol_encoder_ansonic_get_upload(SubGhzProtocolEncoderAnsonic* instance) { + furi_assert(instance); + size_t index = 0; + size_t size_upload = (instance->generic.data_count_bit * 2) + 2; + if(size_upload > instance->encoder.size_upload) { + FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer."); + return false; + } else { + instance->encoder.size_upload = size_upload; + } + //Send header + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_ansonic_const.te_short * 35); + //Send start bit + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_ansonic_const.te_short); + //Send key data + for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) { + if(bit_read(instance->generic.data, i - 1)) { + //send bit 1 + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_ansonic_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_ansonic_const.te_long); + } else { + //send bit 0 + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_ansonic_const.te_long); + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_ansonic_const.te_short); + } + } + return true; +} + +bool subghz_protocol_encoder_ansonic_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderAnsonic* instance = context; + bool res = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + FURI_LOG_E(TAG, "Deserialize error"); + break; + } + if(instance->generic.data_count_bit != + subghz_protocol_ansonic_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + //optional parameter parameter + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + if(!subghz_protocol_encoder_ansonic_get_upload(instance)) break; + instance->encoder.is_running = true; + + res = true; + } while(false); + + return res; +} + +void subghz_protocol_encoder_ansonic_stop(void* context) { + SubGhzProtocolEncoderAnsonic* instance = context; + instance->encoder.is_running = false; +} + +LevelDuration subghz_protocol_encoder_ansonic_yield(void* context) { + SubGhzProtocolEncoderAnsonic* instance = context; + + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; + return level_duration_reset(); + } + + LevelDuration ret = instance->encoder.upload[instance->encoder.front]; + + if(++instance->encoder.front == instance->encoder.size_upload) { + instance->encoder.repeat--; + instance->encoder.front = 0; + } + + return ret; +} + +void* subghz_protocol_decoder_ansonic_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolDecoderAnsonic* instance = malloc(sizeof(SubGhzProtocolDecoderAnsonic)); + instance->base.protocol = &subghz_protocol_ansonic; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void subghz_protocol_decoder_ansonic_free(void* context) { + furi_assert(context); + SubGhzProtocolDecoderAnsonic* instance = context; + free(instance); +} + +void subghz_protocol_decoder_ansonic_reset(void* context) { + furi_assert(context); + SubGhzProtocolDecoderAnsonic* instance = context; + instance->decoder.parser_step = AnsonicDecoderStepReset; +} + +void subghz_protocol_decoder_ansonic_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); + SubGhzProtocolDecoderAnsonic* instance = context; + + switch(instance->decoder.parser_step) { + case AnsonicDecoderStepReset: + if((!level) && (DURATION_DIFF(duration, subghz_protocol_ansonic_const.te_short * 35) < + subghz_protocol_ansonic_const.te_delta * 35)) { + //Found header Ansonic + instance->decoder.parser_step = AnsonicDecoderStepFoundStartBit; + } + break; + case AnsonicDecoderStepFoundStartBit: + if(!level) { + break; + } else if( + DURATION_DIFF(duration, subghz_protocol_ansonic_const.te_short) < + subghz_protocol_ansonic_const.te_delta) { + //Found start bit Ansonic + instance->decoder.parser_step = AnsonicDecoderStepSaveDuration; + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + } else { + instance->decoder.parser_step = AnsonicDecoderStepReset; + } + break; + case AnsonicDecoderStepSaveDuration: + if(!level) { //save interval + if(duration >= (subghz_protocol_ansonic_const.te_short * 4)) { + instance->decoder.parser_step = AnsonicDecoderStepFoundStartBit; + if(instance->decoder.decode_count_bit >= + subghz_protocol_ansonic_const.min_count_bit_for_found) { + instance->generic.serial = 0x0; + instance->generic.btn = 0x0; + + instance->generic.data = instance->decoder.decode_data; + instance->generic.data_count_bit = instance->decoder.decode_count_bit; + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } + break; + } + instance->decoder.te_last = duration; + instance->decoder.parser_step = AnsonicDecoderStepCheckDuration; + } else { + instance->decoder.parser_step = AnsonicDecoderStepReset; + } + break; + case AnsonicDecoderStepCheckDuration: + if(level) { + if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_ansonic_const.te_short) < + subghz_protocol_ansonic_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_ansonic_const.te_long) < + subghz_protocol_ansonic_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = AnsonicDecoderStepSaveDuration; + } else if( + (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_ansonic_const.te_long) < + subghz_protocol_ansonic_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_ansonic_const.te_short) < + subghz_protocol_ansonic_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = AnsonicDecoderStepSaveDuration; + } else + instance->decoder.parser_step = AnsonicDecoderStepReset; + } else { + instance->decoder.parser_step = AnsonicDecoderStepReset; + } + break; + } +} + +/** + * Analysis of received data + * @param instance Pointer to a SubGhzBlockGeneric* instance + */ +static void subghz_protocol_ansonic_check_remote_controller(SubGhzBlockGeneric* instance) { + /* + * 12345678(10) k 9 + * AAA => 10101010 1 01 0 + * + * 1...10 - DIP + * k- KEY + */ + instance->cnt = instance->data & 0xFFF; + instance->btn = ((instance->data >> 1) & 0x3); +} + +uint8_t subghz_protocol_decoder_ansonic_get_hash_data(void* context) { + furi_assert(context); + SubGhzProtocolDecoderAnsonic* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +bool subghz_protocol_decoder_ansonic_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset) { + furi_assert(context); + SubGhzProtocolDecoderAnsonic* instance = context; + return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +bool subghz_protocol_decoder_ansonic_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolDecoderAnsonic* instance = context; + bool ret = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + break; + } + if(instance->generic.data_count_bit != + subghz_protocol_ansonic_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + ret = true; + } while(false); + return ret; +} + +void subghz_protocol_decoder_ansonic_get_string(void* context, FuriString* output) { + furi_assert(context); + SubGhzProtocolDecoderAnsonic* instance = context; + subghz_protocol_ansonic_check_remote_controller(&instance->generic); + furi_string_cat_printf( + output, + "%s %dbit\r\n" + "Key:%03lX\r\n" + "Btn:%X\r\n" + "DIP:" DIP_PATTERN "\r\n", + instance->generic.protocol_name, + instance->generic.data_count_bit, + (uint32_t)(instance->generic.data & 0xFFFFFFFF), + instance->generic.btn, + CNT_TO_DIP(instance->generic.cnt)); +} diff --git a/lib/subghz/protocols/ansonic.h b/lib/subghz/protocols/ansonic.h new file mode 100644 index 00000000..0170a604 --- /dev/null +++ b/lib/subghz/protocols/ansonic.h @@ -0,0 +1,107 @@ +#pragma once + +#include "base.h" + +#define SUBGHZ_PROTOCOL_ANSONIC_NAME "Ansonic" + +typedef struct SubGhzProtocolDecoderAnsonic SubGhzProtocolDecoderAnsonic; +typedef struct SubGhzProtocolEncoderAnsonic SubGhzProtocolEncoderAnsonic; + +extern const SubGhzProtocolDecoder subghz_protocol_ansonic_decoder; +extern const SubGhzProtocolEncoder subghz_protocol_ansonic_encoder; +extern const SubGhzProtocol subghz_protocol_ansonic; + +/** + * Allocate SubGhzProtocolEncoderAnsonic. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderAnsonic* pointer to a SubGhzProtocolEncoderAnsonic instance + */ +void* subghz_protocol_encoder_ansonic_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderAnsonic. + * @param context Pointer to a SubGhzProtocolEncoderAnsonic instance + */ +void subghz_protocol_encoder_ansonic_free(void* context); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderAnsonic instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_encoder_ansonic_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderAnsonic instance + */ +void subghz_protocol_encoder_ansonic_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderAnsonic instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_ansonic_yield(void* context); + +/** + * Allocate SubGhzProtocolDecoderAnsonic. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolDecoderAnsonic* pointer to a SubGhzProtocolDecoderAnsonic instance + */ +void* subghz_protocol_decoder_ansonic_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolDecoderAnsonic. + * @param context Pointer to a SubGhzProtocolDecoderAnsonic instance + */ +void subghz_protocol_decoder_ansonic_free(void* context); + +/** + * Reset decoder SubGhzProtocolDecoderAnsonic. + * @param context Pointer to a SubGhzProtocolDecoderAnsonic instance + */ +void subghz_protocol_decoder_ansonic_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a SubGhzProtocolDecoderAnsonic instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void subghz_protocol_decoder_ansonic_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a SubGhzProtocolDecoderAnsonic instance + * @return hash Hash sum + */ +uint8_t subghz_protocol_decoder_ansonic_get_hash_data(void* context); + +/** + * Serialize data SubGhzProtocolDecoderAnsonic. + * @param context Pointer to a SubGhzProtocolDecoderAnsonic instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzRadioPreset + * @return true On success + */ +bool subghz_protocol_decoder_ansonic_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset); + +/** + * Deserialize data SubGhzProtocolDecoderAnsonic. + * @param context Pointer to a SubGhzProtocolDecoderAnsonic instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_decoder_ansonic_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a SubGhzProtocolDecoderAnsonic instance + * @param output Resulting text + */ +void subghz_protocol_decoder_ansonic_get_string(void* context, FuriString* output); diff --git a/lib/subghz/protocols/protocol_items.c b/lib/subghz/protocols/protocol_items.c index ebf9b93e..24aaae8d 100644 --- a/lib/subghz/protocols/protocol_items.c +++ b/lib/subghz/protocols/protocol_items.c @@ -12,7 +12,7 @@ const SubGhzProtocol* subghz_protocol_registry_items[] = { &subghz_protocol_chamb_code, &subghz_protocol_power_smart, &subghz_protocol_marantec, &subghz_protocol_bett, &subghz_protocol_doitrand, &subghz_protocol_phoenix_v2, &subghz_protocol_honeywell_wdb, &subghz_protocol_magellan, &subghz_protocol_intertechno_v3, - &subghz_protocol_clemsa, + &subghz_protocol_clemsa, &subghz_protocol_ansonic, }; const SubGhzProtocolRegistry subghz_protocol_registry = { diff --git a/lib/subghz/protocols/protocol_items.h b/lib/subghz/protocols/protocol_items.h index 23aa71be..114dc504 100644 --- a/lib/subghz/protocols/protocol_items.h +++ b/lib/subghz/protocols/protocol_items.h @@ -35,5 +35,6 @@ #include "magellan.h" #include "intertechno_v3.h" #include "clemsa.h" +#include "ansonic.h" extern const SubGhzProtocolRegistry subghz_protocol_registry; From b9c483fbf8c0361518c0eb59812aa0edc3dab0bd Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Wed, 23 Nov 2022 13:44:49 +0400 Subject: [PATCH 03/25] [FL-2975] WS: add protocol GT-WT02 (#2001) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * WS: add protocol GT-WT02 * WS: fix text "About" scene Co-authored-by: あく --- .../helpers/weather_station_types.h | 2 +- .../weather_station/protocols/gt_wt_02.c | 265 ++++++++++++++++++ .../weather_station/protocols/gt_wt_02.h | 79 ++++++ .../protocols/protocol_items.c | 1 + .../protocols/protocol_items.h | 1 + .../scenes/weather_station_scene_about.c | 2 +- 6 files changed, 348 insertions(+), 2 deletions(-) create mode 100644 applications/plugins/weather_station/protocols/gt_wt_02.c create mode 100644 applications/plugins/weather_station/protocols/gt_wt_02.h diff --git a/applications/plugins/weather_station/helpers/weather_station_types.h b/applications/plugins/weather_station/helpers/weather_station_types.h index 5a66dd0c..a23540e3 100644 --- a/applications/plugins/weather_station/helpers/weather_station_types.h +++ b/applications/plugins/weather_station/helpers/weather_station_types.h @@ -3,7 +3,7 @@ #include #include -#define WS_VERSION_APP "0.4" +#define WS_VERSION_APP "0.5" #define WS_DEVELOPED "SkorP" #define WS_GITHUB "https://github.com/flipperdevices/flipperzero-firmware" diff --git a/applications/plugins/weather_station/protocols/gt_wt_02.c b/applications/plugins/weather_station/protocols/gt_wt_02.c new file mode 100644 index 00000000..cbe11919 --- /dev/null +++ b/applications/plugins/weather_station/protocols/gt_wt_02.c @@ -0,0 +1,265 @@ +#include "gt_wt_02.h" + +#define TAG "WSProtocolGT_WT02" + +/* + * Help + * https://github.com/merbanan/rtl_433/blob/master/src/devices/gt_wt_02.c + * + * GT-WT-02 sensor on 433.92MHz. + * Example and frame description provided by https://github.com/ludwich66 + * [01] {37} 34 00 ed 47 60 : 00110100 00000000 11101101 01000111 01100000 + * code, BatOK,not-man-send, Channel1, +23,7C, 35% + * [01] {37} 34 8f 87 15 90 : 00110100 10001111 10000111 00010101 10010000 + * code, BatOK,not-man-send, Channel1,-12,1C, 10% + * Humidity: + * - the working range is 20-90 % + * - if "LL" in display view it sends 10 % + * - if "HH" in display view it sends 110% + * SENSOR: GT-WT-02 (ALDI Globaltronics..) + * TYP IIIIIIII BMCCTTTT TTTTTTTT HHHHHHHX XXXXX + * TYPE Description: + * - I = Random Device Code, changes with battery reset + * - B = Battery 0=OK 1=LOW + * - M = Manual Send Button Pressed 0=not pressed 1=pressed + * - C = Channel 00=CH1, 01=CH2, 10=CH3 + * - T = Temperature, 12 Bit 2's complement, scaled by 10 + * - H = Humidity = 7 Bit bin2dez 00-99, Display LL=10%, Display HH=110% (Range 20-90%) + * - X = Checksum, sum modulo 64 + * A Lidl AURIO (from 12/2018) with PCB marking YJ-T12 V02 has two extra bits in front. + * +*/ + +static const SubGhzBlockConst ws_protocol_gt_wt_02_const = { + .te_short = 500, + .te_long = 2000, + .te_delta = 150, + .min_count_bit_for_found = 37, +}; + +struct WSProtocolDecoderGT_WT02 { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + WSBlockGeneric generic; +}; + +struct WSProtocolEncoderGT_WT02 { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + WSBlockGeneric generic; +}; + +typedef enum { + GT_WT02DecoderStepReset = 0, + GT_WT02DecoderStepSaveDuration, + GT_WT02DecoderStepCheckDuration, +} GT_WT02DecoderStep; + +const SubGhzProtocolDecoder ws_protocol_gt_wt_02_decoder = { + .alloc = ws_protocol_decoder_gt_wt_02_alloc, + .free = ws_protocol_decoder_gt_wt_02_free, + + .feed = ws_protocol_decoder_gt_wt_02_feed, + .reset = ws_protocol_decoder_gt_wt_02_reset, + + .get_hash_data = ws_protocol_decoder_gt_wt_02_get_hash_data, + .serialize = ws_protocol_decoder_gt_wt_02_serialize, + .deserialize = ws_protocol_decoder_gt_wt_02_deserialize, + .get_string = ws_protocol_decoder_gt_wt_02_get_string, +}; + +const SubGhzProtocolEncoder ws_protocol_gt_wt_02_encoder = { + .alloc = NULL, + .free = NULL, + + .deserialize = NULL, + .stop = NULL, + .yield = NULL, +}; + +const SubGhzProtocol ws_protocol_gt_wt_02 = { + .name = WS_PROTOCOL_GT_WT_02_NAME, + .type = SubGhzProtocolWeatherStation, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 | + SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable, + + .decoder = &ws_protocol_gt_wt_02_decoder, + .encoder = &ws_protocol_gt_wt_02_encoder, +}; + +void* ws_protocol_decoder_gt_wt_02_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + WSProtocolDecoderGT_WT02* instance = malloc(sizeof(WSProtocolDecoderGT_WT02)); + instance->base.protocol = &ws_protocol_gt_wt_02; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void ws_protocol_decoder_gt_wt_02_free(void* context) { + furi_assert(context); + WSProtocolDecoderGT_WT02* instance = context; + free(instance); +} + +void ws_protocol_decoder_gt_wt_02_reset(void* context) { + furi_assert(context); + WSProtocolDecoderGT_WT02* instance = context; + instance->decoder.parser_step = GT_WT02DecoderStepReset; +} + +static bool ws_protocol_gt_wt_02_check(WSProtocolDecoderGT_WT02* instance) { + if(!instance->decoder.decode_data) return false; + uint8_t sum = (instance->decoder.decode_data >> 5) & 0xe; + uint64_t temp_data = instance->decoder.decode_data >> 9; + for(uint8_t i = 0; i < 7; i++) { + sum += (temp_data >> (i * 4)) & 0xF; + } + return ((uint8_t)(instance->decoder.decode_data & 0x3F) == (sum & 0x3F)); +} + +/** + * Analysis of received data + * @param instance Pointer to a WSBlockGeneric* instance + */ +static void ws_protocol_gt_wt_02_remote_controller(WSBlockGeneric* instance) { + instance->id = (instance->data >> 29) & 0xFF; + instance->battery_low = (instance->data >> 28) & 1; + instance->btn = (instance->data >> 27) & 1; + instance->channel = ((instance->data >> 25) & 0x3) + 1; + + if(!((instance->data >> 24) & 1)) { + instance->temp = (float)((instance->data >> 13) & 0x07FF) / 10.0f; + } else { + instance->temp = (float)((~(instance->data >> 13) & 0x07FF) + 1) / -10.0f; + } + + instance->humidity = (instance->data >> 6) & 0x7F; + if(instance->humidity <= 10) // actually the sensors sends 10 below working range of 20% + instance->humidity = 0; + else if(instance->humidity > 90) // actually the sensors sends 110 above working range of 90% + instance->humidity = 100; +} + +void ws_protocol_decoder_gt_wt_02_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); + WSProtocolDecoderGT_WT02* instance = context; + + switch(instance->decoder.parser_step) { + case GT_WT02DecoderStepReset: + if((!level) && (DURATION_DIFF(duration, ws_protocol_gt_wt_02_const.te_short * 18) < + ws_protocol_gt_wt_02_const.te_delta * 8)) { + //Found syncPrefix + instance->decoder.parser_step = GT_WT02DecoderStepSaveDuration; + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + } + break; + + case GT_WT02DecoderStepSaveDuration: + if(level) { + instance->decoder.te_last = duration; + instance->decoder.parser_step = GT_WT02DecoderStepCheckDuration; + } else { + instance->decoder.parser_step = GT_WT02DecoderStepReset; + } + break; + + case GT_WT02DecoderStepCheckDuration: + if(!level) { + if(DURATION_DIFF(instance->decoder.te_last, ws_protocol_gt_wt_02_const.te_short) < + ws_protocol_gt_wt_02_const.te_delta) { + if(DURATION_DIFF(duration, ws_protocol_gt_wt_02_const.te_short * 18) < + ws_protocol_gt_wt_02_const.te_delta * 8) { + //Found syncPostfix + instance->decoder.parser_step = GT_WT02DecoderStepReset; + if((instance->decoder.decode_count_bit == + ws_protocol_gt_wt_02_const.min_count_bit_for_found) && + ws_protocol_gt_wt_02_check(instance)) { + instance->generic.data = instance->decoder.decode_data; + instance->generic.data_count_bit = instance->decoder.decode_count_bit; + ws_protocol_gt_wt_02_remote_controller(&instance->generic); + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } else if(instance->decoder.decode_count_bit == 1) { + instance->decoder.parser_step = GT_WT02DecoderStepSaveDuration; + } + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + } else if( + DURATION_DIFF(duration, ws_protocol_gt_wt_02_const.te_long) < + ws_protocol_gt_wt_02_const.te_delta * 2) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = GT_WT02DecoderStepSaveDuration; + } else if( + DURATION_DIFF(duration, ws_protocol_gt_wt_02_const.te_long * 2) < + ws_protocol_gt_wt_02_const.te_delta * 4) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = GT_WT02DecoderStepSaveDuration; + } else { + instance->decoder.parser_step = GT_WT02DecoderStepReset; + } + } else { + instance->decoder.parser_step = GT_WT02DecoderStepReset; + } + } else { + instance->decoder.parser_step = GT_WT02DecoderStepReset; + } + break; + } +} + +uint8_t ws_protocol_decoder_gt_wt_02_get_hash_data(void* context) { + furi_assert(context); + WSProtocolDecoderGT_WT02* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +bool ws_protocol_decoder_gt_wt_02_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset) { + furi_assert(context); + WSProtocolDecoderGT_WT02* instance = context; + return ws_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +bool ws_protocol_decoder_gt_wt_02_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + WSProtocolDecoderGT_WT02* instance = context; + bool ret = false; + do { + if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) { + break; + } + if(instance->generic.data_count_bit != + ws_protocol_gt_wt_02_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + ret = true; + } while(false); + return ret; +} + +void ws_protocol_decoder_gt_wt_02_get_string(void* context, FuriString* output) { + furi_assert(context); + WSProtocolDecoderGT_WT02* instance = context; + furi_string_printf( + output, + "%s %dbit\r\n" + "Key:0x%lX%08lX\r\n" + "Sn:0x%lX Ch:%d Bat:%d\r\n" + "Temp:%3.1f C Hum:%d%%", + instance->generic.protocol_name, + instance->generic.data_count_bit, + (uint32_t)(instance->generic.data >> 32), + (uint32_t)(instance->generic.data), + instance->generic.id, + instance->generic.channel, + instance->generic.battery_low, + (double)instance->generic.temp, + instance->generic.humidity); +} diff --git a/applications/plugins/weather_station/protocols/gt_wt_02.h b/applications/plugins/weather_station/protocols/gt_wt_02.h new file mode 100644 index 00000000..f17d5baa --- /dev/null +++ b/applications/plugins/weather_station/protocols/gt_wt_02.h @@ -0,0 +1,79 @@ +#pragma once + +#include + +#include +#include +#include +#include "ws_generic.h" +#include + +#define WS_PROTOCOL_GT_WT_02_NAME "GT-WT02" + +typedef struct WSProtocolDecoderGT_WT02 WSProtocolDecoderGT_WT02; +typedef struct WSProtocolEncoderGT_WT02 WSProtocolEncoderGT_WT02; + +extern const SubGhzProtocolDecoder ws_protocol_gt_wt_02_decoder; +extern const SubGhzProtocolEncoder ws_protocol_gt_wt_02_encoder; +extern const SubGhzProtocol ws_protocol_gt_wt_02; + +/** + * Allocate WSProtocolDecoderGT_WT02. + * @param environment Pointer to a SubGhzEnvironment instance + * @return WSProtocolDecoderGT_WT02* pointer to a WSProtocolDecoderGT_WT02 instance + */ +void* ws_protocol_decoder_gt_wt_02_alloc(SubGhzEnvironment* environment); + +/** + * Free WSProtocolDecoderGT_WT02. + * @param context Pointer to a WSProtocolDecoderGT_WT02 instance + */ +void ws_protocol_decoder_gt_wt_02_free(void* context); + +/** + * Reset decoder WSProtocolDecoderGT_WT02. + * @param context Pointer to a WSProtocolDecoderGT_WT02 instance + */ +void ws_protocol_decoder_gt_wt_02_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a WSProtocolDecoderGT_WT02 instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void ws_protocol_decoder_gt_wt_02_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a WSProtocolDecoderGT_WT02 instance + * @return hash Hash sum + */ +uint8_t ws_protocol_decoder_gt_wt_02_get_hash_data(void* context); + +/** + * Serialize data WSProtocolDecoderGT_WT02. + * @param context Pointer to a WSProtocolDecoderGT_WT02 instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzRadioPreset + * @return true On success + */ +bool ws_protocol_decoder_gt_wt_02_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset); + +/** + * Deserialize data WSProtocolDecoderGT_WT02. + * @param context Pointer to a WSProtocolDecoderGT_WT02 instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool ws_protocol_decoder_gt_wt_02_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a WSProtocolDecoderGT_WT02 instance + * @param output Resulting text + */ +void ws_protocol_decoder_gt_wt_02_get_string(void* context, FuriString* output); diff --git a/applications/plugins/weather_station/protocols/protocol_items.c b/applications/plugins/weather_station/protocols/protocol_items.c index d2b20e51..21768e04 100644 --- a/applications/plugins/weather_station/protocols/protocol_items.c +++ b/applications/plugins/weather_station/protocols/protocol_items.c @@ -4,6 +4,7 @@ const SubGhzProtocol* weather_station_protocol_registry_items[] = { &ws_protocol_infactory, &ws_protocol_thermopro_tx4, &ws_protocol_nexus_th, + &ws_protocol_gt_wt_02, &ws_protocol_gt_wt_03, &ws_protocol_acurite_606tx, &ws_protocol_acurite_609txc, diff --git a/applications/plugins/weather_station/protocols/protocol_items.h b/applications/plugins/weather_station/protocols/protocol_items.h index 45b297e1..aa064f04 100644 --- a/applications/plugins/weather_station/protocols/protocol_items.h +++ b/applications/plugins/weather_station/protocols/protocol_items.h @@ -4,6 +4,7 @@ #include "infactory.h" #include "thermopro_tx4.h" #include "nexus_th.h" +#include "gt_wt_02.h" #include "gt_wt_03.h" #include "acurite_606tx.h" #include "acurite_609txc.h" diff --git a/applications/plugins/weather_station/scenes/weather_station_scene_about.c b/applications/plugins/weather_station/scenes/weather_station_scene_about.c index df784ec9..d916dc76 100644 --- a/applications/plugins/weather_station/scenes/weather_station_scene_about.c +++ b/applications/plugins/weather_station/scenes/weather_station_scene_about.c @@ -24,7 +24,7 @@ void weather_station_scene_about_on_enter(void* context) { furi_string_cat_printf(temp_str, "\e#%s\n", "Description"); furi_string_cat_printf( - temp_str, "Reading messages from\nweather station that work\nwith SubGhz sensors\n\n"); + temp_str, "Reading messages from\nweather stations that work\nwith SubGhz sensors\n\n"); furi_string_cat_printf(temp_str, "Supported protocols:\n"); size_t i = 0; From c511c67e71be4a9f3cc3b3be3f503032038f2b03 Mon Sep 17 00:00:00 2001 From: Sergey Gavrilov Date: Wed, 23 Nov 2022 22:49:17 +1000 Subject: [PATCH 04/25] Core: thread allocation shortcut (#2007) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Core: thread alloc+set shortcut * Apps: use thread allocation shortcut * Mark some service threads as services * Init BT as soon as possible Co-authored-by: あく --- applications/debug/uart_echo/uart_echo.c | 6 +----- .../debug/unit_tests/storage/storage_test.c | 14 ++++---------- applications/main/bad_usb/bad_usb_script.c | 7 +------ applications/main/gpio/usb_uart_bridge.c | 13 +++---------- applications/main/subghz/helpers/subghz_chat.c | 7 ++----- .../helpers/subghz_frequency_analyzer_worker.c | 8 ++------ applications/main/u2f/u2f_hid.c | 6 +----- applications/plugins/dap_link/dap_link.c | 13 ------------- .../plugins/music_player/music_player_worker.c | 7 ++----- .../plugins/nfc_magic/nfc_magic_worker.c | 7 ++----- applications/plugins/picopass/picopass_worker.c | 7 ++----- applications/services/cli/cli_vcp.c | 5 +---- .../services/gui/modules/file_browser_worker.c | 6 +----- applications/services/rpc/rpc.c | 6 +----- applications/services/rpc/rpc_gui.c | 8 ++------ applications/system/updater/cli/updater_cli.c | 7 ++----- applications/system/updater/util/update_task.c | 7 ++----- firmware/targets/f7/Src/main.c | 5 +---- firmware/targets/f7/api_symbols.csv | 1 + firmware/targets/f7/ble_glue/ble_app.c | 6 +----- firmware/targets/f7/ble_glue/ble_glue.c | 6 +----- firmware/targets/f7/ble_glue/gap.c | 6 +----- firmware/targets/f7/furi_hal/furi_hal.c | 17 ++++++++--------- firmware/targets/f7/furi_hal/furi_hal_usb.c | 6 ++---- furi/core/thread.c | 13 +++++++++++++ furi/core/thread.h | 14 ++++++++++++++ furi/flipper.c | 10 +++++----- lib/ST25RFAL002/platform.c | 8 +++----- lib/flipper_application/flipper_application.c | 7 ++----- lib/infrared/worker/infrared_worker.c | 5 +---- lib/lfrfid/lfrfid_raw_worker.c | 5 +---- lib/lfrfid/lfrfid_worker.c | 6 +----- lib/nfc/helpers/reader_analyzer.c | 7 ++----- lib/nfc/nfc_worker.c | 6 +----- lib/one_wire/ibutton/ibutton_worker.c | 6 +----- lib/subghz/subghz_file_encoder_worker.c | 7 ++----- lib/subghz/subghz_tx_rx_worker.c | 7 ++----- lib/subghz/subghz_worker.c | 7 ++----- 38 files changed, 94 insertions(+), 195 deletions(-) diff --git a/applications/debug/uart_echo/uart_echo.c b/applications/debug/uart_echo/uart_echo.c index 701e5325..16996ba8 100644 --- a/applications/debug/uart_echo/uart_echo.c +++ b/applications/debug/uart_echo/uart_echo.c @@ -220,11 +220,7 @@ static UartEchoApp* uart_echo_app_alloc() { furi_hal_uart_set_br(FuriHalUartIdUSART1, 115200); furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, uart_echo_on_irq_cb, app); - app->worker_thread = furi_thread_alloc(); - furi_thread_set_name(app->worker_thread, "UsbUartWorker"); - furi_thread_set_stack_size(app->worker_thread, 1024); - furi_thread_set_context(app->worker_thread, app); - furi_thread_set_callback(app->worker_thread, uart_echo_worker); + app->worker_thread = furi_thread_alloc_ex("UsbUartWorker", 1024, uart_echo_worker, app); furi_thread_start(app->worker_thread); return app; diff --git a/applications/debug/unit_tests/storage/storage_test.c b/applications/debug/unit_tests/storage/storage_test.c index 7c1c669f..11500970 100644 --- a/applications/debug/unit_tests/storage/storage_test.c +++ b/applications/debug/unit_tests/storage/storage_test.c @@ -43,11 +43,8 @@ MU_TEST(storage_file_open_lock) { File* file = storage_file_alloc(storage); // file_locker thread start - FuriThread* locker_thread = furi_thread_alloc(); - furi_thread_set_name(locker_thread, "StorageFileLocker"); - furi_thread_set_stack_size(locker_thread, 2048); - furi_thread_set_context(locker_thread, semaphore); - furi_thread_set_callback(locker_thread, storage_file_locker); + FuriThread* locker_thread = + furi_thread_alloc_ex("StorageFileLocker", 2048, storage_file_locker, semaphore); furi_thread_start(locker_thread); // wait for file lock @@ -133,11 +130,8 @@ MU_TEST(storage_dir_open_lock) { File* file = storage_file_alloc(storage); // file_locker thread start - FuriThread* locker_thread = furi_thread_alloc(); - furi_thread_set_name(locker_thread, "StorageDirLocker"); - furi_thread_set_stack_size(locker_thread, 2048); - furi_thread_set_context(locker_thread, semaphore); - furi_thread_set_callback(locker_thread, storage_dir_locker); + FuriThread* locker_thread = + furi_thread_alloc_ex("StorageDirLocker", 2048, storage_dir_locker, semaphore); furi_thread_start(locker_thread); // wait for dir lock diff --git a/applications/main/bad_usb/bad_usb_script.c b/applications/main/bad_usb/bad_usb_script.c index 295cc1c3..aa465351 100644 --- a/applications/main/bad_usb/bad_usb_script.c +++ b/applications/main/bad_usb/bad_usb_script.c @@ -657,12 +657,7 @@ BadUsbScript* bad_usb_script_open(FuriString* file_path) { bad_usb->st.state = BadUsbStateInit; bad_usb->st.error[0] = '\0'; - bad_usb->thread = furi_thread_alloc(); - furi_thread_set_name(bad_usb->thread, "BadUsbWorker"); - furi_thread_set_stack_size(bad_usb->thread, 2048); - furi_thread_set_context(bad_usb->thread, bad_usb); - furi_thread_set_callback(bad_usb->thread, bad_usb_worker); - + bad_usb->thread = furi_thread_alloc_ex("BadUsbWorker", 2048, bad_usb_worker, bad_usb); furi_thread_start(bad_usb->thread); return bad_usb; } diff --git a/applications/main/gpio/usb_uart_bridge.c b/applications/main/gpio/usb_uart_bridge.c index a1ab4032..927eedb0 100644 --- a/applications/main/gpio/usb_uart_bridge.c +++ b/applications/main/gpio/usb_uart_bridge.c @@ -159,11 +159,8 @@ static int32_t usb_uart_worker(void* context) { usb_uart->tx_sem = furi_semaphore_alloc(1, 1); usb_uart->usb_mutex = furi_mutex_alloc(FuriMutexTypeNormal); - usb_uart->tx_thread = furi_thread_alloc(); - furi_thread_set_name(usb_uart->tx_thread, "UsbUartTxWorker"); - furi_thread_set_stack_size(usb_uart->tx_thread, 512); - furi_thread_set_context(usb_uart->tx_thread, usb_uart); - furi_thread_set_callback(usb_uart->tx_thread, usb_uart_tx_thread); + usb_uart->tx_thread = + furi_thread_alloc_ex("UsbUartTxWorker", 512, usb_uart_tx_thread, usb_uart); usb_uart_vcp_init(usb_uart, usb_uart->cfg.vcp_ch); usb_uart_serial_init(usb_uart, usb_uart->cfg.uart_ch); @@ -338,11 +335,7 @@ UsbUartBridge* usb_uart_enable(UsbUartConfig* cfg) { memcpy(&(usb_uart->cfg_new), cfg, sizeof(UsbUartConfig)); - usb_uart->thread = furi_thread_alloc(); - furi_thread_set_name(usb_uart->thread, "UsbUartWorker"); - furi_thread_set_stack_size(usb_uart->thread, 1024); - furi_thread_set_context(usb_uart->thread, usb_uart); - furi_thread_set_callback(usb_uart->thread, usb_uart_worker); + usb_uart->thread = furi_thread_alloc_ex("UsbUartWorker", 1024, usb_uart_worker, usb_uart); furi_thread_start(usb_uart->thread); return usb_uart; diff --git a/applications/main/subghz/helpers/subghz_chat.c b/applications/main/subghz/helpers/subghz_chat.c index f821feaa..dbf34c97 100644 --- a/applications/main/subghz/helpers/subghz_chat.c +++ b/applications/main/subghz/helpers/subghz_chat.c @@ -59,11 +59,8 @@ SubGhzChatWorker* subghz_chat_worker_alloc(Cli* cli) { instance->cli = cli; - instance->thread = furi_thread_alloc(); - furi_thread_set_name(instance->thread, "SubGhzChat"); - furi_thread_set_stack_size(instance->thread, 2048); - furi_thread_set_context(instance->thread, instance); - furi_thread_set_callback(instance->thread, subghz_chat_worker_thread); + instance->thread = + furi_thread_alloc_ex("SubGhzChat", 2048, subghz_chat_worker_thread, instance); instance->subghz_txrx = subghz_tx_rx_worker_alloc(); instance->event_queue = furi_message_queue_alloc(80, sizeof(SubGhzChatEvent)); return instance; diff --git a/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c b/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c index 0341990d..7826e2ae 100644 --- a/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c +++ b/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c @@ -265,12 +265,8 @@ SubGhzFrequencyAnalyzerWorker* subghz_frequency_analyzer_worker_alloc(void* cont furi_assert(context); SubGhzFrequencyAnalyzerWorker* instance = malloc(sizeof(SubGhzFrequencyAnalyzerWorker)); - instance->thread = furi_thread_alloc(); - furi_thread_set_name(instance->thread, "SubGhzFAWorker"); - furi_thread_set_stack_size(instance->thread, 2048); - furi_thread_set_context(instance->thread, instance); - furi_thread_set_callback(instance->thread, subghz_frequency_analyzer_worker_thread); - + instance->thread = furi_thread_alloc_ex( + "SubGhzFAWorker", 2048, subghz_frequency_analyzer_worker_thread, instance); SubGhz* subghz = context; instance->setting = subghz->setting; return instance; diff --git a/applications/main/u2f/u2f_hid.c b/applications/main/u2f/u2f_hid.c index b6e86384..916400e9 100644 --- a/applications/main/u2f/u2f_hid.c +++ b/applications/main/u2f/u2f_hid.c @@ -282,11 +282,7 @@ U2fHid* u2f_hid_start(U2fData* u2f_inst) { u2f_hid->u2f_instance = u2f_inst; - u2f_hid->thread = furi_thread_alloc(); - furi_thread_set_name(u2f_hid->thread, "U2fHidWorker"); - furi_thread_set_stack_size(u2f_hid->thread, 2048); - furi_thread_set_context(u2f_hid->thread, u2f_hid); - furi_thread_set_callback(u2f_hid->thread, u2f_hid_worker); + u2f_hid->thread = furi_thread_alloc_ex("U2fHidWorker", 2048, u2f_hid_worker, u2f_hid); furi_thread_start(u2f_hid->thread); return u2f_hid; } diff --git a/applications/plugins/dap_link/dap_link.c b/applications/plugins/dap_link/dap_link.c index 443d77c5..5c30e85c 100644 --- a/applications/plugins/dap_link/dap_link.c +++ b/applications/plugins/dap_link/dap_link.c @@ -441,19 +441,6 @@ static int32_t cdc_process(void* p) { /******************************* MAIN APP **********************************/ /***************************************************************************/ -static FuriThread* furi_thread_alloc_ex( - const char* name, - uint32_t stack_size, - FuriThreadCallback callback, - void* context) { - FuriThread* thread = furi_thread_alloc(); - furi_thread_set_name(thread, name); - furi_thread_set_stack_size(thread, stack_size); - furi_thread_set_callback(thread, callback); - furi_thread_set_context(thread, context); - return thread; -} - static DapApp* dap_app_alloc() { DapApp* dap_app = malloc(sizeof(DapApp)); dap_app->dap_thread = furi_thread_alloc_ex("DAP Process", 1024, dap_process, dap_app); diff --git a/applications/plugins/music_player/music_player_worker.c b/applications/plugins/music_player/music_player_worker.c index 3f1ac62f..0d683f4a 100644 --- a/applications/plugins/music_player/music_player_worker.c +++ b/applications/plugins/music_player/music_player_worker.c @@ -97,11 +97,8 @@ MusicPlayerWorker* music_player_worker_alloc() { NoteBlockArray_init(instance->notes); - instance->thread = furi_thread_alloc(); - furi_thread_set_name(instance->thread, "MusicPlayerWorker"); - furi_thread_set_stack_size(instance->thread, 1024); - furi_thread_set_context(instance->thread, instance); - furi_thread_set_callback(instance->thread, music_player_worker_thread_callback); + instance->thread = furi_thread_alloc_ex( + "MusicPlayerWorker", 1024, music_player_worker_thread_callback, instance); instance->volume = 1.0f; diff --git a/applications/plugins/nfc_magic/nfc_magic_worker.c b/applications/plugins/nfc_magic/nfc_magic_worker.c index 0e1f6cea..523c794f 100644 --- a/applications/plugins/nfc_magic/nfc_magic_worker.c +++ b/applications/plugins/nfc_magic/nfc_magic_worker.c @@ -15,11 +15,8 @@ NfcMagicWorker* nfc_magic_worker_alloc() { NfcMagicWorker* nfc_magic_worker = malloc(sizeof(NfcMagicWorker)); // Worker thread attributes - nfc_magic_worker->thread = furi_thread_alloc(); - furi_thread_set_name(nfc_magic_worker->thread, "NfcMagicWorker"); - furi_thread_set_stack_size(nfc_magic_worker->thread, 8192); - furi_thread_set_callback(nfc_magic_worker->thread, nfc_magic_worker_task); - furi_thread_set_context(nfc_magic_worker->thread, nfc_magic_worker); + nfc_magic_worker->thread = + furi_thread_alloc_ex("NfcMagicWorker", 8192, nfc_magic_worker_task, nfc_magic_worker); nfc_magic_worker->callback = NULL; nfc_magic_worker->context = NULL; diff --git a/applications/plugins/picopass/picopass_worker.c b/applications/plugins/picopass/picopass_worker.c index 2c9b1a0c..c2a32cb6 100644 --- a/applications/plugins/picopass/picopass_worker.c +++ b/applications/plugins/picopass/picopass_worker.c @@ -25,11 +25,8 @@ PicopassWorker* picopass_worker_alloc() { PicopassWorker* picopass_worker = malloc(sizeof(PicopassWorker)); // Worker thread attributes - picopass_worker->thread = furi_thread_alloc(); - furi_thread_set_name(picopass_worker->thread, "PicopassWorker"); - furi_thread_set_stack_size(picopass_worker->thread, 8192); - furi_thread_set_callback(picopass_worker->thread, picopass_worker_task); - furi_thread_set_context(picopass_worker->thread, picopass_worker); + picopass_worker->thread = + furi_thread_alloc_ex("PicopassWorker", 8192, picopass_worker_task, picopass_worker); picopass_worker->callback = NULL; picopass_worker->context = NULL; diff --git a/applications/services/cli/cli_vcp.c b/applications/services/cli/cli_vcp.c index 94b82950..ad26dca4 100644 --- a/applications/services/cli/cli_vcp.c +++ b/applications/services/cli/cli_vcp.c @@ -68,10 +68,7 @@ static void cli_vcp_init() { vcp->connected = false; - vcp->thread = furi_thread_alloc(); - furi_thread_set_name(vcp->thread, "CliVcpWorker"); - furi_thread_set_stack_size(vcp->thread, 1024); - furi_thread_set_callback(vcp->thread, vcp_worker); + vcp->thread = furi_thread_alloc_ex("CliVcpWorker", 1024, vcp_worker, NULL); furi_thread_start(vcp->thread); FURI_LOG_I(TAG, "Init OK"); diff --git a/applications/services/gui/modules/file_browser_worker.c b/applications/services/gui/modules/file_browser_worker.c index b9b2b2d8..34d83032 100644 --- a/applications/services/gui/modules/file_browser_worker.c +++ b/applications/services/gui/modules/file_browser_worker.c @@ -367,11 +367,7 @@ BrowserWorker* browser->skip_assets = skip_assets; browser->path_next = furi_string_alloc_set(path); - browser->thread = furi_thread_alloc(); - furi_thread_set_name(browser->thread, "BrowserWorker"); - furi_thread_set_stack_size(browser->thread, 2048); - furi_thread_set_context(browser->thread, browser); - furi_thread_set_callback(browser->thread, browser_worker); + browser->thread = furi_thread_alloc_ex("BrowserWorker", 2048, browser_worker, browser); furi_thread_start(browser->thread); return browser; diff --git a/applications/services/rpc/rpc.c b/applications/services/rpc/rpc.c index f1e0cbd6..ebf01572 100644 --- a/applications/services/rpc/rpc.c +++ b/applications/services/rpc/rpc.c @@ -370,11 +370,7 @@ RpcSession* rpc_session_open(Rpc* rpc) { }; rpc_add_handler(session, PB_Main_stop_session_tag, &rpc_handler); - session->thread = furi_thread_alloc(); - furi_thread_set_name(session->thread, "RpcSessionWorker"); - furi_thread_set_stack_size(session->thread, 3072); - furi_thread_set_context(session->thread, session); - furi_thread_set_callback(session->thread, rpc_session_worker); + session->thread = furi_thread_alloc_ex("RpcSessionWorker", 3072, rpc_session_worker, session); furi_thread_set_state_context(session->thread, session); furi_thread_set_state_callback(session->thread, rpc_session_free_callback); diff --git a/applications/services/rpc/rpc_gui.c b/applications/services/rpc/rpc_gui.c index 029ed010..e66553d5 100644 --- a/applications/services/rpc/rpc_gui.c +++ b/applications/services/rpc/rpc_gui.c @@ -88,12 +88,8 @@ static void rpc_system_gui_start_screen_stream_process(const PB_Main* request, v malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(framebuffer_size)); rpc_gui->transmit_frame->content.gui_screen_frame.data->size = framebuffer_size; // Transmission thread for async TX - rpc_gui->transmit_thread = furi_thread_alloc(); - furi_thread_set_name(rpc_gui->transmit_thread, "GuiRpcWorker"); - furi_thread_set_callback( - rpc_gui->transmit_thread, rpc_system_gui_screen_stream_frame_transmit_thread); - furi_thread_set_context(rpc_gui->transmit_thread, rpc_gui); - furi_thread_set_stack_size(rpc_gui->transmit_thread, 1024); + rpc_gui->transmit_thread = furi_thread_alloc_ex( + "GuiRpcWorker", 1024, rpc_system_gui_screen_stream_frame_transmit_thread, rpc_gui); furi_thread_start(rpc_gui->transmit_thread); // GUI framebuffer callback gui_add_framebuffer_callback( diff --git a/applications/system/updater/cli/updater_cli.c b/applications/system/updater/cli/updater_cli.c index c3cdbb5f..f8e21ca3 100644 --- a/applications/system/updater/cli/updater_cli.c +++ b/applications/system/updater/cli/updater_cli.c @@ -110,11 +110,8 @@ static void updater_start_app() { * inside loader process, at startup. * So, accessing its record would cause a deadlock */ - FuriThread* thread = furi_thread_alloc(); - - furi_thread_set_name(thread, "UpdateAppSpawner"); - furi_thread_set_stack_size(thread, 768); - furi_thread_set_callback(thread, updater_spawner_thread_worker); + FuriThread* thread = + furi_thread_alloc_ex("UpdateAppSpawner", 768, updater_spawner_thread_worker, NULL); furi_thread_set_state_callback(thread, updater_spawner_thread_cleanup); furi_thread_set_state_context(thread, thread); furi_thread_start(thread); diff --git a/applications/system/updater/util/update_task.c b/applications/system/updater/util/update_task.c index de172dd4..b43a6df1 100644 --- a/applications/system/updater/util/update_task.c +++ b/applications/system/updater/util/update_task.c @@ -216,11 +216,8 @@ UpdateTask* update_task_alloc() { update_task->boot_mode = furi_hal_rtc_get_boot_mode(); update_task->update_path = furi_string_alloc(); - FuriThread* thread = update_task->thread = furi_thread_alloc(); - - furi_thread_set_name(thread, "UpdateWorker"); - furi_thread_set_stack_size(thread, 5120); - furi_thread_set_context(thread, update_task); + FuriThread* thread = update_task->thread = + furi_thread_alloc_ex("UpdateWorker", 5120, NULL, update_task); furi_thread_set_state_callback(thread, update_task_worker_thread_cb); furi_thread_set_state_context(thread, update_task); diff --git a/firmware/targets/f7/Src/main.c b/firmware/targets/f7/Src/main.c index 5f33569a..d9a2221a 100644 --- a/firmware/targets/f7/Src/main.c +++ b/firmware/targets/f7/Src/main.c @@ -26,10 +26,7 @@ int main() { // Flipper critical FURI HAL furi_hal_init_early(); - FuriThread* main_thread = furi_thread_alloc(); - furi_thread_set_name(main_thread, "Init"); - furi_thread_set_stack_size(main_thread, 4096); - furi_thread_set_callback(main_thread, init_task); + FuriThread* main_thread = furi_thread_alloc_ex("Init", 4096, init_task, NULL); #ifdef FURI_RAM_EXEC furi_thread_start(main_thread); diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 1ad5efa7..5ccb9d43 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1471,6 +1471,7 @@ Function,+,furi_string_utf8_length,size_t,FuriString* Function,+,furi_string_utf8_push,void,"FuriString*, FuriStringUnicodeValue" Function,+,furi_string_vprintf,int,"FuriString*, const char[], va_list" Function,+,furi_thread_alloc,FuriThread*, +Function,+,furi_thread_alloc_ex,FuriThread*,"const char*, uint32_t, FuriThreadCallback, void*" Function,+,furi_thread_catch,void, Function,-,furi_thread_disable_heap_trace,void,FuriThread* Function,+,furi_thread_enable_heap_trace,void,FuriThread* diff --git a/firmware/targets/f7/ble_glue/ble_app.c b/firmware/targets/f7/ble_glue/ble_app.c index 3cf02009..30be3c7c 100644 --- a/firmware/targets/f7/ble_glue/ble_app.c +++ b/firmware/targets/f7/ble_glue/ble_app.c @@ -40,11 +40,7 @@ bool ble_app_init() { ble_app->hci_mtx = furi_mutex_alloc(FuriMutexTypeNormal); ble_app->hci_sem = furi_semaphore_alloc(1, 0); // HCI transport layer thread to handle user asynch events - ble_app->thread = furi_thread_alloc(); - furi_thread_set_name(ble_app->thread, "BleHciDriver"); - furi_thread_set_stack_size(ble_app->thread, 1024); - furi_thread_set_context(ble_app->thread, ble_app); - furi_thread_set_callback(ble_app->thread, ble_app_hci_thread); + ble_app->thread = furi_thread_alloc_ex("BleHciDriver", 1024, ble_app_hci_thread, ble_app); furi_thread_start(ble_app->thread); // Initialize Ble Transport Layer diff --git a/firmware/targets/f7/ble_glue/ble_glue.c b/firmware/targets/f7/ble_glue/ble_glue.c index 87af5f2a..b3752f17 100644 --- a/firmware/targets/f7/ble_glue/ble_glue.c +++ b/firmware/targets/f7/ble_glue/ble_glue.c @@ -78,11 +78,7 @@ void ble_glue_init() { ble_glue->shci_sem = furi_semaphore_alloc(1, 0); // FreeRTOS system task creation - ble_glue->thread = furi_thread_alloc(); - furi_thread_set_name(ble_glue->thread, "BleShciDriver"); - furi_thread_set_stack_size(ble_glue->thread, 1024); - furi_thread_set_context(ble_glue->thread, ble_glue); - furi_thread_set_callback(ble_glue->thread, ble_glue_shci_thread); + ble_glue->thread = furi_thread_alloc_ex("BleShciDriver", 1024, ble_glue_shci_thread, ble_glue); furi_thread_start(ble_glue->thread); // System channel initialization diff --git a/firmware/targets/f7/ble_glue/gap.c b/firmware/targets/f7/ble_glue/gap.c index cf27df3a..3e29527e 100644 --- a/firmware/targets/f7/ble_glue/gap.c +++ b/firmware/targets/f7/ble_glue/gap.c @@ -492,11 +492,7 @@ bool gap_init(GapConfig* config, GapEventCallback on_event_cb, void* context) { gap->enable_adv = true; // Thread configuration - gap->thread = furi_thread_alloc(); - furi_thread_set_name(gap->thread, "BleGapDriver"); - furi_thread_set_stack_size(gap->thread, 1024); - furi_thread_set_context(gap->thread, gap); - furi_thread_set_callback(gap->thread, gap_app); + gap->thread = furi_thread_alloc_ex("BleGapDriver", 1024, gap_app, gap); furi_thread_start(gap->thread); // Command queue allocation diff --git a/firmware/targets/f7/furi_hal/furi_hal.c b/firmware/targets/f7/furi_hal/furi_hal.c index 141efdb6..ec82c377 100644 --- a/firmware/targets/f7/furi_hal/furi_hal.c +++ b/firmware/targets/f7/furi_hal/furi_hal.c @@ -61,26 +61,25 @@ void furi_hal_init() { furi_hal_crypto_init(); - // USB -#ifndef FURI_RAM_EXEC - furi_hal_usb_init(); - FURI_LOG_I(TAG, "USB OK"); -#endif - furi_hal_i2c_init(); // High Level furi_hal_power_init(); furi_hal_light_init(); + + furi_hal_bt_init(); + furi_hal_memory_init(); + furi_hal_compress_icon_init(); + #ifndef FURI_RAM_EXEC + // USB + furi_hal_usb_init(); + FURI_LOG_I(TAG, "USB OK"); furi_hal_vibro_init(); furi_hal_subghz_init(); furi_hal_nfc_init(); furi_hal_rfid_init(); #endif - furi_hal_bt_init(); - furi_hal_memory_init(); - furi_hal_compress_icon_init(); // FatFS driver initialization MX_FATFS_Init(); diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb.c b/firmware/targets/f7/furi_hal/furi_hal_usb.c index 86b10c79..1eaeffd6 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_usb.c +++ b/firmware/targets/f7/furi_hal/furi_hal_usb.c @@ -80,10 +80,8 @@ void furi_hal_usb_init(void) { NVIC_EnableIRQ(USB_LP_IRQn); NVIC_EnableIRQ(USB_HP_IRQn); - usb.thread = furi_thread_alloc(); - furi_thread_set_name(usb.thread, "UsbDriver"); - furi_thread_set_stack_size(usb.thread, 1024); - furi_thread_set_callback(usb.thread, furi_hal_usb_thread); + usb.thread = furi_thread_alloc_ex("UsbDriver", 1024, furi_hal_usb_thread, NULL); + furi_thread_mark_as_service(usb.thread); furi_thread_start(usb.thread); FURI_LOG_I(TAG, "Init OK"); diff --git a/furi/core/thread.c b/furi/core/thread.c index 201b47fe..34cc7d98 100644 --- a/furi/core/thread.c +++ b/furi/core/thread.c @@ -135,6 +135,19 @@ FuriThread* furi_thread_alloc() { return thread; } +FuriThread* furi_thread_alloc_ex( + const char* name, + uint32_t stack_size, + FuriThreadCallback callback, + void* context) { + FuriThread* thread = furi_thread_alloc(); + furi_thread_set_name(thread, name); + furi_thread_set_stack_size(thread, stack_size); + furi_thread_set_callback(thread, callback); + furi_thread_set_context(thread, context); + return thread; +} + void furi_thread_free(FuriThread* thread) { furi_assert(thread); furi_assert(thread->state == FuriThreadStateStopped); diff --git a/furi/core/thread.h b/furi/core/thread.h index fda81bb3..6ec8ebfe 100644 --- a/furi/core/thread.h +++ b/furi/core/thread.h @@ -60,6 +60,20 @@ typedef void (*FuriThreadStateCallback)(FuriThreadState state, void* context); */ FuriThread* furi_thread_alloc(); +/** Allocate FuriThread, shortcut version + * + * @param name + * @param stack_size + * @param callback + * @param context + * @return FuriThread* + */ +FuriThread* furi_thread_alloc_ex( + const char* name, + uint32_t stack_size, + FuriThreadCallback callback, + void* context); + /** Release FuriThread * * @param thread FuriThread instance diff --git a/furi/flipper.c b/furi/flipper.c index 2acfea01..73899e58 100644 --- a/furi/flipper.c +++ b/furi/flipper.c @@ -34,11 +34,11 @@ void flipper_init() { for(size_t i = 0; i < FLIPPER_SERVICES_COUNT; i++) { FURI_LOG_I(TAG, "starting service %s", FLIPPER_SERVICES[i].name); - FuriThread* thread = furi_thread_alloc(); - - furi_thread_set_name(thread, FLIPPER_SERVICES[i].name); - furi_thread_set_stack_size(thread, FLIPPER_SERVICES[i].stack_size); - furi_thread_set_callback(thread, FLIPPER_SERVICES[i].app); + FuriThread* thread = furi_thread_alloc_ex( + FLIPPER_SERVICES[i].name, + FLIPPER_SERVICES[i].stack_size, + FLIPPER_SERVICES[i].app, + NULL); furi_thread_mark_as_service(thread); furi_thread_start(thread); diff --git a/lib/ST25RFAL002/platform.c b/lib/ST25RFAL002/platform.c index af9dc6ff..754e2565 100644 --- a/lib/ST25RFAL002/platform.c +++ b/lib/ST25RFAL002/platform.c @@ -45,11 +45,9 @@ void platformDisableIrqCallback() { void platformSetIrqCallback(PlatformIrqCallback callback) { rfal_platform.callback = callback; - rfal_platform.thread = furi_thread_alloc(); - - furi_thread_set_name(rfal_platform.thread, "RfalIrqDriver"); - furi_thread_set_callback(rfal_platform.thread, rfal_platform_irq_thread); - furi_thread_set_stack_size(rfal_platform.thread, 1024); + rfal_platform.thread = + furi_thread_alloc_ex("RfalIrqDriver", 1024, rfal_platform_irq_thread, NULL); + furi_thread_mark_as_service(rfal_platform.thread); furi_thread_set_priority(rfal_platform.thread, FuriThreadPriorityIsr); furi_thread_start(rfal_platform.thread); diff --git a/lib/flipper_application/flipper_application.c b/lib/flipper_application/flipper_application.c index cf44eebb..618a3623 100644 --- a/lib/flipper_application/flipper_application.c +++ b/lib/flipper_application/flipper_application.c @@ -104,11 +104,8 @@ FuriThread* flipper_application_spawn(FlipperApplication* app, void* args) { const FlipperApplicationManifest* manifest = flipper_application_get_manifest(app); furi_check(manifest->stack_size > 0); - app->thread = furi_thread_alloc(); - furi_thread_set_stack_size(app->thread, manifest->stack_size); - furi_thread_set_name(app->thread, manifest->name); - furi_thread_set_callback(app->thread, flipper_application_thread); - furi_thread_set_context(app->thread, args); + app->thread = furi_thread_alloc_ex( + manifest->name, manifest->stack_size, flipper_application_thread, args); return app->thread; } diff --git a/lib/infrared/worker/infrared_worker.c b/lib/infrared/worker/infrared_worker.c index c03f180f..57288f3c 100644 --- a/lib/infrared/worker/infrared_worker.c +++ b/lib/infrared/worker/infrared_worker.c @@ -223,10 +223,7 @@ void infrared_worker_rx_set_received_signal_callback( InfraredWorker* infrared_worker_alloc() { InfraredWorker* instance = malloc(sizeof(InfraredWorker)); - instance->thread = furi_thread_alloc(); - furi_thread_set_name(instance->thread, "InfraredWorker"); - furi_thread_set_stack_size(instance->thread, 2048); - furi_thread_set_context(instance->thread, instance); + instance->thread = furi_thread_alloc_ex("InfraredWorker", 2048, NULL, instance); size_t buffer_size = MAX(sizeof(InfraredWorkerTiming) * (MAX_TIMINGS_AMOUNT + 1), diff --git a/lib/lfrfid/lfrfid_raw_worker.c b/lib/lfrfid/lfrfid_raw_worker.c index 1547d20f..8c69aced 100644 --- a/lib/lfrfid/lfrfid_raw_worker.c +++ b/lib/lfrfid/lfrfid_raw_worker.c @@ -61,10 +61,7 @@ static int32_t lfrfid_raw_emulate_worker_thread(void* thread_context); LFRFIDRawWorker* lfrfid_raw_worker_alloc() { LFRFIDRawWorker* worker = malloc(sizeof(LFRFIDRawWorker)); - worker->thread = furi_thread_alloc(); - furi_thread_set_name(worker->thread, "lfrfid_raw_worker"); - furi_thread_set_context(worker->thread, worker); - furi_thread_set_stack_size(worker->thread, 2048); + worker->thread = furi_thread_alloc_ex("LfrfidRawWorker", 2048, NULL, worker); worker->events = furi_event_flag_alloc(NULL); diff --git a/lib/lfrfid/lfrfid_worker.c b/lib/lfrfid/lfrfid_worker.c index f3e37fa3..f33c1aed 100644 --- a/lib/lfrfid/lfrfid_worker.c +++ b/lib/lfrfid/lfrfid_worker.c @@ -29,11 +29,7 @@ LFRFIDWorker* lfrfid_worker_alloc(ProtocolDict* dict) { worker->raw_filename = NULL; worker->mode_storage = NULL; - worker->thread = furi_thread_alloc(); - furi_thread_set_name(worker->thread, "lfrfid_worker"); - furi_thread_set_callback(worker->thread, lfrfid_worker_thread); - furi_thread_set_context(worker->thread, worker); - furi_thread_set_stack_size(worker->thread, 2048); + worker->thread = furi_thread_alloc_ex("LfrfidWorker", 2048, lfrfid_worker_thread, worker); worker->protocols = dict; diff --git a/lib/nfc/helpers/reader_analyzer.c b/lib/nfc/helpers/reader_analyzer.c index 7fed9c6f..73b4b125 100644 --- a/lib/nfc/helpers/reader_analyzer.c +++ b/lib/nfc/helpers/reader_analyzer.c @@ -104,11 +104,8 @@ ReaderAnalyzer* reader_analyzer_alloc() { instance->stream = furi_stream_buffer_alloc(READER_ANALYZER_MAX_BUFF_SIZE, sizeof(ReaderAnalyzerHeader)); - instance->thread = furi_thread_alloc(); - furi_thread_set_name(instance->thread, "ReaderAnalyzerWorker"); - furi_thread_set_stack_size(instance->thread, 2048); - furi_thread_set_callback(instance->thread, reader_analyzer_thread); - furi_thread_set_context(instance->thread, instance); + instance->thread = + furi_thread_alloc_ex("ReaderAnalyzerWorker", 2048, reader_analyzer_thread, instance); furi_thread_set_priority(instance->thread, FuriThreadPriorityLow); return instance; diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c index 5ad37c6e..c701132c 100644 --- a/lib/nfc/nfc_worker.c +++ b/lib/nfc/nfc_worker.c @@ -12,11 +12,7 @@ NfcWorker* nfc_worker_alloc() { NfcWorker* nfc_worker = malloc(sizeof(NfcWorker)); // Worker thread attributes - nfc_worker->thread = furi_thread_alloc(); - furi_thread_set_name(nfc_worker->thread, "NfcWorker"); - furi_thread_set_stack_size(nfc_worker->thread, 8192); - furi_thread_set_callback(nfc_worker->thread, nfc_worker_task); - furi_thread_set_context(nfc_worker->thread, nfc_worker); + nfc_worker->thread = furi_thread_alloc_ex("NfcWorker", 8192, nfc_worker_task, nfc_worker); nfc_worker->callback = NULL; nfc_worker->context = NULL; diff --git a/lib/one_wire/ibutton/ibutton_worker.c b/lib/one_wire/ibutton/ibutton_worker.c index 26982bcb..29126d84 100644 --- a/lib/one_wire/ibutton/ibutton_worker.c +++ b/lib/one_wire/ibutton/ibutton_worker.c @@ -37,11 +37,7 @@ iButtonWorker* ibutton_worker_alloc() { worker->emulate_cb = NULL; worker->cb_ctx = NULL; - worker->thread = furi_thread_alloc(); - furi_thread_set_name(worker->thread, "ibutton_worker"); - furi_thread_set_callback(worker->thread, ibutton_worker_thread); - furi_thread_set_context(worker->thread, worker); - furi_thread_set_stack_size(worker->thread, 2048); + worker->thread = furi_thread_alloc_ex("iButtonWorker", 2048, ibutton_worker_thread, worker); worker->protocols = protocol_dict_alloc(ibutton_protocols, iButtonProtocolMax); diff --git a/lib/subghz/subghz_file_encoder_worker.c b/lib/subghz/subghz_file_encoder_worker.c index 29834b41..f987430d 100644 --- a/lib/subghz/subghz_file_encoder_worker.c +++ b/lib/subghz/subghz_file_encoder_worker.c @@ -174,11 +174,8 @@ static int32_t subghz_file_encoder_worker_thread(void* context) { SubGhzFileEncoderWorker* subghz_file_encoder_worker_alloc() { SubGhzFileEncoderWorker* instance = malloc(sizeof(SubGhzFileEncoderWorker)); - instance->thread = furi_thread_alloc(); - furi_thread_set_name(instance->thread, "SubGhzFEWorker"); - furi_thread_set_stack_size(instance->thread, 2048); - furi_thread_set_context(instance->thread, instance); - furi_thread_set_callback(instance->thread, subghz_file_encoder_worker_thread); + instance->thread = + furi_thread_alloc_ex("SubGhzFEWorker", 2048, subghz_file_encoder_worker_thread, instance); instance->stream = furi_stream_buffer_alloc(sizeof(int32_t) * 2048, sizeof(int32_t)); instance->storage = furi_record_open(RECORD_STORAGE); diff --git a/lib/subghz/subghz_tx_rx_worker.c b/lib/subghz/subghz_tx_rx_worker.c index 37c0bfc5..42124beb 100644 --- a/lib/subghz/subghz_tx_rx_worker.c +++ b/lib/subghz/subghz_tx_rx_worker.c @@ -201,11 +201,8 @@ static int32_t subghz_tx_rx_worker_thread(void* context) { SubGhzTxRxWorker* subghz_tx_rx_worker_alloc() { SubGhzTxRxWorker* instance = malloc(sizeof(SubGhzTxRxWorker)); - instance->thread = furi_thread_alloc(); - furi_thread_set_name(instance->thread, "SubGhzTxRxWorker"); - furi_thread_set_stack_size(instance->thread, 2048); - furi_thread_set_context(instance->thread, instance); - furi_thread_set_callback(instance->thread, subghz_tx_rx_worker_thread); + instance->thread = + furi_thread_alloc_ex("SubGhzTxRxWorker", 2048, subghz_tx_rx_worker_thread, instance); instance->stream_tx = furi_stream_buffer_alloc(sizeof(uint8_t) * SUBGHZ_TXRX_WORKER_BUF_SIZE, sizeof(uint8_t)); instance->stream_rx = diff --git a/lib/subghz/subghz_worker.c b/lib/subghz/subghz_worker.c index 61146c16..35e39988 100644 --- a/lib/subghz/subghz_worker.c +++ b/lib/subghz/subghz_worker.c @@ -88,11 +88,8 @@ static int32_t subghz_worker_thread_callback(void* context) { SubGhzWorker* subghz_worker_alloc() { SubGhzWorker* instance = malloc(sizeof(SubGhzWorker)); - instance->thread = furi_thread_alloc(); - furi_thread_set_name(instance->thread, "SubGhzWorker"); - furi_thread_set_stack_size(instance->thread, 2048); - furi_thread_set_context(instance->thread, instance); - furi_thread_set_callback(instance->thread, subghz_worker_thread_callback); + instance->thread = + furi_thread_alloc_ex("SubGhzWorker", 2048, subghz_worker_thread_callback, instance); instance->stream = furi_stream_buffer_alloc(sizeof(LevelDuration) * 4096, sizeof(LevelDuration)); From 4f3ef83c77490f344ab89222d4800f705e0aa061 Mon Sep 17 00:00:00 2001 From: lauaall <48836917+skelq@users.noreply.github.com> Date: Wed, 23 Nov 2022 14:59:55 +0200 Subject: [PATCH 05/25] Docs: fix typos (#2016) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed typos in UnitTests.md Co-authored-by: あく --- documentation/UnitTests.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/documentation/UnitTests.md b/documentation/UnitTests.md index 3f56a9a9..89642656 100644 --- a/documentation/UnitTests.md +++ b/documentation/UnitTests.md @@ -13,7 +13,7 @@ Running existing unit tests is useful to ensure that the new code doesn't introd In order to run the unit tests, follow these steps: 1. Compile the firmware with the tests enabled: `./fbt FIRMWARE_APP_SET=unit_tests`. 2. Flash the firmware using your preferred method. -3. Copy the [assets/unit_tests](assets/unit_tests) folder to the root your Flipper Zero's SD card. +3. Copy the [assets/unit_tests](assets/unit_tests) folder to the root of your Flipper Zero's SD card. 4. Launch the CLI session and run the `unit_tests` command. **NOTE:** To run a particular test (and skip all others), specify its name as the command argument. @@ -22,9 +22,9 @@ See [test_index.c](applications/debug/unit_tests/test_index.c) for the complete ## Adding unit tests ### General #### Entry point -The common entry point for all tests it the [unit_tests](applications/debug/unit_tests) application. Test-specific code is placed into an arbitrarily named subdirectory and is then called from the [test_index.c](applications/debug/unit_tests/test_index.c) source file. +The common entry point for all tests is the [unit_tests](applications/debug/unit_tests) application. Test-specific code is placed into an arbitrarily named subdirectory and is then called from the [test_index.c](applications/debug/unit_tests/test_index.c) source file. #### Test assets -Some unit tests require external data in order to function. These files (commonly called assets) reside in the [assets/unit_tests](/assets/unit_tests) directory in their respective subdirectories. Asset files can be of any type (plain text, FlipperFormat(FFF), binary etc). +Some unit tests require external data in order to function. These files (commonly called assets) reside in the [assets/unit_tests](/assets/unit_tests) directory in their respective subdirectories. Asset files can be of any type (plain text, FlipperFormat(FFF), binary, etc). ### Application-specific #### Infrared Each infrared protocol has a corresponding set of unit tests, so it makes sense to implement one when adding support for a new protocol. @@ -37,8 +37,8 @@ In order to add unit tests for your protocol, follow these steps: ##### Test data format Each unit test has 3 sections: 1. `decoder` - takes in raw signal and outputs decoded messages. -2. `encoder` - takes in decoded messages and outputs raw signal. -3. `encoder_decoder` - takes in decoded messages, turns them into raw signal and then decodes again. +2. `encoder` - takes in decoded messages and outputs a raw signal. +3. `encoder_decoder` - takes in decoded messages, turns them into a raw signal, and then decodes again. Infrared test asset files have an `.irtest` extension and are regular `.ir` files with a few additions. Decoder input data has signal names `decoder_input_N`, where N is a test sequence number. Expected data goes under the name `decoder_expected_N`. When testing the encoder these two are switched. @@ -46,4 +46,4 @@ Decoder input data has signal names `decoder_input_N`, where N is a test sequenc Decoded data is represented in arrays (since a single raw signal may decode to several messages). If there is only one signal, then it has to be an array of size 1. Use the existing files as syntax examples. ##### Getting raw signals -Recording raw IR signals is possible using Flipper Zero. Launch the CLI session, run `ir rx raw`, then point the remote towards Flipper's receiver and send the signals. The raw signal data will be printed to the console in a convenient format. +Recording raw IR signals are possible using the Flipper Zero. Launch the CLI session, run `ir rx raw`, then point the remote towards Flipper's receiver and send the signals. The raw signal data will be printed to the console in a convenient format. From 669822cdd2d676150a78c7d3336d2af3bc7da529 Mon Sep 17 00:00:00 2001 From: MangoTornado <31556509+MangoTornado@users.noreply.github.com> Date: Wed, 23 Nov 2022 08:15:08 -0500 Subject: [PATCH 06/25] Fix typos in various outputs (#2032) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix typos in various outputs * Update u2f_view.c Co-authored-by: あく --- applications/main/u2f/views/u2f_view.c | 4 ++-- applications/services/cli/cli_command_gpio.c | 2 +- assets/dolphin/ReadMe.md | 2 +- scripts/toolchain/fbtenv.sh | 4 ++-- site_scons/commandline.scons | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/applications/main/u2f/views/u2f_view.c b/applications/main/u2f/views/u2f_view.c index 181c495d..bf220ca2 100644 --- a/applications/main/u2f/views/u2f_view.c +++ b/applications/main/u2f/views/u2f_view.c @@ -37,10 +37,10 @@ static void u2f_view_draw_callback(Canvas* canvas, void* _model) { } else if(model->display_msg == U2fMsgSuccess) { canvas_draw_icon(canvas, 22, 15, &I_Connected_62x31); canvas_draw_str_aligned( - canvas, 128 / 2, 3, AlignCenter, AlignTop, "Authentication successfull!"); + canvas, 128 / 2, 3, AlignCenter, AlignTop, "Authentication successful!"); } else if(model->display_msg == U2fMsgError) { canvas_draw_icon(canvas, 22, 15, &I_Error_62x31); - canvas_draw_str_aligned(canvas, 128 / 2, 3, AlignCenter, AlignTop, "Ceritficate error"); + canvas_draw_str_aligned(canvas, 128 / 2, 3, AlignCenter, AlignTop, "Certificate error"); } } diff --git a/applications/services/cli/cli_command_gpio.c b/applications/services/cli/cli_command_gpio.c index 3e7301cd..0b29f485 100644 --- a/applications/services/cli/cli_command_gpio.c +++ b/applications/services/cli/cli_command_gpio.c @@ -121,7 +121,7 @@ void cli_command_gpio_mode(Cli* cli, FuriString* args, void* context) { if(cli_command_gpio_pins[num].debug) { printf( - "Changeing this pin mode may damage hardware. Are you sure you want to continue? (y/n)?\r\n"); + "Changing this pin mode may damage hardware. Are you sure you want to continue? (y/n)?\r\n"); char c = cli_getc(cli); if(c != 'y' && c != 'Y') { printf("Cancelled.\r\n"); diff --git a/assets/dolphin/ReadMe.md b/assets/dolphin/ReadMe.md index 6b59d231..643086c2 100644 --- a/assets/dolphin/ReadMe.md +++ b/assets/dolphin/ReadMe.md @@ -52,7 +52,7 @@ Version: 1 - `Active cooldown` - amount of seconds (after passive mode) to pass before entering next active mode. - `Bubble slots` - amount of bubble sequences. -- Any bubble sequence plays whole sequence during active mode. There can be many bubble sequences and bubbles inside it. Bubbles in 1 bubble sequence have to reside in 1 slot. Bubbles order in 1 bubble sequence is determined by occurance in file. As soon as frame index goes out of EndFrame index of bubble - next animation bubble is choosen. There can also be free of bubbles frames between 2 bubbles. +- Any bubble sequence plays whole sequence during active mode. There can be many bubble sequences and bubbles inside it. Bubbles in 1 bubble sequence have to reside in 1 slot. Bubbles order in 1 bubble sequence is determined by occurrence in file. As soon as frame index goes out of EndFrame index of bubble - next animation bubble is chosen. There can also be free of bubbles frames between 2 bubbles. - `Slot` - number to unite bubbles for same sequence. - `X`, `Y` - are coordinates of left top corner of bubble. diff --git a/scripts/toolchain/fbtenv.sh b/scripts/toolchain/fbtenv.sh index 852e0039..f3e4cb1f 100755 --- a/scripts/toolchain/fbtenv.sh +++ b/scripts/toolchain/fbtenv.sh @@ -13,7 +13,7 @@ fbtenv_show_usage() echo "Running this script manually is wrong, please source it"; echo "Example:"; printf "\tsource scripts/toolchain/fbtenv.sh\n"; - echo "To restore your enviroment source fbtenv.sh with '--restore'." + echo "To restore your environment source fbtenv.sh with '--restore'." echo "Example:"; printf "\tsource scripts/toolchain/fbtenv.sh --restore\n"; } @@ -227,7 +227,7 @@ fbtenv_curl_wget_check() echo; echo "$TOOLCHAIN_URL"; echo; - echo "And place in $FBT_TOOLCHAIN_PATH/toolchain/ dir mannualy"; + echo "And place in $FBT_TOOLCHAIN_PATH/toolchain/ dir manually"; return 1; fi echo "yes" diff --git a/site_scons/commandline.scons b/site_scons/commandline.scons index 6087c1c7..fc2534ed 100644 --- a/site_scons/commandline.scons +++ b/site_scons/commandline.scons @@ -15,7 +15,7 @@ AddOption( nargs=1, action="store", default="fbt_options.py", - help="Enviroment option file", + help="Environment option file", ) AddOption( @@ -23,7 +23,7 @@ AddOption( action="store", dest="extra_int_apps", default="", - help="List of applications to add to firmare's built-ins. Also see FIRMWARE_APP_SET and FIRMWARE_APPS", + help="List of applications to add to firmware's built-ins. Also see FIRMWARE_APP_SET and FIRMWARE_APPS", ) AddOption( From 1c8451fad49e62a482aa81342631954856742b47 Mon Sep 17 00:00:00 2001 From: Kyhwana Pardus Date: Thu, 24 Nov 2022 02:23:11 +1300 Subject: [PATCH 07/25] Fix typos in subghz_cli.c (#2030) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix up the "receive" typos Co-authored-by: あく --- applications/main/subghz/subghz_cli.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/applications/main/subghz/subghz_cli.c b/applications/main/subghz/subghz_cli.c index ad5d8afb..b6471b33 100644 --- a/applications/main/subghz/subghz_cli.c +++ b/applications/main/subghz/subghz_cli.c @@ -300,7 +300,7 @@ void subghz_cli_command_rx(Cli* cli, FuriString* args, void* context) { furi_hal_power_suppress_charge_exit(); - printf("\r\nPackets recieved %u\r\n", instance->packet_count); + printf("\r\nPackets received %u\r\n", instance->packet_count); // Cleanup subghz_receiver_free(receiver); @@ -408,7 +408,7 @@ void subghz_cli_command_decode_raw(Cli* cli, FuriString* args, void* context) { } } - printf("\r\nPackets recieved \033[0;32m%u\033[0m\r\n", instance->packet_count); + printf("\r\nPackets received \033[0;32m%u\033[0m\r\n", instance->packet_count); // Cleanup subghz_receiver_free(receiver); @@ -438,7 +438,7 @@ static void subghz_cli_command_print_usage() { printf("\r\n"); printf(" debug cmd:\r\n"); printf("\ttx_carrier \t - Transmit carrier\r\n"); - printf("\trx_carrier \t - Receiv carrier\r\n"); + printf("\trx_carrier \t - Receive carrier\r\n"); printf( "\tencrypt_keeloq \t - Encrypt keeloq manufacture keys\r\n"); printf( From 9bb0dbaa3e7cc9f7ded52d6419ed156e318b1c66 Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Wed, 23 Nov 2022 17:31:39 +0400 Subject: [PATCH 08/25] SubGhz: frequency analyzer. 2dbi desensitization, rssi averaging to reduce jitter, new rssi indicators in log_mode, GUI fix (#2020) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- .../subghz_frequency_analyzer_worker.c | 24 +++----- .../subghz_frequency_analyzer_worker.h | 2 + .../subghz/views/subghz_frequency_analyzer.c | 56 ++++++++++--------- 3 files changed, 41 insertions(+), 41 deletions(-) diff --git a/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c b/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c index 7826e2ae..7463cfaf 100644 --- a/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c +++ b/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c @@ -5,8 +5,6 @@ #define TAG "SubghzFrequencyAnalyzerWorker" -#define SUBGHZ_FREQUENCY_ANALYZER_THRESHOLD -95.0f - static const uint8_t subghz_preset_ook_58khz[][2] = { {CC1101_MDMCFG4, 0b11110111}, // Rx BW filter is 58.035714kHz /* End */ @@ -71,7 +69,7 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) { .frequency_coarse = 0, .rssi_coarse = 0, .frequency_fine = 0, .rssi_fine = 0}; float rssi = 0; uint32_t frequency = 0; - float rssi_temp = 0; + float rssi_temp = -127.0f; uint32_t frequency_temp = 0; CC1101Status status; @@ -196,7 +194,7 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) { TAG, "=:%lu:%f", frequency_rssi.frequency_fine, (double)frequency_rssi.rssi_fine); instance->sample_hold_counter = 20; - rssi_temp = frequency_rssi.rssi_fine; + rssi_temp = (rssi_temp + frequency_rssi.rssi_fine) / 2; frequency_temp = frequency_rssi.frequency_fine; if(instance->filVal) { @@ -207,10 +205,7 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) { // Deliver callback if(instance->pair_callback) { instance->pair_callback( - instance->context, - frequency_rssi.frequency_fine, - frequency_rssi.rssi_fine, - true); + instance->context, frequency_rssi.frequency_fine, rssi_temp, true); } } else if( // Deliver results coarse (frequency_rssi.rssi_coarse > SUBGHZ_FREQUENCY_ANALYZER_THRESHOLD) && @@ -222,7 +217,7 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) { (double)frequency_rssi.rssi_coarse); instance->sample_hold_counter = 20; - rssi_temp = frequency_rssi.rssi_coarse; + rssi_temp = (rssi_temp + frequency_rssi.rssi_coarse) / 2; frequency_temp = frequency_rssi.frequency_coarse; if(instance->filVal) { frequency_rssi.frequency_coarse = @@ -232,15 +227,12 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) { // Deliver callback if(instance->pair_callback) { instance->pair_callback( - instance->context, - frequency_rssi.frequency_coarse, - frequency_rssi.rssi_coarse, - true); + instance->context, frequency_rssi.frequency_coarse, rssi_temp, true); } } else { if(instance->sample_hold_counter > 0) { instance->sample_hold_counter--; - if(instance->sample_hold_counter == 18) { + if(instance->sample_hold_counter == 15) { if(instance->pair_callback) { instance->pair_callback( instance->context, frequency_temp, rssi_temp, false); @@ -248,8 +240,8 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) { } } else { instance->filVal = 0; - if(instance->pair_callback) - instance->pair_callback(instance->context, 0, 0, false); + rssi_temp = -127.0f; + instance->pair_callback(instance->context, 0, 0, false); } } } diff --git a/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.h b/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.h index 8bd1addc..ed5bd964 100644 --- a/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.h +++ b/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.h @@ -3,6 +3,8 @@ #include #include "../subghz_i.h" +#define SUBGHZ_FREQUENCY_ANALYZER_THRESHOLD -93.0f + typedef struct SubGhzFrequencyAnalyzerWorker SubGhzFrequencyAnalyzerWorker; typedef void (*SubGhzFrequencyAnalyzerWorkerPairCallback)( diff --git a/applications/main/subghz/views/subghz_frequency_analyzer.c b/applications/main/subghz/views/subghz_frequency_analyzer.c index e980bd97..12989840 100644 --- a/applications/main/subghz/views/subghz_frequency_analyzer.c +++ b/applications/main/subghz/views/subghz_frequency_analyzer.c @@ -13,8 +13,6 @@ #include #define LOG_FREQUENCY_MAX_ITEMS 60 // uint8_t (limited by 'seq' of SubGhzFrequencyAnalyzerLogItem) -#define RSSI_OFFSET 74 -#define RSSI_MAX 53 // 127 - RSSI_OFFSET #define SNPRINTF_FREQUENCY(buff, freq) \ snprintf(buff, sizeof(buff), "%03ld.%03ld", freq / 1000000 % 1000, freq / 1000 % 1000); @@ -49,7 +47,7 @@ typedef struct { } SubGhzFrequencyAnalyzerModel; static inline uint8_t rssi_sanitize(float rssi) { - return (rssi * -1.0f) - RSSI_OFFSET; + return (rssi ? (uint8_t)(rssi - SUBGHZ_FREQUENCY_ANALYZER_THRESHOLD) : 0); } void subghz_frequency_analyzer_set_callback( @@ -65,12 +63,25 @@ void subghz_frequency_analyzer_set_callback( void subghz_frequency_analyzer_draw_rssi(Canvas* canvas, uint8_t rssi, uint8_t x, uint8_t y) { uint8_t column_number = 0; if(rssi) { - rssi = rssi / 3; + rssi = rssi / 3 + 2; + if(rssi > 20) rssi = 20; for(uint8_t i = 1; i < rssi; i++) { - if(i > 20) break; if(i % 4) { column_number++; - canvas_draw_box(canvas, x + 2 * i, y - column_number, 2, 4 + column_number); + canvas_draw_box(canvas, x + 2 * i, y - column_number, 2, column_number); + } + } + } +} + +void subghz_frequency_analyzer_draw_log_rssi(Canvas* canvas, uint8_t rssi, uint8_t x, uint8_t y) { + uint8_t column_height = 6; + if(rssi) { + //rssi = rssi + if(rssi > 54) rssi = 54; + for(uint8_t i = 1; i < rssi; i++) { + if(i % 5) { + canvas_draw_box(canvas, x + i, y - column_height, 1, column_height); } } } @@ -86,9 +97,9 @@ static void subghz_frequency_analyzer_log_frequency_draw( const size_t items_count = SubGhzFrequencyAnalyzerLogItemArray_size(model->log_frequency); if(items_count == 0) { - canvas_draw_rframe(canvas, offset_x + 27u, offset_y - 3u, 73u, 16u, 5u); + canvas_draw_rframe(canvas, offset_x + 27, offset_y - 3, 73, 16, 5); canvas_draw_str_aligned( - canvas, offset_x + 64u, offset_y + 8u, AlignCenter, AlignBottom, "No records"); + canvas, offset_x + 64, offset_y + 8, AlignCenter, AlignBottom, "No records"); return; } else if(items_count > 3) { elements_scrollbar_pos( @@ -117,7 +128,7 @@ static void subghz_frequency_analyzer_log_frequency_draw( canvas_draw_str(canvas, offset_x + 48, offset_y + i * 10, buffer); // Max RSSI - subghz_frequency_analyzer_draw_rssi( + subghz_frequency_analyzer_draw_log_rssi( canvas, (*log_frequency_item)->rssi_max, offset_x + 69, (offset_y + i * 10)); } @@ -167,25 +178,20 @@ void subghz_frequency_analyzer_draw(Canvas* canvas, SubGhzFrequencyAnalyzerModel } else { canvas_draw_str(canvas, 20, 8, "Frequency Analyzer"); canvas_draw_str(canvas, 0, 64, "RSSI"); - subghz_frequency_analyzer_draw_rssi(canvas, model->rssi, 20u, 64u); + subghz_frequency_analyzer_draw_rssi(canvas, model->rssi, 20, 64); subghz_frequency_analyzer_history_frequency_draw(canvas, model); } // Frequency canvas_set_font(canvas, FontBigNumbers); - snprintf( - buffer, - sizeof(buffer), - "%03ld.%03ld", - model->frequency / 1000000 % 1000, - model->frequency / 1000 % 1000); + SNPRINTF_FREQUENCY(buffer, model->frequency); if(model->signal) { - canvas_draw_box(canvas, 4, 12, 121, 22); + canvas_draw_box(canvas, 4, 11, 121, 22); canvas_set_color(canvas, ColorWhite); } - canvas_draw_str(canvas, 8, 30, buffer); - canvas_draw_icon(canvas, 96, 19, &I_MHz_25x11); + canvas_draw_str(canvas, 8, 29, buffer); + canvas_draw_icon(canvas, 96, 18, &I_MHz_25x11); } static void subghz_frequency_analyzer_log_frequency_sort(SubGhzFrequencyAnalyzerModel* model) { @@ -292,7 +298,7 @@ static bool subghz_frequency_analyzer_log_frequency_insert(SubGhzFrequencyAnalyz return false; } (*item)->frequency = model->frequency; - (*item)->count = 1u; + (*item)->count = 1; (*item)->rssi_max = model->rssi; (*item)->seq = items_count; return true; @@ -394,9 +400,9 @@ void subghz_frequency_analyzer_enter(void* context) { model->frequency = 0; model->fragment_bottom_type = SubGhzFrequencyAnalyzerFragmentBottomTypeMain; model->log_frequency_order_by = SubGhzFrequencyAnalyzerLogOrderBySeqDesc; - model->log_frequency_scroll_offset = 0u; + model->log_frequency_scroll_offset = 0; model->history_frequency[0] = model->history_frequency[1] = - model->history_frequency[2] = 0u; + model->history_frequency[2] = 0; SubGhzFrequencyAnalyzerLogItemArray_init(model->log_frequency); }, true); @@ -416,13 +422,13 @@ void subghz_frequency_analyzer_exit(void* context) { instance->view, SubGhzFrequencyAnalyzerModel * model, { - model->rssi = 0u; + model->rssi = 0; model->frequency = 0; model->fragment_bottom_type = SubGhzFrequencyAnalyzerFragmentBottomTypeMain; model->log_frequency_order_by = SubGhzFrequencyAnalyzerLogOrderBySeqDesc; - model->log_frequency_scroll_offset = 0u; + model->log_frequency_scroll_offset = 0; model->history_frequency[0] = model->history_frequency[1] = - model->history_frequency[2] = 0u; + model->history_frequency[2] = 0; SubGhzFrequencyAnalyzerLogItemArray_clear(model->log_frequency); }, true); From 51d478489a0d948b8fc148d394c2724166564e2c Mon Sep 17 00:00:00 2001 From: Anna Prosvetova Date: Wed, 23 Nov 2022 14:43:48 +0100 Subject: [PATCH 09/25] Infrared: Add Olimpia Splendid AC (#2038) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- 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 7ef95305..af776706 100644 --- a/assets/resources/infrared/assets/ac.ir +++ b/assets/resources/infrared/assets/ac.ir @@ -148,4 +148,41 @@ type: raw frequency: 38000 duty_cycle: 0.330000 data: 3013 1709 463 1085 462 1084 463 387 461 355 469 355 444 1084 463 387 461 378 436 1084 462 1084 487 355 469 1059 463 387 460 355 444 1083 463 1098 464 386 437 1083 463 1083 489 361 463 360 463 1082 464 361 462 376 462 1085 461 363 460 364 459 364 459 365 458 365 459 364 459 380 459 365 458 365 458 365 458 365 458 365 458 365 458 365 459 380 458 365 459 365 458 365 459 365 458 365 458 1089 458 365 458 380 459 1088 459 365 458 365 458 365 458 365 459 365 458 365 458 381 458 365 458 365 458 365 458 1089 458 365 458 365 458 365 458 381 458 365 458 365 458 365 458 365 458 365 458 365 458 365 458 381 457 366 457 366 457 366 457 366 457 366 458 365 458 366 457 381 458 366 458 366 457 366 457 366 457 366 457 366 457 366 457 381 458 366 457 366 457 366 457 366 457 366 457 366 457 366 457 382 457 366 457 366 457 366 457 366 457 366 457 367 457 366 457 382 457 367 456 1090 457 1090 456 1090 457 1090 457 1090 456 367 457 372 457 +# +# Model: Olimpia Splendid OS-SEAMH09EI +name: Dh +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4402 4336 561 1641 538 554 535 1616 563 1640 539 554 535 557 532 1645 534 560 539 551 538 1639 540 553 536 556 533 1644 535 1642 537 556 533 1620 558 558 531 561 538 554 535 1641 538 1639 540 1638 530 1620 559 1647 532 1643 536 1641 538 1613 566 553 536 557 532 560 539 553 536 558 531 560 529 1647 532 535 564 1613 555 537 563 1614 565 554 535 559 530 1645 534 559 530 1647 532 560 539 1612 557 562 537 1640 539 1611 557 5189 4398 4344 564 1638 530 563 537 1640 539 1639 529 563 537 530 559 1644 535 560 529 535 564 1639 529 537 563 556 533 1644 535 1643 536 557 532 1647 532 559 530 536 564 555 534 1643 536 1616 563 1640 539 1613 555 1624 565 1610 558 1619 560 1617 562 557 532 560 539 554 535 557 532 562 537 553 536 1641 538 555 534 1643 536 530 559 1644 535 558 531 564 536 1639 539 553 536 1641 537 555 534 1617 562 557 532 1645 534 1645 534 +# +name: Cool_hi +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4404 4345 563 1613 566 553 536 1641 538 1614 565 528 561 557 532 1645 534 560 539 551 538 1639 529 563 536 556 533 1618 561 1642 537 556 533 1645 534 557 532 561 538 1638 530 1646 533 1645 554 1623 556 1621 558 1596 562 1613 586 1591 588 531 537 555 534 559 530 562 537 555 534 561 538 552 537 555 534 559 530 562 537 555 534 559 530 562 537 557 532 1643 536 1615 564 1639 560 1591 588 1616 563 1588 580 1623 556 1621 537 5183 4404 4339 579 1597 581 538 530 1646 533 1619 580 539 529 563 536 1615 564 557 532 532 557 1646 533 560 539 553 536 1641 538 1639 539 554 535 1643 536 555 534 559 530 1647 532 1646 533 1644 535 1617 582 1620 559 1621 537 1612 587 1590 589 530 538 554 535 558 531 561 538 554 535 560 539 551 538 554 535 558 531 561 538 554 535 557 532 561 538 556 533 1642 537 1640 538 1613 565 1638 561 1590 589 1588 580 1623 556 1598 560 +# +name: Cool_lo +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4400 4357 561 1616 563 530 559 1619 559 1644 535 557 532 535 564 1613 555 565 534 556 533 1645 534 533 556 536 563 1614 565 1639 529 537 563 1643 536 529 560 558 531 1647 532 1645 533 1618 561 1643 536 1642 537 1642 537 1613 565 1638 530 537 563 556 533 559 530 563 536 556 533 562 538 527 562 1615 563 555 534 1643 536 531 558 561 538 554 535 560 539 1610 558 560 539 1612 556 563 537 1640 538 1639 539 1612 556 1620 558 5189 4398 4345 562 1614 564 529 560 1643 536 1616 563 531 558 534 565 1639 529 565 534 556 533 1619 559 559 530 563 537 1641 538 1640 538 554 535 1645 534 531 558 560 539 1639 529 1622 556 1621 558 1646 532 1619 559 1646 533 1617 562 1642 537 557 532 560 539 554 535 557 532 561 538 556 533 558 531 1620 559 560 539 1638 530 563 536 556 533 560 539 555 534 1642 537 556 533 1619 559 559 530 1622 557 1621 558 1620 558 1647 532 +# +name: Heat_hi +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4402 4346 561 1615 564 555 534 1644 535 1643 536 531 558 561 538 1639 539 555 534 531 558 1645 533 560 529 563 536 1641 537 1640 538 528 561 1645 533 531 558 561 538 1639 539 1638 530 1622 557 1647 532 1646 564 1590 557 1619 559 1618 561 558 531 562 537 555 534 559 530 563 536 558 531 1645 533 559 530 1648 530 1647 531 1646 532 1646 532 560 539 556 533 558 531 1621 557 561 538 555 534 558 531 562 537 1641 537 1639 539 5183 4405 4339 558 1645 533 559 530 1648 530 1647 532 561 538 555 534 1644 535 560 539 551 538 1614 564 555 534 559 530 1647 532 1620 558 561 538 1615 563 553 536 531 558 1620 558 1644 534 1643 536 1642 537 1641 537 1642 536 1613 565 1638 530 563 536 557 532 534 565 554 535 557 532 563 536 1613 565 554 535 1642 537 1641 537 1640 538 1640 538 554 535 560 539 551 538 1614 564 528 561 558 531 562 537 555 534 1644 534 1645 533 +# +name: Heat_lo +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4404 4354 564 1614 564 528 561 1617 562 1642 537 530 559 534 565 1613 555 539 560 556 533 1619 559 534 555 563 536 1642 537 1641 537 555 534 1646 533 532 557 562 537 1640 538 1613 565 1613 555 1648 531 1647 532 1622 557 1619 559 1618 560 559 530 563 536 556 533 560 539 554 535 559 530 561 538 1639 539 554 535 1616 563 1615 564 1615 563 555 534 561 538 1612 556 563 536 1641 538 529 560 533 556 563 537 1641 538 1614 564 5183 4404 4342 555 1622 557 562 537 1641 537 1640 538 529 560 533 556 1648 531 538 562 555 534 1618 560 559 530 562 537 1615 563 1640 538 529 560 1646 532 532 557 562 537 1640 538 1639 539 1639 539 1638 530 1648 530 1649 540 1611 557 1646 532 561 538 554 535 558 531 562 537 555 534 561 538 552 537 1641 537 555 534 1644 534 1643 536 1617 562 557 532 563 536 1639 539 553 536 1642 537 556 533 560 539 554 535 1642 537 1643 535 +# +name: Off +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4403 4333 563 1615 563 528 561 1618 560 1618 560 531 558 561 538 1614 564 556 533 558 541 1611 557 562 537 555 534 1619 559 1618 560 558 541 1613 565 551 538 1614 564 1614 564 1614 564 1613 565 528 561 1617 561 1619 559 1617 561 557 532 535 564 528 561 533 566 1611 557 562 537 558 531 1619 559 1619 559 1619 559 559 540 553 536 557 532 561 538 557 532 559 540 553 536 557 532 1620 558 1620 558 1620 558 1620 558 1618 560 5188 4398 4346 561 1618 560 558 531 1621 557 1621 557 561 538 555 534 1619 559 561 538 553 536 1616 562 556 533 560 539 1614 564 1613 565 554 535 1619 559 557 532 1621 557 1620 558 1620 558 1620 558 560 539 1613 565 1615 563 1613 565 553 536 557 532 535 564 554 535 1618 560 558 531 564 535 1615 563 1615 563 1614 564 555 534 559 540 552 537 530 559 536 563 528 561 532 557 562 537 1615 563 1615 563 1614 564 1614 564 1616 562 From ffa6249b640c0676cd37b6d24e845e2e6adff802 Mon Sep 17 00:00:00 2001 From: Nikolay Minaylov Date: Wed, 23 Nov 2022 21:12:53 +0300 Subject: [PATCH 10/25] [FL-2985] Fix U2F HID vulnerability #2042 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- applications/main/u2f/u2f_hid.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/applications/main/u2f/u2f_hid.c b/applications/main/u2f/u2f_hid.c index 916400e9..6e1a51f3 100644 --- a/applications/main/u2f/u2f_hid.c +++ b/applications/main/u2f/u2f_hid.c @@ -58,13 +58,13 @@ struct U2fHid_packet { struct U2fHid { FuriThread* thread; FuriTimer* lock_timer; - struct U2fHid_packet packet; uint8_t seq_id_last; uint16_t req_buf_ptr; uint32_t req_len_left; uint32_t lock_cid; bool lock; U2fData* u2f_instance; + struct U2fHid_packet packet; }; static void u2f_hid_event_callback(HidU2fEvent ev, void* context) { @@ -215,10 +215,21 @@ static int32_t u2f_hid_worker(void* context) { } if(flags & WorkerEvtRequest) { uint32_t len_cur = furi_hal_hid_u2f_get_request(packet_buf); - if(len_cur > 0) { + do { + if(len_cur == 0) { + break; + } if((packet_buf[4] & U2F_HID_TYPE_MASK) == U2F_HID_TYPE_INIT) { + if(len_cur < 7) { + u2f_hid->req_len_left = 0; + break; // Wrong chunk len + } // Init packet u2f_hid->packet.len = (packet_buf[5] << 8) | (packet_buf[6]); + if(u2f_hid->packet.len > U2F_HID_MAX_PAYLOAD_LEN) { + u2f_hid->req_len_left = 0; + break; // Wrong packet len + } if(u2f_hid->packet.len > (len_cur - 7)) { u2f_hid->req_len_left = u2f_hid->packet.len - (len_cur - 7); len_cur = len_cur - 7; @@ -232,6 +243,10 @@ static int32_t u2f_hid_worker(void* context) { u2f_hid->req_buf_ptr = len_cur; if(len_cur > 0) memcpy(u2f_hid->packet.payload, &packet_buf[7], len_cur); } else { + if(len_cur < 5) { + u2f_hid->req_len_left = 0; + break; // Wrong chunk len + } // Continuation packet if(u2f_hid->req_len_left > 0) { uint32_t cid_temp = 0; @@ -260,7 +275,7 @@ static int32_t u2f_hid_worker(void* context) { u2f_hid_send_error(u2f_hid, U2F_HID_ERR_INVALID_CMD); } } - } + } while(0); } if(flags & WorkerEvtUnlock) { u2f_hid->lock = false; From 03140e434916e206ac3553e0d1e5dca71f0038cb Mon Sep 17 00:00:00 2001 From: Smooklu <37220586+Smooklu@users.noreply.github.com> Date: Mon, 28 Nov 2022 10:27:16 -0600 Subject: [PATCH 11/25] Bluetooth Remote to HID Remote (#2039) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * WIP BT + USB Hid * Refactoring Submenus/Views * Changed to bool instead of enum * Revamp finished * Removed usb_keyboard * Renaming device_types that can do USB+BT * Removed error view * Renaming folder structure and file names * Fixed views.h * Fixed hid.h * Fixed hid_mouse.c * Fixed a accidetnal renaming * Apps: add missing view remove call in hid app destructor * Hid app: hal abstraction, split into bluetooth and usb remotes. Fbt: customizable icon symbol name. * Hid app: update usb remote icon * Hid: single status change routine * HID App: final touches * HID App: rename BtHidTikTok to HidTikTok, format sources * HID App: fix comma in keyboard Co-authored-by: あく --- .../plugins/bt_hid_app/application.fam | 10 - applications/plugins/bt_hid_app/bt_hid.c | 216 ----------- applications/plugins/bt_hid_app/bt_hid.h | 41 -- .../bt_hid_app/views/bt_hid_keyboard.h | 13 - .../plugins/bt_hid_app/views/bt_hid_keynote.h | 13 - .../plugins/bt_hid_app/views/bt_hid_media.h | 13 - .../plugins/bt_hid_app/views/bt_hid_mouse.h | 13 - .../plugins/bt_hid_app/views/bt_hid_tiktok.h | 13 - applications/plugins/hid_app/application.fam | 24 ++ .../assets/Arr_dwn_7x9.png | Bin .../assets/Arr_up_7x9.png | Bin .../assets/Ble_connected_15x15.png | Bin .../assets/Ble_disconnected_15x15.png | Bin .../assets/ButtonDown_7x4.png | Bin .../assets/ButtonLeft_4x7.png | Bin .../assets/ButtonRight_4x7.png | Bin .../assets/ButtonUp_7x4.png | Bin .../assets/Button_18x18.png | Bin .../assets/Circles_47x47.png | Bin .../assets/Left_mouse_icon_9x9.png | Bin .../assets/Like_def_11x9.png | Bin .../assets/Like_pressed_17x17.png | Bin .../assets/Ok_btn_9x9.png | Bin .../assets/Ok_btn_pressed_13x13.png | Bin .../assets/Pin_arrow_down_7x9.png | Bin .../assets/Pin_arrow_left_9x7.png | Bin .../assets/Pin_arrow_right_9x7.png | Bin .../assets/Pin_arrow_up_7x9.png | Bin .../assets/Pin_back_arrow_10x8.png | Bin .../assets/Pressed_Button_13x13.png | Bin .../assets/Right_mouse_icon_9x9.png | Bin .../assets/Space_65x18.png | Bin .../assets/Voldwn_6x6.png | Bin .../assets/Volup_8x6.png | Bin applications/plugins/hid_app/hid.c | 365 ++++++++++++++++++ applications/plugins/hid_app/hid.h | 60 +++ .../hid_ble_10px.png} | Bin applications/plugins/hid_app/hid_usb_10px.png | Bin 0 -> 969 bytes applications/plugins/hid_app/views.h | 9 + .../views/hid_keyboard.c} | 123 +++--- .../plugins/hid_app/views/hid_keyboard.h | 14 + .../views/hid_keynote.c} | 108 +++--- .../plugins/hid_app/views/hid_keynote.h | 14 + .../views/hid_media.c} | 107 ++--- .../plugins/hid_app/views/hid_media.h | 13 + .../views/hid_mouse.c} | 100 ++--- .../plugins/hid_app/views/hid_mouse.h | 17 + .../views/hid_tiktok.c} | 124 +++--- .../plugins/hid_app/views/hid_tiktok.h | 14 + scripts/fbt/appmanifest.py | 1 + scripts/fbt_tools/fbt_extapps.py | 2 +- 51 files changed, 820 insertions(+), 607 deletions(-) delete mode 100644 applications/plugins/bt_hid_app/application.fam delete mode 100644 applications/plugins/bt_hid_app/bt_hid.c delete mode 100644 applications/plugins/bt_hid_app/bt_hid.h delete mode 100644 applications/plugins/bt_hid_app/views/bt_hid_keyboard.h delete mode 100644 applications/plugins/bt_hid_app/views/bt_hid_keynote.h delete mode 100644 applications/plugins/bt_hid_app/views/bt_hid_media.h delete mode 100644 applications/plugins/bt_hid_app/views/bt_hid_mouse.h delete mode 100644 applications/plugins/bt_hid_app/views/bt_hid_tiktok.h create mode 100644 applications/plugins/hid_app/application.fam rename applications/plugins/{bt_hid_app => hid_app}/assets/Arr_dwn_7x9.png (100%) rename applications/plugins/{bt_hid_app => hid_app}/assets/Arr_up_7x9.png (100%) rename applications/plugins/{bt_hid_app => hid_app}/assets/Ble_connected_15x15.png (100%) rename applications/plugins/{bt_hid_app => hid_app}/assets/Ble_disconnected_15x15.png (100%) rename applications/plugins/{bt_hid_app => hid_app}/assets/ButtonDown_7x4.png (100%) rename applications/plugins/{bt_hid_app => hid_app}/assets/ButtonLeft_4x7.png (100%) rename applications/plugins/{bt_hid_app => hid_app}/assets/ButtonRight_4x7.png (100%) rename applications/plugins/{bt_hid_app => hid_app}/assets/ButtonUp_7x4.png (100%) rename applications/plugins/{bt_hid_app => hid_app}/assets/Button_18x18.png (100%) rename applications/plugins/{bt_hid_app => hid_app}/assets/Circles_47x47.png (100%) rename applications/plugins/{bt_hid_app => hid_app}/assets/Left_mouse_icon_9x9.png (100%) rename applications/plugins/{bt_hid_app => hid_app}/assets/Like_def_11x9.png (100%) rename applications/plugins/{bt_hid_app => hid_app}/assets/Like_pressed_17x17.png (100%) rename applications/plugins/{bt_hid_app => hid_app}/assets/Ok_btn_9x9.png (100%) rename applications/plugins/{bt_hid_app => hid_app}/assets/Ok_btn_pressed_13x13.png (100%) rename applications/plugins/{bt_hid_app => hid_app}/assets/Pin_arrow_down_7x9.png (100%) rename applications/plugins/{bt_hid_app => hid_app}/assets/Pin_arrow_left_9x7.png (100%) rename applications/plugins/{bt_hid_app => hid_app}/assets/Pin_arrow_right_9x7.png (100%) rename applications/plugins/{bt_hid_app => hid_app}/assets/Pin_arrow_up_7x9.png (100%) rename applications/plugins/{bt_hid_app => hid_app}/assets/Pin_back_arrow_10x8.png (100%) rename applications/plugins/{bt_hid_app => hid_app}/assets/Pressed_Button_13x13.png (100%) rename applications/plugins/{bt_hid_app => hid_app}/assets/Right_mouse_icon_9x9.png (100%) rename applications/plugins/{bt_hid_app => hid_app}/assets/Space_65x18.png (100%) rename applications/plugins/{bt_hid_app => hid_app}/assets/Voldwn_6x6.png (100%) rename applications/plugins/{bt_hid_app => hid_app}/assets/Volup_8x6.png (100%) create mode 100644 applications/plugins/hid_app/hid.c create mode 100644 applications/plugins/hid_app/hid.h rename applications/plugins/{bt_hid_app/bt_remote_10px.png => hid_app/hid_ble_10px.png} (100%) create mode 100644 applications/plugins/hid_app/hid_usb_10px.png create mode 100644 applications/plugins/hid_app/views.h rename applications/plugins/{bt_hid_app/views/bt_hid_keyboard.c => hid_app/views/hid_keyboard.c} (80%) create mode 100644 applications/plugins/hid_app/views/hid_keyboard.h rename applications/plugins/{bt_hid_app/views/bt_hid_keynote.c => hid_app/views/hid_keynote.c} (60%) create mode 100644 applications/plugins/hid_app/views/hid_keynote.h rename applications/plugins/{bt_hid_app/views/bt_hid_media.c => hid_app/views/hid_media.c} (59%) create mode 100644 applications/plugins/hid_app/views/hid_media.h rename applications/plugins/{bt_hid_app/views/bt_hid_mouse.c => hid_app/views/hid_mouse.c} (68%) create mode 100644 applications/plugins/hid_app/views/hid_mouse.h rename applications/plugins/{bt_hid_app/views/bt_hid_tiktok.c => hid_app/views/hid_tiktok.c} (59%) create mode 100644 applications/plugins/hid_app/views/hid_tiktok.h diff --git a/applications/plugins/bt_hid_app/application.fam b/applications/plugins/bt_hid_app/application.fam deleted file mode 100644 index 2712fded..00000000 --- a/applications/plugins/bt_hid_app/application.fam +++ /dev/null @@ -1,10 +0,0 @@ -App( - appid="bt_hid", - name="Bluetooth Remote", - apptype=FlipperAppType.EXTERNAL, - entry_point="bt_hid_app", - stack_size=1 * 1024, - fap_category="Tools", - fap_icon="bt_remote_10px.png", - fap_icon_assets="assets", -) diff --git a/applications/plugins/bt_hid_app/bt_hid.c b/applications/plugins/bt_hid_app/bt_hid.c deleted file mode 100644 index 4a77a249..00000000 --- a/applications/plugins/bt_hid_app/bt_hid.c +++ /dev/null @@ -1,216 +0,0 @@ -#include "bt_hid.h" -#include -#include -#include - -#define TAG "BtHidApp" - -enum BtDebugSubmenuIndex { - BtHidSubmenuIndexKeynote, - BtHidSubmenuIndexKeyboard, - BtHidSubmenuIndexMedia, - BtHidSubmenuIndexTikTok, - BtHidSubmenuIndexMouse, -}; - -void bt_hid_submenu_callback(void* context, uint32_t index) { - furi_assert(context); - BtHid* app = context; - if(index == BtHidSubmenuIndexKeynote) { - app->view_id = BtHidViewKeynote; - view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewKeynote); - } else if(index == BtHidSubmenuIndexKeyboard) { - app->view_id = BtHidViewKeyboard; - view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewKeyboard); - } else if(index == BtHidSubmenuIndexMedia) { - app->view_id = BtHidViewMedia; - view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewMedia); - } else if(index == BtHidSubmenuIndexMouse) { - app->view_id = BtHidViewMouse; - view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewMouse); - } else if(index == BtHidSubmenuIndexTikTok) { - app->view_id = BtHidViewTikTok; - view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewTikTok); - } -} - -void bt_hid_dialog_callback(DialogExResult result, void* context) { - furi_assert(context); - BtHid* app = context; - if(result == DialogExResultLeft) { - view_dispatcher_stop(app->view_dispatcher); - } else if(result == DialogExResultRight) { - view_dispatcher_switch_to_view(app->view_dispatcher, app->view_id); // Show last view - } else if(result == DialogExResultCenter) { - view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewSubmenu); - } -} - -uint32_t bt_hid_exit_confirm_view(void* context) { - UNUSED(context); - return BtHidViewExitConfirm; -} - -uint32_t bt_hid_exit(void* context) { - UNUSED(context); - return VIEW_NONE; -} - -void bt_hid_connection_status_changed_callback(BtStatus status, void* context) { - furi_assert(context); - BtHid* bt_hid = context; - bool connected = (status == BtStatusConnected); - if(connected) { - notification_internal_message(bt_hid->notifications, &sequence_set_blue_255); - } else { - notification_internal_message(bt_hid->notifications, &sequence_reset_blue); - } - bt_hid_keynote_set_connected_status(bt_hid->bt_hid_keynote, connected); - bt_hid_keyboard_set_connected_status(bt_hid->bt_hid_keyboard, connected); - bt_hid_media_set_connected_status(bt_hid->bt_hid_media, connected); - bt_hid_mouse_set_connected_status(bt_hid->bt_hid_mouse, connected); - bt_hid_tiktok_set_connected_status(bt_hid->bt_hid_tiktok, connected); -} - -BtHid* bt_hid_app_alloc() { - BtHid* app = malloc(sizeof(BtHid)); - - // Gui - app->gui = furi_record_open(RECORD_GUI); - - // Bt - app->bt = furi_record_open(RECORD_BT); - - // Notifications - app->notifications = furi_record_open(RECORD_NOTIFICATION); - - // View dispatcher - app->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_enable_queue(app->view_dispatcher); - view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); - - // Submenu view - app->submenu = submenu_alloc(); - submenu_add_item( - app->submenu, "Keynote", BtHidSubmenuIndexKeynote, bt_hid_submenu_callback, app); - submenu_add_item( - app->submenu, "Keyboard", BtHidSubmenuIndexKeyboard, bt_hid_submenu_callback, app); - submenu_add_item(app->submenu, "Media", BtHidSubmenuIndexMedia, bt_hid_submenu_callback, app); - submenu_add_item( - app->submenu, "TikTok Controller", BtHidSubmenuIndexTikTok, bt_hid_submenu_callback, app); - submenu_add_item(app->submenu, "Mouse", BtHidSubmenuIndexMouse, bt_hid_submenu_callback, app); - view_set_previous_callback(submenu_get_view(app->submenu), bt_hid_exit); - view_dispatcher_add_view( - app->view_dispatcher, BtHidViewSubmenu, submenu_get_view(app->submenu)); - - // Dialog view - app->dialog = dialog_ex_alloc(); - dialog_ex_set_result_callback(app->dialog, bt_hid_dialog_callback); - dialog_ex_set_context(app->dialog, app); - dialog_ex_set_left_button_text(app->dialog, "Exit"); - dialog_ex_set_right_button_text(app->dialog, "Stay"); - dialog_ex_set_center_button_text(app->dialog, "Menu"); - dialog_ex_set_header(app->dialog, "Close Current App?", 16, 12, AlignLeft, AlignTop); - view_dispatcher_add_view( - app->view_dispatcher, BtHidViewExitConfirm, dialog_ex_get_view(app->dialog)); - - // Keynote view - app->bt_hid_keynote = bt_hid_keynote_alloc(); - view_set_previous_callback( - bt_hid_keynote_get_view(app->bt_hid_keynote), bt_hid_exit_confirm_view); - view_dispatcher_add_view( - app->view_dispatcher, BtHidViewKeynote, bt_hid_keynote_get_view(app->bt_hid_keynote)); - - // Keyboard view - app->bt_hid_keyboard = bt_hid_keyboard_alloc(); - view_set_previous_callback( - bt_hid_keyboard_get_view(app->bt_hid_keyboard), bt_hid_exit_confirm_view); - view_dispatcher_add_view( - app->view_dispatcher, BtHidViewKeyboard, bt_hid_keyboard_get_view(app->bt_hid_keyboard)); - - // Media view - app->bt_hid_media = bt_hid_media_alloc(); - view_set_previous_callback(bt_hid_media_get_view(app->bt_hid_media), bt_hid_exit_confirm_view); - view_dispatcher_add_view( - app->view_dispatcher, BtHidViewMedia, bt_hid_media_get_view(app->bt_hid_media)); - - // TikTok view - app->bt_hid_tiktok = bt_hid_tiktok_alloc(); - view_set_previous_callback( - bt_hid_tiktok_get_view(app->bt_hid_tiktok), bt_hid_exit_confirm_view); - view_dispatcher_add_view( - app->view_dispatcher, BtHidViewTikTok, bt_hid_tiktok_get_view(app->bt_hid_tiktok)); - - // Mouse view - app->bt_hid_mouse = bt_hid_mouse_alloc(); - view_set_previous_callback(bt_hid_mouse_get_view(app->bt_hid_mouse), bt_hid_exit_confirm_view); - view_dispatcher_add_view( - app->view_dispatcher, BtHidViewMouse, bt_hid_mouse_get_view(app->bt_hid_mouse)); - - // TODO switch to menu after Media is done - app->view_id = BtHidViewSubmenu; - view_dispatcher_switch_to_view(app->view_dispatcher, app->view_id); - - return app; -} - -void bt_hid_app_free(BtHid* app) { - furi_assert(app); - - // Reset notification - notification_internal_message(app->notifications, &sequence_reset_blue); - - // Free views - view_dispatcher_remove_view(app->view_dispatcher, BtHidViewSubmenu); - submenu_free(app->submenu); - view_dispatcher_remove_view(app->view_dispatcher, BtHidViewExitConfirm); - dialog_ex_free(app->dialog); - view_dispatcher_remove_view(app->view_dispatcher, BtHidViewKeynote); - bt_hid_keynote_free(app->bt_hid_keynote); - view_dispatcher_remove_view(app->view_dispatcher, BtHidViewKeyboard); - bt_hid_keyboard_free(app->bt_hid_keyboard); - view_dispatcher_remove_view(app->view_dispatcher, BtHidViewMedia); - bt_hid_media_free(app->bt_hid_media); - view_dispatcher_remove_view(app->view_dispatcher, BtHidViewMouse); - bt_hid_mouse_free(app->bt_hid_mouse); - view_dispatcher_remove_view(app->view_dispatcher, BtHidViewTikTok); - bt_hid_tiktok_free(app->bt_hid_tiktok); - view_dispatcher_free(app->view_dispatcher); - - // Close records - furi_record_close(RECORD_GUI); - app->gui = NULL; - furi_record_close(RECORD_NOTIFICATION); - app->notifications = NULL; - furi_record_close(RECORD_BT); - app->bt = NULL; - - // Free rest - free(app); -} - -int32_t bt_hid_app(void* p) { - UNUSED(p); - // Switch profile to Hid - BtHid* app = bt_hid_app_alloc(); - bt_set_status_changed_callback(app->bt, bt_hid_connection_status_changed_callback, app); - // Change profile - if(!bt_set_profile(app->bt, BtProfileHidKeyboard)) { - FURI_LOG_E(TAG, "Failed to switch profile"); - bt_hid_app_free(app); - return -1; - } - furi_hal_bt_start_advertising(); - - DOLPHIN_DEED(DolphinDeedPluginStart); - - view_dispatcher_run(app->view_dispatcher); - - bt_set_status_changed_callback(app->bt, NULL, NULL); - // Change back profile to Serial - bt_set_profile(app->bt, BtProfileSerial); - - bt_hid_app_free(app); - - return 0; -} diff --git a/applications/plugins/bt_hid_app/bt_hid.h b/applications/plugins/bt_hid_app/bt_hid.h deleted file mode 100644 index 89e8807f..00000000 --- a/applications/plugins/bt_hid_app/bt_hid.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -#include -#include -#include "views/bt_hid_keynote.h" -#include "views/bt_hid_keyboard.h" -#include "views/bt_hid_media.h" -#include "views/bt_hid_mouse.h" -#include "views/bt_hid_tiktok.h" - -typedef struct { - Bt* bt; - Gui* gui; - NotificationApp* notifications; - ViewDispatcher* view_dispatcher; - Submenu* submenu; - DialogEx* dialog; - BtHidKeynote* bt_hid_keynote; - BtHidKeyboard* bt_hid_keyboard; - BtHidMedia* bt_hid_media; - BtHidMouse* bt_hid_mouse; - BtHidTikTok* bt_hid_tiktok; - uint32_t view_id; -} BtHid; - -typedef enum { - BtHidViewSubmenu, - BtHidViewKeynote, - BtHidViewKeyboard, - BtHidViewMedia, - BtHidViewMouse, - BtHidViewTikTok, - BtHidViewExitConfirm, -} BtHidView; diff --git a/applications/plugins/bt_hid_app/views/bt_hid_keyboard.h b/applications/plugins/bt_hid_app/views/bt_hid_keyboard.h deleted file mode 100644 index b2cc928e..00000000 --- a/applications/plugins/bt_hid_app/views/bt_hid_keyboard.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include - -typedef struct BtHidKeyboard BtHidKeyboard; - -BtHidKeyboard* bt_hid_keyboard_alloc(); - -void bt_hid_keyboard_free(BtHidKeyboard* bt_hid_keyboard); - -View* bt_hid_keyboard_get_view(BtHidKeyboard* bt_hid_keyboard); - -void bt_hid_keyboard_set_connected_status(BtHidKeyboard* bt_hid_keyboard, bool connected); diff --git a/applications/plugins/bt_hid_app/views/bt_hid_keynote.h b/applications/plugins/bt_hid_app/views/bt_hid_keynote.h deleted file mode 100644 index 05b12145..00000000 --- a/applications/plugins/bt_hid_app/views/bt_hid_keynote.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include - -typedef struct BtHidKeynote BtHidKeynote; - -BtHidKeynote* bt_hid_keynote_alloc(); - -void bt_hid_keynote_free(BtHidKeynote* bt_hid_keynote); - -View* bt_hid_keynote_get_view(BtHidKeynote* bt_hid_keynote); - -void bt_hid_keynote_set_connected_status(BtHidKeynote* bt_hid_keynote, bool connected); diff --git a/applications/plugins/bt_hid_app/views/bt_hid_media.h b/applications/plugins/bt_hid_app/views/bt_hid_media.h deleted file mode 100644 index 804239dc..00000000 --- a/applications/plugins/bt_hid_app/views/bt_hid_media.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include - -typedef struct BtHidMedia BtHidMedia; - -BtHidMedia* bt_hid_media_alloc(); - -void bt_hid_media_free(BtHidMedia* bt_hid_media); - -View* bt_hid_media_get_view(BtHidMedia* bt_hid_media); - -void bt_hid_media_set_connected_status(BtHidMedia* bt_hid_media, bool connected); diff --git a/applications/plugins/bt_hid_app/views/bt_hid_mouse.h b/applications/plugins/bt_hid_app/views/bt_hid_mouse.h deleted file mode 100644 index a82971d7..00000000 --- a/applications/plugins/bt_hid_app/views/bt_hid_mouse.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include - -typedef struct BtHidMouse BtHidMouse; - -BtHidMouse* bt_hid_mouse_alloc(); - -void bt_hid_mouse_free(BtHidMouse* bt_hid_mouse); - -View* bt_hid_mouse_get_view(BtHidMouse* bt_hid_mouse); - -void bt_hid_mouse_set_connected_status(BtHidMouse* bt_hid_mouse, bool connected); diff --git a/applications/plugins/bt_hid_app/views/bt_hid_tiktok.h b/applications/plugins/bt_hid_app/views/bt_hid_tiktok.h deleted file mode 100644 index 03c9afec..00000000 --- a/applications/plugins/bt_hid_app/views/bt_hid_tiktok.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include - -typedef struct BtHidTikTok BtHidTikTok; - -BtHidTikTok* bt_hid_tiktok_alloc(); - -void bt_hid_tiktok_free(BtHidTikTok* bt_hid_tiktok); - -View* bt_hid_tiktok_get_view(BtHidTikTok* bt_hid_tiktok); - -void bt_hid_tiktok_set_connected_status(BtHidTikTok* bt_hid_tiktok, bool connected); diff --git a/applications/plugins/hid_app/application.fam b/applications/plugins/hid_app/application.fam new file mode 100644 index 00000000..b8c13e35 --- /dev/null +++ b/applications/plugins/hid_app/application.fam @@ -0,0 +1,24 @@ +App( + appid="hid_usb", + name="USB Remote", + apptype=FlipperAppType.PLUGIN, + entry_point="hid_usb_app", + stack_size=1 * 1024, + fap_category="Tools", + fap_icon="hid_usb_10px.png", + fap_icon_assets="assets", + fap_icon_assets_symbol="hid", +) + + +App( + appid="hid_ble", + name="Bluetooth Remote", + apptype=FlipperAppType.PLUGIN, + entry_point="hid_ble_app", + stack_size=1 * 1024, + fap_category="Tools", + fap_icon="hid_ble_10px.png", + fap_icon_assets="assets", + fap_icon_assets_symbol="hid", +) diff --git a/applications/plugins/bt_hid_app/assets/Arr_dwn_7x9.png b/applications/plugins/hid_app/assets/Arr_dwn_7x9.png similarity index 100% rename from applications/plugins/bt_hid_app/assets/Arr_dwn_7x9.png rename to applications/plugins/hid_app/assets/Arr_dwn_7x9.png diff --git a/applications/plugins/bt_hid_app/assets/Arr_up_7x9.png b/applications/plugins/hid_app/assets/Arr_up_7x9.png similarity index 100% rename from applications/plugins/bt_hid_app/assets/Arr_up_7x9.png rename to applications/plugins/hid_app/assets/Arr_up_7x9.png diff --git a/applications/plugins/bt_hid_app/assets/Ble_connected_15x15.png b/applications/plugins/hid_app/assets/Ble_connected_15x15.png similarity index 100% rename from applications/plugins/bt_hid_app/assets/Ble_connected_15x15.png rename to applications/plugins/hid_app/assets/Ble_connected_15x15.png diff --git a/applications/plugins/bt_hid_app/assets/Ble_disconnected_15x15.png b/applications/plugins/hid_app/assets/Ble_disconnected_15x15.png similarity index 100% rename from applications/plugins/bt_hid_app/assets/Ble_disconnected_15x15.png rename to applications/plugins/hid_app/assets/Ble_disconnected_15x15.png diff --git a/applications/plugins/bt_hid_app/assets/ButtonDown_7x4.png b/applications/plugins/hid_app/assets/ButtonDown_7x4.png similarity index 100% rename from applications/plugins/bt_hid_app/assets/ButtonDown_7x4.png rename to applications/plugins/hid_app/assets/ButtonDown_7x4.png diff --git a/applications/plugins/bt_hid_app/assets/ButtonLeft_4x7.png b/applications/plugins/hid_app/assets/ButtonLeft_4x7.png similarity index 100% rename from applications/plugins/bt_hid_app/assets/ButtonLeft_4x7.png rename to applications/plugins/hid_app/assets/ButtonLeft_4x7.png diff --git a/applications/plugins/bt_hid_app/assets/ButtonRight_4x7.png b/applications/plugins/hid_app/assets/ButtonRight_4x7.png similarity index 100% rename from applications/plugins/bt_hid_app/assets/ButtonRight_4x7.png rename to applications/plugins/hid_app/assets/ButtonRight_4x7.png diff --git a/applications/plugins/bt_hid_app/assets/ButtonUp_7x4.png b/applications/plugins/hid_app/assets/ButtonUp_7x4.png similarity index 100% rename from applications/plugins/bt_hid_app/assets/ButtonUp_7x4.png rename to applications/plugins/hid_app/assets/ButtonUp_7x4.png diff --git a/applications/plugins/bt_hid_app/assets/Button_18x18.png b/applications/plugins/hid_app/assets/Button_18x18.png similarity index 100% rename from applications/plugins/bt_hid_app/assets/Button_18x18.png rename to applications/plugins/hid_app/assets/Button_18x18.png diff --git a/applications/plugins/bt_hid_app/assets/Circles_47x47.png b/applications/plugins/hid_app/assets/Circles_47x47.png similarity index 100% rename from applications/plugins/bt_hid_app/assets/Circles_47x47.png rename to applications/plugins/hid_app/assets/Circles_47x47.png diff --git a/applications/plugins/bt_hid_app/assets/Left_mouse_icon_9x9.png b/applications/plugins/hid_app/assets/Left_mouse_icon_9x9.png similarity index 100% rename from applications/plugins/bt_hid_app/assets/Left_mouse_icon_9x9.png rename to applications/plugins/hid_app/assets/Left_mouse_icon_9x9.png diff --git a/applications/plugins/bt_hid_app/assets/Like_def_11x9.png b/applications/plugins/hid_app/assets/Like_def_11x9.png similarity index 100% rename from applications/plugins/bt_hid_app/assets/Like_def_11x9.png rename to applications/plugins/hid_app/assets/Like_def_11x9.png diff --git a/applications/plugins/bt_hid_app/assets/Like_pressed_17x17.png b/applications/plugins/hid_app/assets/Like_pressed_17x17.png similarity index 100% rename from applications/plugins/bt_hid_app/assets/Like_pressed_17x17.png rename to applications/plugins/hid_app/assets/Like_pressed_17x17.png diff --git a/applications/plugins/bt_hid_app/assets/Ok_btn_9x9.png b/applications/plugins/hid_app/assets/Ok_btn_9x9.png similarity index 100% rename from applications/plugins/bt_hid_app/assets/Ok_btn_9x9.png rename to applications/plugins/hid_app/assets/Ok_btn_9x9.png diff --git a/applications/plugins/bt_hid_app/assets/Ok_btn_pressed_13x13.png b/applications/plugins/hid_app/assets/Ok_btn_pressed_13x13.png similarity index 100% rename from applications/plugins/bt_hid_app/assets/Ok_btn_pressed_13x13.png rename to applications/plugins/hid_app/assets/Ok_btn_pressed_13x13.png diff --git a/applications/plugins/bt_hid_app/assets/Pin_arrow_down_7x9.png b/applications/plugins/hid_app/assets/Pin_arrow_down_7x9.png similarity index 100% rename from applications/plugins/bt_hid_app/assets/Pin_arrow_down_7x9.png rename to applications/plugins/hid_app/assets/Pin_arrow_down_7x9.png diff --git a/applications/plugins/bt_hid_app/assets/Pin_arrow_left_9x7.png b/applications/plugins/hid_app/assets/Pin_arrow_left_9x7.png similarity index 100% rename from applications/plugins/bt_hid_app/assets/Pin_arrow_left_9x7.png rename to applications/plugins/hid_app/assets/Pin_arrow_left_9x7.png diff --git a/applications/plugins/bt_hid_app/assets/Pin_arrow_right_9x7.png b/applications/plugins/hid_app/assets/Pin_arrow_right_9x7.png similarity index 100% rename from applications/plugins/bt_hid_app/assets/Pin_arrow_right_9x7.png rename to applications/plugins/hid_app/assets/Pin_arrow_right_9x7.png diff --git a/applications/plugins/bt_hid_app/assets/Pin_arrow_up_7x9.png b/applications/plugins/hid_app/assets/Pin_arrow_up_7x9.png similarity index 100% rename from applications/plugins/bt_hid_app/assets/Pin_arrow_up_7x9.png rename to applications/plugins/hid_app/assets/Pin_arrow_up_7x9.png diff --git a/applications/plugins/bt_hid_app/assets/Pin_back_arrow_10x8.png b/applications/plugins/hid_app/assets/Pin_back_arrow_10x8.png similarity index 100% rename from applications/plugins/bt_hid_app/assets/Pin_back_arrow_10x8.png rename to applications/plugins/hid_app/assets/Pin_back_arrow_10x8.png diff --git a/applications/plugins/bt_hid_app/assets/Pressed_Button_13x13.png b/applications/plugins/hid_app/assets/Pressed_Button_13x13.png similarity index 100% rename from applications/plugins/bt_hid_app/assets/Pressed_Button_13x13.png rename to applications/plugins/hid_app/assets/Pressed_Button_13x13.png diff --git a/applications/plugins/bt_hid_app/assets/Right_mouse_icon_9x9.png b/applications/plugins/hid_app/assets/Right_mouse_icon_9x9.png similarity index 100% rename from applications/plugins/bt_hid_app/assets/Right_mouse_icon_9x9.png rename to applications/plugins/hid_app/assets/Right_mouse_icon_9x9.png diff --git a/applications/plugins/bt_hid_app/assets/Space_65x18.png b/applications/plugins/hid_app/assets/Space_65x18.png similarity index 100% rename from applications/plugins/bt_hid_app/assets/Space_65x18.png rename to applications/plugins/hid_app/assets/Space_65x18.png diff --git a/applications/plugins/bt_hid_app/assets/Voldwn_6x6.png b/applications/plugins/hid_app/assets/Voldwn_6x6.png similarity index 100% rename from applications/plugins/bt_hid_app/assets/Voldwn_6x6.png rename to applications/plugins/hid_app/assets/Voldwn_6x6.png diff --git a/applications/plugins/bt_hid_app/assets/Volup_8x6.png b/applications/plugins/hid_app/assets/Volup_8x6.png similarity index 100% rename from applications/plugins/bt_hid_app/assets/Volup_8x6.png rename to applications/plugins/hid_app/assets/Volup_8x6.png diff --git a/applications/plugins/hid_app/hid.c b/applications/plugins/hid_app/hid.c new file mode 100644 index 00000000..2a617fde --- /dev/null +++ b/applications/plugins/hid_app/hid.c @@ -0,0 +1,365 @@ +#include "hid.h" +#include "views.h" +#include +#include + +#define TAG "HidApp" + +enum HidDebugSubmenuIndex { + HidSubmenuIndexKeynote, + HidSubmenuIndexKeyboard, + HidSubmenuIndexMedia, + BtHidSubmenuIndexTikTok, + HidSubmenuIndexMouse, +}; +typedef enum { ConnTypeSubmenuIndexBluetooth, ConnTypeSubmenuIndexUsb } ConnTypeDebugSubmenuIndex; + +static void hid_submenu_callback(void* context, uint32_t index) { + furi_assert(context); + Hid* app = context; + if(index == HidSubmenuIndexKeynote) { + app->view_id = HidViewKeynote; + view_dispatcher_switch_to_view(app->view_dispatcher, HidViewKeynote); + } else if(index == HidSubmenuIndexKeyboard) { + app->view_id = HidViewKeyboard; + view_dispatcher_switch_to_view(app->view_dispatcher, HidViewKeyboard); + } else if(index == HidSubmenuIndexMedia) { + app->view_id = HidViewMedia; + view_dispatcher_switch_to_view(app->view_dispatcher, HidViewMedia); + } else if(index == HidSubmenuIndexMouse) { + app->view_id = HidViewMouse; + view_dispatcher_switch_to_view(app->view_dispatcher, HidViewMouse); + } else if(index == BtHidSubmenuIndexTikTok) { + app->view_id = BtHidViewTikTok; + view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewTikTok); + } +} + +static void bt_hid_connection_status_changed_callback(BtStatus status, void* context) { + furi_assert(context); + Hid* hid = context; + bool connected = (status == BtStatusConnected); + if(connected) { + notification_internal_message(hid->notifications, &sequence_set_blue_255); + } else { + notification_internal_message(hid->notifications, &sequence_reset_blue); + } + hid_keynote_set_connected_status(hid->hid_keynote, connected); + hid_keyboard_set_connected_status(hid->hid_keyboard, connected); + hid_media_set_connected_status(hid->hid_media, connected); + hid_mouse_set_connected_status(hid->hid_mouse, connected); + hid_tiktok_set_connected_status(hid->hid_tiktok, connected); +} + +static void hid_dialog_callback(DialogExResult result, void* context) { + furi_assert(context); + Hid* app = context; + if(result == DialogExResultLeft) { + view_dispatcher_stop(app->view_dispatcher); + } else if(result == DialogExResultRight) { + view_dispatcher_switch_to_view(app->view_dispatcher, app->view_id); // Show last view + } else if(result == DialogExResultCenter) { + view_dispatcher_switch_to_view(app->view_dispatcher, HidViewSubmenu); + } +} + +static uint32_t hid_exit_confirm_view(void* context) { + UNUSED(context); + return HidViewExitConfirm; +} + +static uint32_t hid_exit(void* context) { + UNUSED(context); + return VIEW_NONE; +} + +Hid* hid_alloc(HidTransport transport) { + Hid* app = malloc(sizeof(Hid)); + app->transport = transport; + + // Gui + app->gui = furi_record_open(RECORD_GUI); + + // Bt + app->bt = furi_record_open(RECORD_BT); + + // Notifications + app->notifications = furi_record_open(RECORD_NOTIFICATION); + + // View dispatcher + app->view_dispatcher = view_dispatcher_alloc(); + view_dispatcher_enable_queue(app->view_dispatcher); + view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); + // Device Type Submenu view + app->device_type_submenu = submenu_alloc(); + submenu_add_item( + app->device_type_submenu, "Keynote", HidSubmenuIndexKeynote, hid_submenu_callback, app); + submenu_add_item( + app->device_type_submenu, "Keyboard", HidSubmenuIndexKeyboard, hid_submenu_callback, app); + submenu_add_item( + app->device_type_submenu, "Media", HidSubmenuIndexMedia, hid_submenu_callback, app); + submenu_add_item( + app->device_type_submenu, "Mouse", HidSubmenuIndexMouse, hid_submenu_callback, app); + if(app->transport == HidTransportBle) { + submenu_add_item( + app->device_type_submenu, + "TikTok Controller", + BtHidSubmenuIndexTikTok, + hid_submenu_callback, + app); + } + view_set_previous_callback(submenu_get_view(app->device_type_submenu), hid_exit); + view_dispatcher_add_view( + app->view_dispatcher, HidViewSubmenu, submenu_get_view(app->device_type_submenu)); + app->view_id = HidViewSubmenu; + view_dispatcher_switch_to_view(app->view_dispatcher, app->view_id); + return app; +} + +Hid* hid_app_alloc_view(void* context) { + furi_assert(context); + Hid* app = context; + // Dialog view + app->dialog = dialog_ex_alloc(); + dialog_ex_set_result_callback(app->dialog, hid_dialog_callback); + dialog_ex_set_context(app->dialog, app); + dialog_ex_set_left_button_text(app->dialog, "Exit"); + dialog_ex_set_right_button_text(app->dialog, "Stay"); + dialog_ex_set_center_button_text(app->dialog, "Menu"); + dialog_ex_set_header(app->dialog, "Close Current App?", 16, 12, AlignLeft, AlignTop); + view_dispatcher_add_view( + app->view_dispatcher, HidViewExitConfirm, dialog_ex_get_view(app->dialog)); + + // Keynote view + app->hid_keynote = hid_keynote_alloc(app); + view_set_previous_callback(hid_keynote_get_view(app->hid_keynote), hid_exit_confirm_view); + view_dispatcher_add_view( + app->view_dispatcher, HidViewKeynote, hid_keynote_get_view(app->hid_keynote)); + + // Keyboard view + app->hid_keyboard = hid_keyboard_alloc(app); + view_set_previous_callback(hid_keyboard_get_view(app->hid_keyboard), hid_exit_confirm_view); + view_dispatcher_add_view( + app->view_dispatcher, HidViewKeyboard, hid_keyboard_get_view(app->hid_keyboard)); + + // Media view + app->hid_media = hid_media_alloc(app); + view_set_previous_callback(hid_media_get_view(app->hid_media), hid_exit_confirm_view); + 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); + view_dispatcher_add_view( + app->view_dispatcher, BtHidViewTikTok, hid_tiktok_get_view(app->hid_tiktok)); + + // Mouse view + app->hid_mouse = hid_mouse_alloc(app); + view_set_previous_callback(hid_mouse_get_view(app->hid_mouse), hid_exit_confirm_view); + view_dispatcher_add_view( + app->view_dispatcher, HidViewMouse, hid_mouse_get_view(app->hid_mouse)); + + return app; +} + +void hid_free(Hid* app) { + furi_assert(app); + + // Reset notification + notification_internal_message(app->notifications, &sequence_reset_blue); + + // Free views + view_dispatcher_remove_view(app->view_dispatcher, HidViewSubmenu); + submenu_free(app->device_type_submenu); + view_dispatcher_remove_view(app->view_dispatcher, HidViewExitConfirm); + dialog_ex_free(app->dialog); + view_dispatcher_remove_view(app->view_dispatcher, HidViewKeynote); + hid_keynote_free(app->hid_keynote); + view_dispatcher_remove_view(app->view_dispatcher, HidViewKeyboard); + hid_keyboard_free(app->hid_keyboard); + view_dispatcher_remove_view(app->view_dispatcher, HidViewMedia); + hid_media_free(app->hid_media); + view_dispatcher_remove_view(app->view_dispatcher, HidViewMouse); + hid_mouse_free(app->hid_mouse); + view_dispatcher_remove_view(app->view_dispatcher, BtHidViewTikTok); + hid_tiktok_free(app->hid_tiktok); + view_dispatcher_free(app->view_dispatcher); + + // Close records + furi_record_close(RECORD_GUI); + app->gui = NULL; + furi_record_close(RECORD_NOTIFICATION); + app->notifications = NULL; + furi_record_close(RECORD_BT); + app->bt = NULL; + + // Free rest + free(app); +} + +void hid_hal_keyboard_press(Hid* instance, uint16_t event) { + furi_assert(instance); + if(instance->transport == HidTransportBle) { + furi_hal_bt_hid_kb_press(event); + } else if(instance->transport == HidTransportUsb) { + furi_hal_hid_kb_press(event); + } else { + furi_crash(NULL); + } +} + +void hid_hal_keyboard_release(Hid* instance, uint16_t event) { + furi_assert(instance); + if(instance->transport == HidTransportBle) { + furi_hal_bt_hid_kb_release(event); + } else if(instance->transport == HidTransportUsb) { + furi_hal_hid_kb_release(event); + } else { + furi_crash(NULL); + } +} + +void hid_hal_keyboard_release_all(Hid* instance) { + furi_assert(instance); + if(instance->transport == HidTransportBle) { + furi_hal_bt_hid_kb_release_all(); + } else if(instance->transport == HidTransportUsb) { + furi_hal_hid_kb_release_all(); + } else { + furi_crash(NULL); + } +} + +void hid_hal_consumer_key_press(Hid* instance, uint16_t event) { + furi_assert(instance); + if(instance->transport == HidTransportBle) { + furi_hal_bt_hid_consumer_key_press(event); + } else if(instance->transport == HidTransportUsb) { + furi_hal_hid_consumer_key_press(event); + } else { + furi_crash(NULL); + } +} + +void hid_hal_consumer_key_release(Hid* instance, uint16_t event) { + furi_assert(instance); + if(instance->transport == HidTransportBle) { + furi_hal_bt_hid_consumer_key_release(event); + } else if(instance->transport == HidTransportUsb) { + furi_hal_hid_consumer_key_release(event); + } else { + furi_crash(NULL); + } +} + +void hid_hal_consumer_key_release_all(Hid* instance) { + furi_assert(instance); + if(instance->transport == HidTransportBle) { + furi_hal_bt_hid_consumer_key_release_all(); + } else if(instance->transport == HidTransportUsb) { + furi_hal_hid_kb_release_all(); + } else { + furi_crash(NULL); + } +} + +void hid_hal_mouse_move(Hid* instance, int8_t dx, int8_t dy) { + furi_assert(instance); + if(instance->transport == HidTransportBle) { + furi_hal_bt_hid_mouse_move(dx, dy); + } else if(instance->transport == HidTransportUsb) { + furi_hal_hid_mouse_move(dx, dy); + } else { + furi_crash(NULL); + } +} + +void hid_hal_mouse_scroll(Hid* instance, int8_t delta) { + furi_assert(instance); + if(instance->transport == HidTransportBle) { + furi_hal_bt_hid_mouse_scroll(delta); + } else if(instance->transport == HidTransportUsb) { + furi_hal_hid_mouse_scroll(delta); + } else { + furi_crash(NULL); + } +} + +void hid_hal_mouse_press(Hid* instance, uint16_t event) { + furi_assert(instance); + if(instance->transport == HidTransportBle) { + furi_hal_bt_hid_mouse_press(event); + } else if(instance->transport == HidTransportUsb) { + furi_hal_hid_mouse_press(event); + } else { + furi_crash(NULL); + } +} + +void hid_hal_mouse_release(Hid* instance, uint16_t event) { + furi_assert(instance); + if(instance->transport == HidTransportBle) { + furi_hal_bt_hid_mouse_release(event); + } else if(instance->transport == HidTransportUsb) { + furi_hal_hid_mouse_release(event); + } else { + furi_crash(NULL); + } +} + +void hid_hal_mouse_release_all(Hid* instance) { + furi_assert(instance); + if(instance->transport == HidTransportBle) { + furi_hal_bt_hid_mouse_release_all(); + } else if(instance->transport == HidTransportUsb) { + furi_hal_hid_mouse_release(HID_MOUSE_BTN_LEFT); + furi_hal_hid_mouse_release(HID_MOUSE_BTN_RIGHT); + } else { + furi_crash(NULL); + } +} + +int32_t hid_usb_app(void* p) { + UNUSED(p); + Hid* app = hid_alloc(HidTransportUsb); + app = hid_app_alloc_view(app); + FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config(); + furi_hal_usb_unlock(); + furi_check(furi_hal_usb_set_config(&usb_hid, NULL) == true); + + bt_hid_connection_status_changed_callback(BtStatusConnected, app); + + DOLPHIN_DEED(DolphinDeedPluginStart); + + view_dispatcher_run(app->view_dispatcher); + + furi_hal_usb_set_config(usb_mode_prev, NULL); + + hid_free(app); + + return 0; +} + +int32_t hid_ble_app(void* p) { + UNUSED(p); + Hid* app = hid_alloc(HidTransportBle); + app = hid_app_alloc_view(app); + + if(!bt_set_profile(app->bt, BtProfileHidKeyboard)) { + FURI_LOG_E(TAG, "Failed to switch profile"); + } + furi_hal_bt_start_advertising(); + bt_set_status_changed_callback(app->bt, bt_hid_connection_status_changed_callback, app); + + DOLPHIN_DEED(DolphinDeedPluginStart); + + view_dispatcher_run(app->view_dispatcher); + + bt_set_status_changed_callback(app->bt, NULL, NULL); + bt_set_profile(app->bt, BtProfileSerial); + + hid_free(app); + + return 0; +} diff --git a/applications/plugins/hid_app/hid.h b/applications/plugins/hid_app/hid.h new file mode 100644 index 00000000..81ebcf56 --- /dev/null +++ b/applications/plugins/hid_app/hid.h @@ -0,0 +1,60 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include "views/hid_keynote.h" +#include "views/hid_keyboard.h" +#include "views/hid_media.h" +#include "views/hid_mouse.h" +#include "views/hid_tiktok.h" + +typedef enum { + HidTransportUsb, + HidTransportBle, +} HidTransport; + +typedef struct Hid Hid; + +struct Hid { + Bt* bt; + Gui* gui; + NotificationApp* notifications; + ViewDispatcher* view_dispatcher; + Submenu* device_type_submenu; + DialogEx* dialog; + HidKeynote* hid_keynote; + HidKeyboard* hid_keyboard; + HidMedia* hid_media; + HidMouse* hid_mouse; + HidTikTok* hid_tiktok; + + HidTransport transport; + uint32_t view_id; +}; + +void hid_hal_keyboard_press(Hid* instance, uint16_t event); +void hid_hal_keyboard_release(Hid* instance, uint16_t event); +void hid_hal_keyboard_release_all(Hid* instance); + +void hid_hal_consumer_key_press(Hid* instance, uint16_t event); +void hid_hal_consumer_key_release(Hid* instance, uint16_t event); +void hid_hal_consumer_key_release_all(Hid* instance); + +void hid_hal_mouse_move(Hid* instance, int8_t dx, int8_t dy); +void hid_hal_mouse_scroll(Hid* instance, int8_t delta); +void hid_hal_mouse_press(Hid* instance, uint16_t event); +void hid_hal_mouse_release(Hid* instance, uint16_t event); +void hid_hal_mouse_release_all(Hid* instance); \ No newline at end of file diff --git a/applications/plugins/bt_hid_app/bt_remote_10px.png b/applications/plugins/hid_app/hid_ble_10px.png similarity index 100% rename from applications/plugins/bt_hid_app/bt_remote_10px.png rename to applications/plugins/hid_app/hid_ble_10px.png diff --git a/applications/plugins/hid_app/hid_usb_10px.png b/applications/plugins/hid_app/hid_usb_10px.png new file mode 100644 index 0000000000000000000000000000000000000000..415de7d2304fe982c025b2b9a942abbf0a2b6dd0 GIT binary patch literal 969 zcmaJ=J#W)M7(OY0prTdS3e(9IQYsOjefe;0)l|h!Xha;MG(g5)>`P;{_8I$1oJb(V z#>Co{9{@i91|(QuX5%*?v9pwOnxqT_55D(az0dQ0J@>lZy1%+|YXtzX+Ss!@;>_%o zt2y!i@N?&lIBxPQduOaNrjU+e?;YX%)UR2L%LyN@}>atRF6-9xXE~}dAVr@YBcOX_U zM#>gat3`~BQpG5%aP~Eh*gj89{x|#<%&i_M$ zU=f}04!x-NpTtRb98uJv2|I~hvAe-WmMSu=m=ez7E@Q{@LAHmCvt-C3h|9793l4Gp zF!O9qA&z4-!i1C1r48GZ1c~hXo`JDuS-aJ0wOrd$)taqWN;ON>tZH4WV;fs@tj*k$ zfQEdI^)9g5QfwxOAQG8v8vD3;Z_1q-{ zl$i_hipxU&G!&YTg}8q|eDGX6j4SPCw{~`RCd@~lzrPU2?S{SEO@H(cJnv<$o(G-l ph0_~rZ>7^_`EovpzT_W+OY7j;8rXcd{ -#include -#include #include #include +#include "../hid.h" +#include "hid_icons.h" -#include "bt_hid_icons.h" +#define TAG "HidKeyboard" -struct BtHidKeyboard { +struct HidKeyboard { View* view; + Hid* hid; }; typedef struct { @@ -24,7 +25,7 @@ typedef struct { bool back_pressed; bool connected; char key_string[5]; -} BtHidKeyboardModel; +} HidKeyboardModel; typedef struct { uint8_t width; @@ -32,13 +33,12 @@ typedef struct { const Icon* icon; char* shift_key; uint8_t value; -} BtHidKeyboardKey; +} HidKeyboardKey; typedef struct { int8_t x; int8_t y; -} BtHidKeyboardPoint; - +} HidKeyboardPoint; // 4 BY 12 #define MARGIN_TOP 0 #define MARGIN_LEFT 4 @@ -49,7 +49,7 @@ typedef struct { #define COLUMN_COUNT 12 // 0 width items are not drawn, but there value is used -const BtHidKeyboardKey bt_hid_keyboard_keyset[ROW_COUNT][COLUMN_COUNT] = { +const HidKeyboardKey hid_keyboard_keyset[ROW_COUNT][COLUMN_COUNT] = { { {.width = 1, .icon = NULL, .key = "1", .shift_key = "!", .value = HID_KEYBOARD_1}, {.width = 1, .icon = NULL, .key = "2", .shift_key = "@", .value = HID_KEYBOARD_2}, @@ -112,7 +112,7 @@ const BtHidKeyboardKey bt_hid_keyboard_keyset[ROW_COUNT][COLUMN_COUNT] = { }, { {.width = 1, .icon = &I_Pin_arrow_up_7x9, .value = HID_KEYBOARD_L_SHIFT}, - {.width = 1, .icon = NULL, .key = ",", .shift_key = "<", .value = HID_KEYPAD_COMMA}, + {.width = 1, .icon = NULL, .key = ",", .shift_key = "<", .value = HID_KEYBOARD_COMMA}, {.width = 1, .icon = NULL, .key = ".", .shift_key = ">", .value = HID_KEYBOARD_DOT}, {.width = 4, .icon = NULL, .key = " ", .value = HID_KEYBOARD_SPACEBAR}, {.width = 0, .value = HID_KEYBOARD_SPACEBAR}, @@ -140,19 +140,19 @@ const BtHidKeyboardKey bt_hid_keyboard_keyset[ROW_COUNT][COLUMN_COUNT] = { }, }; -static void bt_hid_keyboard_to_upper(char* str) { +static void hid_keyboard_to_upper(char* str) { while(*str) { *str = toupper((unsigned char)*str); str++; } } -static void bt_hid_keyboard_draw_key( +static void hid_keyboard_draw_key( Canvas* canvas, - BtHidKeyboardModel* model, + HidKeyboardModel* model, uint8_t x, uint8_t y, - BtHidKeyboardKey key, + HidKeyboardKey key, bool selected) { if(!key.width) return; @@ -190,7 +190,7 @@ static void bt_hid_keyboard_draw_key( if((model->ctrl && key.value == HID_KEYBOARD_L_CTRL) || (model->alt && key.value == HID_KEYBOARD_L_ALT) || (model->gui && key.value == HID_KEYBOARD_L_GUI)) { - bt_hid_keyboard_to_upper(model->key_string); + hid_keyboard_to_upper(model->key_string); } canvas_draw_str_aligned( canvas, @@ -202,9 +202,9 @@ static void bt_hid_keyboard_draw_key( } } -static void bt_hid_keyboard_draw_callback(Canvas* canvas, void* context) { +static void hid_keyboard_draw_callback(Canvas* canvas, void* context) { furi_assert(context); - BtHidKeyboardModel* model = context; + HidKeyboardModel* model = context; // Header if(!model->connected) { @@ -225,17 +225,17 @@ static void bt_hid_keyboard_draw_callback(Canvas* canvas, void* context) { // Start shifting the all keys up if on the next row (Scrolling) uint8_t initY = model->y - 4 > 0 ? model->y - 4 : 0; for(uint8_t y = initY; y < ROW_COUNT; y++) { - const BtHidKeyboardKey* keyboardKeyRow = bt_hid_keyboard_keyset[y]; + const HidKeyboardKey* keyboardKeyRow = hid_keyboard_keyset[y]; uint8_t x = 0; for(uint8_t i = 0; i < COLUMN_COUNT; i++) { - BtHidKeyboardKey key = keyboardKeyRow[i]; + HidKeyboardKey key = keyboardKeyRow[i]; // Select when the button is hovered // Select if the button is hovered within its width // Select if back is clicked and its the backspace key // Deselect when the button clicked or not hovered bool keySelected = (x <= model->x && model->x < (x + key.width)) && y == model->y; bool backSelected = model->back_pressed && key.value == HID_KEYBOARD_DELETE; - bt_hid_keyboard_draw_key( + hid_keyboard_draw_key( canvas, model, x, @@ -247,8 +247,8 @@ static void bt_hid_keyboard_draw_callback(Canvas* canvas, void* context) { } } -static uint8_t bt_hid_keyboard_get_selected_key(BtHidKeyboardModel* model) { - BtHidKeyboardKey key = bt_hid_keyboard_keyset[model->y][model->x]; +static uint8_t hid_keyboard_get_selected_key(HidKeyboardModel* model) { + HidKeyboardKey key = hid_keyboard_keyset[model->y][model->x]; // Use upper case if shift is toggled bool useUppercase = model->shift; // Check if the key has an upper case version @@ -259,34 +259,34 @@ static uint8_t bt_hid_keyboard_get_selected_key(BtHidKeyboardModel* model) { return key.value; } -static void bt_hid_keyboard_get_select_key(BtHidKeyboardModel* model, BtHidKeyboardPoint delta) { +static void hid_keyboard_get_select_key(HidKeyboardModel* model, HidKeyboardPoint delta) { // Keep going until a valid spot is found, this allows for nulls and zero width keys in the map do { if(((int8_t)model->y) + delta.y < 0) model->y = ROW_COUNT - 1; else model->y = (model->y + delta.y) % ROW_COUNT; - } while(delta.y != 0 && bt_hid_keyboard_keyset[model->y][model->x].value == 0); + } while(delta.y != 0 && hid_keyboard_keyset[model->y][model->x].value == 0); do { if(((int8_t)model->x) + delta.x < 0) model->x = COLUMN_COUNT - 1; else model->x = (model->x + delta.x) % COLUMN_COUNT; - } while(delta.x != 0 && bt_hid_keyboard_keyset[model->y][model->x].width == + } while(delta.x != 0 && hid_keyboard_keyset[model->y][model->x].width == 0); // Skip zero width keys, pretend they are one key } -static void bt_hid_keyboard_process(BtHidKeyboard* bt_hid_keyboard, InputEvent* event) { +static void hid_keyboard_process(HidKeyboard* hid_keyboard, InputEvent* event) { with_view_model( - bt_hid_keyboard->view, - BtHidKeyboardModel * model, + hid_keyboard->view, + HidKeyboardModel * model, { if(event->key == InputKeyOk) { if(event->type == InputTypePress) { model->ok_pressed = true; } else if(event->type == InputTypeLong || event->type == InputTypeShort) { - model->last_key_code = bt_hid_keyboard_get_selected_key(model); + model->last_key_code = hid_keyboard_get_selected_key(model); // Toggle the modifier key when clicked, and click the key if(model->last_key_code == HID_KEYBOARD_L_SHIFT) { @@ -314,10 +314,12 @@ static void bt_hid_keyboard_process(BtHidKeyboard* bt_hid_keyboard, InputEvent* else model->modifier_code &= ~KEY_MOD_LEFT_GUI; } - furi_hal_bt_hid_kb_press(model->modifier_code | model->last_key_code); + hid_hal_keyboard_press( + hid_keyboard->hid, model->modifier_code | model->last_key_code); } else if(event->type == InputTypeRelease) { // Release happens after short and long presses - furi_hal_bt_hid_kb_release(model->modifier_code | model->last_key_code); + hid_hal_keyboard_release( + hid_keyboard->hid, model->modifier_code | model->last_key_code); model->ok_pressed = false; } } else if(event->key == InputKeyBack) { @@ -325,66 +327,67 @@ static void bt_hid_keyboard_process(BtHidKeyboard* bt_hid_keyboard, InputEvent* if(event->type == InputTypePress) { model->back_pressed = true; } else if(event->type == InputTypeShort) { - furi_hal_bt_hid_kb_press(HID_KEYBOARD_DELETE); - furi_hal_bt_hid_kb_release(HID_KEYBOARD_DELETE); + hid_hal_keyboard_press(hid_keyboard->hid, HID_KEYBOARD_DELETE); + hid_hal_keyboard_release(hid_keyboard->hid, HID_KEYBOARD_DELETE); } else if(event->type == InputTypeRelease) { model->back_pressed = false; } } else if(event->type == InputTypePress || event->type == InputTypeRepeat) { // Cycle the selected keys if(event->key == InputKeyUp) { - bt_hid_keyboard_get_select_key(model, (BtHidKeyboardPoint){.x = 0, .y = -1}); + hid_keyboard_get_select_key(model, (HidKeyboardPoint){.x = 0, .y = -1}); } else if(event->key == InputKeyDown) { - bt_hid_keyboard_get_select_key(model, (BtHidKeyboardPoint){.x = 0, .y = 1}); + hid_keyboard_get_select_key(model, (HidKeyboardPoint){.x = 0, .y = 1}); } else if(event->key == InputKeyLeft) { - bt_hid_keyboard_get_select_key(model, (BtHidKeyboardPoint){.x = -1, .y = 0}); + hid_keyboard_get_select_key(model, (HidKeyboardPoint){.x = -1, .y = 0}); } else if(event->key == InputKeyRight) { - bt_hid_keyboard_get_select_key(model, (BtHidKeyboardPoint){.x = 1, .y = 0}); + hid_keyboard_get_select_key(model, (HidKeyboardPoint){.x = 1, .y = 0}); } } }, true); } -static bool bt_hid_keyboard_input_callback(InputEvent* event, void* context) { +static bool hid_keyboard_input_callback(InputEvent* event, void* context) { furi_assert(context); - BtHidKeyboard* bt_hid_keyboard = context; + HidKeyboard* hid_keyboard = context; bool consumed = false; if(event->type == InputTypeLong && event->key == InputKeyBack) { - furi_hal_bt_hid_kb_release_all(); + hid_hal_keyboard_release_all(hid_keyboard->hid); } else { - bt_hid_keyboard_process(bt_hid_keyboard, event); + hid_keyboard_process(hid_keyboard, event); consumed = true; } return consumed; } -BtHidKeyboard* bt_hid_keyboard_alloc() { - BtHidKeyboard* bt_hid_keyboard = malloc(sizeof(BtHidKeyboard)); - bt_hid_keyboard->view = view_alloc(); - view_set_context(bt_hid_keyboard->view, bt_hid_keyboard); - view_allocate_model(bt_hid_keyboard->view, ViewModelTypeLocking, sizeof(BtHidKeyboardModel)); - view_set_draw_callback(bt_hid_keyboard->view, bt_hid_keyboard_draw_callback); - view_set_input_callback(bt_hid_keyboard->view, bt_hid_keyboard_input_callback); +HidKeyboard* hid_keyboard_alloc(Hid* bt_hid) { + HidKeyboard* hid_keyboard = malloc(sizeof(HidKeyboard)); + hid_keyboard->view = view_alloc(); + hid_keyboard->hid = bt_hid; + view_set_context(hid_keyboard->view, hid_keyboard); + view_allocate_model(hid_keyboard->view, ViewModelTypeLocking, sizeof(HidKeyboardModel)); + view_set_draw_callback(hid_keyboard->view, hid_keyboard_draw_callback); + view_set_input_callback(hid_keyboard->view, hid_keyboard_input_callback); - return bt_hid_keyboard; + return hid_keyboard; } -void bt_hid_keyboard_free(BtHidKeyboard* bt_hid_keyboard) { - furi_assert(bt_hid_keyboard); - view_free(bt_hid_keyboard->view); - free(bt_hid_keyboard); +void hid_keyboard_free(HidKeyboard* hid_keyboard) { + furi_assert(hid_keyboard); + view_free(hid_keyboard->view); + free(hid_keyboard); } -View* bt_hid_keyboard_get_view(BtHidKeyboard* bt_hid_keyboard) { - furi_assert(bt_hid_keyboard); - return bt_hid_keyboard->view; +View* hid_keyboard_get_view(HidKeyboard* hid_keyboard) { + furi_assert(hid_keyboard); + return hid_keyboard->view; } -void bt_hid_keyboard_set_connected_status(BtHidKeyboard* bt_hid_keyboard, bool connected) { - furi_assert(bt_hid_keyboard); +void hid_keyboard_set_connected_status(HidKeyboard* hid_keyboard, bool connected) { + furi_assert(hid_keyboard); with_view_model( - bt_hid_keyboard->view, BtHidKeyboardModel * model, { model->connected = connected; }, true); + hid_keyboard->view, HidKeyboardModel * model, { model->connected = connected; }, true); } diff --git a/applications/plugins/hid_app/views/hid_keyboard.h b/applications/plugins/hid_app/views/hid_keyboard.h new file mode 100644 index 00000000..71277136 --- /dev/null +++ b/applications/plugins/hid_app/views/hid_keyboard.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +typedef struct Hid Hid; +typedef struct HidKeyboard HidKeyboard; + +HidKeyboard* hid_keyboard_alloc(Hid* bt_hid); + +void hid_keyboard_free(HidKeyboard* hid_keyboard); + +View* hid_keyboard_get_view(HidKeyboard* hid_keyboard); + +void hid_keyboard_set_connected_status(HidKeyboard* hid_keyboard, bool connected); diff --git a/applications/plugins/bt_hid_app/views/bt_hid_keynote.c b/applications/plugins/hid_app/views/hid_keynote.c similarity index 60% rename from applications/plugins/bt_hid_app/views/bt_hid_keynote.c rename to applications/plugins/hid_app/views/hid_keynote.c index 0e81c5fa..c95f4278 100644 --- a/applications/plugins/bt_hid_app/views/bt_hid_keynote.c +++ b/applications/plugins/hid_app/views/hid_keynote.c @@ -1,13 +1,14 @@ -#include "bt_hid_keynote.h" -#include -#include -#include +#include "hid_keynote.h" #include +#include "../hid.h" -#include "bt_hid_icons.h" +#include "hid_icons.h" -struct BtHidKeynote { +#define TAG "HidKeynote" + +struct HidKeynote { View* view; + Hid* hid; }; typedef struct { @@ -18,9 +19,9 @@ typedef struct { bool ok_pressed; bool back_pressed; bool connected; -} BtHidKeynoteModel; +} HidKeynoteModel; -static void bt_hid_keynote_draw_arrow(Canvas* canvas, uint8_t x, uint8_t y, CanvasDirection dir) { +static void hid_keynote_draw_arrow(Canvas* canvas, uint8_t x, uint8_t y, CanvasDirection dir) { canvas_draw_triangle(canvas, x, y, 5, 3, dir); if(dir == CanvasDirectionBottomToTop) { canvas_draw_line(canvas, x, y + 6, x, y - 1); @@ -33,9 +34,9 @@ static void bt_hid_keynote_draw_arrow(Canvas* canvas, uint8_t x, uint8_t y, Canv } } -static void bt_hid_keynote_draw_callback(Canvas* canvas, void* context) { +static void hid_keynote_draw_callback(Canvas* canvas, void* context) { furi_assert(context); - BtHidKeynoteModel* model = context; + HidKeynoteModel* model = context; // Header if(model->connected) { @@ -56,7 +57,7 @@ static void bt_hid_keynote_draw_callback(Canvas* canvas, void* context) { elements_slightly_rounded_box(canvas, 24, 26, 13, 13); canvas_set_color(canvas, ColorWhite); } - bt_hid_keynote_draw_arrow(canvas, 30, 30, CanvasDirectionBottomToTop); + hid_keynote_draw_arrow(canvas, 30, 30, CanvasDirectionBottomToTop); canvas_set_color(canvas, ColorBlack); // Down @@ -65,7 +66,7 @@ static void bt_hid_keynote_draw_callback(Canvas* canvas, void* context) { elements_slightly_rounded_box(canvas, 24, 47, 13, 13); canvas_set_color(canvas, ColorWhite); } - bt_hid_keynote_draw_arrow(canvas, 30, 55, CanvasDirectionTopToBottom); + hid_keynote_draw_arrow(canvas, 30, 55, CanvasDirectionTopToBottom); canvas_set_color(canvas, ColorBlack); // Left @@ -74,7 +75,7 @@ static void bt_hid_keynote_draw_callback(Canvas* canvas, void* context) { elements_slightly_rounded_box(canvas, 3, 47, 13, 13); canvas_set_color(canvas, ColorWhite); } - bt_hid_keynote_draw_arrow(canvas, 7, 53, CanvasDirectionRightToLeft); + hid_keynote_draw_arrow(canvas, 7, 53, CanvasDirectionRightToLeft); canvas_set_color(canvas, ColorBlack); // Right @@ -83,7 +84,7 @@ static void bt_hid_keynote_draw_callback(Canvas* canvas, void* context) { elements_slightly_rounded_box(canvas, 45, 47, 13, 13); canvas_set_color(canvas, ColorWhite); } - bt_hid_keynote_draw_arrow(canvas, 53, 53, CanvasDirectionLeftToRight); + hid_keynote_draw_arrow(canvas, 53, 53, CanvasDirectionLeftToRight); canvas_set_color(canvas, ColorBlack); // Ok @@ -106,100 +107,101 @@ static void bt_hid_keynote_draw_callback(Canvas* canvas, void* context) { elements_multiline_text_aligned(canvas, 91, 57, AlignLeft, AlignBottom, "Back"); } -static void bt_hid_keynote_process(BtHidKeynote* bt_hid_keynote, InputEvent* event) { +static void hid_keynote_process(HidKeynote* hid_keynote, InputEvent* event) { with_view_model( - bt_hid_keynote->view, - BtHidKeynoteModel * model, + hid_keynote->view, + HidKeynoteModel * model, { if(event->type == InputTypePress) { if(event->key == InputKeyUp) { model->up_pressed = true; - furi_hal_bt_hid_kb_press(HID_KEYBOARD_UP_ARROW); + hid_hal_keyboard_press(hid_keynote->hid, HID_KEYBOARD_UP_ARROW); } else if(event->key == InputKeyDown) { model->down_pressed = true; - furi_hal_bt_hid_kb_press(HID_KEYBOARD_DOWN_ARROW); + hid_hal_keyboard_press(hid_keynote->hid, HID_KEYBOARD_DOWN_ARROW); } else if(event->key == InputKeyLeft) { model->left_pressed = true; - furi_hal_bt_hid_kb_press(HID_KEYBOARD_LEFT_ARROW); + hid_hal_keyboard_press(hid_keynote->hid, HID_KEYBOARD_LEFT_ARROW); } else if(event->key == InputKeyRight) { model->right_pressed = true; - furi_hal_bt_hid_kb_press(HID_KEYBOARD_RIGHT_ARROW); + hid_hal_keyboard_press(hid_keynote->hid, HID_KEYBOARD_RIGHT_ARROW); } else if(event->key == InputKeyOk) { model->ok_pressed = true; - furi_hal_bt_hid_kb_press(HID_KEYBOARD_SPACEBAR); + hid_hal_keyboard_press(hid_keynote->hid, HID_KEYBOARD_SPACEBAR); } else if(event->key == InputKeyBack) { model->back_pressed = true; } } else if(event->type == InputTypeRelease) { if(event->key == InputKeyUp) { model->up_pressed = false; - furi_hal_bt_hid_kb_release(HID_KEYBOARD_UP_ARROW); + hid_hal_keyboard_release(hid_keynote->hid, HID_KEYBOARD_UP_ARROW); } else if(event->key == InputKeyDown) { model->down_pressed = false; - furi_hal_bt_hid_kb_release(HID_KEYBOARD_DOWN_ARROW); + hid_hal_keyboard_release(hid_keynote->hid, HID_KEYBOARD_DOWN_ARROW); } else if(event->key == InputKeyLeft) { model->left_pressed = false; - furi_hal_bt_hid_kb_release(HID_KEYBOARD_LEFT_ARROW); + hid_hal_keyboard_release(hid_keynote->hid, HID_KEYBOARD_LEFT_ARROW); } else if(event->key == InputKeyRight) { model->right_pressed = false; - furi_hal_bt_hid_kb_release(HID_KEYBOARD_RIGHT_ARROW); + hid_hal_keyboard_release(hid_keynote->hid, HID_KEYBOARD_RIGHT_ARROW); } else if(event->key == InputKeyOk) { model->ok_pressed = false; - furi_hal_bt_hid_kb_release(HID_KEYBOARD_SPACEBAR); + hid_hal_keyboard_release(hid_keynote->hid, HID_KEYBOARD_SPACEBAR); } else if(event->key == InputKeyBack) { model->back_pressed = false; } } else if(event->type == InputTypeShort) { if(event->key == InputKeyBack) { - furi_hal_bt_hid_kb_press(HID_KEYBOARD_DELETE); - furi_hal_bt_hid_kb_release(HID_KEYBOARD_DELETE); - furi_hal_bt_hid_consumer_key_press(HID_CONSUMER_AC_BACK); - furi_hal_bt_hid_consumer_key_release(HID_CONSUMER_AC_BACK); + hid_hal_keyboard_press(hid_keynote->hid, HID_KEYBOARD_DELETE); + hid_hal_keyboard_release(hid_keynote->hid, HID_KEYBOARD_DELETE); + hid_hal_consumer_key_press(hid_keynote->hid, HID_CONSUMER_AC_BACK); + hid_hal_consumer_key_release(hid_keynote->hid, HID_CONSUMER_AC_BACK); } } }, true); } -static bool bt_hid_keynote_input_callback(InputEvent* event, void* context) { +static bool hid_keynote_input_callback(InputEvent* event, void* context) { furi_assert(context); - BtHidKeynote* bt_hid_keynote = context; + HidKeynote* hid_keynote = context; bool consumed = false; if(event->type == InputTypeLong && event->key == InputKeyBack) { - furi_hal_bt_hid_kb_release_all(); + hid_hal_keyboard_release_all(hid_keynote->hid); } else { - bt_hid_keynote_process(bt_hid_keynote, event); + hid_keynote_process(hid_keynote, event); consumed = true; } return consumed; } -BtHidKeynote* bt_hid_keynote_alloc() { - BtHidKeynote* bt_hid_keynote = malloc(sizeof(BtHidKeynote)); - bt_hid_keynote->view = view_alloc(); - view_set_context(bt_hid_keynote->view, bt_hid_keynote); - view_allocate_model(bt_hid_keynote->view, ViewModelTypeLocking, sizeof(BtHidKeynoteModel)); - view_set_draw_callback(bt_hid_keynote->view, bt_hid_keynote_draw_callback); - view_set_input_callback(bt_hid_keynote->view, bt_hid_keynote_input_callback); +HidKeynote* hid_keynote_alloc(Hid* hid) { + HidKeynote* hid_keynote = malloc(sizeof(HidKeynote)); + hid_keynote->view = view_alloc(); + hid_keynote->hid = hid; + view_set_context(hid_keynote->view, hid_keynote); + view_allocate_model(hid_keynote->view, ViewModelTypeLocking, sizeof(HidKeynoteModel)); + view_set_draw_callback(hid_keynote->view, hid_keynote_draw_callback); + view_set_input_callback(hid_keynote->view, hid_keynote_input_callback); - return bt_hid_keynote; + return hid_keynote; } -void bt_hid_keynote_free(BtHidKeynote* bt_hid_keynote) { - furi_assert(bt_hid_keynote); - view_free(bt_hid_keynote->view); - free(bt_hid_keynote); +void hid_keynote_free(HidKeynote* hid_keynote) { + furi_assert(hid_keynote); + view_free(hid_keynote->view); + free(hid_keynote); } -View* bt_hid_keynote_get_view(BtHidKeynote* bt_hid_keynote) { - furi_assert(bt_hid_keynote); - return bt_hid_keynote->view; +View* hid_keynote_get_view(HidKeynote* hid_keynote) { + furi_assert(hid_keynote); + return hid_keynote->view; } -void bt_hid_keynote_set_connected_status(BtHidKeynote* bt_hid_keynote, bool connected) { - furi_assert(bt_hid_keynote); +void hid_keynote_set_connected_status(HidKeynote* hid_keynote, bool connected) { + furi_assert(hid_keynote); with_view_model( - bt_hid_keynote->view, BtHidKeynoteModel * model, { model->connected = connected; }, true); + hid_keynote->view, HidKeynoteModel * model, { model->connected = connected; }, true); } diff --git a/applications/plugins/hid_app/views/hid_keynote.h b/applications/plugins/hid_app/views/hid_keynote.h new file mode 100644 index 00000000..4d4a0a9b --- /dev/null +++ b/applications/plugins/hid_app/views/hid_keynote.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +typedef struct Hid Hid; +typedef struct HidKeynote HidKeynote; + +HidKeynote* hid_keynote_alloc(Hid* bt_hid); + +void hid_keynote_free(HidKeynote* hid_keynote); + +View* hid_keynote_get_view(HidKeynote* hid_keynote); + +void hid_keynote_set_connected_status(HidKeynote* hid_keynote, bool connected); diff --git a/applications/plugins/bt_hid_app/views/bt_hid_media.c b/applications/plugins/hid_app/views/hid_media.c similarity index 59% rename from applications/plugins/bt_hid_app/views/bt_hid_media.c rename to applications/plugins/hid_app/views/hid_media.c index df7349a9..5d764f73 100644 --- a/applications/plugins/bt_hid_app/views/bt_hid_media.c +++ b/applications/plugins/hid_app/views/hid_media.c @@ -1,13 +1,17 @@ -#include "bt_hid_media.h" +#include "hid_media.h" #include #include #include #include +#include "../hid.h" -#include "bt_hid_icons.h" +#include "hid_icons.h" -struct BtHidMedia { +#define TAG "HidMedia" + +struct HidMedia { View* view; + Hid* hid; }; typedef struct { @@ -17,9 +21,9 @@ typedef struct { bool down_pressed; bool ok_pressed; bool connected; -} BtHidMediaModel; +} HidMediaModel; -static void bt_hid_media_draw_arrow(Canvas* canvas, uint8_t x, uint8_t y, CanvasDirection dir) { +static void hid_media_draw_arrow(Canvas* canvas, uint8_t x, uint8_t y, CanvasDirection dir) { canvas_draw_triangle(canvas, x, y, 5, 3, dir); if(dir == CanvasDirectionBottomToTop) { canvas_draw_dot(canvas, x, y - 1); @@ -32,9 +36,9 @@ static void bt_hid_media_draw_arrow(Canvas* canvas, uint8_t x, uint8_t y, Canvas } } -static void bt_hid_media_draw_callback(Canvas* canvas, void* context) { +static void hid_media_draw_callback(Canvas* canvas, void* context) { furi_assert(context); - BtHidMediaModel* model = context; + HidMediaModel* model = context; // Header if(model->connected) { @@ -76,8 +80,8 @@ static void bt_hid_media_draw_callback(Canvas* canvas, void* context) { canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - bt_hid_media_draw_arrow(canvas, 82, 31, CanvasDirectionRightToLeft); - bt_hid_media_draw_arrow(canvas, 86, 31, CanvasDirectionRightToLeft); + hid_media_draw_arrow(canvas, 82, 31, CanvasDirectionRightToLeft); + hid_media_draw_arrow(canvas, 86, 31, CanvasDirectionRightToLeft); canvas_set_color(canvas, ColorBlack); // Right @@ -87,8 +91,8 @@ static void bt_hid_media_draw_callback(Canvas* canvas, void* context) { canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - bt_hid_media_draw_arrow(canvas, 112, 31, CanvasDirectionLeftToRight); - bt_hid_media_draw_arrow(canvas, 116, 31, CanvasDirectionLeftToRight); + hid_media_draw_arrow(canvas, 112, 31, CanvasDirectionLeftToRight); + hid_media_draw_arrow(canvas, 116, 31, CanvasDirectionLeftToRight); canvas_set_color(canvas, ColorBlack); // Ok @@ -96,7 +100,7 @@ static void bt_hid_media_draw_callback(Canvas* canvas, void* context) { canvas_draw_icon(canvas, 93, 25, &I_Pressed_Button_13x13); canvas_set_color(canvas, ColorWhite); } - bt_hid_media_draw_arrow(canvas, 96, 31, CanvasDirectionLeftToRight); + hid_media_draw_arrow(canvas, 96, 31, CanvasDirectionLeftToRight); canvas_draw_line(canvas, 100, 29, 100, 33); canvas_draw_line(canvas, 102, 29, 102, 33); canvas_set_color(canvas, ColorBlack); @@ -107,100 +111,101 @@ static void bt_hid_media_draw_callback(Canvas* canvas, void* context) { elements_multiline_text_aligned(canvas, 13, 62, AlignLeft, AlignBottom, "Hold to exit"); } -static void bt_hid_media_process_press(BtHidMedia* bt_hid_media, InputEvent* event) { +static void hid_media_process_press(HidMedia* hid_media, InputEvent* event) { with_view_model( - bt_hid_media->view, - BtHidMediaModel * model, + hid_media->view, + HidMediaModel * model, { if(event->key == InputKeyUp) { model->up_pressed = true; - furi_hal_bt_hid_consumer_key_press(HID_CONSUMER_VOLUME_INCREMENT); + hid_hal_consumer_key_press(hid_media->hid, HID_CONSUMER_VOLUME_INCREMENT); } else if(event->key == InputKeyDown) { model->down_pressed = true; - furi_hal_bt_hid_consumer_key_press(HID_CONSUMER_VOLUME_DECREMENT); + hid_hal_consumer_key_press(hid_media->hid, HID_CONSUMER_VOLUME_DECREMENT); } else if(event->key == InputKeyLeft) { model->left_pressed = true; - furi_hal_bt_hid_consumer_key_press(HID_CONSUMER_SCAN_PREVIOUS_TRACK); + hid_hal_consumer_key_press(hid_media->hid, HID_CONSUMER_SCAN_PREVIOUS_TRACK); } else if(event->key == InputKeyRight) { model->right_pressed = true; - furi_hal_bt_hid_consumer_key_press(HID_CONSUMER_SCAN_NEXT_TRACK); + hid_hal_consumer_key_press(hid_media->hid, HID_CONSUMER_SCAN_NEXT_TRACK); } else if(event->key == InputKeyOk) { model->ok_pressed = true; - furi_hal_bt_hid_consumer_key_press(HID_CONSUMER_PLAY_PAUSE); + hid_hal_consumer_key_press(hid_media->hid, HID_CONSUMER_PLAY_PAUSE); } }, true); } -static void bt_hid_media_process_release(BtHidMedia* bt_hid_media, InputEvent* event) { +static void hid_media_process_release(HidMedia* hid_media, InputEvent* event) { with_view_model( - bt_hid_media->view, - BtHidMediaModel * model, + hid_media->view, + HidMediaModel * model, { if(event->key == InputKeyUp) { model->up_pressed = false; - furi_hal_bt_hid_consumer_key_release(HID_CONSUMER_VOLUME_INCREMENT); + hid_hal_consumer_key_release(hid_media->hid, HID_CONSUMER_VOLUME_INCREMENT); } else if(event->key == InputKeyDown) { model->down_pressed = false; - furi_hal_bt_hid_consumer_key_release(HID_CONSUMER_VOLUME_DECREMENT); + hid_hal_consumer_key_release(hid_media->hid, HID_CONSUMER_VOLUME_DECREMENT); } else if(event->key == InputKeyLeft) { model->left_pressed = false; - furi_hal_bt_hid_consumer_key_release(HID_CONSUMER_SCAN_PREVIOUS_TRACK); + hid_hal_consumer_key_release(hid_media->hid, HID_CONSUMER_SCAN_PREVIOUS_TRACK); } else if(event->key == InputKeyRight) { model->right_pressed = false; - furi_hal_bt_hid_consumer_key_release(HID_CONSUMER_SCAN_NEXT_TRACK); + hid_hal_consumer_key_release(hid_media->hid, HID_CONSUMER_SCAN_NEXT_TRACK); } else if(event->key == InputKeyOk) { model->ok_pressed = false; - furi_hal_bt_hid_consumer_key_release(HID_CONSUMER_PLAY_PAUSE); + hid_hal_consumer_key_release(hid_media->hid, HID_CONSUMER_PLAY_PAUSE); } }, true); } -static bool bt_hid_media_input_callback(InputEvent* event, void* context) { +static bool hid_media_input_callback(InputEvent* event, void* context) { furi_assert(context); - BtHidMedia* bt_hid_media = context; + HidMedia* hid_media = context; bool consumed = false; if(event->type == InputTypePress) { - bt_hid_media_process_press(bt_hid_media, event); + hid_media_process_press(hid_media, event); consumed = true; } else if(event->type == InputTypeRelease) { - bt_hid_media_process_release(bt_hid_media, event); + hid_media_process_release(hid_media, event); consumed = true; } else if(event->type == InputTypeShort) { if(event->key == InputKeyBack) { - furi_hal_bt_hid_consumer_key_release_all(); + hid_hal_consumer_key_release_all(hid_media->hid); } } return consumed; } -BtHidMedia* bt_hid_media_alloc() { - BtHidMedia* bt_hid_media = malloc(sizeof(BtHidMedia)); - bt_hid_media->view = view_alloc(); - view_set_context(bt_hid_media->view, bt_hid_media); - view_allocate_model(bt_hid_media->view, ViewModelTypeLocking, sizeof(BtHidMediaModel)); - view_set_draw_callback(bt_hid_media->view, bt_hid_media_draw_callback); - view_set_input_callback(bt_hid_media->view, bt_hid_media_input_callback); +HidMedia* hid_media_alloc(Hid* hid) { + HidMedia* hid_media = malloc(sizeof(HidMedia)); + hid_media->view = view_alloc(); + hid_media->hid = hid; + view_set_context(hid_media->view, hid_media); + view_allocate_model(hid_media->view, ViewModelTypeLocking, sizeof(HidMediaModel)); + view_set_draw_callback(hid_media->view, hid_media_draw_callback); + view_set_input_callback(hid_media->view, hid_media_input_callback); - return bt_hid_media; + return hid_media; } -void bt_hid_media_free(BtHidMedia* bt_hid_media) { - furi_assert(bt_hid_media); - view_free(bt_hid_media->view); - free(bt_hid_media); +void hid_media_free(HidMedia* hid_media) { + furi_assert(hid_media); + view_free(hid_media->view); + free(hid_media); } -View* bt_hid_media_get_view(BtHidMedia* bt_hid_media) { - furi_assert(bt_hid_media); - return bt_hid_media->view; +View* hid_media_get_view(HidMedia* hid_media) { + furi_assert(hid_media); + return hid_media->view; } -void bt_hid_media_set_connected_status(BtHidMedia* bt_hid_media, bool connected) { - furi_assert(bt_hid_media); +void hid_media_set_connected_status(HidMedia* hid_media, bool connected) { + furi_assert(hid_media); with_view_model( - bt_hid_media->view, BtHidMediaModel * model, { model->connected = connected; }, true); + hid_media->view, HidMediaModel * model, { model->connected = connected; }, true); } diff --git a/applications/plugins/hid_app/views/hid_media.h b/applications/plugins/hid_app/views/hid_media.h new file mode 100644 index 00000000..4aa51dc1 --- /dev/null +++ b/applications/plugins/hid_app/views/hid_media.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +typedef struct HidMedia HidMedia; + +HidMedia* hid_media_alloc(); + +void hid_media_free(HidMedia* hid_media); + +View* hid_media_get_view(HidMedia* hid_media); + +void hid_media_set_connected_status(HidMedia* hid_media, bool connected); diff --git a/applications/plugins/bt_hid_app/views/bt_hid_mouse.c b/applications/plugins/hid_app/views/hid_mouse.c similarity index 68% rename from applications/plugins/bt_hid_app/views/bt_hid_mouse.c rename to applications/plugins/hid_app/views/hid_mouse.c index bd48bab1..d1d76c15 100644 --- a/applications/plugins/bt_hid_app/views/bt_hid_mouse.c +++ b/applications/plugins/hid_app/views/hid_mouse.c @@ -1,16 +1,15 @@ -#include "bt_hid_mouse.h" -#include -#include -#include +#include "hid_mouse.h" #include +#include "../hid.h" -#include "bt_hid_icons.h" +#include "hid_icons.h" -struct BtHidMouse { +#define TAG "HidMouse" + +struct HidMouse { View* view; + Hid* hid; }; -#define MOUSE_MOVE_SHORT 5 -#define MOUSE_MOVE_LONG 20 typedef struct { bool left_pressed; @@ -21,11 +20,11 @@ typedef struct { bool left_mouse_held; bool right_mouse_pressed; bool connected; -} BtHidMouseModel; +} HidMouseModel; -static void bt_hid_mouse_draw_callback(Canvas* canvas, void* context) { +static void hid_mouse_draw_callback(Canvas* canvas, void* context) { furi_assert(context); - BtHidMouseModel* model = context; + HidMouseModel* model = context; // Header if(model->connected) { @@ -103,15 +102,15 @@ static void bt_hid_mouse_draw_callback(Canvas* canvas, void* context) { } } -static void bt_hid_mouse_process(BtHidMouse* bt_hid_mouse, InputEvent* event) { +static void hid_mouse_process(HidMouse* hid_mouse, InputEvent* event) { with_view_model( - bt_hid_mouse->view, - BtHidMouseModel * model, + hid_mouse->view, + HidMouseModel * model, { if(event->key == InputKeyBack) { if(event->type == InputTypeShort) { - furi_hal_bt_hid_mouse_press(HID_MOUSE_BTN_RIGHT); - furi_hal_bt_hid_mouse_release(HID_MOUSE_BTN_RIGHT); + hid_hal_mouse_press(hid_mouse->hid, HID_MOUSE_BTN_RIGHT); + hid_hal_mouse_release(hid_mouse->hid, HID_MOUSE_BTN_RIGHT); } else if(event->type == InputTypePress) { model->right_mouse_pressed = true; } else if(event->type == InputTypeRelease) { @@ -120,11 +119,12 @@ static void bt_hid_mouse_process(BtHidMouse* bt_hid_mouse, InputEvent* event) { } else if(event->key == InputKeyOk) { if(event->type == InputTypeShort) { // Just release if it was being held before - if(!model->left_mouse_held) furi_hal_bt_hid_mouse_press(HID_MOUSE_BTN_LEFT); - furi_hal_bt_hid_mouse_release(HID_MOUSE_BTN_LEFT); + if(!model->left_mouse_held) + hid_hal_mouse_press(hid_mouse->hid, HID_MOUSE_BTN_LEFT); + hid_hal_mouse_release(hid_mouse->hid, HID_MOUSE_BTN_LEFT); model->left_mouse_held = false; } else if(event->type == InputTypeLong) { - furi_hal_bt_hid_mouse_press(HID_MOUSE_BTN_LEFT); + hid_hal_mouse_press(hid_mouse->hid, HID_MOUSE_BTN_LEFT); model->left_mouse_held = true; model->left_mouse_pressed = true; } else if(event->type == InputTypePress) { @@ -133,40 +133,39 @@ static void bt_hid_mouse_process(BtHidMouse* bt_hid_mouse, InputEvent* event) { // Only release if it wasn't a long press if(!model->left_mouse_held) model->left_mouse_pressed = false; } - } else if(event->key == InputKeyRight) { if(event->type == InputTypePress) { model->right_pressed = true; - furi_hal_bt_hid_mouse_move(MOUSE_MOVE_SHORT, 0); + hid_hal_mouse_move(hid_mouse->hid, MOUSE_MOVE_SHORT, 0); } else if(event->type == InputTypeRepeat) { - furi_hal_bt_hid_mouse_move(MOUSE_MOVE_LONG, 0); + hid_hal_mouse_move(hid_mouse->hid, MOUSE_MOVE_LONG, 0); } else if(event->type == InputTypeRelease) { model->right_pressed = false; } } else if(event->key == InputKeyLeft) { if(event->type == InputTypePress) { model->left_pressed = true; - furi_hal_bt_hid_mouse_move(-MOUSE_MOVE_SHORT, 0); + hid_hal_mouse_move(hid_mouse->hid, -MOUSE_MOVE_SHORT, 0); } else if(event->type == InputTypeRepeat) { - furi_hal_bt_hid_mouse_move(-MOUSE_MOVE_LONG, 0); + hid_hal_mouse_move(hid_mouse->hid, -MOUSE_MOVE_LONG, 0); } else if(event->type == InputTypeRelease) { model->left_pressed = false; } } else if(event->key == InputKeyDown) { if(event->type == InputTypePress) { model->down_pressed = true; - furi_hal_bt_hid_mouse_move(0, MOUSE_MOVE_SHORT); + hid_hal_mouse_move(hid_mouse->hid, 0, MOUSE_MOVE_SHORT); } else if(event->type == InputTypeRepeat) { - furi_hal_bt_hid_mouse_move(0, MOUSE_MOVE_LONG); + hid_hal_mouse_move(hid_mouse->hid, 0, MOUSE_MOVE_LONG); } else if(event->type == InputTypeRelease) { model->down_pressed = false; } } else if(event->key == InputKeyUp) { if(event->type == InputTypePress) { model->up_pressed = true; - furi_hal_bt_hid_mouse_move(0, -MOUSE_MOVE_SHORT); + hid_hal_mouse_move(hid_mouse->hid, 0, -MOUSE_MOVE_SHORT); } else if(event->type == InputTypeRepeat) { - furi_hal_bt_hid_mouse_move(0, -MOUSE_MOVE_LONG); + hid_hal_mouse_move(hid_mouse->hid, 0, -MOUSE_MOVE_LONG); } else if(event->type == InputTypeRelease) { model->up_pressed = false; } @@ -175,45 +174,46 @@ static void bt_hid_mouse_process(BtHidMouse* bt_hid_mouse, InputEvent* event) { true); } -static bool bt_hid_mouse_input_callback(InputEvent* event, void* context) { +static bool hid_mouse_input_callback(InputEvent* event, void* context) { furi_assert(context); - BtHidMouse* bt_hid_mouse = context; + HidMouse* hid_mouse = context; bool consumed = false; if(event->type == InputTypeLong && event->key == InputKeyBack) { - furi_hal_bt_hid_mouse_release_all(); + hid_hal_mouse_release_all(hid_mouse->hid); } else { - bt_hid_mouse_process(bt_hid_mouse, event); + hid_mouse_process(hid_mouse, event); consumed = true; } return consumed; } -BtHidMouse* bt_hid_mouse_alloc() { - BtHidMouse* bt_hid_mouse = malloc(sizeof(BtHidMouse)); - bt_hid_mouse->view = view_alloc(); - view_set_context(bt_hid_mouse->view, bt_hid_mouse); - view_allocate_model(bt_hid_mouse->view, ViewModelTypeLocking, sizeof(BtHidMouseModel)); - view_set_draw_callback(bt_hid_mouse->view, bt_hid_mouse_draw_callback); - view_set_input_callback(bt_hid_mouse->view, bt_hid_mouse_input_callback); +HidMouse* hid_mouse_alloc(Hid* hid) { + HidMouse* hid_mouse = malloc(sizeof(HidMouse)); + hid_mouse->view = view_alloc(); + hid_mouse->hid = hid; + view_set_context(hid_mouse->view, hid_mouse); + view_allocate_model(hid_mouse->view, ViewModelTypeLocking, sizeof(HidMouseModel)); + view_set_draw_callback(hid_mouse->view, hid_mouse_draw_callback); + view_set_input_callback(hid_mouse->view, hid_mouse_input_callback); - return bt_hid_mouse; + return hid_mouse; } -void bt_hid_mouse_free(BtHidMouse* bt_hid_mouse) { - furi_assert(bt_hid_mouse); - view_free(bt_hid_mouse->view); - free(bt_hid_mouse); +void hid_mouse_free(HidMouse* hid_mouse) { + furi_assert(hid_mouse); + view_free(hid_mouse->view); + free(hid_mouse); } -View* bt_hid_mouse_get_view(BtHidMouse* bt_hid_mouse) { - furi_assert(bt_hid_mouse); - return bt_hid_mouse->view; +View* hid_mouse_get_view(HidMouse* hid_mouse) { + furi_assert(hid_mouse); + return hid_mouse->view; } -void bt_hid_mouse_set_connected_status(BtHidMouse* bt_hid_mouse, bool connected) { - furi_assert(bt_hid_mouse); +void hid_mouse_set_connected_status(HidMouse* hid_mouse, bool connected) { + furi_assert(hid_mouse); with_view_model( - bt_hid_mouse->view, BtHidMouseModel * model, { model->connected = connected; }, true); + hid_mouse->view, HidMouseModel * model, { model->connected = connected; }, true); } diff --git a/applications/plugins/hid_app/views/hid_mouse.h b/applications/plugins/hid_app/views/hid_mouse.h new file mode 100644 index 00000000..d9fb2fd8 --- /dev/null +++ b/applications/plugins/hid_app/views/hid_mouse.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +#define MOUSE_MOVE_SHORT 5 +#define MOUSE_MOVE_LONG 20 + +typedef struct Hid Hid; +typedef struct HidMouse HidMouse; + +HidMouse* hid_mouse_alloc(Hid* bt_hid); + +void hid_mouse_free(HidMouse* hid_mouse); + +View* hid_mouse_get_view(HidMouse* hid_mouse); + +void hid_mouse_set_connected_status(HidMouse* hid_mouse, bool connected); diff --git a/applications/plugins/bt_hid_app/views/bt_hid_tiktok.c b/applications/plugins/hid_app/views/hid_tiktok.c similarity index 59% rename from applications/plugins/bt_hid_app/views/bt_hid_tiktok.c rename to applications/plugins/hid_app/views/hid_tiktok.c index fe1005b2..42abf414 100644 --- a/applications/plugins/bt_hid_app/views/bt_hid_tiktok.c +++ b/applications/plugins/hid_app/views/hid_tiktok.c @@ -1,13 +1,14 @@ -#include "bt_hid_tiktok.h" -#include -#include -#include +#include "hid_tiktok.h" +#include "../hid.h" #include -#include "bt_hid_icons.h" +#include "hid_icons.h" -struct BtHidTikTok { +#define TAG "HidTikTok" + +struct HidTikTok { View* view; + Hid* hid; }; typedef struct { @@ -18,11 +19,11 @@ typedef struct { bool ok_pressed; bool connected; bool is_cursor_set; -} BtHidTikTokModel; +} HidTikTokModel; -static void bt_hid_tiktok_draw_callback(Canvas* canvas, void* context) { +static void hid_tiktok_draw_callback(Canvas* canvas, void* context) { furi_assert(context); - BtHidTikTokModel* model = context; + HidTikTokModel* model = context; // Header if(model->connected) { @@ -89,102 +90,104 @@ static void bt_hid_tiktok_draw_callback(Canvas* canvas, void* context) { elements_multiline_text_aligned(canvas, 13, 62, AlignLeft, AlignBottom, "Hold to exit"); } -static void bt_hid_tiktok_reset_cursor() { +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++) { - furi_hal_bt_hid_mouse_move(-127, -127); + hid_hal_mouse_move(hid_tiktok->hid, -127, -127); furi_delay_ms(50); } // Move cursor from the corner - furi_hal_bt_hid_mouse_move(20, 120); + hid_hal_mouse_move(hid_tiktok->hid, 20, 120); furi_delay_ms(50); } -static void bt_hid_tiktok_process_press(BtHidTikTokModel* model, InputEvent* event) { +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; - furi_hal_bt_hid_consumer_key_press(HID_CONSUMER_VOLUME_DECREMENT); + hid_hal_consumer_key_press(hid_tiktok->hid, HID_CONSUMER_VOLUME_DECREMENT); } else if(event->key == InputKeyRight) { model->right_pressed = true; - furi_hal_bt_hid_consumer_key_press(HID_CONSUMER_VOLUME_INCREMENT); + hid_hal_consumer_key_press(hid_tiktok->hid, HID_CONSUMER_VOLUME_INCREMENT); } else if(event->key == InputKeyOk) { model->ok_pressed = true; } } -static void bt_hid_tiktok_process_release(BtHidTikTokModel* model, InputEvent* event) { +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; - furi_hal_bt_hid_consumer_key_release(HID_CONSUMER_VOLUME_DECREMENT); + hid_hal_consumer_key_release(hid_tiktok->hid, HID_CONSUMER_VOLUME_DECREMENT); } else if(event->key == InputKeyRight) { model->right_pressed = false; - furi_hal_bt_hid_consumer_key_release(HID_CONSUMER_VOLUME_INCREMENT); + hid_hal_consumer_key_release(hid_tiktok->hid, HID_CONSUMER_VOLUME_INCREMENT); } else if(event->key == InputKeyOk) { model->ok_pressed = false; } } -static bool bt_hid_tiktok_input_callback(InputEvent* event, void* context) { +static bool hid_tiktok_input_callback(InputEvent* event, void* context) { furi_assert(context); - BtHidTikTok* bt_hid_tiktok = context; + HidTikTok* hid_tiktok = context; bool consumed = false; with_view_model( - bt_hid_tiktok->view, - BtHidTikTokModel * model, + hid_tiktok->view, + HidTikTokModel * model, { if(event->type == InputTypePress) { - bt_hid_tiktok_process_press(model, event); + hid_tiktok_process_press(hid_tiktok, model, event); if(model->connected && !model->is_cursor_set) { - bt_hid_tiktok_reset_cursor(); + hid_tiktok_reset_cursor(hid_tiktok); model->is_cursor_set = true; } consumed = true; } else if(event->type == InputTypeRelease) { - bt_hid_tiktok_process_release(model, event); + hid_tiktok_process_release(hid_tiktok, model, event); consumed = true; } else if(event->type == InputTypeShort) { if(event->key == InputKeyOk) { - furi_hal_bt_hid_mouse_press(HID_MOUSE_BTN_LEFT); + hid_hal_mouse_press(hid_tiktok->hid, HID_MOUSE_BTN_LEFT); furi_delay_ms(50); - furi_hal_bt_hid_mouse_release(HID_MOUSE_BTN_LEFT); + hid_hal_mouse_release(hid_tiktok->hid, HID_MOUSE_BTN_LEFT); furi_delay_ms(50); - furi_hal_bt_hid_mouse_press(HID_MOUSE_BTN_LEFT); + hid_hal_mouse_press(hid_tiktok->hid, HID_MOUSE_BTN_LEFT); furi_delay_ms(50); - furi_hal_bt_hid_mouse_release(HID_MOUSE_BTN_LEFT); + hid_hal_mouse_release(hid_tiktok->hid, HID_MOUSE_BTN_LEFT); consumed = true; } else if(event->key == InputKeyUp) { // Emulate up swipe - furi_hal_bt_hid_mouse_scroll(-6); - furi_hal_bt_hid_mouse_scroll(-12); - furi_hal_bt_hid_mouse_scroll(-19); - furi_hal_bt_hid_mouse_scroll(-12); - furi_hal_bt_hid_mouse_scroll(-6); + hid_hal_mouse_scroll(hid_tiktok->hid, -6); + hid_hal_mouse_scroll(hid_tiktok->hid, -12); + hid_hal_mouse_scroll(hid_tiktok->hid, -19); + hid_hal_mouse_scroll(hid_tiktok->hid, -12); + hid_hal_mouse_scroll(hid_tiktok->hid, -6); consumed = true; } else if(event->key == InputKeyDown) { // Emulate down swipe - furi_hal_bt_hid_mouse_scroll(6); - furi_hal_bt_hid_mouse_scroll(12); - furi_hal_bt_hid_mouse_scroll(19); - furi_hal_bt_hid_mouse_scroll(12); - furi_hal_bt_hid_mouse_scroll(6); + hid_hal_mouse_scroll(hid_tiktok->hid, 6); + hid_hal_mouse_scroll(hid_tiktok->hid, 12); + hid_hal_mouse_scroll(hid_tiktok->hid, 19); + hid_hal_mouse_scroll(hid_tiktok->hid, 12); + hid_hal_mouse_scroll(hid_tiktok->hid, 6); consumed = true; } else if(event->key == InputKeyBack) { - furi_hal_bt_hid_consumer_key_release_all(); + hid_hal_consumer_key_release_all(hid_tiktok->hid); consumed = true; } } else if(event->type == InputTypeLong) { if(event->key == InputKeyBack) { - furi_hal_bt_hid_consumer_key_release_all(); + hid_hal_consumer_key_release_all(hid_tiktok->hid); model->is_cursor_set = false; consumed = false; } @@ -195,33 +198,34 @@ static bool bt_hid_tiktok_input_callback(InputEvent* event, void* context) { return consumed; } -BtHidTikTok* bt_hid_tiktok_alloc() { - BtHidTikTok* bt_hid_tiktok = malloc(sizeof(BtHidTikTok)); - bt_hid_tiktok->view = view_alloc(); - view_set_context(bt_hid_tiktok->view, bt_hid_tiktok); - view_allocate_model(bt_hid_tiktok->view, ViewModelTypeLocking, sizeof(BtHidTikTokModel)); - view_set_draw_callback(bt_hid_tiktok->view, bt_hid_tiktok_draw_callback); - view_set_input_callback(bt_hid_tiktok->view, bt_hid_tiktok_input_callback); +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); - return bt_hid_tiktok; + return hid_tiktok; } -void bt_hid_tiktok_free(BtHidTikTok* bt_hid_tiktok) { - furi_assert(bt_hid_tiktok); - view_free(bt_hid_tiktok->view); - free(bt_hid_tiktok); +void hid_tiktok_free(HidTikTok* hid_tiktok) { + furi_assert(hid_tiktok); + view_free(hid_tiktok->view); + free(hid_tiktok); } -View* bt_hid_tiktok_get_view(BtHidTikTok* bt_hid_tiktok) { - furi_assert(bt_hid_tiktok); - return bt_hid_tiktok->view; +View* hid_tiktok_get_view(HidTikTok* hid_tiktok) { + furi_assert(hid_tiktok); + return hid_tiktok->view; } -void bt_hid_tiktok_set_connected_status(BtHidTikTok* bt_hid_tiktok, bool connected) { - furi_assert(bt_hid_tiktok); +void hid_tiktok_set_connected_status(HidTikTok* hid_tiktok, bool connected) { + furi_assert(hid_tiktok); with_view_model( - bt_hid_tiktok->view, - BtHidTikTokModel * model, + hid_tiktok->view, + HidTikTokModel * model, { model->connected = connected; model->is_cursor_set = false; diff --git a/applications/plugins/hid_app/views/hid_tiktok.h b/applications/plugins/hid_app/views/hid_tiktok.h new file mode 100644 index 00000000..b2efc369 --- /dev/null +++ b/applications/plugins/hid_app/views/hid_tiktok.h @@ -0,0 +1,14 @@ +#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/scripts/fbt/appmanifest.py b/scripts/fbt/appmanifest.py index 908a64a6..a7460d88 100644 --- a/scripts/fbt/appmanifest.py +++ b/scripts/fbt/appmanifest.py @@ -64,6 +64,7 @@ class FlipperApplication: fap_author: str = "" fap_weburl: str = "" fap_icon_assets: Optional[str] = None + fap_icon_assets_symbol: Optional[str] = None fap_extbuild: List[ExternallyBuiltFile] = field(default_factory=list) fap_private_libs: List[Library] = field(default_factory=list) # Internally used by fbt diff --git a/scripts/fbt_tools/fbt_extapps.py b/scripts/fbt_tools/fbt_extapps.py index a4116e51..f0015cf2 100644 --- a/scripts/fbt_tools/fbt_extapps.py +++ b/scripts/fbt_tools/fbt_extapps.py @@ -60,7 +60,7 @@ def BuildAppElf(env, app): fap_icons = app_env.CompileIcons( app_env.Dir(app_work_dir), app._appdir.Dir(app.fap_icon_assets), - icon_bundle_name=f"{app.appid}_icons", + icon_bundle_name=f"{app.fap_icon_assets_symbol if app.fap_icon_assets_symbol else app.appid }_icons", ) app_env.Alias("_fap_icons", fap_icons) From e121e6a2877857ec19a027ed361579eaaf2911bd Mon Sep 17 00:00:00 2001 From: Maksim Derbasov Date: Tue, 29 Nov 2022 01:51:51 +0900 Subject: [PATCH 12/25] Fix for spelling (#2051) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix for spelling * Review iteration Co-authored-by: あく --- CONTRIBUTING.md | 6 +++--- applications/debug/accessor/helpers/wiegand.cpp | 2 +- applications/debug/bt_debug_app/bt_debug_app.c | 2 +- applications/debug/display_test/display_test.c | 2 +- applications/debug/unit_tests/furi/furi_memmgr_test.c | 4 ++-- applications/debug/unit_tests/nfc/nfc_test.c | 2 +- applications/debug/unit_tests/stream/stream_test.c | 6 +++--- applications/main/archive/helpers/archive_browser.h | 2 +- applications/main/fap_loader/elf_cpp/elf_hashtable.cpp | 2 +- .../helpers/subghz_frequency_analyzer_log_item_array.h | 2 +- applications/services/applications.h | 2 +- .../services/desktop/animations/animation_manager.h | 6 +++--- applications/services/gui/elements.h | 2 +- applications/services/gui/modules/dialog_ex.h | 8 ++++---- applications/services/gui/modules/popup.h | 4 ++-- applications/services/gui/modules/text_box.c | 2 +- applications/services/gui/modules/text_input.h | 2 +- applications/services/gui/view_dispatcher.c | 2 +- applications/services/input/input.h | 4 ++-- applications/services/power/power_service/power.h | 2 +- applications/services/rpc/rpc.h | 2 +- applications/services/rpc/rpc_storage.c | 2 +- applications/services/storage/filesystem_api_defines.h | 4 ++-- applications/services/storage/filesystem_api_internal.h | 2 +- applications/services/storage/storage.h | 6 +++--- applications/settings/storage_settings/storage_settings.h | 2 +- .../system/storage_move_to_sd/storage_move_to_sd.h | 2 +- documentation/fbt.md | 2 +- fbt_options.py | 2 +- furi/core/log.c | 8 ++++---- furi/core/memmgr.h | 2 +- furi/core/memmgr_heap.h | 2 +- furi/core/thread.h | 4 ++-- furi/core/valuemutex.c | 2 +- furi/core/valuemutex.h | 4 ++-- furi/furi.c | 6 +++--- 36 files changed, 58 insertions(+), 58 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 00a0191e..dc1d41e2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,7 +2,7 @@ Thank you for investing your time in contributing to our project! -Read our [Code of Coduct](CODE_OF_CONDUCT.md) to keep our community approachable and respectable. +Read our [Code of Conduct](CODE_OF_CONDUCT.md) to keep our community approachable and respectable. In this guide you will get an overview of the contribution workflow from opening an issue, creating a PR, reviewing, and merging the PR. @@ -17,12 +17,12 @@ See the [ReadMe](ReadMe.md) to get an overview of the project. Here are some hel ## Getting started -Before writing code and creating PR make sure that it aligns with our mission and guidlines: +Before writing code and creating PR make sure that it aligns with our mission and guidelines: - All our devices are intended for research and education. - PR that contains code intended to commit crimes is not going to be accepted. - Your PR must comply with our [Coding Style](CODING_STYLE.md) -- Your PR must contain code compatiable with project [LICENSE](LICENSE). +- Your PR must contain code compatible with project [LICENSE](LICENSE). - PR will only be merged if it pass CI/CD. - PR will only be merged if it pass review by code owner. diff --git a/applications/debug/accessor/helpers/wiegand.cpp b/applications/debug/accessor/helpers/wiegand.cpp index 79c9f723..bb288554 100644 --- a/applications/debug/accessor/helpers/wiegand.cpp +++ b/applications/debug/accessor/helpers/wiegand.cpp @@ -71,7 +71,7 @@ void WIEGAND::end() { } void WIEGAND::ReadD0() { - _bitCount++; // Increament bit count for Interrupt connected to D0 + _bitCount++; // Increment bit count for Interrupt connected to D0 if(_bitCount > 31) // If bit count more than 31, process high bits { _cardTempHigh |= ((0x80000000 & _cardTemp) >> 31); // shift value to high bits diff --git a/applications/debug/bt_debug_app/bt_debug_app.c b/applications/debug/bt_debug_app/bt_debug_app.c index ac442de0..405051a4 100644 --- a/applications/debug/bt_debug_app/bt_debug_app.c +++ b/applications/debug/bt_debug_app/bt_debug_app.c @@ -98,7 +98,7 @@ void bt_debug_app_free(BtDebugApp* app) { int32_t bt_debug_app(void* p) { UNUSED(p); if(!furi_hal_bt_is_testing_supported()) { - FURI_LOG_E(TAG, "Incorrect radio stack: radio testing fetures are absent."); + FURI_LOG_E(TAG, "Incorrect radio stack: radio testing features are absent."); DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS); dialog_message_show_storage_error(dialogs, "Incorrect\nRadioStack"); return 255; diff --git a/applications/debug/display_test/display_test.c b/applications/debug/display_test/display_test.c index e7f366cb..5b46d2b4 100644 --- a/applications/debug/display_test/display_test.c +++ b/applications/debug/display_test/display_test.c @@ -145,7 +145,7 @@ DisplayTest* display_test_alloc() { view_set_previous_callback(view, display_test_previous_callback); view_dispatcher_add_view(instance->view_dispatcher, DisplayTestViewConfigure, view); - // Configurtion items + // Configuration items VariableItem* item; instance->config_bias = false; instance->config_contrast = 32; diff --git a/applications/debug/unit_tests/furi/furi_memmgr_test.c b/applications/debug/unit_tests/furi/furi_memmgr_test.c index b0fd060c..cf384874 100644 --- a/applications/debug/unit_tests/furi/furi_memmgr_test.c +++ b/applications/debug/unit_tests/furi/furi_memmgr_test.c @@ -11,7 +11,7 @@ extern size_t memmgr_get_free_heap(void); extern size_t memmgr_get_minimum_free_heap(void); -// current heap managment realization consume: +// current heap management realization consume: // X bytes after allocate and 0 bytes after allocate and free, // where X = sizeof(void*) + sizeof(size_t), look to BlockLink_t const size_t heap_overhead_max_size = sizeof(void*) + sizeof(size_t); @@ -21,7 +21,7 @@ bool heap_equal(size_t heap_size, size_t heap_size_old) { const size_t heap_low = heap_size_old - heap_overhead_max_size; const size_t heap_high = heap_size_old + heap_overhead_max_size; - // not extact, so we must test it against bigger numbers than "overhead size" + // not exact, so we must test it against bigger numbers than "overhead size" const bool result = ((heap_size >= heap_low) && (heap_size <= heap_high)); // debug allocation info diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index 454c11c0..07ec73a0 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -136,7 +136,7 @@ static bool nfc_test_digital_signal_test_encode( ref_timings_sum += ref[i]; if(timings_diff > timing_tolerance) { FURI_LOG_E( - TAG, "Too big differece in %d timings. Ref: %ld, DUT: %ld", i, ref[i], dut[i]); + TAG, "Too big difference in %d timings. Ref: %ld, DUT: %ld", i, ref[i], dut[i]); timing_check_success = false; break; } diff --git a/applications/debug/unit_tests/stream/stream_test.c b/applications/debug/unit_tests/stream/stream_test.c index c04e119c..802e3402 100644 --- a/applications/debug/unit_tests/stream/stream_test.c +++ b/applications/debug/unit_tests/stream/stream_test.c @@ -219,21 +219,21 @@ MU_TEST_1(stream_composite_subtest, Stream* stream) { mu_check(stream_eof(stream)); mu_assert_int_eq(0, stream_tell(stream)); - // insert formated string at the end of stream + // insert formatted string at the end of stream // "" -> "dio666" mu_check(stream_insert_format(stream, "%s%d", "dio", 666)); mu_assert_int_eq(6, stream_size(stream)); mu_check(stream_eof(stream)); mu_assert_int_eq(6, stream_tell(stream)); - // insert formated string at the end of stream + // insert formatted string at the end of stream // "dio666" -> "dio666zlo555" mu_check(stream_insert_format(stream, "%s%d", "zlo", 555)); mu_assert_int_eq(12, stream_size(stream)); mu_check(stream_eof(stream)); mu_assert_int_eq(12, stream_tell(stream)); - // insert formated string at the 6 pos + // insert formatted string at the 6 pos // "dio666" -> "dio666baba13zlo555" mu_check(stream_seek(stream, 6, StreamOffsetFromStart)); mu_check(stream_insert_format(stream, "%s%d", "baba", 13)); diff --git a/applications/main/archive/helpers/archive_browser.h b/applications/main/archive/helpers/archive_browser.h index 519a34a2..1a7e01f5 100644 --- a/applications/main/archive/helpers/archive_browser.h +++ b/applications/main/archive/helpers/archive_browser.h @@ -3,7 +3,7 @@ #include "../archive_i.h" #include -#define TAB_RIGHT InputKeyRight // Default tab swith direction +#define TAB_RIGHT InputKeyRight // Default tab switch direction #define TAB_DEFAULT ArchiveTabFavorites // Start tab #define FILE_LIST_BUF_LEN 100 diff --git a/applications/main/fap_loader/elf_cpp/elf_hashtable.cpp b/applications/main/fap_loader/elf_cpp/elf_hashtable.cpp index f8adbf9d..e845ed00 100644 --- a/applications/main/fap_loader/elf_cpp/elf_hashtable.cpp +++ b/applications/main/fap_loader/elf_cpp/elf_hashtable.cpp @@ -31,7 +31,7 @@ bool elf_resolve_from_hashtable(const char* name, Elf32_Addr* address) { auto find_res = std::lower_bound(elf_api_table.cbegin(), elf_api_table.cend(), key); if((find_res == elf_api_table.cend() || (find_res->hash != gnu_sym_hash))) { - FURI_LOG_W(TAG, "Cant find symbol '%s' (hash %lx)!", name, gnu_sym_hash); + FURI_LOG_W(TAG, "Can't find symbol '%s' (hash %lx)!", name, gnu_sym_hash); result = false; } else { result = true; diff --git a/applications/main/subghz/helpers/subghz_frequency_analyzer_log_item_array.h b/applications/main/subghz/helpers/subghz_frequency_analyzer_log_item_array.h index eaf53b66..b94ebe38 100644 --- a/applications/main/subghz/helpers/subghz_frequency_analyzer_log_item_array.h +++ b/applications/main/subghz/helpers/subghz_frequency_analyzer_log_item_array.h @@ -25,7 +25,7 @@ TUPLE_DEF2( (frequency, uint32_t), (count, uint8_t), (rssi_max, uint8_t)) -/* Register globaly the oplist */ +/* Register globally the oplist */ #define M_OPL_SubGhzFrequencyAnalyzerLogItem_t() \ TUPLE_OPLIST(SubGhzFrequencyAnalyzerLogItem, M_POD_OPLIST, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST) diff --git a/applications/services/applications.h b/applications/services/applications.h index 012e80dd..acbfea31 100644 --- a/applications/services/applications.h +++ b/applications/services/applications.h @@ -56,7 +56,7 @@ extern const size_t FLIPPER_DEBUG_APPS_COUNT; extern const FlipperApplication FLIPPER_SYSTEM_APPS[]; extern const size_t FLIPPER_SYSTEM_APPS_COUNT; -/* Seperate scene app holder +/* Separate scene app holder * Spawned by loader */ extern const FlipperApplication FLIPPER_SCENE; diff --git a/applications/services/desktop/animations/animation_manager.h b/applications/services/desktop/animations/animation_manager.h index 9802c4f1..234d20de 100644 --- a/applications/services/desktop/animations/animation_manager.h +++ b/applications/services/desktop/animations/animation_manager.h @@ -69,7 +69,7 @@ View* animation_manager_get_animation_view(AnimationManager* animation_manager); void animation_manager_set_context(AnimationManager* animation_manager, void* context); /** - * Set callback for Animation Manager for defered calls + * Set callback for Animation Manager for deferred calls * for animation_manager_new_idle_process(). * Animation Manager doesn't have it's own thread, so main thread gives * callbacks to A.M. to call when it should perform some inner manipulations. @@ -96,7 +96,7 @@ void animation_manager_set_new_idle_callback( void animation_manager_new_idle_process(AnimationManager* animation_manager); /** - * Set callback for Animation Manager for defered calls + * Set callback for Animation Manager for deferred calls * for animation_manager_check_blocking_process(). * * @animation_manager instance @@ -115,7 +115,7 @@ void animation_manager_set_check_callback( void animation_manager_check_blocking_process(AnimationManager* animation_manager); /** - * Set callback for Animation Manager for defered calls + * Set callback for Animation Manager for deferred calls * for animation_manager_interact_process(). * * @animation_manager instance diff --git a/applications/services/gui/elements.h b/applications/services/gui/elements.h index b2d204de..9f155402 100644 --- a/applications/services/gui/elements.h +++ b/applications/services/gui/elements.h @@ -90,7 +90,7 @@ void elements_button_center(Canvas* canvas, const char* str); * * @param canvas Canvas instance * @param x, y coordinates based on align param - * @param horizontal, vertical aligment of multiline text + * @param horizontal, vertical alignment of multiline text * @param text string (possible multiline) */ void elements_multiline_text_aligned( diff --git a/applications/services/gui/modules/dialog_ex.h b/applications/services/gui/modules/dialog_ex.h index 4c609423..26a46535 100644 --- a/applications/services/gui/modules/dialog_ex.h +++ b/applications/services/gui/modules/dialog_ex.h @@ -76,8 +76,8 @@ void dialog_ex_set_context(DialogEx* dialog_ex, void* context); * @param text text to be shown, can be multiline * @param x x position * @param y y position - * @param horizontal horizontal text aligment - * @param vertical vertical text aligment + * @param horizontal horizontal text alignment + * @param vertical vertical text alignment */ void dialog_ex_set_header( DialogEx* dialog_ex, @@ -95,8 +95,8 @@ void dialog_ex_set_header( * @param text text to be shown, can be multiline * @param x x position * @param y y position - * @param horizontal horizontal text aligment - * @param vertical vertical text aligment + * @param horizontal horizontal text alignment + * @param vertical vertical text alignment */ void dialog_ex_set_text( DialogEx* dialog_ex, diff --git a/applications/services/gui/modules/popup.h b/applications/services/gui/modules/popup.h index 94f49a2b..13371a05 100644 --- a/applications/services/gui/modules/popup.h +++ b/applications/services/gui/modules/popup.h @@ -64,7 +64,7 @@ void popup_set_context(Popup* popup, void* context); * @param x x position * @param y y position * @param horizontal horizontal alignment - * @param vertical vertical aligment + * @param vertical vertical alignment */ void popup_set_header( Popup* popup, @@ -83,7 +83,7 @@ void popup_set_header( * @param x x position * @param y y position * @param horizontal horizontal alignment - * @param vertical vertical aligment + * @param vertical vertical alignment */ void popup_set_text( Popup* popup, diff --git a/applications/services/gui/modules/text_box.c b/applications/services/gui/modules/text_box.c index 99d7d04f..079a1294 100644 --- a/applications/services/gui/modules/text_box.c +++ b/applications/services/gui/modules/text_box.c @@ -43,7 +43,7 @@ static void text_box_process_up(TextBox* text_box) { model->scroll_pos--; // Reach last symbol of previous line model->text_pos--; - // Search prevous line start + // Search previous line start while((model->text_pos != model->text) && (*(--model->text_pos) != '\n')) ; if(*model->text_pos == '\n') { diff --git a/applications/services/gui/modules/text_input.h b/applications/services/gui/modules/text_input.h index 893fbd53..218df314 100644 --- a/applications/services/gui/modules/text_input.h +++ b/applications/services/gui/modules/text_input.h @@ -1,6 +1,6 @@ /** * @file text_input.h - * GUI: TextInput keybord view module API + * GUI: TextInput keyboard view module API */ #pragma once diff --git a/applications/services/gui/view_dispatcher.c b/applications/services/gui/view_dispatcher.c index 4034cc0b..04695874 100644 --- a/applications/services/gui/view_dispatcher.c +++ b/applications/services/gui/view_dispatcher.c @@ -152,7 +152,7 @@ void view_dispatcher_remove_view(ViewDispatcher* view_dispatcher, uint32_t view_ if(view_dispatcher->current_view == view) { view_dispatcher_set_current_view(view_dispatcher, NULL); } - // Check if view is recieving input + // Check if view is receiving input if(view_dispatcher->ongoing_input_view == view) { view_dispatcher->ongoing_input_view = NULL; } diff --git a/applications/services/input/input.h b/applications/services/input/input.h index 172b1636..ec3d0971 100644 --- a/applications/services/input/input.h +++ b/applications/services/input/input.h @@ -20,8 +20,8 @@ typedef enum { InputTypePress, /**< Press event, emitted after debounce */ InputTypeRelease, /**< Release event, emitted after debounce */ InputTypeShort, /**< Short event, emitted after InputTypeRelease done withing INPUT_LONG_PRESS interval */ - InputTypeLong, /**< Long event, emmited after INPUT_LONG_PRESS interval, asynchronouse to InputTypeRelease */ - InputTypeRepeat, /**< Repeat event, emmited with INPUT_REPEATE_PRESS period after InputTypeLong event */ + InputTypeLong, /**< Long event, emitted after INPUT_LONG_PRESS_COUNTS interval, asynchronous to InputTypeRelease */ + InputTypeRepeat, /**< Repeat event, emitted with INPUT_LONG_PRESS_COUNTS period after InputTypeLong event */ InputTypeMAX, /**< Special value for exceptional */ } InputType; diff --git a/applications/services/power/power_service/power.h b/applications/services/power/power_service/power.h index bdf5fa52..32433ebc 100644 --- a/applications/services/power/power_service/power.h +++ b/applications/services/power/power_service/power.h @@ -86,7 +86,7 @@ FuriPubSub* power_get_pubsub(Power* power); */ bool power_is_battery_healthy(Power* power); -/** Enable or disable battery low level notification mesage +/** Enable or disable battery low level notification message * * @param power Power instance * @param enable true - enable, false - disable diff --git a/applications/services/rpc/rpc.h b/applications/services/rpc/rpc.h index 40493949..21836d9a 100644 --- a/applications/services/rpc/rpc.h +++ b/applications/services/rpc/rpc.h @@ -25,7 +25,7 @@ typedef void (*RpcSendBytesCallback)(void* context, uint8_t* bytes, size_t bytes typedef void (*RpcBufferIsEmptyCallback)(void* context); /** Callback to notify transport layer that close_session command * is received. Any other actions lays on transport layer. - * No destruction or session close preformed. */ + * No destruction or session close performed. */ typedef void (*RpcSessionClosedCallback)(void* context); /** Callback to notify transport layer that session was closed * and all operations were finished */ diff --git a/applications/services/rpc/rpc_storage.c b/applications/services/rpc/rpc_storage.c index 16e343fc..3c6ff7f9 100644 --- a/applications/services/rpc/rpc_storage.c +++ b/applications/services/rpc/rpc_storage.c @@ -330,7 +330,7 @@ static void rpc_system_storage_read_process(const PB_Main* request, void* contex rpc_system_storage_reset_state(rpc_storage, session, true); - /* use same message memory to send reponse */ + /* use same message memory to send response */ PB_Main* response = malloc(sizeof(PB_Main)); const char* path = request->content.storage_read_request.path; Storage* fs_api = furi_record_open(RECORD_STORAGE); diff --git a/applications/services/storage/filesystem_api_defines.h b/applications/services/storage/filesystem_api_defines.h index b6f1d8f1..b73e6eb3 100644 --- a/applications/services/storage/filesystem_api_defines.h +++ b/applications/services/storage/filesystem_api_defines.h @@ -25,13 +25,13 @@ typedef enum { typedef enum { FSE_OK, /**< No error */ FSE_NOT_READY, /**< FS not ready */ - FSE_EXIST, /**< File/Dir alrady exist */ + FSE_EXIST, /**< File/Dir already exist */ FSE_NOT_EXIST, /**< File/Dir does not exist */ FSE_INVALID_PARAMETER, /**< Invalid API parameter */ FSE_DENIED, /**< Access denied */ FSE_INVALID_NAME, /**< Invalid name/path */ FSE_INTERNAL, /**< Internal error */ - FSE_NOT_IMPLEMENTED, /**< Functon not implemented */ + FSE_NOT_IMPLEMENTED, /**< Function not implemented */ FSE_ALREADY_OPEN, /**< File/Dir already opened */ } FS_Error; diff --git a/applications/services/storage/filesystem_api_internal.h b/applications/services/storage/filesystem_api_internal.h index bd4bcf82..967d3bb4 100644 --- a/applications/services/storage/filesystem_api_internal.h +++ b/applications/services/storage/filesystem_api_internal.h @@ -17,7 +17,7 @@ typedef enum { struct File { uint32_t file_id; /**< File ID for internal references */ FileType type; - FS_Error error_id; /**< Standart API error from FS_Error enum */ + FS_Error error_id; /**< Standard API error from FS_Error enum */ int32_t internal_error_id; /**< Internal API error value */ void* storage; }; diff --git a/applications/services/storage/storage.h b/applications/services/storage/storage.h index 9c133e9b..e093cbe0 100644 --- a/applications/services/storage/storage.h +++ b/applications/services/storage/storage.h @@ -255,19 +255,19 @@ FS_Error storage_common_fs_info( const char* storage_error_get_desc(FS_Error error_id); /** Retrieves the error id from the file object - * @param file pointer to file object. Pointer must not point to NULL. YOU CANNOT RETREIVE THE ERROR ID IF THE FILE HAS BEEN CLOSED + * @param file pointer to file object. Pointer must not point to NULL. YOU CANNOT RETRIEVE THE ERROR ID IF THE FILE HAS BEEN CLOSED * @return FS_Error error id */ FS_Error storage_file_get_error(File* file); /** Retrieves the internal (storage-specific) error id from the file object - * @param file pointer to file object. Pointer must not point to NULL. YOU CANNOT RETREIVE THE INTERNAL ERROR ID IF THE FILE HAS BEEN CLOSED + * @param file pointer to file object. Pointer must not point to NULL. YOU CANNOT RETRIEVE THE INTERNAL ERROR ID IF THE FILE HAS BEEN CLOSED * @return FS_Error error id */ int32_t storage_file_get_internal_error(File* file); /** Retrieves the error text from the file object - * @param file pointer to file object. Pointer must not point to NULL. YOU CANNOT RETREIVE THE ERROR TEXT IF THE FILE HAS BEEN CLOSED + * @param file pointer to file object. Pointer must not point to NULL. YOU CANNOT RETRIEVE THE ERROR TEXT IF THE FILE HAS BEEN CLOSED * @return const char* error text */ const char* storage_file_get_error_desc(File* file); diff --git a/applications/settings/storage_settings/storage_settings.h b/applications/settings/storage_settings/storage_settings.h index 664e74c8..fd841623 100644 --- a/applications/settings/storage_settings/storage_settings.h +++ b/applications/settings/storage_settings/storage_settings.h @@ -26,7 +26,7 @@ typedef struct { NotificationApp* notification; Storage* fs_api; - // view managment + // view management SceneManager* scene_manager; ViewDispatcher* view_dispatcher; diff --git a/applications/system/storage_move_to_sd/storage_move_to_sd.h b/applications/system/storage_move_to_sd/storage_move_to_sd.h index dc1d669b..a62d87c1 100644 --- a/applications/system/storage_move_to_sd/storage_move_to_sd.h +++ b/applications/system/storage_move_to_sd/storage_move_to_sd.h @@ -30,7 +30,7 @@ typedef struct { Widget* widget; NotificationApp* notifications; - // view managment + // view management SceneManager* scene_manager; ViewDispatcher* view_dispatcher; diff --git a/documentation/fbt.md b/documentation/fbt.md index 2bf9ea28..4726268d 100644 --- a/documentation/fbt.md +++ b/documentation/fbt.md @@ -44,7 +44,7 @@ To run cleanup (think of `make clean`) for specified targets, add `-c` option. - `fw_dist` - build & publish firmware to `dist` folder. This is a default target, when no other are specified - `fap_dist` - build external plugins & publish to `dist` folder -- `updater_package`, `updater_minpackage` - build self-update package. Minimal version only inclues firmware's DFU file; full version also includes radio stack & resources for SD card +- `updater_package`, `updater_minpackage` - build self-update package. Minimal version only includes firmware's DFU file; full version also includes radio stack & resources for SD card - `copro_dist` - bundle Core2 FUS+stack binaries for qFlipper - `flash` - flash attached device with OpenOCD over ST-Link - `flash_usb`, `flash_usb_full` - build, upload and install update package to device over USB. See details on `updater_package`, `updater_minpackage` diff --git a/fbt_options.py b/fbt_options.py index a00f7c1b..7a805c99 100644 --- a/fbt_options.py +++ b/fbt_options.py @@ -32,7 +32,7 @@ COPRO_STACK_TYPE = "ble_light" # Leave 0 to let scripts automatically calculate it COPRO_STACK_ADDR = "0x0" -# If you override COPRO_CUBE_DIR on commandline, override this aswell +# If you override COPRO_CUBE_DIR on commandline, override this as well COPRO_STACK_BIN_DIR = posixpath.join( COPRO_CUBE_DIR, "Projects", diff --git a/furi/core/log.c b/furi/core/log.c index bb163c95..a3967ed9 100644 --- a/furi/core/log.c +++ b/furi/core/log.c @@ -8,7 +8,7 @@ typedef struct { FuriLogLevel log_level; FuriLogPuts puts; - FuriLogTimestamp timetamp; + FuriLogTimestamp timestamp; FuriMutex* mutex; } FuriLogParams; @@ -18,7 +18,7 @@ void furi_log_init() { // Set default logging parameters furi_log.log_level = FURI_LOG_LEVEL_DEFAULT; furi_log.puts = furi_hal_console_puts; - furi_log.timetamp = furi_get_tick; + furi_log.timestamp = furi_get_tick; furi_log.mutex = furi_mutex_alloc(FuriMutexTypeNormal); } @@ -59,7 +59,7 @@ void furi_log_print_format(FuriLogLevel level, const char* tag, const char* form furi_string_printf( string, "%lu %s[%s][%s] " FURI_LOG_CLR_RESET, - furi_log.timetamp(), + furi_log.timestamp(), color, log_letter, tag); @@ -98,5 +98,5 @@ void furi_log_set_puts(FuriLogPuts puts) { void furi_log_set_timestamp(FuriLogTimestamp timestamp) { furi_assert(timestamp); - furi_log.timetamp = timestamp; + furi_log.timestamp = timestamp; } diff --git a/furi/core/memmgr.h b/furi/core/memmgr.h index d3ad0c87..bc0c35fa 100644 --- a/furi/core/memmgr.h +++ b/furi/core/memmgr.h @@ -1,6 +1,6 @@ /** * @file memmgr.h - * Furi: memory managment API and glue + * Furi: memory management API and glue */ #pragma once diff --git a/furi/core/memmgr_heap.h b/furi/core/memmgr_heap.h index 1521fce4..9aacba1c 100644 --- a/furi/core/memmgr_heap.h +++ b/furi/core/memmgr_heap.h @@ -1,6 +1,6 @@ /** * @file memmgr_heap.h - * Furi: heap memory managment API and allocator + * Furi: heap memory management API and allocator */ #pragma once diff --git a/furi/core/thread.h b/furi/core/thread.h index 6ec8ebfe..c2f5a913 100644 --- a/furi/core/thread.h +++ b/furi/core/thread.h @@ -48,7 +48,7 @@ typedef int32_t (*FuriThreadCallback)(void* context); */ typedef void (*FuriThreadStdoutWriteCallback)(const char* data, size_t size); -/** FuriThread state change calback called upon thread state change +/** FuriThread state change callback called upon thread state change * @param state new thread state * @param context callback context */ @@ -194,7 +194,7 @@ size_t furi_thread_get_heap_size(FuriThread* thread); */ int32_t furi_thread_get_return_code(FuriThread* thread); -/** Thread releated methods that doesn't involve FuriThread directly */ +/** Thread related methods that doesn't involve FuriThread directly */ /** Get FreeRTOS FuriThreadId for current thread * diff --git a/furi/core/valuemutex.c b/furi/core/valuemutex.c index af2a0755..bf4e6130 100644 --- a/furi/core/valuemutex.c +++ b/furi/core/valuemutex.c @@ -4,7 +4,7 @@ bool init_mutex(ValueMutex* valuemutex, void* value, size_t size) { // mutex without name, - // no attributes (unfortunatly robust mutex is not supported by FreeRTOS), + // no attributes (unfortunately robust mutex is not supported by FreeRTOS), // with dynamic memory allocation valuemutex->mutex = furi_mutex_alloc(FuriMutexTypeNormal); if(valuemutex->mutex == NULL) return false; diff --git a/furi/core/valuemutex.h b/furi/core/valuemutex.h index 41762fdd..0d867a1d 100644 --- a/furi/core/valuemutex.h +++ b/furi/core/valuemutex.h @@ -39,7 +39,7 @@ bool delete_mutex(ValueMutex* valuemutex); void* acquire_mutex(ValueMutex* valuemutex, uint32_t timeout); /** - * Helper: infinitly wait for mutex + * Helper: infinitely wait for mutex */ static inline void* acquire_mutex_block(ValueMutex* valuemutex) { return acquire_mutex(valuemutex, FuriWaitForever); @@ -135,7 +135,7 @@ void consumer_app(void* _p) { flapp_exit(NULL); } - // continously read value every 1s + // continuously read value every 1s uint32_t counter; while(1) { if(read_mutex(counter_mutex, &counter, sizeof(counter), OsWaitForever)) { diff --git a/furi/furi.c b/furi/furi.c index 76aed024..a616bce6 100644 --- a/furi/furi.c +++ b/furi/furi.c @@ -15,9 +15,9 @@ void furi_run() { furi_assert(xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED); #if(__ARM_ARCH_7A__ == 0U) - /* Service Call interrupt might be configured before kernel start */ - /* and when its priority is lower or equal to BASEPRI, svc intruction */ - /* causes a Hard Fault. */ + /* Service Call interrupt might be configured before kernel start */ + /* and when its priority is lower or equal to BASEPRI, svc instruction */ + /* causes a Hard Fault. */ NVIC_SetPriority(SVCall_IRQn, 0U); #endif From a82c3ccc2258271deb2cd9f7a0c2b44eded3035c Mon Sep 17 00:00:00 2001 From: Stephen Kent Date: Mon, 28 Nov 2022 09:05:24 -0800 Subject: [PATCH 13/25] NFC: Fix MIFARE DESfire info action to open app menu (#2058) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When examining a MIFARE DESfire card, selecting "More >" currently leads to the file menu for a single application even if the scanned card contains multiple applications. On examining the source code, a MIFARE DESfire application selection menu is present as `NfcSceneMfDesfireData`. This change updates the MIFARE DESfire Info "More >" action to open the application selection menu. That menu may then be used to open the file selection menu for any application in the read MIFARE DESfire card data. Tested interactively with https://github.com/flipperdevices/flipperzero-sd-card-examples/blob/c4cbdcd94706836fe0e3cda42587814237b1cfde/nfc/Desfire.nfc Co-authored-by: あく --- applications/main/nfc/scenes/nfc_scene_nfc_data_info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 8f33972e..bd6f5e2e 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c +++ b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c @@ -115,7 +115,7 @@ bool nfc_scene_nfc_data_info_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == GuiButtonTypeRight) { if(protocol == NfcDeviceProtocolMifareDesfire) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireApp); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireData); consumed = true; } else if(protocol == NfcDeviceProtocolMifareUl) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightData); From 1b3156521cb0aaef696b58673f932b2b88747865 Mon Sep 17 00:00:00 2001 From: Michael Huebler Date: Mon, 28 Nov 2022 18:14:13 +0100 Subject: [PATCH 14/25] NFC: Accept non-parsed apps in Mifare DESFire. (#2041) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * NFC: Accept non-parsed apps in Mifare DESFire. Fixes #2040 Co-authored-by: gornekich Co-authored-by: あく --- lib/nfc/nfc_device.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/nfc/nfc_device.c b/lib/nfc/nfc_device.c index 9f17aed3..5d86da0c 100644 --- a/lib/nfc/nfc_device.c +++ b/lib/nfc/nfc_device.c @@ -7,6 +7,7 @@ #include #include +#define TAG "NfcDevice" #define NFC_DEVICE_KEYS_FOLDER EXT_PATH("nfc/cache") #define NFC_DEVICE_KEYS_EXTENSION ".keys" @@ -627,7 +628,10 @@ bool nfc_device_load_mifare_df_data(FlipperFormat* file, NfcDevice* dev) { *app_head = app; app_head = &app->next; } - if(!parsed_apps) break; + if(!parsed_apps) { + // accept non-parsed apps, just log a warning: + FURI_LOG_W(TAG, "Non-parsed apps found!"); + } } parsed = true; } while(false); From 6b47bc1af42f2925606f5e201cb8db65eef29f25 Mon Sep 17 00:00:00 2001 From: Yukai Li Date: Mon, 28 Nov 2022 11:16:22 -0700 Subject: [PATCH 15/25] Nfc: NTAG password auto capture (and other password-related changes) (#1843) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * nfc: MFUL minor cleanup * nfc: Add mechanism to pass event data * nfc: Add NTAG authentication event to emulation * nfc: Rename enum member to align with existing convention * nfc: Add function to determine whether MFUL is fully captured * nfc: Fix emulation of incompletely-read password-protected MFUL * nfc: Add reader password capture scene * nfc: Set default MFUL password input to 0xFFFFFFFF * nfc: Fix MFUL auth counter loading * nfc: Be explicit about using manual auth method when using auto unlock * nfc: Fill in MFUL has_auth when loading file * nfc: Fix MFUL auth success usage, remove unused variable * nfc: Display PWD and PACK in MFUL info if available * nfc: Remove unnecessary include * nfc: Add unlock options to loaded MFUL menu * nfc: Move set default MFUL password. This way it can be edited if needed instead of reentered * nfc: Fix unlock menu not maintaining selection index * nfc: Move captured MFUL auth data from worker to device data * nfc: Attempt to authenticate with default PWD when possible when reading NTAG * nfc: Don't try to auth NTAG on read if we already authed * nfc: Add title for all pages read but failed auth for NTAG auth * nfc: Add faster auth callback patch * lib: Remove scons submodule from index * nfc: Revise MFUL unlock UI flow * nfc: Disallow MFUL unlock with reader if card not read yet. Trying to read first results in either needing to make a new scene or badly jury rigging other scenes, so let's just not do that * f7: Bump API symbols * Format code Co-authored-by: gornekich Co-authored-by: あく --- .../main/nfc/scenes/nfc_scene_config.h | 1 + .../nfc/scenes/nfc_scene_mf_ultralight_menu.c | 4 +- .../nfc_scene_mf_ultralight_read_auth.c | 25 +++++-- ...nfc_scene_mf_ultralight_read_auth_result.c | 32 +++++++-- .../nfc_scene_mf_ultralight_unlock_auto.c | 64 +++++++++++++++++ .../nfc_scene_mf_ultralight_unlock_menu.c | 31 +++++--- .../nfc_scene_mf_ultralight_unlock_warn.c | 71 ++++++++++++++++--- .../main/nfc/scenes/nfc_scene_nfc_data_info.c | 14 ++++ applications/main/nfc/scenes/nfc_scene_read.c | 2 + .../main/nfc/scenes/nfc_scene_saved_menu.c | 23 ++++++ firmware/targets/f7/api_symbols.csv | 3 +- lib/nfc/nfc_device.c | 3 + lib/nfc/nfc_device.h | 1 + lib/nfc/nfc_worker.c | 18 ++++- lib/nfc/nfc_worker.h | 4 +- lib/nfc/protocols/mifare_ultralight.c | 57 ++++++++++++++- lib/nfc/protocols/mifare_ultralight.h | 15 +++- 17 files changed, 326 insertions(+), 42 deletions(-) create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_auto.c diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index 49c8412c..ce51d000 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -21,6 +21,7 @@ ADD_SCENE(nfc, mf_ultralight_emulate, MfUltralightEmulate) ADD_SCENE(nfc, mf_ultralight_read_auth, MfUltralightReadAuth) ADD_SCENE(nfc, mf_ultralight_read_auth_result, MfUltralightReadAuthResult) ADD_SCENE(nfc, mf_ultralight_key_input, MfUltralightKeyInput) +ADD_SCENE(nfc, mf_ultralight_unlock_auto, MfUltralightUnlockAuto) ADD_SCENE(nfc, mf_ultralight_unlock_menu, MfUltralightUnlockMenu) ADD_SCENE(nfc, mf_ultralight_unlock_warn, MfUltralightUnlockWarn) ADD_SCENE(nfc, mf_desfire_read_success, MfDesfireReadSuccess) 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 ab4d37b0..c511e9dc 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c @@ -19,10 +19,10 @@ void nfc_scene_mf_ultralight_menu_on_enter(void* context) { Submenu* submenu = nfc->submenu; MfUltralightData* data = &nfc->dev->dev_data.mf_ul_data; - if(data->data_read != data->data_size) { + if(!mf_ul_is_full_capture(data)) { submenu_add_item( submenu, - "Unlock With Password", + "Unlock", SubmenuIndexUnlock, nfc_scene_mf_ultralight_menu_submenu_callback, nfc); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c index 5dbb0c18..2ab5e3f3 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c @@ -24,25 +24,29 @@ void nfc_scene_mf_ultralight_read_auth_set_state(Nfc* nfc, NfcSceneMfUlReadState if(curr_state != state) { if(state == NfcSceneMfUlReadStateDetecting) { popup_reset(nfc->popup); - popup_set_text( - nfc->popup, "Apply card to\nFlipper's back", 97, 24, AlignCenter, AlignTop); + popup_set_text(nfc->popup, "Apply the\ntarget card", 97, 24, AlignCenter, AlignTop); popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual_60x50); + nfc_blink_read_start(nfc); } else if(state == NfcSceneMfUlReadStateReading) { popup_reset(nfc->popup); popup_set_header( nfc->popup, "Reading card\nDon't move...", 85, 24, AlignCenter, AlignTop); popup_set_icon(nfc->popup, 12, 23, &A_Loading_24); + nfc_blink_detect_start(nfc); } else if(state == NfcSceneMfUlReadStateNotSupportedCard) { popup_reset(nfc->popup); popup_set_header(nfc->popup, "Wrong type of card!", 64, 3, AlignCenter, AlignTop); popup_set_text( nfc->popup, - "Only MIFARE\nUltralight & NTAG\n are supported", + "Only MIFARE\nUltralight & NTAG\nare supported", 4, 22, AlignLeft, AlignTop); popup_set_icon(nfc->popup, 73, 20, &I_DolphinCommon_56x48); + nfc_blink_stop(nfc); + notification_message(nfc->notifications, &sequence_error); + notification_message(nfc->notifications, &sequence_set_red_255); } scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfUltralightReadAuth, state); } @@ -62,8 +66,6 @@ void nfc_scene_mf_ultralight_read_auth_on_enter(void* context) { &nfc->dev->dev_data, nfc_scene_mf_ultralight_read_auth_worker_callback, nfc); - - nfc_blink_read_start(nfc); } bool nfc_scene_mf_ultralight_read_auth_on_event(void* context, SceneManagerEvent event) { @@ -86,8 +88,17 @@ bool nfc_scene_mf_ultralight_read_auth_on_event(void* context, SceneManagerEvent nfc, NfcSceneMfUlReadStateNotSupportedCard); } } else if(event.type == SceneManagerEventTypeBack) { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); + MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; + NfcScene next_scene; + if(mf_ul_data->auth_method == MfUltralightAuthMethodManual) { + next_scene = NfcSceneMfUltralightKeyInput; + } else if(mf_ul_data->auth_method == MfUltralightAuthMethodAuto) { + next_scene = NfcSceneMfUltralightUnlockAuto; + } else { + next_scene = NfcSceneMfUltralightUnlockMenu; + } + consumed = + scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, next_scene); } return consumed; } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth_result.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth_result.c index 178d0335..b125e999 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth_result.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth_result.c @@ -19,16 +19,20 @@ void nfc_scene_mf_ultralight_read_auth_result_on_enter(void* context) { MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; MfUltralightConfigPages* config_pages = mf_ultralight_get_config_pages(mf_ul_data); Widget* widget = nfc->widget; + const char* title; FuriString* temp_str; temp_str = furi_string_alloc(); if((mf_ul_data->data_read == mf_ul_data->data_size) && (mf_ul_data->data_read > 0)) { - widget_add_string_element( - widget, 64, 0, AlignCenter, AlignTop, FontPrimary, "All pages are unlocked!"); + if(mf_ul_data->auth_success) { + title = "All pages are unlocked!"; + } else { + title = "All unlocked but failed auth!"; + } } else { - widget_add_string_element( - widget, 64, 0, AlignCenter, AlignTop, FontPrimary, "Not all pages unlocked!"); + title = "Not all pages unlocked!"; } + widget_add_string_element(widget, 64, 0, AlignCenter, AlignTop, FontPrimary, title); furi_string_set(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]); @@ -65,6 +69,7 @@ void nfc_scene_mf_ultralight_read_auth_result_on_enter(void* context) { nfc); furi_string_free(temp_str); + notification_message(nfc->notifications, &sequence_set_green_255); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); } @@ -81,8 +86,21 @@ bool nfc_scene_mf_ultralight_read_auth_result_on_event(void* context, SceneManag consumed = true; } } else if(event.type == SceneManagerEventTypeBack) { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); + MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; + if(mf_ul_data->auth_method == MfUltralightAuthMethodManual || + mf_ul_data->auth_method == MfUltralightAuthMethodAuto) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } else { + NfcScene next_scene; + if((mf_ul_data->data_read == mf_ul_data->data_size) && (mf_ul_data->data_read > 0)) { + next_scene = NfcSceneMfUltralightMenu; + } else { + next_scene = NfcSceneMfUltralightUnlockMenu; + } + + consumed = + scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, next_scene); + } } return consumed; @@ -93,4 +111,6 @@ void nfc_scene_mf_ultralight_read_auth_result_on_exit(void* context) { // Clean views widget_reset(nfc->widget); + + notification_message_block(nfc->notifications, &sequence_reset_green); } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_auto.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_auto.c new file mode 100644 index 00000000..c59fe3a7 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_auto.c @@ -0,0 +1,64 @@ +#include "../nfc_i.h" + +bool nfc_scene_mf_ultralight_unlock_auto_worker_callback(NfcWorkerEvent event, void* context) { + Nfc* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, event); + return true; +} + +void nfc_scene_mf_ultralight_unlock_auto_on_enter(void* context) { + Nfc* nfc = context; + + // Setup view + widget_add_string_multiline_element( + nfc->widget, + 54, + 30, + AlignLeft, + AlignCenter, + FontPrimary, + "Touch the\nreader to get\npassword..."); + widget_add_icon_element(nfc->widget, 0, 15, &I_Modern_reader_18x34); + widget_add_icon_element(nfc->widget, 20, 12, &I_Move_flipper_26x39); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); + + // Start worker + nfc_worker_start( + nfc->worker, + NfcWorkerStateMfUltralightEmulate, + &nfc->dev->dev_data, + nfc_scene_mf_ultralight_unlock_auto_worker_callback, + nfc); + + nfc_blink_read_start(nfc); +} + +bool nfc_scene_mf_ultralight_unlock_auto_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if((event.event == NfcWorkerEventMfUltralightPwdAuth)) { + MfUltralightAuth* auth = &nfc->dev->dev_data.mf_ul_auth; + memcpy(nfc->byte_input_store, auth->pwd.raw, sizeof(auth->pwd.raw)); + nfc->dev->dev_data.mf_ul_data.auth_method = MfUltralightAuthMethodAuto; + nfc_worker_stop(nfc->worker); + notification_message(nfc->notifications, &sequence_success); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockWarn); + consumed = true; + } + } + return consumed; +} + +void nfc_scene_mf_ultralight_unlock_auto_on_exit(void* context) { + Nfc* nfc = context; + + // Stop worker + nfc_worker_stop(nfc->worker); + // Clear view + widget_reset(nfc->widget); + + nfc_blink_stop(nfc); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c index 648aa31d..484629b0 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c @@ -1,9 +1,10 @@ #include "../nfc_i.h" enum SubmenuIndex { - SubmenuIndexMfUlUnlockMenuManual, + SubmenuIndexMfUlUnlockMenuAuto, SubmenuIndexMfUlUnlockMenuAmeebo, SubmenuIndexMfUlUnlockMenuXiaomi, + SubmenuIndexMfUlUnlockMenuManual, }; void nfc_scene_mf_ultralight_unlock_menu_submenu_callback(void* context, uint32_t index) { @@ -18,12 +19,14 @@ void nfc_scene_mf_ultralight_unlock_menu_on_enter(void* context) { uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); - submenu_add_item( - submenu, - "Enter Password Manually", - SubmenuIndexMfUlUnlockMenuManual, - nfc_scene_mf_ultralight_unlock_menu_submenu_callback, - nfc); + if(nfc->dev->dev_data.protocol == NfcDeviceProtocolMifareUl) { + submenu_add_item( + submenu, + "Unlock With Reader", + SubmenuIndexMfUlUnlockMenuAuto, + nfc_scene_mf_ultralight_unlock_menu_submenu_callback, + nfc); + } submenu_add_item( submenu, "Auth As Ameebo", @@ -32,10 +35,16 @@ void nfc_scene_mf_ultralight_unlock_menu_on_enter(void* context) { nfc); submenu_add_item( submenu, - "Auth As Xiaomi", + "Auth As Xiaomi Air Purifier", SubmenuIndexMfUlUnlockMenuXiaomi, nfc_scene_mf_ultralight_unlock_menu_submenu_callback, nfc); + submenu_add_item( + submenu, + "Enter Password Manually", + SubmenuIndexMfUlUnlockMenuManual, + nfc_scene_mf_ultralight_unlock_menu_submenu_callback, + nfc); submenu_set_selected_item(submenu, state); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); } @@ -57,8 +66,12 @@ bool nfc_scene_mf_ultralight_unlock_menu_on_event(void* context, SceneManagerEve nfc->dev->dev_data.mf_ul_data.auth_method = MfUltralightAuthMethodXiaomi; scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockWarn); consumed = true; + } else if(event.event == SubmenuIndexMfUlUnlockMenuAuto) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockAuto); + consumed = true; } - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneExtraActions, event.event); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneMfUltralightUnlockMenu, event.event); } return consumed; } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c index 514cd4e9..16efae9d 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c @@ -10,15 +10,43 @@ void nfc_scene_mf_ultralight_unlock_warn_dialog_callback(DialogExResult result, void nfc_scene_mf_ultralight_unlock_warn_on_enter(void* context) { Nfc* nfc = context; DialogEx* dialog_ex = nfc->dialog_ex; + MfUltralightAuthMethod auth_method = nfc->dev->dev_data.mf_ul_data.auth_method; dialog_ex_set_context(dialog_ex, nfc); dialog_ex_set_result_callback(dialog_ex, nfc_scene_mf_ultralight_unlock_warn_dialog_callback); - dialog_ex_set_header(dialog_ex, "Risky function!", 64, 4, AlignCenter, AlignTop); - dialog_ex_set_text( - dialog_ex, "Wrong password\ncan block your\ncard.", 4, 18, AlignLeft, AlignTop); - dialog_ex_set_icon(dialog_ex, 73, 20, &I_DolphinCommon_56x48); - dialog_ex_set_center_button_text(dialog_ex, "OK"); + if(auth_method == MfUltralightAuthMethodManual || auth_method == MfUltralightAuthMethodAuto) { + // Build dialog text + MfUltralightAuth* auth = &nfc->dev->dev_data.mf_ul_auth; + FuriString* password_str = + furi_string_alloc_set_str("Try to unlock the card with\npassword: "); + for(size_t i = 0; i < sizeof(auth->pwd.raw); ++i) { + furi_string_cat_printf(password_str, "%02X ", nfc->byte_input_store[i]); + } + furi_string_cat_str(password_str, "?\nCaution, a wrong password\ncan block the card!"); + nfc_text_store_set(nfc, furi_string_get_cstr(password_str)); + furi_string_free(password_str); + + dialog_ex_set_header( + dialog_ex, + auth_method == MfUltralightAuthMethodAuto ? "Password captured!" : "Risky function!", + 64, + 0, + AlignCenter, + AlignTop); + dialog_ex_set_text(dialog_ex, nfc->text_store, 64, 12, AlignCenter, AlignTop); + dialog_ex_set_left_button_text(dialog_ex, "Cancel"); + dialog_ex_set_right_button_text(dialog_ex, "Continue"); + + if(auth_method == MfUltralightAuthMethodAuto) + notification_message(nfc->notifications, &sequence_set_green_255); + } else { + dialog_ex_set_header(dialog_ex, "Risky function!", 64, 4, AlignCenter, AlignTop); + dialog_ex_set_text( + dialog_ex, "Wrong password\ncan block your\ncard.", 4, 18, AlignLeft, AlignTop); + dialog_ex_set_icon(dialog_ex, 73, 20, &I_DolphinCommon_56x48); + dialog_ex_set_center_button_text(dialog_ex, "OK"); + } view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); } @@ -28,12 +56,33 @@ bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEve bool consumed = false; - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == DialogExResultCenter) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadAuth); - DOLPHIN_DEED(DolphinDeedNfcRead); + MfUltralightAuthMethod auth_method = nfc->dev->dev_data.mf_ul_data.auth_method; + if(auth_method == MfUltralightAuthMethodManual || auth_method == MfUltralightAuthMethodAuto) { + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == DialogExResultRight) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadAuth); + DOLPHIN_DEED(DolphinDeedNfcRead); + consumed = true; + } else if(event.event == DialogExResultLeft) { + if(auth_method == MfUltralightAuthMethodAuto) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); + } else { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } + } + } else if(event.type == SceneManagerEventTypeBack) { + // Cannot press back consumed = true; } + } else { + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == DialogExResultCenter) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadAuth); + DOLPHIN_DEED(DolphinDeedNfcRead); + consumed = true; + } + } } return consumed; @@ -43,5 +92,7 @@ void nfc_scene_mf_ultralight_unlock_warn_on_exit(void* context) { Nfc* nfc = context; dialog_ex_reset(nfc->dialog_ex); - submenu_reset(nfc->submenu); + nfc_text_store_clear(nfc); + + notification_message_block(nfc->notifications, &sequence_reset_green); } 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 bd6f5e2e..7318fd00 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c +++ b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c @@ -87,6 +87,20 @@ void nfc_scene_nfc_data_info_on_enter(void* context) { temp_str, "\nPages Read %d/%d", data->data_read / 4, data->data_size / 4); if(data->data_size > data->data_read) { furi_string_cat_printf(temp_str, "\nPassword-protected"); + } else if(data->auth_success) { + MfUltralightConfigPages* config_pages = mf_ultralight_get_config_pages(data); + furi_string_cat_printf( + temp_str, + "\nPassword: %02X %02X %02X %02X", + config_pages->auth_data.pwd.raw[0], + config_pages->auth_data.pwd.raw[1], + config_pages->auth_data.pwd.raw[2], + config_pages->auth_data.pwd.raw[3]); + furi_string_cat_printf( + temp_str, + "\nPACK: %02X %02X", + config_pages->auth_data.pack.raw[0], + config_pages->auth_data.pack.raw[1]); } } else if(protocol == NfcDeviceProtocolMifareClassic) { MfClassicData* data = &dev_data->mf_classic_data; diff --git a/applications/main/nfc/scenes/nfc_scene_read.c b/applications/main/nfc/scenes/nfc_scene_read.c index 1f82aef0..a64d4d00 100644 --- a/applications/main/nfc/scenes/nfc_scene_read.c +++ b/applications/main/nfc/scenes/nfc_scene_read.c @@ -70,6 +70,8 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { consumed = true; } else if(event.event == NfcWorkerEventReadMfUltralight) { notification_message(nfc->notifications, &sequence_success); + // Set unlock password input to 0xFFFFFFFF only on fresh read + memset(nfc->byte_input_store, 0xFF, 4); scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadSuccess); DOLPHIN_DEED(DolphinDeedNfcReadSuccess); consumed = true; diff --git a/applications/main/nfc/scenes/nfc_scene_saved_menu.c b/applications/main/nfc/scenes/nfc_scene_saved_menu.c index 231f1208..e0839d66 100644 --- a/applications/main/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_saved_menu.c @@ -11,6 +11,8 @@ enum SubmenuIndex { SubmenuIndexDelete, SubmenuIndexInfo, SubmenuIndexRestoreOriginal, + SubmenuIndexMfUlUnlockByReader, + SubmenuIndexMfUlUnlockByPassword, }; void nfc_scene_saved_menu_submenu_callback(void* context, uint32_t index) { @@ -69,6 +71,21 @@ 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 && + !mf_ul_is_full_capture(&nfc->dev->dev_data.mf_ul_data)) { + submenu_add_item( + submenu, + "Unlock With Reader", + SubmenuIndexMfUlUnlockByReader, + nfc_scene_saved_menu_submenu_callback, + nfc); + submenu_add_item( + submenu, + "Unlock With Password", + SubmenuIndexMfUlUnlockByPassword, + nfc_scene_saved_menu_submenu_callback, + nfc); + } if(nfc->dev->shadow_file_exist) { submenu_add_item( submenu, @@ -141,6 +158,12 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { } else if(event.event == SubmenuIndexRestoreOriginal) { scene_manager_next_scene(nfc->scene_manager, NfcSceneRestoreOriginalConfirm); consumed = true; + } else if(event.event == SubmenuIndexMfUlUnlockByReader) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockAuto); + consumed = true; + } else if(event.event == SubmenuIndexMfUlUnlockByPassword) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); + consumed = true; } } diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 5ccb9d43..f3ed374b 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,+,7.5,, +Version,+,7.6,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1900,6 +1900,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_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*" Function,-,mf_ul_pwdgen_amiibo,uint32_t,FuriHalNfcDevData* diff --git a/lib/nfc/nfc_device.c b/lib/nfc/nfc_device.c index 5d86da0c..dc1faa34 100644 --- a/lib/nfc/nfc_device.c +++ b/lib/nfc/nfc_device.c @@ -214,6 +214,9 @@ bool nfc_device_load_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) { uint32_t auth_counter; if(!flipper_format_read_uint32(file, "Failed authentication attempts", &auth_counter, 1)) auth_counter = 0; + data->curr_authlim = auth_counter; + + data->auth_success = mf_ul_is_full_capture(data); parsed = true; } while(false); diff --git a/lib/nfc/nfc_device.h b/lib/nfc/nfc_device.h index 3d302c18..4be07f01 100644 --- a/lib/nfc/nfc_device.h +++ b/lib/nfc/nfc_device.h @@ -67,6 +67,7 @@ typedef struct { union { NfcReaderRequestData reader_data; NfcMfClassicDictAttackData mf_classic_dict_attack_data; + MfUltralightAuth mf_ul_auth; }; union { EmvData emv_data; diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c index c701132c..450428a1 100644 --- a/lib/nfc/nfc_worker.c +++ b/lib/nfc/nfc_worker.c @@ -527,10 +527,25 @@ void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) { } } +void nfc_worker_mf_ultralight_auth_received_callback(MfUltralightAuth auth, void* context) { + furi_assert(context); + + NfcWorker* nfc_worker = context; + nfc_worker->dev_data->mf_ul_auth = auth; + if(nfc_worker->callback) { + nfc_worker->callback(NfcWorkerEventMfUltralightPwdAuth, nfc_worker->context); + } +} + void nfc_worker_emulate_mf_ultralight(NfcWorker* nfc_worker) { FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; MfUltralightEmulator emulator = {}; mf_ul_prepare_emulation(&emulator, &nfc_worker->dev_data->mf_ul_data); + + // TODO rework with reader analyzer + emulator.auth_received_callback = nfc_worker_mf_ultralight_auth_received_callback; + emulator.context = nfc_worker; + while(nfc_worker->state == NfcWorkerStateMfUltralightEmulate) { mf_ul_reset_emulation(&emulator, true); furi_hal_nfc_emulate_nfca( @@ -905,7 +920,8 @@ void nfc_worker_mf_ultralight_read_auth(NfcWorker* nfc_worker) { if(furi_hal_nfc_detect(nfc_data, 300) && nfc_data->type == FuriHalNfcTypeA) { if(mf_ul_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) { nfc_worker->callback(NfcWorkerEventCardDetected, nfc_worker->context); - if(data->auth_method == MfUltralightAuthMethodManual) { + if(data->auth_method == MfUltralightAuthMethodManual || + data->auth_method == MfUltralightAuthMethodAuto) { nfc_worker->callback(NfcWorkerEventMfUltralightPassKey, nfc_worker->context); key = nfc_util_bytes2num(data->auth_key, 4); } else if(data->auth_method == MfUltralightAuthMethodAmeebo) { diff --git a/lib/nfc/nfc_worker.h b/lib/nfc/nfc_worker.h index ddee34c9..fdcaa72f 100644 --- a/lib/nfc/nfc_worker.h +++ b/lib/nfc/nfc_worker.h @@ -65,8 +65,8 @@ typedef enum { NfcWorkerEventDetectReaderMfkeyCollected, // Mifare Ultralight events - NfcWorkerEventMfUltralightPassKey, - + NfcWorkerEventMfUltralightPassKey, // NFC worker requesting manual key + NfcWorkerEventMfUltralightPwdAuth, // Reader sent auth command } NfcWorkerEvent; typedef bool (*NfcWorkerCallback)(NfcWorkerEvent event, void* context); diff --git a/lib/nfc/protocols/mifare_ultralight.c b/lib/nfc/protocols/mifare_ultralight.c index a8d1f554..85e234bd 100644 --- a/lib/nfc/protocols/mifare_ultralight.c +++ b/lib/nfc/protocols/mifare_ultralight.c @@ -51,7 +51,7 @@ void mf_ul_reset(MfUltralightData* data) { data->data_size = 0; data->data_read = 0; data->curr_authlim = 0; - data->has_auth = false; + data->auth_success = false; } static MfUltralightFeatures mf_ul_get_features(MfUltralightType type) { @@ -756,6 +756,34 @@ bool mf_ul_read_card( mf_ultralight_read_tearing_flags(tx_rx, data); } data->curr_authlim = 0; + + if(reader->pages_read == reader->pages_to_read && + reader->supported_features & MfUltralightSupportAuth && !data->auth_success) { + MfUltralightConfigPages* config = mf_ultralight_get_config_pages(data); + if(config->access.authlim == 0) { + // Attempt to auth with default PWD + uint16_t pack; + data->auth_success = mf_ultralight_authenticate(tx_rx, MF_UL_DEFAULT_PWD, &pack); + if(data->auth_success) { + config->auth_data.pwd.value = MF_UL_DEFAULT_PWD; + config->auth_data.pack.value = pack; + } else { + furi_hal_nfc_sleep(); + furi_hal_nfc_activate_nfca(300, NULL); + } + } + } + } + + if(reader->pages_read != reader->pages_to_read) { + if(reader->supported_features & MfUltralightSupportAuth) { + // Probably password protected, fix AUTH0 and PROT so before AUTH0 + // can be written and since AUTH0 won't be readable, like on the + // original card + MfUltralightConfigPages* config = mf_ultralight_get_config_pages(data); + config->auth0 = reader->pages_read; + config->access.prot = true; + } } return card_read; @@ -1201,6 +1229,8 @@ static void mf_ul_emulate_write( } void mf_ul_reset_emulation(MfUltralightEmulator* emulator, bool is_power_cycle) { + emulator->comp_write_cmd_started = false; + emulator->sector_select_cmd_started = false; emulator->curr_sector = 0; emulator->ntag_i2c_plus_sector3_lockout = false; emulator->auth_success = false; @@ -1244,8 +1274,7 @@ void mf_ul_prepare_emulation(MfUltralightEmulator* emulator, MfUltralightData* d emulator->config = mf_ultralight_get_config_pages(&emulator->data); emulator->page_num = emulator->data.data_size / 4; emulator->data_changed = false; - emulator->comp_write_cmd_started = false; - emulator->sector_select_cmd_started = false; + memset(&emulator->auth_attempt, 0, sizeof(MfUltralightAuth)); mf_ul_reset_emulation(emulator, true); } @@ -1706,6 +1735,17 @@ bool mf_ul_prepare_emulation_response( } else if(cmd == MF_UL_AUTH) { if(emulator->supported_features & MfUltralightSupportAuth) { if(buff_rx_len == (1 + 4) * 8) { + // Record password sent by PCD + memcpy( + emulator->auth_attempt.pwd.raw, + &buff_rx[1], + sizeof(emulator->auth_attempt.pwd.raw)); + emulator->auth_attempted = true; + if(emulator->auth_received_callback) { + emulator->auth_received_callback( + emulator->auth_attempt, emulator->context); + } + uint16_t scaled_authlim = mf_ultralight_calc_auth_count(&emulator->data); if(scaled_authlim != 0 && emulator->data.curr_authlim >= scaled_authlim) { if(emulator->data.curr_authlim != UINT16_MAX) { @@ -1863,3 +1903,14 @@ bool mf_ul_prepare_emulation_response( return tx_bits > 0; } + +bool mf_ul_is_full_capture(MfUltralightData* data) { + if(data->data_read != data->data_size) return false; + + // Having read all the pages doesn't mean that we've got everything. + // By default PWD is 0xFFFFFFFF, but if read back it is always 0x00000000, + // so a default read on an auth-supported NTAG is never complete. + if(!(mf_ul_get_features(data->type) & MfUltralightSupportAuth)) return true; + MfUltralightConfigPages* config = mf_ultralight_get_config_pages(data); + return config->auth_data.pwd.value != 0 || config->auth_data.pack.value != 0; +} diff --git a/lib/nfc/protocols/mifare_ultralight.h b/lib/nfc/protocols/mifare_ultralight.h index 9642824f..4ab22e89 100644 --- a/lib/nfc/protocols/mifare_ultralight.h +++ b/lib/nfc/protocols/mifare_ultralight.h @@ -28,10 +28,13 @@ #define MF_UL_NTAG203_COUNTER_PAGE (41) +#define MF_UL_DEFAULT_PWD (0xFFFFFFFF) + typedef enum { MfUltralightAuthMethodManual, MfUltralightAuthMethodAmeebo, MfUltralightAuthMethodXiaomi, + MfUltralightAuthMethodAuto, } MfUltralightAuthMethod; // Important: order matters; some features are based on positioning in this enum @@ -110,7 +113,6 @@ typedef struct { uint8_t signature[32]; uint32_t counter[3]; uint8_t tearing[3]; - bool has_auth; MfUltralightAuthMethod auth_method; uint8_t auth_key[4]; bool auth_success; @@ -169,6 +171,9 @@ typedef struct { MfUltralightFeatures supported_features; } MfUltralightReader; +// TODO rework with reader analyzer +typedef void (*MfUltralightAuthReceivedCallback)(MfUltralightAuth auth, void* context); + typedef struct { MfUltralightData data; MfUltralightConfigPages* config; @@ -185,6 +190,12 @@ typedef struct { bool sector_select_cmd_started; bool ntag_i2c_plus_sector3_lockout; bool read_counter_incremented; + bool auth_attempted; + MfUltralightAuth auth_attempt; + + // TODO rework with reader analyzer + MfUltralightAuthReceivedCallback auth_received_callback; + void* context; } MfUltralightEmulator; void mf_ul_reset(MfUltralightData* data); @@ -241,3 +252,5 @@ bool mf_ul_prepare_emulation_response( uint32_t mf_ul_pwdgen_amiibo(FuriHalNfcDevData* data); uint32_t mf_ul_pwdgen_xiaomi(FuriHalNfcDevData* data); + +bool mf_ul_is_full_capture(MfUltralightData* data); From 769c53b6da48a59d0e0d43a2ddc3f6221f9ccfe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Tue, 29 Nov 2022 03:59:24 +0900 Subject: [PATCH 16/25] [FL-2977] Gui: better navigation in file browser dialog (#2014) * Gui: proper navigation in file browser dialog * Trim file name from start path * File list loading fix * File list offset fix Co-authored-by: nminaylov Co-authored-by: Sergey Gavrilov --- .../main/archive/helpers/archive_browser.c | 3 +-- .../main/archive/helpers/archive_browser.h | 2 +- .../services/gui/modules/file_browser.c | 22 ++++++++++++++++--- .../gui/modules/file_browser_worker.c | 17 ++++++++++++++ .../gui/modules/file_browser_worker.h | 2 ++ firmware/targets/f7/api_symbols.csv | 1 + 6 files changed, 41 insertions(+), 6 deletions(-) diff --git a/applications/main/archive/helpers/archive_browser.c b/applications/main/archive/helpers/archive_browser.c index 9689454b..149b3908 100644 --- a/applications/main/archive/helpers/archive_browser.c +++ b/applications/main/archive/helpers/archive_browser.c @@ -265,8 +265,7 @@ void archive_file_array_load(ArchiveBrowserView* browser, int8_t dir) { offset_new = model->item_idx - FILE_LIST_BUF_LEN / 4 * 1; } if(offset_new > 0) { - offset_new = - CLAMP(offset_new, (int32_t)model->item_cnt - FILE_LIST_BUF_LEN, 0); + offset_new = CLAMP(offset_new, (int32_t)model->item_cnt, 0); } else { offset_new = 0; } diff --git a/applications/main/archive/helpers/archive_browser.h b/applications/main/archive/helpers/archive_browser.h index 1a7e01f5..09ffea1f 100644 --- a/applications/main/archive/helpers/archive_browser.h +++ b/applications/main/archive/helpers/archive_browser.h @@ -5,7 +5,7 @@ #define TAB_RIGHT InputKeyRight // Default tab switch direction #define TAB_DEFAULT ArchiveTabFavorites // Start tab -#define FILE_LIST_BUF_LEN 100 +#define FILE_LIST_BUF_LEN 50 static const char* tab_default_paths[] = { [ArchiveTabFavorites] = "/app:favorites", diff --git a/applications/services/gui/modules/file_browser.c b/applications/services/gui/modules/file_browser.c index 60e78b01..203be23e 100644 --- a/applications/services/gui/modules/file_browser.c +++ b/applications/services/gui/modules/file_browser.c @@ -232,7 +232,10 @@ static bool browser_is_item_in_array(FileBrowserModel* model, uint32_t idx) { static bool browser_is_list_load_required(FileBrowserModel* model) { size_t array_size = items_array_size(model->items); - uint32_t item_cnt = (model->is_root) ? model->item_cnt : model->item_cnt - 1; + if((array_size > 0) && (!model->is_root) && (model->array_offset == 0)) { + array_size--; + } + uint32_t item_cnt = (model->is_root) ? (model->item_cnt) : (model->item_cnt - 1); if((model->list_loading) || (array_size >= item_cnt)) { return false; @@ -524,7 +527,7 @@ static bool file_browser_view_input_callback(InputEvent* event, void* context) { model->list_loading = true; int32_t load_offset = CLAMP( model->item_idx - ITEM_LIST_LEN_MAX / 4 * 3, - (int32_t)model->item_cnt - ITEM_LIST_LEN_MAX, + (int32_t)model->item_cnt, 0); file_browser_worker_load( browser->worker, load_offset, ITEM_LIST_LEN_MAX); @@ -535,7 +538,7 @@ static bool file_browser_view_input_callback(InputEvent* event, void* context) { model->list_loading = true; int32_t load_offset = CLAMP( model->item_idx - ITEM_LIST_LEN_MAX / 4 * 1, - (int32_t)model->item_cnt - ITEM_LIST_LEN_MAX, + (int32_t)model->item_cnt, 0); file_browser_worker_load( browser->worker, load_offset, ITEM_LIST_LEN_MAX); @@ -590,6 +593,19 @@ static bool file_browser_view_input_callback(InputEvent* event, void* context) { } consumed = true; } + } else if(event->key == InputKeyBack) { + if(event->type == InputTypeShort) { + bool is_root = false; + with_view_model( + browser->view, FileBrowserModel * model, { is_root = model->is_root; }, false); + + if(!is_root && !file_browser_worker_is_in_start_folder(browser->worker)) { + consumed = true; + if(!is_root) { + file_browser_worker_folder_exit(browser->worker); + } + } + } } return consumed; diff --git a/applications/services/gui/modules/file_browser_worker.c b/applications/services/gui/modules/file_browser_worker.c index 34d83032..a85a14b7 100644 --- a/applications/services/gui/modules/file_browser_worker.c +++ b/applications/services/gui/modules/file_browser_worker.c @@ -35,6 +35,8 @@ struct BrowserWorker { FuriThread* thread; FuriString* filter_extension; + FuriString* path_start; + FuriString* path_current; FuriString* path_next; int32_t item_sel_idx; uint32_t load_offset; @@ -289,6 +291,7 @@ static int32_t browser_worker(void* context) { int32_t file_idx = 0; browser_folder_init(browser, path, filename, &items_cnt, &file_idx); + furi_string_set(browser->path_current, path); FURI_LOG_D( TAG, "Enter folder: %s items: %lu idx: %ld", @@ -311,6 +314,7 @@ static int32_t browser_worker(void* context) { // Pop previous selected item index from history array idx_last_array_pop_back(&file_idx, browser->idx_last); } + furi_string_set(browser->path_current, path); FURI_LOG_D( TAG, "Exit to: %s items: %lu idx: %ld", @@ -365,8 +369,14 @@ BrowserWorker* browser->filter_extension = furi_string_alloc_set(filter_ext); browser->skip_assets = skip_assets; + browser->path_start = furi_string_alloc_set(path); + browser->path_current = furi_string_alloc_set(path); browser->path_next = furi_string_alloc_set(path); + if(browser_path_is_file(browser->path_start)) { + browser_path_trim(browser->path_start); + } + browser->thread = furi_thread_alloc_ex("BrowserWorker", 2048, browser_worker, browser); furi_thread_start(browser->thread); @@ -382,6 +392,8 @@ void file_browser_worker_free(BrowserWorker* browser) { furi_string_free(browser->filter_extension); furi_string_free(browser->path_next); + furi_string_free(browser->path_current); + furi_string_free(browser->path_start); idx_last_array_clear(browser->idx_last); @@ -440,6 +452,11 @@ void file_browser_worker_folder_enter(BrowserWorker* browser, FuriString* path, furi_thread_flags_set(furi_thread_get_id(browser->thread), WorkerEvtFolderEnter); } +bool file_browser_worker_is_in_start_folder(BrowserWorker* browser) { + furi_assert(browser); + return (furi_string_cmp(browser->path_start, browser->path_current) == 0); +} + void file_browser_worker_folder_exit(BrowserWorker* browser) { furi_assert(browser); furi_thread_flags_set(furi_thread_get_id(browser->thread), WorkerEvtFolderExit); diff --git a/applications/services/gui/modules/file_browser_worker.h b/applications/services/gui/modules/file_browser_worker.h index 230bb5b4..2f815540 100644 --- a/applications/services/gui/modules/file_browser_worker.h +++ b/applications/services/gui/modules/file_browser_worker.h @@ -52,6 +52,8 @@ void file_browser_worker_set_config( void file_browser_worker_folder_enter(BrowserWorker* browser, FuriString* path, int32_t item_idx); +bool file_browser_worker_is_in_start_folder(BrowserWorker* browser); + void file_browser_worker_folder_exit(BrowserWorker* browser); void file_browser_worker_folder_refresh(BrowserWorker* browser, int32_t item_idx); diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index f3ed374b..17b36a2a 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -817,6 +817,7 @@ Function,+,file_browser_worker_folder_enter,void,"BrowserWorker*, FuriString*, i Function,+,file_browser_worker_folder_exit,void,BrowserWorker* Function,+,file_browser_worker_folder_refresh,void,"BrowserWorker*, int32_t" Function,+,file_browser_worker_free,void,BrowserWorker* +Function,+,file_browser_worker_is_in_start_folder,_Bool,BrowserWorker* Function,+,file_browser_worker_load,void,"BrowserWorker*, uint32_t, uint32_t" Function,+,file_browser_worker_set_callback_context,void,"BrowserWorker*, void*" Function,+,file_browser_worker_set_config,void,"BrowserWorker*, FuriString*, const char*, _Bool" From 97e8da7a7bf781ef1670e38b52f984c551253d3f Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 28 Nov 2022 22:08:28 +0300 Subject: [PATCH 17/25] Weather Station: Add protocol - Auriol HG0601A (#2056) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add protocol Auriol hg0601a: Made by @LY2NEO * Improve readability of code: fix protocol name Co-authored-by: あく --- .../protocols/auriol_hg0601a.c | 258 ++++++++++++++++++ .../protocols/auriol_hg0601a.h | 79 ++++++ .../protocols/protocol_items.c | 1 + .../protocols/protocol_items.h | 1 + 4 files changed, 339 insertions(+) create mode 100644 applications/plugins/weather_station/protocols/auriol_hg0601a.c create mode 100644 applications/plugins/weather_station/protocols/auriol_hg0601a.h diff --git a/applications/plugins/weather_station/protocols/auriol_hg0601a.c b/applications/plugins/weather_station/protocols/auriol_hg0601a.c new file mode 100644 index 00000000..d5f89fc8 --- /dev/null +++ b/applications/plugins/weather_station/protocols/auriol_hg0601a.c @@ -0,0 +1,258 @@ +#include "auriol_hg0601a.h" + +#define TAG "WSProtocolAuriol_TH" + +/* + * +Auriol HG06061A-DCF-TX sensor. + +Data layout: + DDDDDDDD-B0-NN-TT-TTTTTTTTTT-CCCC-HHHHHHHH +Exmpl.: 11110100-10-01-00-0001001100-1111-01011101 + +- D: id, 8 bit +- B: where B is the battery status: 1=OK, 0=LOW, 1 bit +- 0: just zero :) +- N: NN is the channel: 00=CH1, 01=CH2, 11=CH3, 2bit +- T: temperature, 12 bit: 2's complement, scaled by 10 +- C: 4 bit: seems to be 0xf constantly, a separator between temp and humidity +- H: humidity sensor, humidity is 8 bits + + * The sensor sends 37 bits 10 times, + * the packets are ppm modulated (distance coding) with a pulse of ~500 us + * followed by a short gap of ~1000 us for a 0 bit or a long ~2000 us gap for a + * 1 bit, the sync gap is ~4000 us. + * + */ + +#define AURIOL_TH_CONST_DATA 0b1110 + +static const SubGhzBlockConst ws_protocol_auriol_th_const = { + .te_short = 500, + .te_long = 2000, + .te_delta = 150, + .min_count_bit_for_found = 37, +}; + +struct WSProtocolDecoderAuriol_TH { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + WSBlockGeneric generic; +}; + +struct WSProtocolEncoderAuriol_TH { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + WSBlockGeneric generic; +}; + +typedef enum { + auriol_THDecoderStepReset = 0, + auriol_THDecoderStepSaveDuration, + auriol_THDecoderStepCheckDuration, +} auriol_THDecoderStep; + +const SubGhzProtocolDecoder ws_protocol_auriol_th_decoder = { + .alloc = ws_protocol_decoder_auriol_th_alloc, + .free = ws_protocol_decoder_auriol_th_free, + + .feed = ws_protocol_decoder_auriol_th_feed, + .reset = ws_protocol_decoder_auriol_th_reset, + + .get_hash_data = ws_protocol_decoder_auriol_th_get_hash_data, + .serialize = ws_protocol_decoder_auriol_th_serialize, + .deserialize = ws_protocol_decoder_auriol_th_deserialize, + .get_string = ws_protocol_decoder_auriol_th_get_string, +}; + +const SubGhzProtocolEncoder ws_protocol_auriol_th_encoder = { + .alloc = NULL, + .free = NULL, + + .deserialize = NULL, + .stop = NULL, + .yield = NULL, +}; + +const SubGhzProtocol ws_protocol_auriol_th = { + .name = WS_PROTOCOL_AURIOL_TH_NAME, + .type = SubGhzProtocolWeatherStation, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 | + SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable, + + .decoder = &ws_protocol_auriol_th_decoder, + .encoder = &ws_protocol_auriol_th_encoder, +}; + +void* ws_protocol_decoder_auriol_th_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + WSProtocolDecoderAuriol_TH* instance = malloc(sizeof(WSProtocolDecoderAuriol_TH)); + instance->base.protocol = &ws_protocol_auriol_th; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void ws_protocol_decoder_auriol_th_free(void* context) { + furi_assert(context); + WSProtocolDecoderAuriol_TH* instance = context; + free(instance); +} + +void ws_protocol_decoder_auriol_th_reset(void* context) { + furi_assert(context); + WSProtocolDecoderAuriol_TH* instance = context; + instance->decoder.parser_step = auriol_THDecoderStepReset; +} + +static bool ws_protocol_auriol_th_check(WSProtocolDecoderAuriol_TH* instance) { + uint8_t type = (instance->decoder.decode_data >> 8) & 0x0F; + + if((type == AURIOL_TH_CONST_DATA) && ((instance->decoder.decode_data >> 4) != 0xffffffff)) { + return true; + } else { + return false; + } + return true; +} + +/** + * Analysis of received data + * @param instance Pointer to a WSBlockGeneric* instance + */ +static void ws_protocol_auriol_th_remote_controller(WSBlockGeneric* instance) { + instance->id = (instance->data >> 31) & 0xFF; + instance->battery_low = ((instance->data >> 30) & 1); + instance->channel = ((instance->data >> 25) & 0x03) + 1; + instance->btn = WS_NO_BTN; + if(!((instance->data >> 23) & 1)) { + instance->temp = (float)((instance->data >> 13) & 0x07FF) / 10.0f; + } else { + instance->temp = (float)((~(instance->data >> 13) & 0x07FF) + 1) / -10.0f; + } + + instance->humidity = (instance->data >> 1) & 0x7F; +} + +void ws_protocol_decoder_auriol_th_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); + WSProtocolDecoderAuriol_TH* instance = context; + + switch(instance->decoder.parser_step) { + case auriol_THDecoderStepReset: + if((!level) && (DURATION_DIFF(duration, ws_protocol_auriol_th_const.te_short * 8) < + ws_protocol_auriol_th_const.te_delta)) { + //Found sync + instance->decoder.parser_step = auriol_THDecoderStepSaveDuration; + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + } + break; + + case auriol_THDecoderStepSaveDuration: + if(level) { + instance->decoder.te_last = duration; + instance->decoder.parser_step = auriol_THDecoderStepCheckDuration; + } else { + instance->decoder.parser_step = auriol_THDecoderStepReset; + } + break; + + case auriol_THDecoderStepCheckDuration: + if(!level) { + if(DURATION_DIFF(duration, ws_protocol_auriol_th_const.te_short * 8) < + ws_protocol_auriol_th_const.te_delta) { + //Found sync + instance->decoder.parser_step = auriol_THDecoderStepReset; + if((instance->decoder.decode_count_bit == + ws_protocol_auriol_th_const.min_count_bit_for_found) && + ws_protocol_auriol_th_check(instance)) { + instance->generic.data = instance->decoder.decode_data; + instance->generic.data_count_bit = instance->decoder.decode_count_bit; + ws_protocol_auriol_th_remote_controller(&instance->generic); + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + instance->decoder.parser_step = auriol_THDecoderStepCheckDuration; + } + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + + break; + } else if( + (DURATION_DIFF(instance->decoder.te_last, ws_protocol_auriol_th_const.te_short) < + ws_protocol_auriol_th_const.te_delta) && + (DURATION_DIFF(duration, ws_protocol_auriol_th_const.te_short * 2) < + ws_protocol_auriol_th_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = auriol_THDecoderStepSaveDuration; + } else if( + (DURATION_DIFF(instance->decoder.te_last, ws_protocol_auriol_th_const.te_short) < + ws_protocol_auriol_th_const.te_delta) && + (DURATION_DIFF(duration, ws_protocol_auriol_th_const.te_short * 4) < + ws_protocol_auriol_th_const.te_delta * 2)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = auriol_THDecoderStepSaveDuration; + } else { + instance->decoder.parser_step = auriol_THDecoderStepReset; + } + } else { + instance->decoder.parser_step = auriol_THDecoderStepReset; + } + break; + } +} + +uint8_t ws_protocol_decoder_auriol_th_get_hash_data(void* context) { + furi_assert(context); + WSProtocolDecoderAuriol_TH* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +bool ws_protocol_decoder_auriol_th_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset) { + furi_assert(context); + WSProtocolDecoderAuriol_TH* instance = context; + return ws_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +bool ws_protocol_decoder_auriol_th_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + WSProtocolDecoderAuriol_TH* instance = context; + bool ret = false; + do { + if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) { + break; + } + if(instance->generic.data_count_bit != + ws_protocol_auriol_th_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + ret = true; + } while(false); + return ret; +} + +void ws_protocol_decoder_auriol_th_get_string(void* context, FuriString* output) { + furi_assert(context); + WSProtocolDecoderAuriol_TH* instance = context; + furi_string_printf( + output, + "%s %dbit\r\n" + "Key:0x%lX%08lX\r\n" + "Sn:0x%lX Ch:%d Bat:%d\r\n" + "Temp:%3.1f C Hum:%d%%", + instance->generic.protocol_name, + instance->generic.data_count_bit, + (uint32_t)(instance->generic.data >> 32), + (uint32_t)(instance->generic.data), + instance->generic.id, + instance->generic.channel, + instance->generic.battery_low, + (double)instance->generic.temp, + instance->generic.humidity); +} diff --git a/applications/plugins/weather_station/protocols/auriol_hg0601a.h b/applications/plugins/weather_station/protocols/auriol_hg0601a.h new file mode 100644 index 00000000..c23007c1 --- /dev/null +++ b/applications/plugins/weather_station/protocols/auriol_hg0601a.h @@ -0,0 +1,79 @@ +#pragma once + +#include + +#include +#include +#include +#include "ws_generic.h" +#include + +#define WS_PROTOCOL_AURIOL_TH_NAME "Auriol HG06061" //HG06061A-DCF-TX + +typedef struct WSProtocolDecoderAuriol_TH WSProtocolDecoderAuriol_TH; +typedef struct WSProtocolEncoderAuriol_TH WSProtocolEncoderAuriol_TH; + +extern const SubGhzProtocolDecoder ws_protocol_auriol_th_decoder; +extern const SubGhzProtocolEncoder ws_protocol_auriol_th_encoder; +extern const SubGhzProtocol ws_protocol_auriol_th; + +/** + * Allocate WSProtocolDecoderAuriol_TH. + * @param environment Pointer to a SubGhzEnvironment instance + * @return WSProtocolDecoderAuriol_TH* pointer to a WSProtocolDecoderAuriol_TH instance + */ +void* ws_protocol_decoder_auriol_th_alloc(SubGhzEnvironment* environment); + +/** + * Free WSProtocolDecoderAuriol_TH. + * @param context Pointer to a WSProtocolDecoderAuriol_TH instance + */ +void ws_protocol_decoder_auriol_th_free(void* context); + +/** + * Reset decoder WSProtocolDecoderAuriol_TH. + * @param context Pointer to a WSProtocolDecoderAuriol_TH instance + */ +void ws_protocol_decoder_auriol_th_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a WSProtocolDecoderAuriol_TH instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void ws_protocol_decoder_auriol_th_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a WSProtocolDecoderAuriol_TH instance + * @return hash Hash sum + */ +uint8_t ws_protocol_decoder_auriol_th_get_hash_data(void* context); + +/** + * Serialize data WSProtocolDecoderAuriol_TH. + * @param context Pointer to a WSProtocolDecoderAuriol_TH instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzRadioPreset + * @return true On success + */ +bool ws_protocol_decoder_auriol_th_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset); + +/** + * Deserialize data WSProtocolDecoderAuriol_TH. + * @param context Pointer to a WSProtocolDecoderAuriol_TH instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool ws_protocol_decoder_auriol_th_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a WSProtocolDecoderAuriol_TH instance + * @param output Resulting text + */ +void ws_protocol_decoder_auriol_th_get_string(void* context, FuriString* output); diff --git a/applications/plugins/weather_station/protocols/protocol_items.c b/applications/plugins/weather_station/protocols/protocol_items.c index 21768e04..9ad8ce1a 100644 --- a/applications/plugins/weather_station/protocols/protocol_items.c +++ b/applications/plugins/weather_station/protocols/protocol_items.c @@ -12,6 +12,7 @@ const SubGhzProtocol* weather_station_protocol_registry_items[] = { &ws_protocol_oregon2, &ws_protocol_acurite_592txr, &ws_protocol_ambient_weather, + &ws_protocol_auriol_th, }; const SubGhzProtocolRegistry weather_station_protocol_registry = { diff --git a/applications/plugins/weather_station/protocols/protocol_items.h b/applications/plugins/weather_station/protocols/protocol_items.h index aa064f04..4fef8944 100644 --- a/applications/plugins/weather_station/protocols/protocol_items.h +++ b/applications/plugins/weather_station/protocols/protocol_items.h @@ -12,5 +12,6 @@ #include "oregon2.h" #include "acurite_592txr.h" #include "ambient_weather.h" +#include "auriol_hg0601a.h" extern const SubGhzProtocolRegistry weather_station_protocol_registry; From 84f9af3e7e872499c035285e48cd3e087a0f9c18 Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Mon, 28 Nov 2022 23:17:57 +0400 Subject: [PATCH 18/25] SubGhz: fix duration pricenton protocol (#2054) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- lib/subghz/protocols/princeton.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/subghz/protocols/princeton.c b/lib/subghz/protocols/princeton.c index a4a0921a..ab1c5876 100644 --- a/lib/subghz/protocols/princeton.c +++ b/lib/subghz/protocols/princeton.c @@ -15,8 +15,8 @@ #define TAG "SubGhzProtocolPrinceton" static const SubGhzBlockConst subghz_protocol_princeton_const = { - .te_short = 400, - .te_long = 1200, + .te_short = 390, + .te_long = 1170, .te_delta = 300, .min_count_bit_for_found = 24, }; @@ -245,8 +245,7 @@ void subghz_protocol_decoder_princeton_feed(void* context, bool level, uint32_t break; case PrincetonDecoderStepCheckDuration: if(!level) { - if(duration >= ((uint32_t)subghz_protocol_princeton_const.te_short * 10 + - subghz_protocol_princeton_const.te_delta)) { + if(duration >= ((uint32_t)subghz_protocol_princeton_const.te_long * 2)) { instance->decoder.parser_step = PrincetonDecoderStepSaveDuration; if(instance->decoder.decode_count_bit == subghz_protocol_princeton_const.min_count_bit_for_found) { From c535ce9b768cb1a02a2eab77b37567d185bd83b5 Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Mon, 28 Nov 2022 22:28:51 +0300 Subject: [PATCH 19/25] [FL-2997] Improve file name filtering #2047 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- lib/toolbox/path.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/lib/toolbox/path.c b/lib/toolbox/path.c index ce65aca4..3d161a19 100644 --- a/lib/toolbox/path.c +++ b/lib/toolbox/path.c @@ -95,22 +95,17 @@ bool path_contains_only_ascii(const char* path) { name_pos++; } - while(*name_pos != '\0') { - if((*name_pos >= '0') && (*name_pos <= '9')) { - name_pos++; - continue; - } else if((*name_pos >= 'A') && (*name_pos <= 'Z')) { - name_pos++; - continue; - } else if((*name_pos >= 'a') && (*name_pos <= 'z')) { - name_pos++; - continue; - } else if(strchr(" .!#\\$%&'()-@^_`{}~", *name_pos) != NULL) { - name_pos++; - continue; - } + for(; *name_pos; ++name_pos) { + const char c = *name_pos; - return false; + // Regular ASCII characters from 0x20 to 0x7e + const bool is_out_of_range = (c < ' ') || (c > '~'); + // Cross-platform forbidden character set + const bool is_forbidden = strchr("\\<>*|\":?", c); + + if(is_out_of_range || is_forbidden) { + return false; + } } return true; From 849afc8798b4a2594090a2abff9ca32bc44909bc Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Mon, 28 Nov 2022 22:49:51 +0300 Subject: [PATCH 20/25] [FL-2998] IR TV Universal Remote refactor and docs (#2052) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Rename signals for IR TV universal remote * Update UniversalRemotes.md Co-authored-by: あく --- .../scenes/infrared_scene_universal_tv.c | 12 +- assets/resources/infrared/assets/tv.ir | 540 +++++++++--------- documentation/UniversalRemotes.md | 22 +- 3 files changed, 291 insertions(+), 283 deletions(-) diff --git a/applications/main/infrared/scenes/infrared_scene_universal_tv.c b/applications/main/infrared/scenes/infrared_scene_universal_tv.c index 583f21fa..e21bf8f9 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/tv.ir b/assets/resources/infrared/assets/tv.ir index 79478e7e..8945465c 100755 --- a/assets/resources/infrared/assets/tv.ir +++ b/assets/resources/infrared/assets/tv.ir @@ -1,1621 +1,1621 @@ Filetype: IR library file Version: 1 # -name: POWER +name: Power type: parsed protocol: SIRC address: 01 00 00 00 command: 15 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: 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: 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: 50 00 00 00 command: 17 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 40 00 00 00 command: 12 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: Samsung32 address: 0e 00 00 00 command: 14 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: NEC address: 00 00 00 00 command: 01 00 00 00 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 634 2571 505 519 479 519 479 518 480 518 480 518 480 518 480 517 481 547 481 517 481 20040 590 2555 501 1007 999 997 510 548 480 486 512 486 512 486 542 485 513 516 482 116758 593 2552 504 1004 992 1004 514 514 514 483 515 513 485 483 545 482 516 482 516 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 525 1955 449 1999 476 4545 446 4544 478 2032 443 2006 469 2011 444 4577 445 4545 447 4574 448 2002 473 4547 444 34913 447 2032 443 2007 478 4542 449 4541 471 2039 446 2004 471 2008 447 4574 448 4543 448 4572 450 2030 445 4545 446 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 2445 582 1221 603 548 602 1191 609 572 602 1191 609 542 607 544 631 1172 603 568 606 545 605 566 608 543 26263 2414 611 1192 607 544 606 1197 602 569 606 1197 602 539 611 540 635 1168 606 565 610 541 608 563 587 564 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 3461 1802 439 452 444 1283 469 448 438 453 443 447 439 452 444 419 497 448 438 425 471 419 467 451 445 445 441 450 446 1281 471 420 466 425 471 446 440 424 472 445 461 456 440 451 445 445 441 450 446 1281 471 447 439 451 445 419 467 423 473 445 441 422 494 450 436 428 468 1259 493 425 471 1256 496 1259 472 1281 471 1285 467 423 473 417 469 1286 466 452 444 1283 469 1285 467 1261 491 1263 468 423 493 1260 471 74142 3578 1713 467 423 473 1281 471 420 466 452 444 419 467 424 472 418 488 429 467 451 445 445 441 450 446 444 442 449 437 1290 472 446 440 423 473 445 441 449 467 396 490 428 468 449 447 444 442 448 438 1289 473 445 441 450 446 444 442 449 437 426 470 421 495 422 464 426 470 1257 495 450 446 1254 488 1267 464 1290 472 1282 470 421 465 453 443 1284 468 450 446 1281 471 1283 469 1259 493 1261 470 448 468 1258 473 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 389 1737 280 796 253 744 295 754 274 775 274 776 273 1827 271 1828 270 805 254 1820 278 796 253 797 252 745 294 1806 302 773 245 48942 305 1821 277 798 251 746 303 747 271 778 271 1829 279 796 253 796 253 1821 277 798 251 1823 275 1824 274 1825 273 802 247 1827 271 42824 381 1745 272 804 245 752 297 753 275 773 276 774 275 1825 273 1826 272 803 246 1828 270 805 254 795 244 753 296 1804 294 781 247 48939 379 1746 271 804 245 779 270 753 275 774 275 1825 273 802 247 802 247 1827 271 804 245 1829 279 1820 278 1821 277 798 251 1823 275 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 562 1721 561 594 557 597 564 617 513 615 536 618 543 1715 566 1716 566 1692 559 594 567 588 563 618 543 611 540 615 536 618 543 1715 556 623 538 617 534 621 530 624 516 638 513 642 509 1722 560 620 541 1717 565 1692 559 1724 568 1715 556 1701 560 1723 559 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8436 4189 538 1563 566 1559 539 510 559 543 516 507 542 560 509 540 509 567 512 1586 512 1562 567 1559 539 536 533 1566 542 507 562 513 536 540 509 22102 647 1478 559 1568 540 508 541 535 534 515 534 568 511 538 511 539 540 1585 513 1560 559 1567 541 534 535 1564 534 515 534 568 511 538 511 22125 644 1482 565 1561 537 511 538 564 515 508 541 535 534 541 508 516 563 1588 510 1563 556 1570 538 510 559 1567 541 534 515 535 534 541 508 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 929 825 1711 934 797 930 791 909 822 932 789 938 793 934 797 930 791 1719 899 856 1711 907 824 90848 923 830 1706 912 819 908 823 931 790 910 822 933 788 912 819 935 796 1714 904 850 1707 939 792 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 448 2031 444 2005 480 4540 452 4539 473 2037 438 2011 474 2006 449 4571 451 4539 453 4568 444 2036 449 4541 451 34906 527 1953 451 1998 477 4543 449 4542 480 2030 445 2004 471 2009 446 4575 447 4543 449 4572 450 1999 476 4545 446 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 9021 4496 567 1664 567 1690 561 567 533 1698 563 1667 564 1693 568 1663 568 586 534 567 563 565 535 594 536 591 539 589 531 571 539 563 567 1690 541 560 560 594 536 592 538 564 536 1695 566 1664 567 1690 561 1670 561 1696 555 1675 566 562 558 596 514 562 568 559 561 594 536 565 535 593 537 591 539 1665 566 1692 559 1671 560 1697 564 1666 565 1666 565 1693 558 1672 569 23181 9013 4504 569 1689 542 1689 562 565 535 1697 564 1666 646 1610 560 1672 559 595 535 593 537 590 510 566 564 590 540 588 532 596 514 588 542 1689 542 560 560 594 536 592 538 590 510 1694 567 1664 567 1690 561 1669 562 1695 556 1675 566 561 559 596 514 588 542 585 535 593 537 591 509 593 537 591 539 1665 566 1692 559 1671 560 1697 564 1667 564 1667 564 1693 558 1672 569 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8041 3979 513 536 482 515 513 1559 509 515 514 1560 508 515 514 509 509 514 484 4000 533 1566 512 537 481 1566 512 537 481 1566 512 537 481 516 513 537 481 24150 8044 3977 505 518 510 539 479 1567 511 512 506 1568 510 539 479 543 485 538 480 3977 536 1564 514 534 484 1563 515 508 510 1563 515 508 510 540 489 534 484 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 383 2027 295 2112 271 2138 266 890 271 887 294 926 235 2114 300 887 274 915 236 2145 269 887 274 884 297 923 238 920 241 917 264 895 266 26573 384 2026 296 2111 273 2136 268 889 272 886 295 924 237 2113 301 886 275 914 237 2144 270 886 275 914 267 921 240 919 242 916 265 924 237 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 177 8474 175 5510 174 8476 173 8477 177 8504 171 5515 175 8476 178 8472 177 8473 176 5541 174 8476 173 45583 171 8481 178 5507 177 8473 176 8474 175 8506 173 5512 172 8478 176 8475 174 8476 178 5538 177 8474 175 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8044 3976 506 517 511 1563 505 517 511 538 480 517 511 538 460 563 455 568 460 3993 530 545 483 1564 514 1559 509 1564 514 509 509 540 488 535 483 513 505 24150 8043 3978 514 509 509 1564 514 509 509 540 478 519 509 540 458 565 464 559 459 3994 529 546 482 1565 513 1560 508 1565 513 510 508 541 487 536 482 541 477 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 558 2942 450 10021 482 2989 484 10015 447 3024 449 10021 472 3100 485 2986 477 2994 500 2999 475 2996 477 2994 479 2992 482 3018 476 2995 479 6464 484 36270 477 3023 450 10020 473 2999 485 10014 448 3022 452 10019 474 3098 478 2994 480 2991 503 2996 477 2994 480 2992 482 2990 484 3015 479 2992 481 6462 485 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 587 2407 476 1062 965 547 482 547 451 577 452 546 452 22108 590 2404 479 1060 967 1028 510 519 509 548 480 487 511 120791 645 2411 472 1066 961 1065 483 515 514 514 504 493 515 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 172 7439 171 7441 169 7443 177 7434 176 7462 178 4887 176 4916 177 4914 169 7469 171 4920 174 4918 175 55174 176 7436 174 7437 173 7439 171 7440 175 7463 172 4894 174 4917 171 4921 172 7465 175 4916 178 4914 169 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 589 2556 500 524 474 554 454 544 454 543 455 543 455 543 455 543 445 583 446 552 446 20046 584 2561 505 1033 485 514 963 518 480 1032 516 512 476 522 506 491 507 522 476 116758 586 2560 506 1033 484 513 964 548 450 1031 507 522 476 521 507 490 508 521 477 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 586 2407 476 1063 964 578 450 548 450 547 481 517 481 577 451 546 452 546 472 556 452 545 453 575 453 514 484 544 484 543 455 14954 510 2483 481 1058 480 548 959 552 446 1067 481 516 512 546 482 515 992 1003 535 493 515 543 486 513 475 522 506 552 446 111671 589 2405 478 1061 477 551 967 514 484 1059 479 549 479 548 480 517 990 1036 512 516 482 546 483 515 503 525 483 544 454 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8444 4180 537 1564 565 1560 538 1561 557 1568 540 1559 539 536 533 542 517 559 510 1563 535 1564 565 1561 537 512 567 1558 540 535 534 1566 542 1557 562 23122 564 1562 557 1569 539 1560 538 1587 542 1558 540 534 535 515 534 541 538 1587 511 1563 566 1560 538 536 533 1567 541 534 515 1585 533 1566 542 23166 561 1565 564 1561 537 1563 535 1590 539 1561 537 538 541 534 515 535 534 1564 534 1566 563 1563 535 540 539 1560 538 511 538 1588 541 1559 539 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 527 1923 481 1998 477 4543 449 4542 470 2040 445 2004 471 2009 446 4575 447 4543 449 4572 450 1999 476 2034 441 34899 524 1956 448 2001 474 4546 446 4545 477 2033 442 2007 478 2002 443 4578 444 4546 445 4575 447 2003 472 2037 448 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 533 1356 437 3474 427 3483 429 3455 436 1454 430 1459 405 28168 510 1379 434 3477 434 3476 425 3459 432 1457 427 1462 402 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 921 833 1714 932 789 938 793 934 797 903 818 909 822 905 816 938 793 1716 902 853 1714 905 816 90856 922 805 1742 931 790 937 794 933 788 939 792 935 796 930 791 937 794 1715 903 825 1742 904 817 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 179 7433 177 4915 178 7434 175 7436 174 7464 176 7435 175 4916 177 4915 173 4918 170 4922 171 4920 173 55174 175 7437 173 4919 174 7437 173 7439 171 7467 173 7438 172 4920 173 4919 174 4917 176 4915 178 4914 169 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 169 6731 176 6748 169 6730 177 6748 169 6755 172 4427 177 4447 178 6721 175 6749 178 4446 168 4456 169 54704 176 6723 174 6750 177 6723 173 6750 177 6747 170 4429 175 4449 176 6723 174 6751 176 4448 177 4447 178 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 3506 3494 876 830 840 2576 847 2568 844 862 819 2570 842 864 816 863 818 2570 842 836 844 2572 840 866 815 865 815 2573 839 867 813 866 814 2573 850 857 813 2575 847 2568 844 834 847 2569 843 835 845 2571 872 2571 842 32654 3512 3488 872 834 847 2570 842 2573 839 867 814 2574 849 858 822 857 813 2575 848 859 821 2566 846 832 848 860 821 2567 845 833 848 860 820 2568 844 834 847 2569 843 2572 840 838 843 2574 849 829 841 2575 868 2575 837 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 560 2939 453 10018 475 2996 477 10022 450 3021 452 10018 475 3097 478 6464 483 6460 477 6466 502 6469 479 2993 480 2990 484 36274 564 2936 456 10015 478 2993 481 10020 534 2936 456 10014 479 3093 482 6461 476 6466 482 6461 476 6495 473 2999 485 2986 477 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 10726 41047 10727 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 1617 4604 1559 1537 1560 1537 1560 4661 1533 33422 1613 4607 1566 1530 1556 1540 1536 4685 1539 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 174 4972 177 4910 173 4944 170 6988 174 6984 177 6951 175 6983 174 14269 177 4969 175 4912 176 4941 178 6979 172 6986 175 6953 178 6980 171 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 174 7067 176 10544 1055 719 1053 739 1054 738 953 822 1052 2566 169 3435 171 3431 175 3446 170 3432 174 3446 170 3432 174 3428 178 3442 174 3429 177 3425 171 39320 2323 4900 178 10543 1056 719 1053 739 1054 738 953 821 1053 2566 169 3435 171 3431 175 3445 171 3432 174 3446 170 3432 174 3428 178 3442 174 3428 178 3425 171 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 3506 3492 868 839 841 2575 848 858 822 2566 846 832 848 859 821 858 812 2576 847 860 820 2567 845 833 847 860 821 2568 844 862 818 2570 842 864 817 2571 841 2574 849 2567 845 861 820 2568 845 834 847 2570 873 2570 842 34395 3503 3496 874 833 847 2568 845 834 847 2570 842 864 816 835 846 862 819 2569 843 835 846 2571 841 865 816 864 816 2571 841 837 844 2573 850 857 813 2575 848 2567 845 2570 842 864 816 2572 840 838 842 2574 869 2574 838 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 170 8479 170 5516 178 8472 177 8474 175 8506 173 5513 171 8479 175 8476 178 8472 177 5540 175 8475 174 45584 177 8473 176 5509 175 8476 173 8477 176 8504 170 5516 178 8472 177 8474 175 8476 173 5543 172 8479 170 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 178 4969 170 6958 173 4944 175 6983 173 6956 174 6984 177 6980 171 16308 180 4966 173 6955 176 4941 172 6985 176 6982 169 6960 176 6982 174 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 585 2409 474 550 478 550 448 1033 994 1063 485 512 506 79916 585 2410 473 551 477 550 448 1034 993 1033 515 543 475 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 1192 1012 6649 26844 1192 1013 6648 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 3134 6105 6263 82963 3134 6105 6263 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 588 1511 567 1533 565 589 531 597 513 589 541 587 533 1565 533 569 541 1533 565 562 568 1531 537 1537 561 593 537 591 539 1507 561 1539 569 22152 586 1513 565 1535 563 590 540 562 538 564 566 588 542 1557 531 597 513 1534 564 590 540 1533 535 1539 559 568 562 592 538 1509 569 1531 567 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 923 831 1715 903 818 936 795 932 789 938 793 934 797 1713 1740 932 789 911 821 934 798 930 791 90853 928 799 1737 935 796 931 790 937 795 932 789 938 793 1717 1736 936 796 932 789 911 820 934 798 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 689 1461 566 1534 564 589 531 597 513 1534 564 564 566 1533 535 620 510 1537 561 592 538 1535 543 1531 567 587 533 595 535 1511 567 1533 565 22161 588 1512 566 1534 564 564 556 598 512 1535 563 565 565 1534 534 594 536 1538 560 593 537 1536 542 1532 566 587 543 585 535 1511 567 1534 564 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 588 2558 498 526 482 515 483 546 452 545 453 545 453 545 453 545 453 544 474 554 444 20047 583 2562 504 519 479 519 479 1003 515 483 1024 548 450 1001 995 1001 506 116771 593 2552 504 520 478 551 447 1004 513 514 993 549 449 1002 994 1002 516 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 587 2559 507 517 481 517 481 547 451 516 482 546 452 546 452 546 452 545 473 525 483 20038 592 2553 503 521 477 552 446 521 477 1004 514 515 992 1034 483 514 484 513 485 116769 593 2552 504 520 478 550 448 520 478 1003 515 514 993 1032 486 513 475 522 476 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 4558 4576 558 596 565 97881 4554 4579 565 589 562 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 1039 7202 958 4713 981 4713 961 7255 956 4739 955 16077 1038 7204 956 4714 980 4715 959 7256 954 4741 954 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 506 2638 510 516 482 516 482 546 452 546 452 545 453 545 453 545 453 575 443 554 444 20048 592 2554 502 1036 481 517 481 517 511 516 482 516 961 1035 513 515 483 514 484 116757 594 2552 504 1034 484 514 484 514 504 524 484 513 964 1032 506 522 476 492 506 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 170 7441 169 4924 174 7437 193 7444 171 7441 174 4918 170 7441 174 4917 171 7440 195 7443 172 7439 171 55187 174 7437 173 4919 175 7437 173 7438 172 7466 175 4891 172 7439 171 4921 172 7439 171 7441 174 7464 171 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 179 4967 172 4915 178 6980 171 4945 169 4948 176 4912 176 4941 178 16307 176 4969 175 4912 176 6982 174 4942 171 4945 169 4919 174 4943 176 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 1042 793 898 883 869 858 924 884 878 877 875 879 873 855 928 1717 901 854 1794 878 894 887 875 1716 902 89114 985 798 903 878 874 880 902 852 900 855 897 857 905 876 896 1722 906 849 1789 883 899 855 897 1721 897 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 170 8480 169 8481 178 8472 177 8474 175 8476 173 5513 176 8474 175 8476 173 8507 178 5509 175 8505 174 45558 175 8476 173 8476 173 8477 172 8478 171 8480 169 5517 177 8473 176 8474 175 8506 174 5512 172 8509 171 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 628 2577 499 528 480 545 453 544 454 544 454 544 454 544 454 543 455 543 475 553 445 20047 593 2553 503 521 477 551 447 1004 514 515 992 519 479 1003 515 513 485 543 455 116768 585 2561 505 519 479 519 479 1002 516 513 994 548 450 1001 506 522 476 521 477 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8987 4505 568 586 534 594 536 591 509 567 563 591 539 563 567 587 513 1692 559 1672 559 1698 563 590 510 592 538 590 540 1664 567 1690 561 593 507 1699 562 1668 563 1694 567 1663 568 586 534 568 562 592 508 595 535 1695 536 592 538 1693 558 595 515 1690 561 593 517 585 535 567 563 39551 8994 4497 566 589 541 560 560 594 516 586 534 594 536 592 538 590 510 1695 566 1664 567 1690 561 593 507 595 535 566 564 1667 564 1693 558 596 534 1670 561 1670 561 1696 565 1666 565 589 541 587 533 595 515 587 533 1697 534 568 562 1695 556 572 538 1693 568 559 541 588 542 585 535 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8987 4504 569 559 561 593 537 565 535 567 563 591 539 588 532 597 513 1691 560 568 562 592 508 1697 564 589 511 565 565 1692 559 1672 559 569 561 1669 562 566 564 564 566 1665 566 588 542 586 534 1670 561 567 563 565 535 593 537 591 539 1692 539 589 541 586 534 594 536 592 508 40679 8987 4504 569 585 535 593 537 591 509 566 564 591 539 588 532 596 514 1691 560 594 536 592 508 1697 564 589 511 591 539 1692 559 1671 560 594 536 1669 562 592 538 590 540 1664 567 587 543 585 535 1670 561 593 537 565 535 593 537 591 539 1691 540 588 542 586 534 594 536 592 508 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 298 1828 270 804 245 1829 279 1820 278 797 252 771 278 1822 276 1824 274 800 249 1825 273 802 247 776 252 771 278 1822 276 799 250 48931 388 1737 280 796 253 1821 277 1822 276 798 251 1823 275 800 249 774 275 1825 273 776 273 1801 297 1828 270 1829 279 796 253 1821 277 42813 301 1825 273 801 248 1826 272 1827 271 804 245 805 244 1830 278 1821 277 798 251 1823 275 799 250 774 244 779 280 1820 278 796 253 48926 382 1744 354 696 271 1828 270 1829 279 796 253 1821 277 797 252 746 303 1823 275 774 275 1799 299 1826 272 1827 271 804 245 1829 279 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 177 5508 176 5539 176 8475 174 5542 173 8478 171 5545 170 8481 168 8482 177 8473 176 5541 174 8476 173 45573 169 5517 177 5538 177 8473 176 5541 174 8476 173 5544 171 8479 170 8481 178 8472 177 5540 175 8475 174 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 175 8474 175 8475 174 8477 172 8478 171 8480 169 8481 178 5538 177 5510 174 5542 173 5543 172 5544 171 45575 177 8472 177 8474 175 8476 173 8477 172 8478 171 8481 178 5507 177 5539 176 5540 175 5542 173 5543 172 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8050 3971 511 1562 516 1558 510 539 490 1557 511 1563 515 533 485 538 490 533 485 3983 530 1569 509 1564 514 1559 509 1565 513 1560 508 515 513 536 482 541 488 24152 8042 3979 514 1560 508 1565 513 510 508 1565 513 1560 508 515 513 536 482 541 488 3980 533 1567 511 1562 516 1557 511 1563 515 1558 510 539 489 534 484 539 490 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 175 8475 174 5512 177 8473 176 8475 174 8506 179 5508 176 8474 175 8475 174 8477 172 5544 171 8480 169 45587 176 8475 174 5511 173 8477 177 8473 176 8504 170 5516 178 8472 177 8473 176 8475 174 5542 173 8478 171 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 176 7436 174 7438 172 7439 171 7441 174 7463 172 7440 170 4921 172 4919 174 4917 176 4916 177 4914 174 55176 175 7437 173 7439 191 7446 174 7438 177 7434 176 7435 175 4917 176 4915 179 4914 174 4917 171 4946 178 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 176 7435 175 4917 177 7435 175 7436 189 7449 176 7435 175 7437 173 4918 175 7436 174 4918 175 4916 178 55171 175 7436 174 4918 170 7441 174 7438 177 7460 170 7441 174 7438 177 4914 174 7437 178 4914 169 4922 171 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8049 3973 509 1564 514 509 509 1564 514 535 483 1564 514 535 483 540 489 535 483 3980 533 1566 512 537 481 1566 512 511 507 1566 512 537 481 542 486 511 507 24149 8045 3976 516 1558 510 512 516 1557 511 512 516 1558 510 512 516 507 511 512 506 3984 539 1560 508 515 513 1560 508 541 488 1560 508 541 488 536 482 514 504 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 366 202 867 527 170 130516 343 227 863 529 168 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 176 5992 176 1372 176 1320 177 1345 172 1349 179 1370 178 1317 175 4444 176 1346 171 1351 177 1345 172 1349 179 1344 174 5963 175 65574 172 5995 178 1344 174 1348 175 1347 175 1347 170 1378 170 1325 172 4447 178 1344 173 1349 169 1353 175 1347 170 1351 177 5961 177 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 497 1478 488 511 467 1482 494 531 447 1477 499 501 466 533 445 530 468 507 471 529 438 12857 488 1485 491 509 469 1481 495 529 448 1476 490 510 468 532 445 529 469 480 498 502 465 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 982 6313 961 2662 903 2718 929 2719 907 6363 900 2722 904 6365 909 6361 903 6368 906 2742 905 46364 989 6307 906 2716 911 2712 925 2723 903 6367 907 2715 901 6369 905 6365 909 6361 903 2745 902 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 599 257 975 317 177 130649 308 228 974 319 175 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 176 4969 170 6958 173 6985 177 6981 171 6958 178 6980 177 6981 170 16308 180 4966 173 6955 176 6982 169 6988 174 6956 175 6983 173 6984 172 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 178 5990 173 1349 174 1348 175 1348 174 4444 176 1346 171 1351 177 4416 178 1344 173 1348 169 1353 175 1347 170 1351 177 9048 177 65573 173 5995 173 1348 175 1348 174 1347 176 4444 171 1351 177 1345 173 4421 173 1348 169 1352 176 1347 170 1351 177 1345 172 9053 177 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 174 4972 177 4910 173 6985 177 4940 174 6984 178 6951 175 6983 174 14269 177 4968 176 4912 176 6981 175 4941 173 6985 177 6953 178 6979 172 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 1318 225 177 130305 1609 231 171 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 585 2410 473 1065 962 581 447 519 479 580 448 549 449 579 449 518 480 548 480 517 481 517 481 577 451 516 482 576 452 545 453 14955 510 2483 481 1058 480 549 969 543 445 1037 511 547 481 546 482 516 482 545 484 545 483 514 484 544 963 1063 485 543 445 111612 626 2427 557 954 513 512 995 547 451 1031 507 521 508 551 477 520 478 550 478 549 479 488 510 548 969 1057 481 517 481 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 203 272 1215 302 171 130229 1423 275 178 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 176 7436 174 7438 192 7446 174 7437 178 7434 176 7435 175 4917 176 4915 178 4913 175 4917 197 7440 175 55130 286 7377 177 7435 175 7437 173 7438 172 7466 174 7411 178 4913 170 4921 172 4919 174 4918 175 7436 174 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 175 7437 173 4918 170 7441 174 7437 178 7460 170 7441 179 7433 177 4915 178 4913 170 4922 171 4920 173 55124 291 7372 172 4921 172 7439 171 7441 174 7463 172 7440 170 7442 178 4913 170 4922 171 4920 173 4918 175 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 172 8477 172 8478 171 8480 169 5516 179 8502 178 5509 175 8475 174 8476 173 8479 170 5545 170 8480 169 45588 176 8473 176 8474 175 8476 173 5513 177 8504 171 5515 174 8476 178 8472 177 8473 176 5541 174 8476 173 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 177 7436 174 4918 175 7436 174 4918 175 7462 178 4887 176 4916 177 4914 174 4917 171 4921 172 4919 175 55184 175 7435 175 4918 175 7436 174 4918 175 7462 178 4914 174 4917 171 4920 173 4919 174 4917 176 4915 178 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 508 2484 480 1060 967 544 485 544 454 574 454 543 455 573 445 553 445 522 506 552 446 552 446 551 477 551 447 581 447 520 478 550 478 15908 626 2427 476 1062 476 522 995 547 451 1061 477 520 508 550 478 519 479 519 999 1058 959 1037 990 582 446 1035 483 111666 590 2404 479 1059 479 549 968 543 455 1027 511 548 480 517 511 486 512 546 961 1065 962 1034 993 579 449 1032 486 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 175 8475 174 8475 174 8477 172 8478 171 8480 169 5517 178 8473 175 8475 179 8501 173 5513 176 8505 169 45562 179 8472 177 8473 176 8474 175 8476 173 8478 171 5515 174 8476 178 8473 176 8505 174 5512 172 8508 171 120769 178 93377 175 7437 173 4919 174 7437 173 7439 171 7467 173 7439 171 7441 174 4918 170 4921 172 7439 171 7467 173 55167 171 7440 170 4922 171 7440 195 7443 172 7439 171 7441 174 7438 177 4915 173 4918 195 7442 173 7439 170 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 295 1805 273 776 242 1808 270 754 244 1806 272 777 241 758 270 754 264 760 268 756 272 14149 297 1802 266 784 244 1805 263 762 246 1803 265 785 244 780 248 751 267 758 271 753 265 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 535 1723 569 585 566 615 536 619 542 586 565 616 535 1722 539 615 536 1721 561 620 541 587 564 617 534 621 540 588 563 618 543 1714 537 617 534 621 540 615 536 618 543 612 539 615 536 1722 560 594 567 1717 534 1723 569 1714 557 1700 643 1639 643 1641 559 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 502 2521 504 521 997 545 453 575 453 545 453 575 454 22097 591 2433 511 513 994 1062 476 552 476 522 476 552 476 120839 628 2455 509 515 992 1064 484 513 505 493 515 543 475 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 591 2404 479 1060 967 1029 509 519 509 549 479 518 480 79926 585 2408 556 956 989 1033 515 544 484 543 475 522 476 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 586 2560 506 518 480 548 450 548 450 517 481 517 481 517 481 547 451 546 482 516 482 20040 590 2556 500 1038 480 518 969 543 455 543 475 1006 511 517 481 517 511 486 481 116778 584 2561 505 1033 485 513 964 548 450 548 480 1001 506 522 476 522 506 521 446 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 917 206 175 186 170 21561 170 2280 175 2274 502 1929 174 2276 169 5178 170 2261 173 3724 498 1932 171 2279 176 2273 172 3709 172 2277 178 3720 171 17223 177 7619 174 2275 170 2279 176 2256 168 2280 175 5172 176 2256 168 3729 173 2276 179 2253 171 2278 177 3703 178 2271 174 3724 177 17251 170 7627 177 2272 173 2276 169 2263 171 2277 178 5169 169 2262 172 3726 175 2256 168 2280 175 2274 171 3710 171 2278 177 3720 171 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 565 233 653 313 170 130328 752 235 233 107 229 398 177 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 586 2439 505 549 968 1027 511 517 511 517 481 547 481 21583 584 2439 505 520 997 1059 479 549 479 518 480 548 480 120894 593 2432 501 522 995 1061 477 521 507 520 478 550 478 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 558 8032 474 8115 503 8116 482 8108 480 8141 477 5239 476 8114 504 8115 483 8107 481 5236 509 8111 477 45290 554 8036 481 8108 510 8110 478 8112 476 8145 473 5243 482 8107 511 8109 479 8111 477 5240 505 8115 473 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 173 7438 172 4920 173 7438 172 4920 173 7465 175 4890 173 7439 171 4920 173 4919 174 4917 176 4915 178 55179 170 7441 169 4924 174 7437 178 4913 175 7463 172 4893 170 7441 174 4918 170 4922 171 4920 173 4918 175 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 225 745 222 774 193 778 200 797 175 769 193 777 201 771 196 774 224 747 220 776 202 769 198 248 220 252 196 250 218 253 225 746 221 250 198 248 220 252 226 246 222 223 225 248 220 252 216 229 219 253 225 247 221 277 176 243 220 279 189 230 228 244 224 248 220 252 196 250 218 253 215 257 201 770 197 799 189 257 201 271 197 37716 222 749 218 778 200 771 196 801 172 772 200 771 196 774 193 777 221 750 217 780 197 773 194 251 217 255 193 279 199 273 195 749 218 254 194 252 226 245 223 275 178 242 221 277 201 245 193 253 225 247 221 250 218 254 194 252 226 272 196 223 225 248 220 251 217 255 193 253 225 247 221 251 197 773 194 803 174 297 176 244 219 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 3503 2655 197 642 876 2568 844 834 846 833 848 860 821 831 839 2576 847 2569 843 2572 841 2574 849 858 823 857 813 866 815 865 815 2572 841 2575 848 2568 844 2570 842 836 844 863 818 834 847 861 820 2568 845 2571 872 2571 842 32651 3505 3495 875 2567 845 861 820 832 849 859 811 840 840 2576 847 2568 844 2571 842 2574 849 830 840 867 814 838 842 865 815 2572 840 2575 848 2568 845 2571 841 865 815 864 817 834 846 861 819 2569 843 2572 871 2572 840 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 347 677 219 252 196 276 202 742 225 798 174 770 192 778 200 771 196 775 223 748 219 777 200 770 197 249 219 253 195 251 227 271 197 747 220 252 216 229 219 253 225 273 195 277 176 244 219 253 215 230 228 244 224 248 220 252 196 250 218 280 198 247 201 245 223 249 219 253 195 251 227 245 223 248 200 797 175 795 198 248 200 246 222 37666 344 678 228 245 223 222 226 771 196 800 198 747 220 750 217 753 224 773 194 776 202 769 198 799 173 246 227 245 223 249 199 247 221 749 218 280 198 247 201 245 223 249 219 253 195 251 227 244 224 248 200 272 196 250 218 254 194 252 226 245 223 249 199 274 194 251 227 245 193 253 225 273 195 251 217 753 225 746 221 251 197 275 193 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 174 7437 173 7440 174 7437 178 7433 177 7461 169 7442 178 4914 174 4917 171 4921 172 4919 174 7463 177 55163 177 7435 174 7437 173 7438 172 7440 175 7463 172 7413 176 4915 178 4913 175 4917 171 4920 174 7438 172 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8042 3979 513 510 508 541 487 1559 509 515 513 1560 508 515 513 510 508 541 477 3981 532 1568 510 1563 515 1558 510 1564 514 1559 509 514 514 535 483 540 488 24151 8042 3979 513 536 482 541 487 1560 508 541 488 1560 508 541 487 536 482 541 477 3980 533 1566 512 1561 507 1566 512 1562 516 1557 511 538 491 533 485 538 490 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8989 4501 562 1696 565 1665 566 562 568 586 514 588 542 586 534 594 536 1667 564 591 539 1692 539 563 567 1690 561 1669 562 1669 562 1696 565 562 538 564 566 588 542 586 534 1670 561 568 562 592 538 590 510 592 538 590 540 561 539 563 567 561 569 585 535 593 507 595 535 593 537 39547 8987 4504 569 1689 562 1668 563 591 539 589 511 591 539 589 541 561 559 1671 560 568 562 1695 536 592 538 1693 558 1673 568 1663 568 1689 562 592 508 594 536 592 538 590 540 1664 567 561 569 559 561 567 543 585 535 593 537 591 509 593 537 591 539 589 541 587 513 589 541 587 533 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8988 4504 640 487 562 592 538 590 510 592 538 590 540 588 532 596 514 614 516 1689 562 1668 563 1695 536 1695 566 1664 567 1690 612 1618 643 1430 801 1613 648 481 558 570 540 589 541 587 533 595 535 592 508 594 536 592 538 1667 564 1693 558 1672 569 1688 563 1668 644 1586 563 1694 567 40630 8994 2265 557 96833 8987 2273 538 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 173 7439 171 4922 172 7439 171 4921 172 7466 174 4917 176 4915 173 4918 170 7441 174 7438 192 7445 175 55181 174 7437 173 4918 175 7437 173 4919 175 7463 177 4888 175 4917 176 4915 178 7460 170 7440 175 7437 178 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 1636 4610 1563 1533 1584 7760 1561 28769 1641 4606 1557 1539 1588 7757 1564 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 590 2404 479 1059 968 575 454 544 454 574 454 543 455 543 475 522 476 552 476 552 446 551 447 581 448 520 478 581 447 519 479 549 479 15967 587 2407 476 1062 476 522 995 547 451 1030 508 520 509 550 478 519 479 519 998 1028 999 1057 481 547 960 1066 482 111641 587 2407 476 1063 485 513 994 547 451 1031 507 551 477 551 477 520 478 550 968 1059 968 1027 511 548 959 1036 512 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 588 2406 477 1061 966 577 451 516 482 545 483 545 453 575 443 524 484 514 504 554 454 543 455 543 475 553 445 583 445 521 477 582 446 15969 585 2409 474 1065 483 514 993 549 449 1033 515 543 475 553 475 522 476 552 965 1030 997 576 452 1029 998 1028 479 111668 587 2407 475 1063 485 543 964 517 481 1031 507 552 476 551 477 520 478 550 968 1028 999 574 454 1027 990 1036 481 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 174 7439 196 7441 174 7437 173 7439 171 7441 174 7438 177 7460 170 7442 178 7433 177 4915 173 4918 170 55186 174 7438 172 7440 170 7441 174 7438 177 7461 169 7416 173 7464 176 7435 175 7437 173 4918 175 4917 176 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 173 7438 172 7441 174 7438 177 7434 176 7462 168 7443 177 7435 175 4917 176 4915 173 7438 177 4941 173 55166 174 7438 197 7441 174 7437 173 7439 171 7441 174 7438 177 7460 170 4922 171 4893 195 7443 172 4920 173 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 175 7436 179 4913 175 4917 171 4920 173 4945 169 4896 177 7435 175 7436 174 7464 176 4916 177 4914 169 55180 170 7441 169 4924 169 4922 171 4920 173 4919 174 4917 176 7435 175 7463 177 7434 176 4916 177 4914 174 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 927 827 1709 936 796 932 789 938 793 1717 1736 936 795 932 789 1721 927 827 1709 909 822 90851 898 829 1738 934 798 930 791 936 796 1715 1738 934 797 930 791 1719 899 828 1739 934 797 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 176 5991 177 1372 176 1320 177 1344 173 1349 174 1374 169 1327 170 4449 176 1346 171 1351 177 1345 172 1349 168 1353 175 5963 175 65573 173 5995 178 1344 174 1348 175 1348 174 1347 170 1378 170 1325 172 4447 178 1344 174 1349 169 1353 175 1347 170 1352 176 5961 177 # -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: raw frequency: 38000 duty_cycle: 0.33 data: 2383 609 1214 600 612 580 1213 608 614 583 1210 605 607 586 616 611 1192 599 613 608 614 579 613 615 607 26670 2387 601 1212 600 612 589 1214 603 609 586 1217 595 607 594 618 606 1187 602 610 609 613 588 614 610 612 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 178 7761 176 11308 546 957 540 1958 538 970 537 1955 541 962 545 1953 543 964 543 962 545 957 540 970 548 960 547 1945 541 1950 546 965 542 1953 543 962 545 1945 540 970 537 1958 538 7881 172 7744 172 11318 536 971 536 1956 540 963 534 1964 542 966 541 1951 535 968 539 971 536 971 536 969 538 964 533 1965 541 1954 542 963 534 1956 540 971 536 1959 537 968 539 1951 535 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 3444 1767 413 486 420 1343 419 478 418 485 411 490 416 479 417 489 417 482 414 485 421 482 414 483 413 490 416 485 411 1343 419 487 419 480 416 483 413 490 416 482 414 488 418 483 413 483 413 492 414 1345 417 482 414 489 417 480 416 487 419 482 414 481 415 491 415 484 412 1347 415 488 418 1338 414 1348 414 1347 415 1340 412 494 412 487 419 1340 412 491 415 1341 421 1341 421 1340 412 1343 419 487 419 1339 413 74311 3445 1753 437 461 445 1316 446 456 440 455 441 465 441 458 438 461 445 458 438 460 436 466 440 461 445 451 445 460 446 1313 439 460 446 457 439 459 437 465 441 460 446 450 436 469 437 462 444 456 440 1322 440 457 439 464 442 459 437 459 437 468 438 461 445 455 441 462 444 1312 440 463 443 1317 445 1310 442 1323 439 1320 442 457 439 464 442 1315 437 466 440 1320 442 1313 439 1326 446 1313 439 460 446 1317 445 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 278 1845 274 808 271 806 273 812 278 805 275 805 274 1840 279 1844 275 809 281 1836 272 806 274 812 278 805 274 1842 277 802 277 44956 279 1842 277 804 275 802 277 808 271 811 279 1838 281 798 271 814 276 1844 275 806 273 1841 278 1845 274 1846 273 808 271 1843 276 44959 275 1845 274 807 272 805 275 811 279 804 275 805 274 1839 280 1844 275 808 271 1845 274 805 274 811 279 804 275 1841 278 801 278 44955 280 1841 278 802 277 801 278 807 272 810 280 1837 271 807 272 813 277 1843 276 805 274 1839 280 1843 276 1845 274 807 272 1842 277 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 881 909 1750 928 875 927 876 921 872 929 874 927 876 918 875 930 873 1815 874 924 1745 937 876 88694 880 922 1747 933 880 914 879 926 877 922 871 927 876 927 876 920 873 1818 871 929 1740 934 879 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 509 1717 504 629 512 631 510 627 504 633 508 633 508 1713 508 1719 512 1713 508 625 505 637 504 633 508 629 512 629 512 623 508 1719 512 626 505 628 513 631 510 627 514 623 507 632 509 1713 508 632 509 1716 505 1715 506 1724 507 1716 505 1719 512 1715 506 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 506 493 505 4059 505 5051 501 506 502 4065 499 511 497 4063 501 5058 504 504 504 4060 504 5052 500 507 501 4066 498 5056 506 5042 500 515 503 119614 504 505 503 4065 499 5051 501 511 497 4069 505 499 499 4072 502 5050 502 506 502 4066 498 5053 499 512 506 4060 504 5044 498 5061 501 508 500 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8887 4470 532 1738 513 1708 533 1708 533 577 533 576 534 569 531 582 538 1705 536 571 539 1707 534 571 539 571 539 570 540 1699 532 581 539 568 532 575 535 576 534 571 539 571 539 569 541 1698 533 1717 534 1708 533 1710 531 1716 535 1706 535 1711 540 1705 536 567 533 580 540 567 533 39042 8915 2231 530 94849 8917 2256 535 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8313 4161 515 1574 514 1571 507 569 510 562 507 563 506 562 507 568 511 562 507 1580 508 1577 511 1582 506 567 513 1575 513 554 505 571 509 564 505 22604 513 1573 505 1589 509 563 506 564 505 562 507 569 511 562 507 563 506 1579 509 1584 514 1576 512 558 511 1574 514 562 507 565 515 556 513 22593 514 1581 507 1583 505 564 505 563 506 570 510 563 506 564 505 562 507 1586 512 1578 510 1577 511 557 512 1581 507 566 514 556 513 555 514 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8735 4383 558 573 557 550 560 568 562 544 566 1722 560 540 560 1732 560 544 566 1719 563 1701 560 1723 559 1704 557 574 556 1699 562 574 556 1703 559 1727 565 1698 563 1721 561 546 564 1723 559 541 559 577 564 541 559 571 560 548 562 565 566 1697 565 567 564 1693 558 1733 559 1701 560 39926 8754 2247 565 92341 8758 2243 589 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 3298 3336 821 2506 825 881 820 2505 826 2529 823 856 825 2524 817 866 825 2528 813 2513 818 888 813 862 819 887 814 865 826 2522 820 864 827 2526 815 861 820 887 814 2510 821 885 816 863 818 2531 821 2512 819 2559 793 32401 3298 3349 818 2507 824 882 819 2509 822 2527 814 868 823 2530 821 855 826 2531 821 2504 827 879 822 857 824 875 816 867 824 2529 823 854 827 2530 821 853 817 889 822 2506 825 873 818 866 825 2527 814 2513 818 2564 788 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8840 4439 532 566 534 566 534 1668 532 1674 536 1669 531 562 538 566 534 563 537 1667 533 567 533 563 537 563 537 562 538 1662 538 1671 529 568 532 565 535 566 534 1668 532 1674 536 1669 531 562 538 1672 528 1675 536 1668 532 1675 535 559 531 1676 534 565 535 558 532 1678 532 565 535 562 538 563 537 1665 535 565 535 1670 530 1669 531 572 538 1666 534 1669 531 1676 534 22777 8858 4447 535 92577 8858 4413 538 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 289 2112 261 2109 295 2101 262 918 294 912 259 915 297 2098 265 916 296 909 262 2107 297 905 266 913 289 918 263 910 292 909 262 918 294 24789 263 2106 298 2098 265 2110 294 913 258 916 296 905 266 2108 296 911 260 914 288 2107 266 914 298 908 263 911 291 910 261 919 293 913 258 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8898 4453 569 578 573 577 574 571 570 1745 567 1747 565 1743 569 583 568 579 572 1740 572 1744 568 1742 570 579 572 576 575 568 573 1746 566 1746 566 580 571 1745 567 577 574 576 575 1739 573 569 572 581 570 577 574 1738 574 576 575 1735 567 1748 574 574 567 1742 570 1748 574 1737 575 41005 8876 2261 571 93850 8898 2264 568 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 3215 1637 410 430 405 439 406 1242 408 435 410 1242 408 428 407 440 405 435 410 1240 410 1243 407 431 404 440 405 437 408 1238 402 1254 406 434 401 439 406 438 407 431 404 440 405 437 408 428 407 439 406 434 401 439 406 438 407 1241 409 434 401 441 404 432 403 444 401 1249 401 439 406 438 407 1241 409 434 401 441 404 433 402 444 401 1249 401 439 406 1248 402 436 409 434 401 441 404 433 402 444 401 439 406 45471 3239 1614 403 435 400 444 401 1250 400 437 408 1248 402 438 407 433 402 442 403 1245 405 1248 423 420 405 431 404 443 402 1248 402 1248 422 421 404 435 400 443 402 440 405 431 404 443 402 438 407 433 402 442 403 435 400 443 402 1250 400 436 399 447 408 432 403 438 407 1246 404 434 401 443 402 1250 400 436 399 447 408 432 403 437 408 1246 404 434 401 1253 407 434 401 436 399 447 408 432 403 437 408 436 399 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 7928 3948 504 515 503 518 500 1583 505 516 502 1584 504 510 508 516 502 516 502 3952 510 1579 509 507 501 1587 501 519 510 1571 507 518 500 517 501 517 501 23073 7931 3943 509 514 504 515 503 1578 500 524 505 1580 508 510 508 514 504 511 507 3951 511 1576 502 513 505 1586 502 515 503 1582 506 515 503 513 505 516 502 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8837 4464 538 610 531 619 532 613 538 1748 534 1750 532 611 540 613 538 609 532 615 536 614 537 608 533 1753 539 1745 537 606 535 618 533 614 537 609 532 619 532 613 538 611 540 609 532 611 540 1748 534 1749 533 1750 532 1754 538 1743 539 1747 535 1750 532 1747 535 618 533 613 538 44105 8864 2224 537 93399 8912 2202 538 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 492 4975 496 4993 498 498 500 4056 498 504 494 4055 499 4963 497 532 496 4031 492 4996 495 502 496 4060 494 4972 499 4990 491 506 492 4063 491 511 497 4052 492 4970 490 539 500 4027 496 103358 500 4961 500 4995 496 505 493 4056 498 499 499 4057 497 4969 491 533 496 4026 497 4997 494 508 490 4059 495 4967 494 5001 490 511 497 4053 491 505 493 4063 491 4975 496 528 490 4032 491 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 2357 610 1183 592 1191 614 1179 595 1188 618 584 613 1180 593 588 613 1190 612 590 605 587 613 589 605 587 25398 2355 623 1180 591 1181 627 1186 589 1183 618 584 616 1187 587 584 614 1189 615 587 605 587 615 587 609 593 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 3425 3482 848 2607 846 2639 845 2608 846 2639 845 2612 852 2624 850 2613 851 911 851 885 847 919 843 891 851 915 847 890 852 907 845 897 845 917 845 891 851 915 847 887 845 2639 845 2612 852 2625 849 2613 851 2630 844 34282 3455 3478 852 2601 852 2633 851 2605 848 2629 845 2617 847 2633 851 2604 849 917 845 890 852 913 849 889 843 915 847 896 846 916 846 890 852 914 848 885 847 919 843 895 847 2630 844 2617 847 2634 850 2605 848 2636 848 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 500 500 498 4066 498 5058 504 502 506 4061 503 508 500 4060 504 5055 497 5055 497 511 497 4071 503 5047 505 507 501 4065 499 5049 503 512 496 124314 501 508 500 4067 507 5043 499 513 505 4060 504 501 497 4073 501 5052 500 5052 500 512 496 4066 498 5058 504 506 502 4058 506 5053 499 509 499 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 176 7763 174 8817 169 10842 544 1955 541 967 540 1952 544 959 538 972 546 962 545 1947 538 1952 544 967 540 1955 541 964 543 1947 539 972 546 1949 547 7873 170 7746 170 10350 175 11811 543 960 537 1961 535 972 535 970 537 965 542 1956 540 1956 540 965 542 1947 539 973 534 1960 536 969 538 1952 534 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 2570 2682 1189 1208 1186 2665 1186 1217 1187 2668 1183 1215 1179 2671 1190 2695 1186 1187 1187 2692 1179 2671 1190 1213 1181 1193 1191 1207 1187 2663 1188 1215 1179 2676 1185 46941 2563 2685 1186 1191 1183 2698 1184 1188 1186 2691 1180 1197 1187 2694 1187 2666 1185 1210 1184 2674 1187 2695 1186 1185 1189 1206 1188 1189 1185 2696 1186 1186 1187 2689 1182 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 873 916 1773 906 877 925 878 919 874 928 875 925 878 1806 1770 914 879 1809 870 928 1772 88684 870 926 1774 908 875 926 877 917 876 929 874 925 878 1809 1777 905 877 1808 871 930 1770 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 874 906 877 912 1767 904 879 908 874 918 875 915 878 907 875 920 873 1795 874 914 1775 897 875 88704 879 914 868 922 1767 897 875 919 874 915 878 911 872 920 873 914 879 1792 877 914 1775 889 873 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 3325 1560 406 444 401 453 402 1226 404 449 406 1226 404 443 402 454 401 449 406 1224 406 1228 402 446 409 444 401 451 404 1223 407 1230 410 440 405 445 410 443 402 446 409 444 401 451 404 442 403 453 402 448 407 443 402 451 404 1224 406 448 407 444 401 445 410 446 409 1221 409 442 403 1231 409 439 406 1227 403 450 405 441 404 452 403 1227 403 448 407 446 409 439 406 447 408 444 401 445 400 456 410 440 405 52348 3320 1553 403 445 400 454 401 1230 400 447 408 1228 402 449 406 444 401 452 403 1225 405 1229 431 421 404 442 403 454 401 1229 401 1229 431 423 402 446 399 455 400 451 404 442 403 453 402 448 407 443 402 451 404 444 401 452 403 1229 401 445 400 457 398 451 404 446 399 1235 405 443 402 1232 408 444 401 1225 405 452 403 447 398 452 403 1231 399 449 406 447 408 443 402 444 401 456 399 450 405 445 400 453 402 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 990 915 980 909 986 924 981 2829 981 934 981 2823 987 923 982 2828 982 933 982 906 989 33895 989 907 988 927 988 900 985 2841 979 915 980 2851 980 909 986 2840 980 914 981 934 981 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 821 5754 848 2490 841 2492 819 2524 817 5726 845 2492 839 5727 844 5757 845 5727 854 2483 848 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 5092 1621 406 2599 406 2598 407 2605 1653 1616 411 2619 1609 1606 1654 1618 409 2623 382 2600 405 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8879 4446 566 1747 565 584 567 1744 568 581 570 1744 568 574 567 586 565 582 569 578 563 1753 570 575 566 1749 563 585 566 1743 569 1749 563 1748 564 582 569 1747 565 580 571 578 573 1741 571 572 569 584 567 580 571 1741 571 578 573 1738 564 1751 572 577 564 1744 568 1750 572 1740 572 41007 8906 2257 565 93855 8872 2265 567 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 1144 1010 6795 26754 1151 997 6798 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 1144 1009 1120 1006 1143 1991 1116 26758 1146 1006 1123 1003 1146 1988 1119 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 170 46238 169 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8906 4165 572 1672 569 1678 563 640 572 637 565 643 569 633 569 643 569 1674 567 639 563 1684 567 637 565 1681 570 1675 566 1673 568 1681 570 636 566 640 572 637 565 639 563 1684 567 640 572 630 572 640 572 634 568 1675 566 1681 570 1670 571 638 564 1681 570 1669 572 1678 563 1680 571 40485 8898 2252 570 85621 8955 2194 567 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 446 1191 449 1194 446 1195 445 1204 446 1200 1316 459 447 1193 447 1202 448 1197 443 1201 449 1191 449 34491 443 1204 446 1197 443 1198 442 1207 443 1202 1314 436 440 1201 449 1199 441 1205 445 1198 442 1199 441 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 4268 4327 522 1593 516 1603 516 1597 522 519 520 520 519 515 514 531 518 520 519 519 520 521 518 519 520 1597 522 1595 514 1597 522 1599 520 1595 514 524 515 1604 515 521 518 523 516 524 515 519 520 525 514 524 515 1599 520 522 517 1596 513 1605 514 1602 517 1595 514 1607 522 1592 516 40481 8748 2187 523 93986 8721 2189 521 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 247 3006 244 153 178 1007 251 117 637 597 381 678 218 156 175 529 382 679 217 157 174 24963 247 3038 252 117 219 994 249 119 217 483 250 117 173 531 278 779 173 167 169 569 383 679 217 156 175 126538 246 3039 251 118 218 995 247 120 195 504 249 118 172 532 277 780 172 168 178 560 382 680 216 157 174 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8872 4454 568 579 572 578 573 572 569 581 570 1744 568 575 566 587 564 582 569 1743 569 1747 565 1745 567 1748 564 584 567 1741 571 1747 565 1747 565 1747 565 1751 571 1739 563 1752 570 578 563 1745 567 1751 572 1741 571 575 566 585 566 578 573 577 564 1750 573 571 570 583 568 579 572 41007 8905 2258 574 93846 8871 2266 566 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 4278 4318 521 517 522 520 519 517 522 520 519 521 518 516 513 531 518 520 519 1595 514 1605 514 1599 520 1598 521 1595 513 1598 521 1600 519 1596 513 1602 517 1601 518 1595 514 1604 515 525 514 520 519 526 513 525 514 524 515 527 522 513 516 526 513 1603 516 1595 514 1607 522 1593 516 40481 8749 2186 524 93985 8722 2189 521 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 2746 8423 2744 19607 2746 19601 2742 8431 2745 8424 2742 19608 2745 8419 2747 19608 2745 19607 2746 8422 2744 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 170 6683 174 4889 175 10382 372 849 821 2498 176 10378 264 2479 842 2492 839 2475 846 2483 838 2481 840 2495 836 2477 844 845 846 37009 172 6681 176 4888 175 10381 373 848 924 2395 844 2490 174 10383 248 2492 172 10386 245 2495 169 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8898 4453 569 578 573 577 574 1737 565 584 567 582 569 574 567 1751 572 1741 571 1741 571 1744 568 576 575 1741 571 1743 569 1739 573 579 572 575 566 581 570 580 571 574 567 1748 575 1739 573 570 571 582 569 578 573 1739 573 1742 570 1740 572 577 574 575 566 1742 570 1749 574 1738 574 41006 8875 2262 570 93850 8907 2256 566 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8872 4454 568 1745 567 1749 563 1746 566 584 567 1747 565 1743 569 583 568 579 572 575 566 584 567 578 563 1752 571 578 563 580 571 1747 565 1747 565 581 570 1746 566 578 573 577 564 1751 572 571 570 583 568 579 572 1740 572 578 563 1747 565 1750 573 576 565 1743 569 1749 563 1749 563 41017 8906 2257 565 93855 8872 2265 567 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 179 2644 178 8174 170 2646 176 8181 173 2648 174 8177 177 2640 172 5419 174 5413 170 2649 173 2644 178 2646 176 2646 176 5409 174 28831 174 2651 171 8183 171 2648 174 8174 170 2655 177 8177 177 2642 170 5412 171 5420 173 2649 173 2646 176 2640 172 2653 169 5419 174 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 174 2648 174 8178 176 2640 171 8185 169 2653 169 8182 172 2645 177 2647 557 2264 558 5027 174 5410 173 5418 175 5413 170 28837 168 2649 173 8184 170 2652 170 8181 173 2643 169 8188 176 2646 176 2643 168 2648 174 5417 176 5411 172 5413 170 5413 170 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 178 706 266 139 268 137 173 173 198 234 178 126768 175 299 169 86 275 130 267 138 172 230 177 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 554 1922 584 3809 582 3782 578 3821 580 1920 555 1941 544 1922 574 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 476 1470 465 3479 474 3469 474 3477 475 1467 468 1471 474 27473 472 1474 472 3475 467 3478 475 3468 474 1471 475 1468 467 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 301 2188 236 2169 235 2205 230 1009 234 1070 183 1064 179 2198 206 1046 207 1069 173 2207 207 1042 211 1062 201 1043 210 1032 231 1005 237 1039 234 1006 236 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8872 4453 570 1744 568 582 569 1741 571 1744 568 580 571 1738 564 1754 569 578 563 584 567 1749 563 581 570 580 571 1743 569 573 568 585 566 1746 566 580 571 580 571 1739 563 586 565 1749 563 579 572 582 569 577 564 1748 564 1752 571 574 567 1748 564 584 567 1742 570 1748 564 1747 565 41015 8898 2265 567 93853 8875 2262 570 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8904 4446 576 572 569 581 570 575 566 584 567 582 569 1739 573 579 572 575 566 1746 566 1750 572 1738 574 1741 571 1742 570 573 568 1750 572 1740 572 1740 572 578 573 572 569 581 570 1744 568 574 567 586 575 572 569 578 573 1742 570 1740 572 1743 569 579 572 1737 565 1753 570 1743 569 41010 8881 2257 565 93855 8903 2259 573 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8878 4448 564 584 567 583 568 577 564 586 565 584 567 1741 571 582 569 1743 569 1743 569 1746 566 1744 568 1747 565 1749 563 579 572 1747 565 581 570 1743 569 1746 566 578 573 1743 569 579 572 571 570 583 568 579 572 575 566 584 567 1743 569 581 570 1744 568 1740 572 1746 566 1746 566 41013 8898 2264 568 93853 8872 2265 567 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8900 4450 572 575 566 585 566 578 573 1743 569 579 572 1736 566 587 574 572 569 1743 569 1747 565 1745 567 582 569 1745 567 575 566 1753 570 1742 570 1742 570 1746 566 578 573 1742 570 578 573 570 571 582 569 578 573 574 567 583 568 1742 570 579 572 1742 570 1738 574 1744 568 1744 568 41012 8871 2266 566 93855 8903 2258 574 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8872 4454 568 1745 567 1749 563 1747 565 1750 562 1752 571 1737 565 1754 568 1743 569 578 563 587 564 581 570 580 571 577 564 579 572 581 570 576 565 1748 564 1751 572 1739 563 1752 571 1743 569 1739 563 590 571 575 566 581 570 580 571 574 567 583 568 580 571 572 569 1750 562 1749 563 41017 8905 2257 575 93846 8871 2266 566 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 176 7764 173 11361 544 1951 545 1948 176 8815 171 2319 177 2322 174 2321 175 2318 178 2313 173 18281 170 7746 170 11369 536 1954 542 1957 539 969 538 1954 542 1949 536 1962 534 1960 174 2320 176 2315 170 2328 178 2317 168 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 172 23035 176 2267 178 2285 170 2270 175 2288 177 11602 222 2218 216 2246 173 183 173 935 221 218 174 864 221 1250 171 1310 223 2219 216 2247 218 1244 223 216 176 869 170 1296 217 2239 216 1254 223 216 176 866 219 9127 169 7642 173 2284 171 2273 172 2290 175 2263 171 10143 178 10623 222 1245 222 217 175 1843 220 2226 219 1264 223 1237 174 183 178 952 219 2222 223 216 176 866 219 1249 172 9190 173 7637 178 2266 169 2286 169 2280 175 2284 171 10125 175 10622 224 215 177 868 216 2228 217 2238 171 1299 224 215 177 865 174 183 173 934 222 216 176 1848 215 1247 220 1265 222 762 170 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 7410 1482 382 2742 375 2747 380 2751 1630 1535 400 2724 1657 1529 1629 1538 407 2720 407 2716 401 2722 4125 1549 376 2751 376 2748 379 2744 1626 1541 405 2723 1658 1530 1628 1531 404 2726 401 2726 401 2723 4124 1542 383 2747 380 2747 380 2745 1626 1534 401 2729 1652 1539 1629 1532 403 2719 408 2722 405 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 4277 4319 520 518 521 521 518 518 521 1597 522 1594 515 1597 522 1599 520 1594 515 1600 519 1600 519 1594 515 526 513 527 522 512 517 528 521 517 522 516 513 1605 514 522 517 525 514 525 514 521 518 526 513 525 514 1600 519 523 516 1597 522 1596 513 1603 516 1595 514 1607 522 1593 516 40481 8749 2186 524 93986 8721 2188 522 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 1325 431 445 1199 1317 455 441 1207 443 1202 1294 457 449 1190 440 1209 441 1205 445 1198 1318 454 442 93237 1320 434 442 1201 1325 448 448 1200 440 1205 1291 460 446 1193 447 1202 448 1198 442 1201 1325 447 449 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8876 4450 572 575 566 585 566 578 573 577 564 585 566 577 564 589 572 574 567 1745 567 1749 563 1747 565 1750 562 1751 571 1737 565 1754 569 1743 569 1743 569 1747 565 579 572 1743 569 579 572 571 570 583 568 579 572 575 566 584 567 1743 569 581 570 1744 568 1740 572 1746 566 1746 566 41013 8898 2265 567 93853 8873 2264 568 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 300 1791 297 744 295 743 296 751 298 745 294 747 302 736 293 1837 271 745 294 747 302 1793 295 752 297 1802 296 1801 297 742 297 1806 302 31592 296 1801 297 742 297 749 300 744 295 745 294 745 294 752 297 1829 269 746 293 745 294 1809 300 744 295 1802 296 1799 299 748 301 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 178 2003 177 2899 177 1996 174 2908 168 2910 177 2000 170 2004 176 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8898 4173 564 642 570 1677 564 1677 564 645 567 640 572 631 571 641 571 635 567 639 563 1683 568 1673 568 641 571 636 566 637 565 647 565 641 571 634 568 642 570 1671 570 639 563 1682 569 632 570 643 569 636 566 1677 564 1683 568 636 566 1680 571 636 566 1674 567 1682 569 1674 567 40489 8904 2246 566 85626 8902 2248 564 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8897 4454 569 578 573 1743 569 576 565 1750 572 576 575 1733 569 584 567 1745 567 1745 567 583 568 1742 570 579 572 1742 570 573 568 1750 573 574 567 580 571 580 571 573 568 582 569 580 571 572 569 584 567 1744 568 1744 568 1748 575 1735 567 1749 574 1740 572 1736 566 1752 571 576 575 41005 8878 2259 563 93858 8901 2260 572 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8880 4446 566 1747 565 585 566 578 573 577 564 1750 573 571 570 1748 564 582 569 578 573 1743 569 1741 571 1744 568 580 571 1737 565 588 563 1749 563 583 568 582 569 576 565 1750 573 576 565 578 573 580 571 576 565 1747 565 1751 571 1738 564 586 565 1749 563 1745 567 1751 572 1741 571 41008 8905 2258 574 93846 8871 2266 566 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 3892 3856 525 978 529 977 530 969 528 977 530 974 523 975 532 1924 531 971 526 1924 531 975 532 1916 529 976 531 1921 524 1947 508 1925 530 1920 525 1926 529 1925 530 970 527 1927 528 976 531 1915 530 978 529 1921 1033 9201 3871 3867 524 977 530 975 522 981 526 972 525 983 524 978 529 1921 524 982 525 1923 532 973 524 1928 527 971 526 1931 524 1950 505 1922 523 1931 524 1924 531 1923 532 972 525 1922 523 985 533 1918 527 975 532 1922 1032 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8900 4451 571 576 575 1742 570 1739 573 1742 570 578 573 1736 566 1752 570 576 575 1737 575 575 566 579 572 578 573 1741 571 571 570 583 568 1745 567 579 572 578 573 1738 574 575 566 1748 575 568 573 581 570 576 575 1737 565 1751 572 573 568 1747 576 573 568 1741 571 1747 565 1747 565 41014 8878 2260 562 93858 8901 2261 571 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 875 904 1745 924 879 913 880 1786 873 919 874 917 1742 922 871 1802 877 912 1747 921 872 88714 880 907 1742 930 873 917 876 1788 871 924 879 910 1749 919 874 1798 871 916 1743 928 875 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 4758 1543 403 2731 407 2726 402 2739 1601 1514 401 2760 1580 1530 1577 1540 406 2758 400 2708 1602 1535 400 2740 408 2729 409 2726 401 2731 1599 1520 405 2758 1572 1540 1578 1532 403 2737 431 2706 1604 1535 411 2722 405 2734 403 2734 404 2731 1599 1512 403 2764 1576 1539 1578 1533 402 2730 428 2712 1608 1534 402 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8873 4453 570 578 563 1753 570 575 566 1749 563 585 566 1742 570 583 568 1744 568 1744 568 582 569 1741 571 578 573 1741 571 572 569 1749 563 583 568 1745 567 1748 564 1746 566 583 568 581 570 1738 564 589 572 1740 572 574 567 584 567 577 564 1752 571 1743 569 573 568 1751 572 575 566 41014 8900 2263 569 93851 8878 2259 563 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 171 313 176 798 337 133 600 232 170 126777 176 65 169 496 176 200 609 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 500 527 491 4033 500 4986 495 510 498 4054 500 499 499 4048 496 4974 497 530 499 4026 497 4989 492 513 495 4057 497 4967 493 4992 499 506 492 4060 494 505 493 4054 500 98563 497 529 500 4025 498 4988 493 512 496 4056 498 501 497 4050 493 4976 495 532 497 4028 495 4991 500 505 493 4059 495 4969 491 4994 497 508 490 4062 492 507 491 4056 498 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 879 901 871 1796 1770 903 869 917 876 916 877 913 880 906 877 918 875 914 879 1788 1768 1784 875 87826 871 921 872 1797 1769 897 875 919 874 915 878 910 873 920 873 914 879 913 870 1800 1776 1767 871 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 874 905 1774 894 878 914 879 908 875 917 876 915 878 907 876 919 874 1793 876 913 1777 895 878 88703 872 920 1769 901 872 913 870 925 878 910 873 916 877 916 877 910 873 1798 871 919 1770 894 878 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 3339 1714 415 445 420 1283 418 440 415 448 418 444 422 435 420 446 420 440 415 445 421 443 412 445 421 443 412 449 416 1279 412 455 421 439 416 443 412 452 414 444 411 452 414 1287 414 442 413 453 413 1287 414 446 419 444 422 437 418 445 421 441 414 442 413 452 414 447 419 1281 420 443 412 1285 416 1287 414 1287 414 1282 419 447 419 441 414 1286 415 448 418 1280 421 1282 419 443 412 1283 418 448 418 1283 418 73871 3336 1694 414 444 411 1291 410 452 414 442 413 453 413 448 418 442 413 450 416 443 412 450 416 447 419 437 418 448 418 1282 419 441 414 449 417 442 413 449 417 446 420 436 419 1287 414 446 420 440 415 1288 413 445 410 453 413 449 417 439 416 450 416 445 421 439 416 447 419 1279 412 451 415 1287 414 1282 419 1287 414 1285 416 444 411 453 413 1285 416 447 419 1283 418 1278 413 453 413 1287 414 446 419 1284 417 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 4411 4332 558 1660 561 596 565 612 559 597 564 617 565 585 566 620 561 591 560 620 561 595 566 611 560 597 564 1653 558 592 559 627 565 589 562 617 564 1630 560 617 564 592 559 22591 4439 4322 558 1639 561 618 563 590 561 622 560 592 559 624 557 597 564 612 559 600 561 618 563 590 561 622 559 1628 562 621 561 594 567 609 562 597 564 1652 559 595 566 617 564 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 3444 1767 413 487 419 1274 417 481 415 1277 414 488 418 1267 414 492 414 1276 415 484 412 1282 419 478 418 1275 416 1276 415 480 416 1280 421 479 417 1272 419 1275 416 1272 419 1274 417 484 412 484 412 493 413 1277 414 485 421 1273 418 479 417 486 420 1271 420 476 420 486 420 479 417 482 414 1280 411 1276 415 488 418 1273 418 478 418 488 418 481 415 1275 416 487 419 478 418 485 411 1280 421 475 421 1275 416 1273 418 69071 3439 1759 441 456 440 1253 438 463 443 1243 438 468 438 1251 440 460 446 1247 444 454 442 1251 440 461 445 1241 440 1256 445 455 441 1248 443 461 445 1242 439 1254 447 1245 446 1240 441 465 441 458 438 462 444 1249 442 456 440 1252 439 463 443 452 444 1252 439 461 445 454 442 461 445 452 444 1249 442 1250 441 454 442 1254 437 463 443 456 440 463 443 1245 446 456 440 462 444 451 445 1251 440 460 436 1253 438 1256 445 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8705 4317 583 682 581 688 585 678 585 1721 581 1722 580 681 582 690 583 682 581 1721 581 1725 587 1713 579 689 584 683 580 1718 584 1724 588 1714 588 677 586 683 580 683 580 1726 586 680 583 678 585 687 586 679 584 1718 584 1721 581 1719 583 685 588 1716 586 1713 579 1729 583 1719 583 41145 8706 2217 585 94686 8705 2217 584 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8888 4470 532 576 534 576 534 571 539 572 538 1706 535 568 532 581 529 578 532 1711 530 581 529 1711 530 1717 534 574 536 1703 538 575 535 572 538 1705 536 1711 530 1711 530 1716 535 1709 532 571 529 585 535 571 529 579 531 579 531 574 536 574 536 573 537 1701 530 1720 531 1712 529 39045 8912 2261 540 94838 8911 2235 536 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 874 915 1774 904 879 923 870 1816 1770 1800 1776 904 879 1805 874 931 1769 909 874 88698 876 927 1773 904 879 922 871 1819 1767 1796 1770 914 879 1809 870 928 1772 910 873 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 178 7753 174 2308 178 2284 171 2316 170 2298 177 10228 174 10724 223 1256 221 217 175 1868 169 2293 172 1327 216 1263 178 1316 217 2245 220 218 174 887 218 1261 170 10707 174 7752 175 2296 169 2314 171 2293 172 2307 179 10216 176 6265 174 10729 219 1258 219 1272 215 1268 173 2310 221 1255 222 217 175 877 172 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 532 1692 559 561 529 574 567 559 531 566 564 555 535 1694 557 568 532 1691 560 560 530 573 557 568 532 565 565 555 535 567 563 1688 533 564 567 554 536 567 563 562 538 558 562 558 532 1697 565 561 539 1683 558 1689 532 1697 564 1687 534 1689 562 1684 537 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 874 915 1774 904 879 923 870 927 876 1814 876 925 1775 900 872 1821 879 920 1769 909 874 88702 871 926 1774 907 876 925 878 917 876 1817 873 927 1773 905 878 1813 876 921 1769 912 871 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8884 4474 538 569 531 1716 535 570 530 580 530 1715 536 567 533 580 530 577 533 1710 531 1715 536 1705 536 1710 531 1714 537 1702 529 1720 531 1712 529 578 532 1715 536 1705 536 1710 531 577 533 570 530 584 536 571 529 1714 537 573 537 568 532 578 532 1713 538 1701 530 1719 532 1711 530 39044 8913 2260 531 94848 8907 2239 532 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 446 1694 455 1706 453 1705 424 628 452 597 452 622 458 1673 456 625 455 594 455 1706 454 590 459 621 459 591 458 616 453 591 458 622 539 22750 459 1675 454 1733 427 1712 427 622 458 588 451 622 458 1681 458 618 451 595 454 1705 455 598 451 625 454 592 457 616 453 598 451 626 535 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 3429 3445 875 2555 868 875 867 871 871 2560 873 868 874 2551 872 874 868 871 871 869 873 870 872 865 867 2565 868 873 869 2556 867 2567 866 874 868 2560 873 870 872 2555 868 2564 869 2586 847 2577 846 2589 844 870 872 32983 3470 3430 869 2559 874 868 874 867 875 2550 873 873 869 2559 874 865 867 877 875 862 870 873 869 872 870 2555 868 877 875 2554 869 2559 874 869 873 2554 869 873 869 2562 871 2553 870 2590 843 2586 847 2581 842 876 866 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8873 4452 571 1743 569 580 571 574 567 583 568 1746 566 1742 570 1748 564 582 569 578 563 1753 570 1740 572 1743 569 579 572 571 570 583 568 1744 568 579 572 578 573 572 569 1746 566 582 569 574 567 586 565 582 569 1743 569 1746 566 1744 568 581 570 1745 567 1741 571 1747 565 1746 566 41014 8898 2264 568 93853 8874 2263 569 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8902 4448 574 1739 573 1742 570 575 566 584 567 581 570 573 568 585 566 1746 566 580 571 580 571 1739 573 1742 570 1743 569 1739 573 1745 567 579 572 1741 571 1744 568 1742 570 1745 567 1747 565 1743 569 1749 573 1739 573 573 568 583 568 576 575 575 566 583 568 575 566 587 574 572 569 41011 8871 2266 566 93854 8902 2260 572 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 4275 4320 519 520 519 523 516 520 519 1599 520 520 519 515 524 521 518 520 519 1595 524 1595 524 1588 520 521 518 1599 520 1591 517 1603 516 1599 520 1595 524 1594 525 1588 521 1597 522 518 521 513 526 519 520 518 521 517 522 520 519 517 522 519 520 1597 522 1589 519 1601 518 1597 522 40475 8724 2186 514 93995 8752 2183 516 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 10380 4892 599 620 592 605 597 620 592 604 598 623 589 2081 598 627 595 2080 599 2101 598 2105 574 2099 590 2088 591 2111 599 591 590 2116 594 599 593 626 596 2082 597 619 593 2086 593 626 596 594 598 627 595 598 594 2106 593 604 598 2100 589 607 595 2107 593 2079 590 2116 594 2082 750 41149 8722 2109 590 94682 8727 2104 596 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 8879 4446 566 1747 565 1751 571 573 568 582 569 580 571 571 570 584 567 1744 568 579 572 578 573 1737 565 1751 572 1742 570 1738 564 1754 568 578 573 574 567 584 567 577 564 1752 571 577 564 580 571 582 569 577 564 1748 564 1752 571 1739 563 587 564 1750 572 1736 566 1752 571 1742 570 41009 8903 2260 572 93848 8880 2257 565 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 data: 4271 4324 515 1600 519 1600 519 1594 515 1603 516 1601 518 1593 516 1605 514 1601 518 520 519 522 517 520 519 522 517 523 516 518 521 523 516 522 517 1598 521 1597 522 1591 518 1600 519 521 518 516 523 522 517 521 518 520 519 523 516 520 519 522 517 1599 520 1591 518 1603 516 1599 520 40477 8753 2183 516 93993 8724 2185 515 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.33 diff --git a/documentation/UniversalRemotes.md b/documentation/UniversalRemotes.md index 0a833727..186a0e65 100644 --- a/documentation/UniversalRemotes.md +++ b/documentation/UniversalRemotes.md @@ -1,7 +1,19 @@ # Universal Remotes +## Televisions +Adding your TV set to the universal remote is quite straightforward. Up to 6 signals can be recorded: `Power`, `Mute`, `Vol_up`, `Vol_dn`, `Ch_next`, `Ch_prev`. Any of them can be omitted if not supported by the TV. + +Each signal is recorded using the following algorithm: +1. Get the remote and point it to Flipper's IR receiver. +2. Start learning a new remote if it's the first button or press `+` to add a new button otherwise. +3. Press a remote button and save it under a corresponding name. +4. Repeat steps 2-3 until all required signals are saved. + +The signal names are self-explanatory. Don't forget to make sure that every recorded signal does what it's supposed to. + +If everything checks out, append these signals **to the end** of the [TV universal remote file](/assets/resources/infrared/assets/tv.ir). + ## Audio Players -### Recording signals -Adding your audio player to the universal remote is quite straightforward. 8 signals can be recorded: `Power`, `Play`, `Pause`, `Vol_up`, `Vol_dn`, `Next`, `Prev`, `Mute`. Any of them can be omitted if it is not supported by the device. +Adding your audio player to the universal remote is done in the same manner as described above. Up to 8 signals can be recorded: `Power`, `Play`, `Pause`, `Vol_up`, `Vol_dn`, `Next`, `Prev`, `Mute`. Any of them can be omitted if not supported by the player. The signal names are self-explanatory. On many remotes, the `Play` button doubles as `Pause`. In this case record it as `Play` omitting the `Pause`. @@ -9,12 +21,7 @@ Make sure that every signal does what it's supposed to. If everything checks out, append these signals **to the end** of the [Audio players universal remote file](/assets/resources/infrared/assets/audio.ir). -The order of signals is not important, but they must be preceded by a following comment: `# Model: ` in order to keep the library organised. - -When done, open a pull request containing the changed file. - ## Air Conditioners -### Recording signals Air conditioners differ from most other infrared-controlled devices because their state is tracked by the remote. The majority of A/C remotes have a small display which shows current mode, temperature and other settings. When the user presses a button, a whole set of parameters is transmitted to the device, which must be recorded and used as a whole. @@ -49,6 +56,7 @@ Test the file against the actual device. Make sure that every signal does what i If everything checks out, append these signals **to the end** of the [A/C universal remote file](/assets/resources/infrared/assets/ac.ir). +## Final steps The order of signals is not important, but they must be preceded by a following comment: `# Model: ` in order to keep the library organised. When done, open a pull request containing the changed file. From 0261dc30759d56a54e29e57d3a5edfa54f1913c3 Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Tue, 29 Nov 2022 12:08:08 +0300 Subject: [PATCH 21/25] [FL-2957] Unified Info API, App Error, Data Xchange (#1998) * Update protobuf definitions * Add Property subsystem entry point function * Key-based system info and power info function stubs * Remove unneeded functions * Working power info * Working system info * Replace #defines with string literals * Remove unneeded field * Simplify system info formatting * Refactor output callback handling * Handle the last info element correctly * Optimise power info, rename methods * Add comments * Add power debug * Remove unneeded definitions * Rename some files and functions * Update protobuf definitions * Implement App GetError and DataExchange APIs * Send GetErrorReply with correct command_id * Add RPC debug app stub * Add more scenes * Add warning, increase stack size * Add receive data exchange scene * Improve data exchange * Add notifications * Update application requirements * Bump format version for property-based infos * Correctly reset error text * RCP: sync protobuf repo to latest release tag Co-authored-by: Aleksandr Kutuzov --- .../debug/rpc_debug_app/application.fam | 10 + .../debug/rpc_debug_app/rpc_debug_app.c | 138 ++++++++ .../debug/rpc_debug_app/rpc_debug_app.h | 54 ++++ .../scenes/rpc_debug_app_scene.c | 30 ++ .../scenes/rpc_debug_app_scene.h | 29 ++ .../scenes/rpc_debug_app_scene_config.h | 8 + .../rpc_debug_app_scene_input_data_exchange.c | 40 +++ .../rpc_debug_app_scene_input_error_code.c | 60 ++++ .../rpc_debug_app_scene_input_error_text.c | 40 +++ ...pc_debug_app_scene_receive_data_exchange.c | 70 ++++ .../scenes/rpc_debug_app_scene_start.c | 57 ++++ .../scenes/rpc_debug_app_scene_start_dummy.c | 30 ++ .../rpc_debug_app_scene_test_app_error.c | 57 ++++ .../rpc_debug_app_scene_test_data_exchange.c | 58 ++++ applications/services/cli/cli_commands.c | 2 +- applications/services/power/power_cli.c | 6 +- applications/services/rpc/rpc.c | 7 +- applications/services/rpc/rpc_app.c | 120 +++++++ applications/services/rpc/rpc_app.h | 13 + applications/services/rpc/rpc_i.h | 1 + applications/services/rpc/rpc_property.c | 107 ++++++ applications/services/rpc/rpc_system.c | 4 +- assets/protobuf | 2 +- firmware/targets/f7/api_symbols.csv | 13 +- firmware/targets/f7/furi_hal/furi_hal_info.c | 299 ++++++++++++----- firmware/targets/f7/furi_hal/furi_hal_power.c | 306 ++++++++++++------ .../targets/furi_hal_include/furi_hal_info.h | 15 +- .../targets/furi_hal_include/furi_hal_power.h | 26 +- lib/toolbox/property.c | 33 ++ lib/toolbox/property.h | 39 +++ 30 files changed, 1452 insertions(+), 222 deletions(-) create mode 100644 applications/debug/rpc_debug_app/application.fam create mode 100644 applications/debug/rpc_debug_app/rpc_debug_app.c create mode 100644 applications/debug/rpc_debug_app/rpc_debug_app.h create mode 100644 applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene.c create mode 100644 applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene.h create mode 100644 applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_config.h create mode 100644 applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_input_data_exchange.c create mode 100644 applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_input_error_code.c create mode 100644 applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_input_error_text.c create mode 100644 applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_receive_data_exchange.c create mode 100644 applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_start.c create mode 100644 applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_start_dummy.c create mode 100644 applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_test_app_error.c create mode 100644 applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_test_data_exchange.c create mode 100644 applications/services/rpc/rpc_property.c create mode 100644 lib/toolbox/property.c create mode 100644 lib/toolbox/property.h diff --git a/applications/debug/rpc_debug_app/application.fam b/applications/debug/rpc_debug_app/application.fam new file mode 100644 index 00000000..d71065af --- /dev/null +++ b/applications/debug/rpc_debug_app/application.fam @@ -0,0 +1,10 @@ +App( + appid="rpc_debug", + name="RPC Debug", + apptype=FlipperAppType.DEBUG, + entry_point="rpc_debug_app", + requires=["gui", "rpc_start", "notification"], + stack_size=2 * 1024, + order=10, + fap_category="Debug", +) diff --git a/applications/debug/rpc_debug_app/rpc_debug_app.c b/applications/debug/rpc_debug_app/rpc_debug_app.c new file mode 100644 index 00000000..314be5e7 --- /dev/null +++ b/applications/debug/rpc_debug_app/rpc_debug_app.c @@ -0,0 +1,138 @@ +#include "rpc_debug_app.h" +#include + +#include + +static bool rpc_debug_app_custom_event_callback(void* context, uint32_t event) { + furi_assert(context); + RpcDebugApp* app = context; + return scene_manager_handle_custom_event(app->scene_manager, event); +} + +static bool rpc_debug_app_back_event_callback(void* context) { + furi_assert(context); + RpcDebugApp* app = context; + return scene_manager_handle_back_event(app->scene_manager); +} + +static void rpc_debug_app_tick_event_callback(void* context) { + furi_assert(context); + RpcDebugApp* app = context; + scene_manager_handle_tick_event(app->scene_manager); +} + +static void rpc_debug_app_rpc_command_callback(RpcAppSystemEvent event, void* context) { + furi_assert(context); + RpcDebugApp* app = context; + furi_assert(app->rpc); + + if(event == RpcAppEventSessionClose) { + scene_manager_stop(app->scene_manager); + view_dispatcher_stop(app->view_dispatcher); + rpc_system_app_set_callback(app->rpc, NULL, NULL); + app->rpc = NULL; + } else if(event == RpcAppEventAppExit) { + scene_manager_stop(app->scene_manager); + view_dispatcher_stop(app->view_dispatcher); + rpc_system_app_confirm(app->rpc, RpcAppEventAppExit, true); + } else { + rpc_system_app_confirm(app->rpc, event, false); + } +} + +static bool rpc_debug_app_rpc_init_rpc(RpcDebugApp* app, const char* args) { + bool ret = false; + if(args && strlen(args)) { + uint32_t rpc = 0; + if(sscanf(args, "RPC %lX", &rpc) == 1) { + app->rpc = (RpcAppSystem*)rpc; + rpc_system_app_set_callback(app->rpc, rpc_debug_app_rpc_command_callback, app); + rpc_system_app_send_started(app->rpc); + ret = true; + } + } + return ret; +} + +static RpcDebugApp* rpc_debug_app_alloc() { + RpcDebugApp* app = malloc(sizeof(RpcDebugApp)); + + app->gui = furi_record_open(RECORD_GUI); + app->notifications = furi_record_open(RECORD_NOTIFICATION); + app->scene_manager = scene_manager_alloc(&rpc_debug_app_scene_handlers, app); + app->view_dispatcher = view_dispatcher_alloc(); + + view_dispatcher_set_event_callback_context(app->view_dispatcher, app); + view_dispatcher_set_custom_event_callback( + app->view_dispatcher, rpc_debug_app_custom_event_callback); + view_dispatcher_set_navigation_event_callback( + app->view_dispatcher, rpc_debug_app_back_event_callback); + view_dispatcher_set_tick_event_callback( + app->view_dispatcher, rpc_debug_app_tick_event_callback, 100); + view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); + view_dispatcher_enable_queue(app->view_dispatcher); + + app->widget = widget_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, RpcDebugAppViewWidget, widget_get_view(app->widget)); + app->submenu = submenu_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, RpcDebugAppViewSubmenu, submenu_get_view(app->submenu)); + app->text_box = text_box_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, RpcDebugAppViewTextBox, text_box_get_view(app->text_box)); + app->text_input = text_input_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, RpcDebugAppViewTextInput, text_input_get_view(app->text_input)); + app->byte_input = byte_input_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, RpcDebugAppViewByteInput, byte_input_get_view(app->byte_input)); + + return app; +} + +static void rpc_debug_app_free(RpcDebugApp* app) { + view_dispatcher_remove_view(app->view_dispatcher, RpcDebugAppViewByteInput); + view_dispatcher_remove_view(app->view_dispatcher, RpcDebugAppViewTextInput); + view_dispatcher_remove_view(app->view_dispatcher, RpcDebugAppViewTextBox); + view_dispatcher_remove_view(app->view_dispatcher, RpcDebugAppViewSubmenu); + view_dispatcher_remove_view(app->view_dispatcher, RpcDebugAppViewWidget); + + free(app->byte_input); + free(app->text_input); + free(app->text_box); + free(app->submenu); + free(app->widget); + + free(app->scene_manager); + free(app->view_dispatcher); + + furi_record_close(RECORD_NOTIFICATION); + app->notifications = NULL; + furi_record_close(RECORD_GUI); + app->gui = NULL; + + if(app->rpc) { + rpc_system_app_set_callback(app->rpc, NULL, NULL); + rpc_system_app_send_exited(app->rpc); + app->rpc = NULL; + } + + free(app); +} + +int32_t rpc_debug_app(void* args) { + RpcDebugApp* app = rpc_debug_app_alloc(); + + if(rpc_debug_app_rpc_init_rpc(app, args)) { + notification_message(app->notifications, &sequence_display_backlight_on); + scene_manager_next_scene(app->scene_manager, RpcDebugAppSceneStart); + } else { + scene_manager_next_scene(app->scene_manager, RpcDebugAppSceneStartDummy); + } + + view_dispatcher_run(app->view_dispatcher); + + rpc_debug_app_free(app); + return 0; +} diff --git a/applications/debug/rpc_debug_app/rpc_debug_app.h b/applications/debug/rpc_debug_app/rpc_debug_app.h new file mode 100644 index 00000000..100fc124 --- /dev/null +++ b/applications/debug/rpc_debug_app/rpc_debug_app.h @@ -0,0 +1,54 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "scenes/rpc_debug_app_scene.h" + +#define DATA_STORE_SIZE 64U +#define TEXT_STORE_SIZE 64U + +typedef struct { + Gui* gui; + RpcAppSystem* rpc; + SceneManager* scene_manager; + ViewDispatcher* view_dispatcher; + NotificationApp* notifications; + + Widget* widget; + Submenu* submenu; + TextBox* text_box; + TextInput* text_input; + ByteInput* byte_input; + + char text_store[TEXT_STORE_SIZE]; + uint8_t data_store[DATA_STORE_SIZE]; +} RpcDebugApp; + +typedef enum { + RpcDebugAppViewWidget, + RpcDebugAppViewSubmenu, + RpcDebugAppViewTextBox, + RpcDebugAppViewTextInput, + RpcDebugAppViewByteInput, +} RpcDebugAppView; + +typedef enum { + // Reserve first 100 events for button types and indexes, starting from 0 + RpcDebugAppCustomEventInputErrorCode = 100, + RpcDebugAppCustomEventInputErrorText, + RpcDebugAppCustomEventInputDataExchange, + RpcDebugAppCustomEventRpcDataExchange, +} RpcDebugAppCustomEvent; diff --git a/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene.c b/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene.c new file mode 100644 index 00000000..2c593cde --- /dev/null +++ b/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene.c @@ -0,0 +1,30 @@ +#include "rpc_debug_app_scene.h" + +// Generate scene on_enter handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, +void (*const rpc_debug_app_on_enter_handlers[])(void*) = { +#include "rpc_debug_app_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 rpc_debug_app_on_event_handlers[])(void* context, SceneManagerEvent event) = { +#include "rpc_debug_app_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 rpc_debug_app_on_exit_handlers[])(void* context) = { +#include "rpc_debug_app_scene_config.h" +}; +#undef ADD_SCENE + +// Initialize scene handlers configuration structure +const SceneManagerHandlers rpc_debug_app_scene_handlers = { + .on_enter_handlers = rpc_debug_app_on_enter_handlers, + .on_event_handlers = rpc_debug_app_on_event_handlers, + .on_exit_handlers = rpc_debug_app_on_exit_handlers, + .scene_num = RpcDebugAppSceneNum, +}; diff --git a/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene.h b/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene.h new file mode 100644 index 00000000..eb3424fb --- /dev/null +++ b/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +// Generate scene id and total number +#define ADD_SCENE(prefix, name, id) RpcDebugAppScene##id, +typedef enum { +#include "rpc_debug_app_scene_config.h" + RpcDebugAppSceneNum, +} RpcDebugAppScene; +#undef ADD_SCENE + +extern const SceneManagerHandlers rpc_debug_app_scene_handlers; + +// Generate scene on_enter handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); +#include "rpc_debug_app_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 "rpc_debug_app_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 "rpc_debug_app_scene_config.h" +#undef ADD_SCENE diff --git a/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_config.h b/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_config.h new file mode 100644 index 00000000..8f163253 --- /dev/null +++ b/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_config.h @@ -0,0 +1,8 @@ +ADD_SCENE(rpc_debug_app, start, Start) +ADD_SCENE(rpc_debug_app, start_dummy, StartDummy) +ADD_SCENE(rpc_debug_app, test_app_error, TestAppError) +ADD_SCENE(rpc_debug_app, test_data_exchange, TestDataExchange) +ADD_SCENE(rpc_debug_app, input_error_code, InputErrorCode) +ADD_SCENE(rpc_debug_app, input_error_text, InputErrorText) +ADD_SCENE(rpc_debug_app, input_data_exchange, InputDataExchange) +ADD_SCENE(rpc_debug_app, receive_data_exchange, ReceiveDataExchange) diff --git a/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_input_data_exchange.c b/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_input_data_exchange.c new file mode 100644 index 00000000..3ae2ba44 --- /dev/null +++ b/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_input_data_exchange.c @@ -0,0 +1,40 @@ +#include "../rpc_debug_app.h" + +static void rpc_debug_app_scene_input_data_exchange_result_callback(void* context) { + RpcDebugApp* app = context; + view_dispatcher_send_custom_event( + app->view_dispatcher, RpcDebugAppCustomEventInputDataExchange); +} + +void rpc_debug_app_scene_input_data_exchange_on_enter(void* context) { + RpcDebugApp* app = context; + byte_input_set_header_text(app->byte_input, "Enter data to exchange"); + byte_input_set_result_callback( + app->byte_input, + rpc_debug_app_scene_input_data_exchange_result_callback, + NULL, + app, + app->data_store, + DATA_STORE_SIZE); + view_dispatcher_switch_to_view(app->view_dispatcher, RpcDebugAppViewByteInput); +} + +bool rpc_debug_app_scene_input_data_exchange_on_event(void* context, SceneManagerEvent event) { + RpcDebugApp* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == RpcDebugAppCustomEventInputDataExchange) { + rpc_system_app_exchange_data(app->rpc, app->data_store, DATA_STORE_SIZE); + scene_manager_previous_scene(app->scene_manager); + consumed = true; + } + } + + return consumed; +} + +void rpc_debug_app_scene_input_data_exchange_on_exit(void* context) { + RpcDebugApp* app = context; + UNUSED(app); +} diff --git a/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_input_error_code.c b/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_input_error_code.c new file mode 100644 index 00000000..eae12e6e --- /dev/null +++ b/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_input_error_code.c @@ -0,0 +1,60 @@ +#include "../rpc_debug_app.h" + +static bool rpc_debug_app_scene_input_error_code_validator_callback( + const char* text, + FuriString* error, + void* context) { + UNUSED(context); + + for(; *text; ++text) { + const char c = *text; + if(c < '0' || c > '9') { + furi_string_printf(error, "%s", "Please enter\na number!"); + return false; + } + } + + return true; +} + +static void rpc_debug_app_scene_input_error_code_result_callback(void* context) { + RpcDebugApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, RpcDebugAppCustomEventInputErrorCode); +} + +void rpc_debug_app_scene_input_error_code_on_enter(void* context) { + RpcDebugApp* app = context; + strncpy(app->text_store, "666", TEXT_STORE_SIZE); + text_input_set_header_text(app->text_input, "Enter error code"); + text_input_set_validator( + app->text_input, rpc_debug_app_scene_input_error_code_validator_callback, NULL); + text_input_set_result_callback( + app->text_input, + rpc_debug_app_scene_input_error_code_result_callback, + app, + app->text_store, + TEXT_STORE_SIZE, + true); + view_dispatcher_switch_to_view(app->view_dispatcher, RpcDebugAppViewTextInput); +} + +bool rpc_debug_app_scene_input_error_code_on_event(void* context, SceneManagerEvent event) { + RpcDebugApp* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == RpcDebugAppCustomEventInputErrorCode) { + rpc_system_app_set_error_code(app->rpc, (uint32_t)atol(app->text_store)); + scene_manager_previous_scene(app->scene_manager); + consumed = true; + } + } + + return consumed; +} + +void rpc_debug_app_scene_input_error_code_on_exit(void* context) { + RpcDebugApp* app = context; + text_input_reset(app->text_input); + text_input_set_validator(app->text_input, NULL, NULL); +} diff --git a/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_input_error_text.c b/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_input_error_text.c new file mode 100644 index 00000000..b07f8f4a --- /dev/null +++ b/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_input_error_text.c @@ -0,0 +1,40 @@ +#include "../rpc_debug_app.h" + +static void rpc_debug_app_scene_input_error_text_result_callback(void* context) { + RpcDebugApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, RpcDebugAppCustomEventInputErrorText); +} + +void rpc_debug_app_scene_input_error_text_on_enter(void* context) { + RpcDebugApp* app = context; + strncpy(app->text_store, "I'm a scary error message!", TEXT_STORE_SIZE); + text_input_set_header_text(app->text_input, "Enter error text"); + text_input_set_result_callback( + app->text_input, + rpc_debug_app_scene_input_error_text_result_callback, + app, + app->text_store, + TEXT_STORE_SIZE, + true); + view_dispatcher_switch_to_view(app->view_dispatcher, RpcDebugAppViewTextInput); +} + +bool rpc_debug_app_scene_input_error_text_on_event(void* context, SceneManagerEvent event) { + RpcDebugApp* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == RpcDebugAppCustomEventInputErrorText) { + rpc_system_app_set_error_text(app->rpc, app->text_store); + scene_manager_previous_scene(app->scene_manager); + consumed = true; + } + } + + return consumed; +} + +void rpc_debug_app_scene_input_error_text_on_exit(void* context) { + RpcDebugApp* app = context; + text_input_reset(app->text_input); +} diff --git a/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_receive_data_exchange.c b/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_receive_data_exchange.c new file mode 100644 index 00000000..98bafff8 --- /dev/null +++ b/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_receive_data_exchange.c @@ -0,0 +1,70 @@ +#include "../rpc_debug_app.h" + +static void rpc_debug_app_scene_start_format_hex( + const uint8_t* data, + size_t data_size, + char* buf, + size_t buf_size) { + furi_assert(data); + furi_assert(buf); + + const size_t byte_width = 3; + const size_t line_width = 7; + + data_size = MIN(data_size, buf_size / (byte_width + 1)); + + for(size_t i = 0; i < data_size; ++i) { + char* p = buf + (i * byte_width); + char sep = !((i + 1) % line_width) ? '\n' : ' '; + snprintf(p, byte_width + 1, "%02X%c", data[i], sep); + } + + buf[buf_size - 1] = '\0'; +} + +static void rpc_debug_app_scene_receive_data_exchange_callback( + const uint8_t* data, + size_t data_size, + void* context) { + RpcDebugApp* app = context; + if(data) { + rpc_debug_app_scene_start_format_hex(data, data_size, app->text_store, TEXT_STORE_SIZE); + } else { + strncpy(app->text_store, "", TEXT_STORE_SIZE); + } + view_dispatcher_send_custom_event(app->view_dispatcher, RpcDebugAppCustomEventRpcDataExchange); +} + +void rpc_debug_app_scene_receive_data_exchange_on_enter(void* context) { + RpcDebugApp* app = context; + strncpy(app->text_store, "Received data will appear here...", TEXT_STORE_SIZE); + + text_box_set_text(app->text_box, app->text_store); + text_box_set_font(app->text_box, TextBoxFontHex); + + rpc_system_app_set_data_exchange_callback( + app->rpc, rpc_debug_app_scene_receive_data_exchange_callback, app); + view_dispatcher_switch_to_view(app->view_dispatcher, RpcDebugAppViewTextBox); +} + +bool rpc_debug_app_scene_receive_data_exchange_on_event(void* context, SceneManagerEvent event) { + RpcDebugApp* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == RpcDebugAppCustomEventRpcDataExchange) { + notification_message(app->notifications, &sequence_blink_cyan_100); + notification_message(app->notifications, &sequence_display_backlight_on); + text_box_set_text(app->text_box, app->text_store); + consumed = true; + } + } + + return consumed; +} + +void rpc_debug_app_scene_receive_data_exchange_on_exit(void* context) { + RpcDebugApp* app = context; + text_box_reset(app->text_box); + rpc_system_app_set_data_exchange_callback(app->rpc, NULL, NULL); +} diff --git a/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_start.c b/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_start.c new file mode 100644 index 00000000..9461649b --- /dev/null +++ b/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_start.c @@ -0,0 +1,57 @@ +#include "../rpc_debug_app.h" + +enum SubmenuIndex { + SubmenuIndexTestAppError, + SubmenuIndexTestDataExchange, +}; + +static void rpc_debug_app_scene_start_submenu_callback(void* context, uint32_t index) { + RpcDebugApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, index); +} + +void rpc_debug_app_scene_start_on_enter(void* context) { + RpcDebugApp* app = context; + Submenu* submenu = app->submenu; + + submenu_add_item( + submenu, + "Test App Error", + SubmenuIndexTestAppError, + rpc_debug_app_scene_start_submenu_callback, + app); + submenu_add_item( + submenu, + "Test Data Exchange", + SubmenuIndexTestDataExchange, + rpc_debug_app_scene_start_submenu_callback, + app); + + submenu_set_selected_item(submenu, SubmenuIndexTestAppError); + view_dispatcher_switch_to_view(app->view_dispatcher, RpcDebugAppViewSubmenu); +} + +bool rpc_debug_app_scene_start_on_event(void* context, SceneManagerEvent event) { + RpcDebugApp* app = context; + SceneManager* scene_manager = app->scene_manager; + + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + const uint32_t submenu_index = event.event; + if(submenu_index == SubmenuIndexTestAppError) { + scene_manager_next_scene(scene_manager, RpcDebugAppSceneTestAppError); + consumed = true; + } else if(submenu_index == SubmenuIndexTestDataExchange) { + scene_manager_next_scene(scene_manager, RpcDebugAppSceneTestDataExchange); + consumed = true; + } + } + + return consumed; +} + +void rpc_debug_app_scene_start_on_exit(void* context) { + RpcDebugApp* app = context; + submenu_reset(app->submenu); +} diff --git a/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_start_dummy.c b/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_start_dummy.c new file mode 100644 index 00000000..5a30a079 --- /dev/null +++ b/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_start_dummy.c @@ -0,0 +1,30 @@ +#include "../rpc_debug_app.h" + +void rpc_debug_app_scene_start_dummy_on_enter(void* context) { + RpcDebugApp* app = context; + widget_add_text_box_element( + app->widget, + 0, + 0, + 128, + 64, + AlignCenter, + AlignCenter, + "This application\nis meant to be run\nin \e#RPC\e# mode.", + false); + view_dispatcher_switch_to_view(app->view_dispatcher, RpcDebugAppViewWidget); +} + +bool rpc_debug_app_scene_start_dummy_on_event(void* context, SceneManagerEvent event) { + RpcDebugApp* app = context; + UNUSED(app); + UNUSED(event); + + bool consumed = false; + return consumed; +} + +void rpc_debug_app_scene_start_dummy_on_exit(void* context) { + RpcDebugApp* app = context; + widget_reset(app->widget); +} diff --git a/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_test_app_error.c b/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_test_app_error.c new file mode 100644 index 00000000..865d475a --- /dev/null +++ b/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_test_app_error.c @@ -0,0 +1,57 @@ +#include "../rpc_debug_app.h" + +typedef enum { + SubmenuIndexSetErrorCode, + SubmenuIndexSetErrorText, +} SubmenuIndex; + +static void rpc_debug_app_scene_test_app_error_submenu_callback(void* context, uint32_t index) { + RpcDebugApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, index); +} + +void rpc_debug_app_scene_test_app_error_on_enter(void* context) { + RpcDebugApp* app = context; + Submenu* submenu = app->submenu; + + submenu_add_item( + submenu, + "Set Error Code", + SubmenuIndexSetErrorCode, + rpc_debug_app_scene_test_app_error_submenu_callback, + app); + submenu_add_item( + submenu, + "Set Error Text", + SubmenuIndexSetErrorText, + rpc_debug_app_scene_test_app_error_submenu_callback, + app); + + submenu_set_selected_item(submenu, SubmenuIndexSetErrorCode); + view_dispatcher_switch_to_view(app->view_dispatcher, RpcDebugAppViewSubmenu); +} + +bool rpc_debug_app_scene_test_app_error_on_event(void* context, SceneManagerEvent event) { + RpcDebugApp* app = context; + SceneManager* scene_manager = app->scene_manager; + + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + const uint32_t submenu_index = event.event; + if(submenu_index == SubmenuIndexSetErrorCode) { + scene_manager_next_scene(scene_manager, RpcDebugAppSceneInputErrorCode); + consumed = true; + } else if(submenu_index == SubmenuIndexSetErrorText) { + scene_manager_next_scene(scene_manager, RpcDebugAppSceneInputErrorText); + consumed = true; + } + } + + return consumed; +} + +void rpc_debug_app_scene_test_app_error_on_exit(void* context) { + RpcDebugApp* app = context; + submenu_reset(app->submenu); +} diff --git a/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_test_data_exchange.c b/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_test_data_exchange.c new file mode 100644 index 00000000..f90f480c --- /dev/null +++ b/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_test_data_exchange.c @@ -0,0 +1,58 @@ +#include "../rpc_debug_app.h" + +typedef enum { + SubmenuIndexSendData, + SubmenuIndexReceiveData, +} SubmenuIndex; + +static void + rpc_debug_app_scene_test_data_exchange_submenu_callback(void* context, uint32_t index) { + RpcDebugApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, index); +} + +void rpc_debug_app_scene_test_data_exchange_on_enter(void* context) { + RpcDebugApp* app = context; + Submenu* submenu = app->submenu; + + submenu_add_item( + submenu, + "Send Data", + SubmenuIndexSendData, + rpc_debug_app_scene_test_data_exchange_submenu_callback, + app); + submenu_add_item( + submenu, + "Receive Data", + SubmenuIndexReceiveData, + rpc_debug_app_scene_test_data_exchange_submenu_callback, + app); + + submenu_set_selected_item(submenu, SubmenuIndexSendData); + view_dispatcher_switch_to_view(app->view_dispatcher, RpcDebugAppViewSubmenu); +} + +bool rpc_debug_app_scene_test_data_exchange_on_event(void* context, SceneManagerEvent event) { + RpcDebugApp* app = context; + SceneManager* scene_manager = app->scene_manager; + + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + const uint32_t submenu_index = event.event; + if(submenu_index == SubmenuIndexSendData) { + scene_manager_next_scene(scene_manager, RpcDebugAppSceneInputDataExchange); + consumed = true; + } else if(submenu_index == SubmenuIndexReceiveData) { + scene_manager_next_scene(scene_manager, RpcDebugAppSceneReceiveDataExchange); + consumed = true; + } + } + + return consumed; +} + +void rpc_debug_app_scene_test_data_exchange_on_exit(void* context) { + RpcDebugApp* app = context; + submenu_reset(app->submenu); +} diff --git a/applications/services/cli/cli_commands.c b/applications/services/cli/cli_commands.c index 64ff8ef7..3534a541 100644 --- a/applications/services/cli/cli_commands.c +++ b/applications/services/cli/cli_commands.c @@ -25,7 +25,7 @@ void cli_command_device_info_callback(const char* key, const char* value, bool l void cli_command_device_info(Cli* cli, FuriString* args, void* context) { UNUSED(cli); UNUSED(args); - furi_hal_info_get(cli_command_device_info_callback, context); + furi_hal_info_get(cli_command_device_info_callback, '_', context); } void cli_command_help(Cli* cli, FuriString* args, void* context) { diff --git a/applications/services/power/power_cli.c b/applications/services/power/power_cli.c index 5c28137e..f4a10f0a 100644 --- a/applications/services/power/power_cli.c +++ b/applications/services/power/power_cli.c @@ -26,7 +26,7 @@ void power_cli_reboot2dfu(Cli* cli, FuriString* args) { power_reboot(PowerBootModeDfu); } -static void power_cli_info_callback(const char* key, const char* value, bool last, void* context) { +static void power_cli_callback(const char* key, const char* value, bool last, void* context) { UNUSED(last); UNUSED(context); printf("%-24s: %s\r\n", key, value); @@ -35,13 +35,13 @@ static void power_cli_info_callback(const char* key, const char* value, bool las void power_cli_info(Cli* cli, FuriString* args) { UNUSED(cli); UNUSED(args); - furi_hal_power_info_get(power_cli_info_callback, NULL); + furi_hal_power_info_get(power_cli_callback, '_', NULL); } void power_cli_debug(Cli* cli, FuriString* args) { UNUSED(cli); UNUSED(args); - furi_hal_power_dump_state(); + furi_hal_power_debug_get(power_cli_callback, NULL); } void power_cli_5v(Cli* cli, FuriString* args) { diff --git a/applications/services/rpc/rpc.c b/applications/services/rpc/rpc.c index ebf01572..63a71ad0 100644 --- a/applications/services/rpc/rpc.c +++ b/applications/services/rpc/rpc.c @@ -52,7 +52,12 @@ static RpcSystemCallbacks rpc_systems[] = { { .alloc = rpc_system_gpio_alloc, .free = NULL, - }}; + }, + { + .alloc = rpc_system_property_alloc, + .free = NULL, + }, +}; struct RpcSession { Rpc* rpc; diff --git a/applications/services/rpc/rpc_app.c b/applications/services/rpc/rpc_app.c index 30105557..4e1af1fb 100644 --- a/applications/services/rpc/rpc_app.c +++ b/applications/services/rpc/rpc_app.c @@ -9,9 +9,15 @@ struct RpcAppSystem { RpcSession* session; + RpcAppSystemCallback app_callback; void* app_context; + + RpcAppSystemDataExchangeCallback data_exchange_callback; + void* data_exchange_context; + PB_Main* state_msg; + PB_Main* error_msg; uint32_t last_id; char* last_data; @@ -195,6 +201,50 @@ static void rpc_system_app_button_release(const PB_Main* request, void* context) } } +static void rpc_system_app_get_error_process(const PB_Main* request, void* context) { + furi_assert(request); + furi_assert(request->which_content == PB_Main_app_get_error_request_tag); + furi_assert(context); + + RpcAppSystem* rpc_app = context; + RpcSession* session = rpc_app->session; + furi_assert(session); + + rpc_app->error_msg->command_id = request->command_id; + + FURI_LOG_D(TAG, "GetError"); + rpc_send(session, rpc_app->error_msg); +} + +static void rpc_system_app_data_exchange_process(const PB_Main* request, void* context) { + furi_assert(request); + furi_assert(request->which_content == PB_Main_app_data_exchange_request_tag); + furi_assert(context); + + RpcAppSystem* rpc_app = context; + RpcSession* session = rpc_app->session; + furi_assert(session); + + PB_CommandStatus command_status; + pb_bytes_array_t* data = request->content.app_data_exchange_request.data; + + if(rpc_app->data_exchange_callback) { + uint8_t* data_bytes = NULL; + size_t data_size = 0; + if(data) { + data_bytes = data->bytes; + data_size = data->size; + } + rpc_app->data_exchange_callback(data_bytes, data_size, rpc_app->data_exchange_context); + command_status = PB_CommandStatus_OK; + } else { + command_status = PB_CommandStatus_ERROR_APP_CMD_ERROR; + } + + FURI_LOG_D(TAG, "DataExchange"); + rpc_send_and_release_empty(session, request->command_id, command_status); +} + void rpc_system_app_send_started(RpcAppSystem* rpc_app) { furi_assert(rpc_app); RpcSession* session = rpc_app->session; @@ -259,6 +309,58 @@ void rpc_system_app_set_callback(RpcAppSystem* rpc_app, RpcAppSystemCallback cal rpc_app->app_context = ctx; } +void rpc_system_app_set_error_code(RpcAppSystem* rpc_app, uint32_t error_code) { + furi_assert(rpc_app); + PB_App_GetErrorResponse* content = &rpc_app->error_msg->content.app_get_error_response; + content->code = error_code; +} + +void rpc_system_app_set_error_text(RpcAppSystem* rpc_app, const char* error_text) { + furi_assert(rpc_app); + PB_App_GetErrorResponse* content = &rpc_app->error_msg->content.app_get_error_response; + + if(content->text) { + free(content->text); + } + + content->text = error_text ? strdup(error_text) : NULL; +} + +void rpc_system_app_set_data_exchange_callback( + RpcAppSystem* rpc_app, + RpcAppSystemDataExchangeCallback callback, + void* ctx) { + furi_assert(rpc_app); + + rpc_app->data_exchange_callback = callback; + rpc_app->data_exchange_context = ctx; +} + +void rpc_system_app_exchange_data(RpcAppSystem* rpc_app, const uint8_t* data, size_t data_size) { + furi_assert(rpc_app); + RpcSession* session = rpc_app->session; + furi_assert(session); + + PB_Main message = { + .command_id = 0, + .command_status = PB_CommandStatus_OK, + .has_next = false, + .which_content = PB_Main_app_data_exchange_request_tag, + }; + + PB_App_DataExchangeRequest* content = &message.content.app_data_exchange_request; + + if(data && data_size) { + content->data = malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(data_size)); + content->data->size = data_size; + memcpy(content->data->bytes, data, data_size); + } else { + content->data = NULL; + } + + rpc_send_and_release(session, &message); +} + void* rpc_system_app_alloc(RpcSession* session) { furi_assert(session); @@ -270,6 +372,13 @@ void* rpc_system_app_alloc(RpcSession* session) { rpc_app->state_msg->which_content = PB_Main_app_state_response_tag; rpc_app->state_msg->command_status = PB_CommandStatus_OK; + // App error message + rpc_app->error_msg = malloc(sizeof(PB_Main)); + rpc_app->error_msg->which_content = PB_Main_app_get_error_response_tag; + rpc_app->error_msg->command_status = PB_CommandStatus_OK; + rpc_app->error_msg->content.app_get_error_response.code = 0; + rpc_app->error_msg->content.app_get_error_response.text = NULL; + RpcHandler rpc_handler = { .message_handler = NULL, .decode_submessage = NULL, @@ -294,6 +403,12 @@ void* rpc_system_app_alloc(RpcSession* session) { rpc_handler.message_handler = rpc_system_app_button_release; rpc_add_handler(session, PB_Main_app_button_release_request_tag, &rpc_handler); + rpc_handler.message_handler = rpc_system_app_get_error_process; + rpc_add_handler(session, PB_Main_app_get_error_request_tag, &rpc_handler); + + rpc_handler.message_handler = rpc_system_app_data_exchange_process; + rpc_add_handler(session, PB_Main_app_data_exchange_request_tag, &rpc_handler); + return rpc_app; } @@ -311,8 +426,13 @@ void rpc_system_app_free(void* context) { furi_delay_tick(1); } + furi_assert(!rpc_app->data_exchange_callback); + if(rpc_app->last_data) free(rpc_app->last_data); + pb_release(&PB_Main_msg, rpc_app->error_msg); + + free(rpc_app->error_msg); free(rpc_app->state_msg); free(rpc_app); } diff --git a/applications/services/rpc/rpc_app.h b/applications/services/rpc/rpc_app.h index 635c9f8c..70febe49 100644 --- a/applications/services/rpc/rpc_app.h +++ b/applications/services/rpc/rpc_app.h @@ -14,6 +14,8 @@ typedef enum { } RpcAppSystemEvent; typedef void (*RpcAppSystemCallback)(RpcAppSystemEvent event, void* context); +typedef void ( + *RpcAppSystemDataExchangeCallback)(const uint8_t* data, size_t data_size, void* context); typedef struct RpcAppSystem RpcAppSystem; @@ -27,6 +29,17 @@ const char* rpc_system_app_get_data(RpcAppSystem* rpc_app); void rpc_system_app_confirm(RpcAppSystem* rpc_app, RpcAppSystemEvent event, bool result); +void rpc_system_app_set_error_code(RpcAppSystem* rpc_app, uint32_t error_code); + +void rpc_system_app_set_error_text(RpcAppSystem* rpc_app, const char* error_text); + +void rpc_system_app_set_data_exchange_callback( + RpcAppSystem* rpc_app, + RpcAppSystemDataExchangeCallback callback, + void* ctx); + +void rpc_system_app_exchange_data(RpcAppSystem* rpc_app, const uint8_t* data, size_t data_size); + #ifdef __cplusplus } #endif diff --git a/applications/services/rpc/rpc_i.h b/applications/services/rpc/rpc_i.h index af9033f0..91a176da 100644 --- a/applications/services/rpc/rpc_i.h +++ b/applications/services/rpc/rpc_i.h @@ -34,6 +34,7 @@ void* rpc_system_gui_alloc(RpcSession* session); void rpc_system_gui_free(void* ctx); void* rpc_system_gpio_alloc(RpcSession* session); void rpc_system_gpio_free(void* ctx); +void* rpc_system_property_alloc(RpcSession* session); void rpc_debug_print_message(const PB_Main* message); void rpc_debug_print_data(const char* prefix, uint8_t* buffer, size_t size); diff --git a/applications/services/rpc/rpc_property.c b/applications/services/rpc/rpc_property.c new file mode 100644 index 00000000..ad15051e --- /dev/null +++ b/applications/services/rpc/rpc_property.c @@ -0,0 +1,107 @@ +#include +#include +#include +#include +#include + +#include "rpc_i.h" + +#define TAG "RpcProperty" + +#define PROPERTY_CATEGORY_DEVICE_INFO "devinfo" +#define PROPERTY_CATEGORY_POWER_INFO "pwrinfo" +#define PROPERTY_CATEGORY_POWER_DEBUG "pwrdebug" + +typedef struct { + RpcSession* session; + PB_Main* response; + FuriString* subkey; +} RpcPropertyContext; + +static void + rpc_system_property_get_callback(const char* key, const char* value, bool last, void* context) { + furi_assert(key); + furi_assert(value); + furi_assert(context); + furi_assert(key); + furi_assert(value); + + RpcPropertyContext* ctx = context; + RpcSession* session = ctx->session; + PB_Main* response = ctx->response; + + if(!strncmp(key, furi_string_get_cstr(ctx->subkey), furi_string_size(ctx->subkey))) { + response->content.system_device_info_response.key = strdup(key); + response->content.system_device_info_response.value = strdup(value); + rpc_send_and_release(session, response); + } + + if(last) { + rpc_send_and_release_empty(session, response->command_id, PB_CommandStatus_OK); + } +} + +static void rpc_system_property_get_process(const PB_Main* request, void* context) { + furi_assert(request); + furi_assert(request->which_content == PB_Main_property_get_request_tag); + + FURI_LOG_D(TAG, "GetProperty"); + + RpcSession* session = (RpcSession*)context; + furi_assert(session); + + FuriString* topkey = furi_string_alloc(); + FuriString* subkey = furi_string_alloc_set_str(request->content.property_get_request.key); + + const size_t sep_idx = furi_string_search_char(subkey, '.'); + + if(sep_idx == FURI_STRING_FAILURE) { + furi_string_swap(topkey, subkey); + } else { + furi_string_set_n(topkey, subkey, 0, sep_idx); + furi_string_right(subkey, sep_idx + 1); + } + + PB_Main* response = malloc(sizeof(PB_Main)); + + response->command_id = request->command_id; + response->command_status = PB_CommandStatus_OK; + response->has_next = true; + response->which_content = PB_Main_property_get_response_tag; + + RpcPropertyContext property_context = { + .session = session, + .response = response, + .subkey = subkey, + }; + + if(!furi_string_cmp(topkey, PROPERTY_CATEGORY_DEVICE_INFO)) { + furi_hal_info_get(rpc_system_property_get_callback, '.', &property_context); + } else if(!furi_string_cmp(topkey, PROPERTY_CATEGORY_POWER_INFO)) { + furi_hal_power_info_get(rpc_system_property_get_callback, '.', &property_context); + } else if(!furi_string_cmp(topkey, PROPERTY_CATEGORY_POWER_DEBUG)) { + furi_hal_power_debug_get(rpc_system_property_get_callback, &property_context); + } else { + rpc_send_and_release_empty( + session, request->command_id, PB_CommandStatus_ERROR_INVALID_PARAMETERS); + } + + furi_string_free(subkey); + furi_string_free(topkey); + + free(response); +} + +void* rpc_system_property_alloc(RpcSession* session) { + furi_assert(session); + + RpcHandler rpc_handler = { + .message_handler = NULL, + .decode_submessage = NULL, + .context = session, + }; + + rpc_handler.message_handler = rpc_system_property_get_process; + rpc_add_handler(session, PB_Main_property_get_request_tag, &rpc_handler); + return NULL; +} diff --git a/applications/services/rpc/rpc_system.c b/applications/services/rpc/rpc_system.c index 1681bb17..a17be7d2 100644 --- a/applications/services/rpc/rpc_system.c +++ b/applications/services/rpc/rpc_system.c @@ -109,7 +109,7 @@ static void rpc_system_system_device_info_process(const PB_Main* request, void* .session = session, .response = response, }; - furi_hal_info_get(rpc_system_system_device_info_callback, &device_info_context); + furi_hal_info_get(rpc_system_system_device_info_callback, '_', &device_info_context); free(response); } @@ -266,7 +266,7 @@ static void rpc_system_system_get_power_info_process(const PB_Main* request, voi .session = session, .response = response, }; - furi_hal_power_info_get(rpc_system_system_power_info_callback, &power_info_context); + furi_hal_power_info_get(rpc_system_system_power_info_callback, '_', &power_info_context); free(response); } diff --git a/assets/protobuf b/assets/protobuf index e5af96e0..64606602 160000 --- a/assets/protobuf +++ b/assets/protobuf @@ -1 +1 @@ -Subproject commit e5af96e08fea8351898f7b8c6d1e34ce5fd6cdef +Subproject commit 6460660237005d02d5c223835659b40e373bade9 diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 17b36a2a..afc7c4e9 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,+,7.6,, +Version,+,8.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1120,7 +1120,7 @@ Function,+,furi_hal_ibutton_start_drive_in_isr,void, Function,+,furi_hal_ibutton_start_interrupt,void, Function,+,furi_hal_ibutton_start_interrupt_in_isr,void, Function,+,furi_hal_ibutton_stop,void, -Function,+,furi_hal_info_get,void,"FuriHalInfoValueCallback, void*" +Function,+,furi_hal_info_get,void,"PropertyValueCallback, char, void*" Function,+,furi_hal_infrared_async_rx_set_capture_isr_callback,void,"FuriHalInfraredRxCaptureCallback, void*" Function,+,furi_hal_infrared_async_rx_set_timeout,void,uint32_t Function,+,furi_hal_infrared_async_rx_set_timeout_isr_callback,void,"FuriHalInfraredRxTimeoutCallback, void*" @@ -1185,10 +1185,10 @@ Function,+,furi_hal_nfc_tx_rx_full,_Bool,FuriHalNfcTxRxContext* Function,-,furi_hal_os_init,void, Function,+,furi_hal_os_tick,void, Function,+,furi_hal_power_check_otg_status,void, +Function,+,furi_hal_power_debug_get,void,"PropertyValueCallback, void*" Function,+,furi_hal_power_deep_sleep_available,_Bool, Function,+,furi_hal_power_disable_external_3_3v,void, Function,+,furi_hal_power_disable_otg,void, -Function,+,furi_hal_power_dump_state,void, Function,+,furi_hal_power_enable_external_3_3v,void, Function,+,furi_hal_power_enable_otg,void, Function,+,furi_hal_power_gauge_is_ok,_Bool, @@ -1201,7 +1201,7 @@ Function,+,furi_hal_power_get_battery_temperature,float,FuriHalPowerIC Function,+,furi_hal_power_get_battery_voltage,float,FuriHalPowerIC Function,+,furi_hal_power_get_pct,uint8_t, Function,+,furi_hal_power_get_usb_voltage,float, -Function,+,furi_hal_power_info_get,void,"FuriHalPowerInfoCallback, void*" +Function,+,furi_hal_power_info_get,void,"PropertyValueCallback, char, void*" Function,-,furi_hal_power_init,void, Function,+,furi_hal_power_insomnia_enter,void, Function,+,furi_hal_power_insomnia_exit,void, @@ -2039,6 +2039,7 @@ Function,+,powf,float,"float, float" Function,-,powl,long double,"long double, long double" Function,-,printf,int,"const char*, ..." Function,-,prng_successor,uint32_t,"uint32_t, uint32_t" +Function,+,property_value_out,void,"PropertyValueContext*, const char*, unsigned int, ..." Function,+,protocol_dict_alloc,ProtocolDict*,"const ProtocolBase**, size_t" Function,+,protocol_dict_decoders_feed,ProtocolId,"ProtocolDict*, _Bool, uint32_t" Function,+,protocol_dict_decoders_feed_by_feature,ProtocolId,"ProtocolDict*, uint32_t, _Bool, uint32_t" @@ -2284,10 +2285,14 @@ Function,+,rpc_session_set_context,void,"RpcSession*, void*" Function,+,rpc_session_set_send_bytes_callback,void,"RpcSession*, RpcSendBytesCallback" Function,+,rpc_session_set_terminated_callback,void,"RpcSession*, RpcSessionTerminatedCallback" Function,+,rpc_system_app_confirm,void,"RpcAppSystem*, RpcAppSystemEvent, _Bool" +Function,+,rpc_system_app_exchange_data,void,"RpcAppSystem*, const uint8_t*, size_t" Function,+,rpc_system_app_get_data,const char*,RpcAppSystem* Function,+,rpc_system_app_send_exited,void,RpcAppSystem* Function,+,rpc_system_app_send_started,void,RpcAppSystem* Function,+,rpc_system_app_set_callback,void,"RpcAppSystem*, RpcAppSystemCallback, void*" +Function,+,rpc_system_app_set_data_exchange_callback,void,"RpcAppSystem*, RpcAppSystemDataExchangeCallback, void*" +Function,+,rpc_system_app_set_error_code,void,"RpcAppSystem*, uint32_t" +Function,+,rpc_system_app_set_error_text,void,"RpcAppSystem*, const char*" Function,-,rpmatch,int,const char* Function,+,saved_struct_load,_Bool,"const char*, void*, size_t, uint8_t, uint8_t" Function,+,saved_struct_save,_Bool,"const char*, void*, size_t, uint8_t, uint8_t" diff --git a/firmware/targets/f7/furi_hal/furi_hal_info.c b/firmware/targets/f7/furi_hal/furi_hal_info.c index 15ce41a2..c984ef4d 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_info.c +++ b/firmware/targets/f7/furi_hal/furi_hal_info.c @@ -8,16 +8,25 @@ #include #include -void furi_hal_info_get(FuriHalInfoValueCallback out, void* context) { - FuriString* value; - value = furi_string_alloc(); +void furi_hal_info_get(PropertyValueCallback out, char sep, void* context) { + FuriString* key = furi_string_alloc(); + FuriString* value = furi_string_alloc(); + + PropertyValueContext property_context = { + .key = key, .value = value, .out = out, .sep = sep, .last = false, .context = context}; // Device Info version - out("device_info_major", "2", false, context); - out("device_info_minor", "0", false, context); + if(sep == '.') { + property_value_out(&property_context, NULL, 2, "format", "major", "3"); + property_value_out(&property_context, NULL, 2, "format", "minor", "0"); + } else { + property_value_out(&property_context, NULL, 3, "device", "info", "major", "2"); + property_value_out(&property_context, NULL, 3, "device", "info", "minor", "0"); + } // Model name - out("hardware_model", furi_hal_version_get_model_name(), false, context); + property_value_out( + &property_context, NULL, 2, "hardware", "model", furi_hal_version_get_model_name()); // Unique ID furi_string_reset(value); @@ -25,93 +34,211 @@ void furi_hal_info_get(FuriHalInfoValueCallback out, void* context) { for(size_t i = 0; i < furi_hal_version_uid_size(); i++) { furi_string_cat_printf(value, "%02X", uid[i]); } - out("hardware_uid", furi_string_get_cstr(value), false, context); + property_value_out(&property_context, NULL, 2, "hardware", "uid", furi_string_get_cstr(value)); // OTP Revision - furi_string_printf(value, "%d", furi_hal_version_get_otp_version()); - out("hardware_otp_ver", furi_string_get_cstr(value), false, context); - furi_string_printf(value, "%lu", furi_hal_version_get_hw_timestamp()); - out("hardware_timestamp", furi_string_get_cstr(value), false, context); + property_value_out( + &property_context, "%d", 3, "hardware", "otp", "ver", furi_hal_version_get_otp_version()); + property_value_out( + &property_context, "%lu", 2, "hardware", "timestamp", furi_hal_version_get_hw_timestamp()); // Board Revision - furi_string_printf(value, "%d", furi_hal_version_get_hw_version()); - out("hardware_ver", furi_string_get_cstr(value), false, context); - furi_string_printf(value, "%d", furi_hal_version_get_hw_target()); - out("hardware_target", furi_string_get_cstr(value), false, context); - furi_string_printf(value, "%d", furi_hal_version_get_hw_body()); - out("hardware_body", furi_string_get_cstr(value), false, context); - furi_string_printf(value, "%d", furi_hal_version_get_hw_connect()); - out("hardware_connect", furi_string_get_cstr(value), false, context); - furi_string_printf(value, "%d", furi_hal_version_get_hw_display()); - out("hardware_display", furi_string_get_cstr(value), false, context); + property_value_out( + &property_context, "%d", 2, "hardware", "ver", furi_hal_version_get_hw_version()); + property_value_out( + &property_context, "%d", 2, "hardware", "target", furi_hal_version_get_hw_target()); + property_value_out( + &property_context, "%d", 2, "hardware", "body", furi_hal_version_get_hw_body()); + property_value_out( + &property_context, "%d", 2, "hardware", "connect", furi_hal_version_get_hw_connect()); + property_value_out( + &property_context, "%d", 2, "hardware", "display", furi_hal_version_get_hw_display()); // Board Personification - furi_string_printf(value, "%d", furi_hal_version_get_hw_color()); - out("hardware_color", furi_string_get_cstr(value), false, context); - furi_string_printf(value, "%d", furi_hal_version_get_hw_region()); - out("hardware_region", furi_string_get_cstr(value), false, context); - out("hardware_region_provisioned", furi_hal_region_get_name(), false, context); + property_value_out( + &property_context, "%d", 2, "hardware", "color", furi_hal_version_get_hw_color()); + + if(sep == '.') { + property_value_out( + &property_context, + "%d", + 3, + "hardware", + "region", + "builtin", + furi_hal_version_get_hw_region()); + } else { + property_value_out( + &property_context, "%d", 2, "hardware", "region", furi_hal_version_get_hw_region()); + } + + property_value_out( + &property_context, + NULL, + 3, + "hardware", + "region", + "provisioned", + furi_hal_region_get_name()); + const char* name = furi_hal_version_get_name_ptr(); if(name) { - out("hardware_name", name, false, context); + property_value_out(&property_context, NULL, 2, "hardware", "name", name); } // Firmware version const Version* firmware_version = furi_hal_version_get_firmware_version(); if(firmware_version) { - out("firmware_commit", version_get_githash(firmware_version), false, context); - out("firmware_commit_dirty", - version_get_dirty_flag(firmware_version) ? "true" : "false", - false, - context); - out("firmware_branch", version_get_gitbranch(firmware_version), false, context); - out("firmware_branch_num", version_get_gitbranchnum(firmware_version), false, context); - out("firmware_version", version_get_version(firmware_version), false, context); - out("firmware_build_date", version_get_builddate(firmware_version), false, context); - furi_string_printf(value, "%d", version_get_target(firmware_version)); - out("firmware_target", furi_string_get_cstr(value), false, context); + if(sep == '.') { + property_value_out( + &property_context, + NULL, + 3, + "firmware", + "commit", + "hash", + version_get_githash(firmware_version)); + } else { + property_value_out( + &property_context, + NULL, + 2, + "firmware", + "commit", + version_get_githash(firmware_version)); + } + + property_value_out( + &property_context, + NULL, + 3, + "firmware", + "commit", + "dirty", + version_get_dirty_flag(firmware_version) ? "true" : "false"); + + if(sep == '.') { + property_value_out( + &property_context, + NULL, + 3, + "firmware", + "branch", + "name", + version_get_gitbranch(firmware_version)); + } else { + property_value_out( + &property_context, + NULL, + 2, + "firmware", + "branch", + version_get_gitbranch(firmware_version)); + } + + property_value_out( + &property_context, + NULL, + 3, + "firmware", + "branch", + "num", + version_get_gitbranchnum(firmware_version)); + property_value_out( + &property_context, + NULL, + 2, + "firmware", + "version", + version_get_version(firmware_version)); + property_value_out( + &property_context, + NULL, + 3, + "firmware", + "build", + "date", + version_get_builddate(firmware_version)); + property_value_out( + &property_context, "%d", 2, "firmware", "target", version_get_target(firmware_version)); } if(furi_hal_bt_is_alive()) { const BleGlueC2Info* ble_c2_info = ble_glue_get_c2_info(); - out("radio_alive", "true", false, context); - out("radio_mode", ble_c2_info->mode == BleGlueC2ModeFUS ? "FUS" : "Stack", false, context); + property_value_out(&property_context, NULL, 2, "radio", "alive", "true"); + property_value_out( + &property_context, + NULL, + 2, + "radio", + "mode", + ble_c2_info->mode == BleGlueC2ModeFUS ? "FUS" : "Stack"); // FUS Info - furi_string_printf(value, "%d", ble_c2_info->FusVersionMajor); - out("radio_fus_major", furi_string_get_cstr(value), false, context); - furi_string_printf(value, "%d", ble_c2_info->FusVersionMinor); - out("radio_fus_minor", furi_string_get_cstr(value), false, context); - furi_string_printf(value, "%d", ble_c2_info->FusVersionSub); - out("radio_fus_sub", furi_string_get_cstr(value), false, context); - furi_string_printf(value, "%dK", ble_c2_info->FusMemorySizeSram2B); - out("radio_fus_sram2b", furi_string_get_cstr(value), false, context); - furi_string_printf(value, "%dK", ble_c2_info->FusMemorySizeSram2A); - out("radio_fus_sram2a", furi_string_get_cstr(value), false, context); - furi_string_printf(value, "%dK", ble_c2_info->FusMemorySizeFlash * 4); - out("radio_fus_flash", furi_string_get_cstr(value), false, context); + property_value_out( + &property_context, "%d", 3, "radio", "fus", "major", ble_c2_info->FusVersionMajor); + property_value_out( + &property_context, "%d", 3, "radio", "fus", "minor", ble_c2_info->FusVersionMinor); + property_value_out( + &property_context, "%d", 3, "radio", "fus", "sub", ble_c2_info->FusVersionSub); + property_value_out( + &property_context, + "%dK", + 3, + "radio", + "fus", + "sram2b", + ble_c2_info->FusMemorySizeSram2B); + property_value_out( + &property_context, + "%dK", + 3, + "radio", + "fus", + "sram2a", + ble_c2_info->FusMemorySizeSram2A); + property_value_out( + &property_context, + "%dK", + 3, + "radio", + "fus", + "flash", + ble_c2_info->FusMemorySizeFlash * 4); // Stack Info - furi_string_printf(value, "%d", ble_c2_info->StackType); - out("radio_stack_type", furi_string_get_cstr(value), false, context); - furi_string_printf(value, "%d", ble_c2_info->VersionMajor); - out("radio_stack_major", furi_string_get_cstr(value), false, context); - furi_string_printf(value, "%d", ble_c2_info->VersionMinor); - out("radio_stack_minor", furi_string_get_cstr(value), false, context); - furi_string_printf(value, "%d", ble_c2_info->VersionSub); - out("radio_stack_sub", furi_string_get_cstr(value), false, context); - furi_string_printf(value, "%d", ble_c2_info->VersionBranch); - out("radio_stack_branch", furi_string_get_cstr(value), false, context); - furi_string_printf(value, "%d", ble_c2_info->VersionReleaseType); - out("radio_stack_release", furi_string_get_cstr(value), false, context); - furi_string_printf(value, "%dK", ble_c2_info->MemorySizeSram2B); - out("radio_stack_sram2b", furi_string_get_cstr(value), false, context); - furi_string_printf(value, "%dK", ble_c2_info->MemorySizeSram2A); - out("radio_stack_sram2a", furi_string_get_cstr(value), false, context); - furi_string_printf(value, "%dK", ble_c2_info->MemorySizeSram1); - out("radio_stack_sram1", furi_string_get_cstr(value), false, context); - furi_string_printf(value, "%dK", ble_c2_info->MemorySizeFlash * 4); - out("radio_stack_flash", furi_string_get_cstr(value), false, context); + property_value_out( + &property_context, "%d", 3, "radio", "stack", "type", ble_c2_info->StackType); + property_value_out( + &property_context, "%d", 3, "radio", "stack", "major", ble_c2_info->VersionMajor); + property_value_out( + &property_context, "%d", 3, "radio", "stack", "minor", ble_c2_info->VersionMinor); + property_value_out( + &property_context, "%d", 3, "radio", "stack", "sub", ble_c2_info->VersionSub); + property_value_out( + &property_context, "%d", 3, "radio", "stack", "branch", ble_c2_info->VersionBranch); + property_value_out( + &property_context, + "%d", + 3, + "radio", + "stack", + "release", + ble_c2_info->VersionReleaseType); + property_value_out( + &property_context, "%dK", 3, "radio", "stack", "sram2b", ble_c2_info->MemorySizeSram2B); + property_value_out( + &property_context, "%dK", 3, "radio", "stack", "sram2a", ble_c2_info->MemorySizeSram2A); + property_value_out( + &property_context, "%dK", 3, "radio", "stack", "sram1", ble_c2_info->MemorySizeSram1); + property_value_out( + &property_context, + "%dK", + 3, + "radio", + "stack", + "flash", + ble_c2_info->MemorySizeFlash * 4); // Mac address furi_string_reset(value); @@ -119,23 +246,33 @@ void furi_hal_info_get(FuriHalInfoValueCallback out, void* context) { for(size_t i = 0; i < 6; i++) { furi_string_cat_printf(value, "%02X", ble_mac[i]); } - out("radio_ble_mac", furi_string_get_cstr(value), false, context); + property_value_out( + &property_context, NULL, 3, "radio", "ble", "mac", furi_string_get_cstr(value)); // Signature verification uint8_t enclave_keys = 0; uint8_t enclave_valid_keys = 0; bool enclave_valid = furi_hal_crypto_verify_enclave(&enclave_keys, &enclave_valid_keys); - furi_string_printf(value, "%d", enclave_valid_keys); - out("enclave_valid_keys", furi_string_get_cstr(value), false, context); - out("enclave_valid", enclave_valid ? "true" : "false", false, context); + if(sep == '.') { + property_value_out( + &property_context, "%d", 3, "enclave", "keys", "valid", enclave_valid_keys); + } else { + property_value_out( + &property_context, "%d", 3, "enclave", "valid", "keys", enclave_valid_keys); + } + + property_value_out( + &property_context, NULL, 2, "enclave", "valid", enclave_valid ? "true" : "false"); } else { - out("radio_alive", "false", false, context); + property_value_out(&property_context, NULL, 2, "radio", "alive", "false"); } - furi_string_printf(value, "%u", PROTOBUF_MAJOR_VERSION); - out("protobuf_version_major", furi_string_get_cstr(value), false, context); - furi_string_printf(value, "%u", PROTOBUF_MINOR_VERSION); - out("protobuf_version_minor", furi_string_get_cstr(value), true, context); + property_value_out( + &property_context, "%u", 3, "protobuf", "version", "major", PROTOBUF_MAJOR_VERSION); + property_context.last = true; + property_value_out( + &property_context, "%u", 3, "protobuf", "version", "minor", PROTOBUF_MINOR_VERSION); + furi_string_free(key); furi_string_free(value); } diff --git a/firmware/targets/f7/furi_hal/furi_hal_power.c b/firmware/targets/f7/furi_hal/furi_hal_power.c index 86505c57..88e191e9 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_power.c +++ b/firmware/targets/f7/furi_hal/furi_hal_power.c @@ -422,76 +422,6 @@ float furi_hal_power_get_usb_voltage() { return ret; } -void furi_hal_power_dump_state() { - BatteryStatus battery_status; - OperationStatus operation_status; - - furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); - - if(bq27220_get_battery_status(&furi_hal_i2c_handle_power, &battery_status) == BQ27220_ERROR || - bq27220_get_operation_status(&furi_hal_i2c_handle_power, &operation_status) == - BQ27220_ERROR) { - printf("Failed to get bq27220 status. Communication error.\r\n"); - } else { - // Operation status register - printf( - "bq27220: CALMD: %d, SEC: %d, EDV2: %d, VDQ: %d, INITCOMP: %d, SMTH: %d, BTPINT: %d, CFGUPDATE: %d\r\n", - operation_status.CALMD, - operation_status.SEC, - operation_status.EDV2, - operation_status.VDQ, - operation_status.INITCOMP, - operation_status.SMTH, - operation_status.BTPINT, - operation_status.CFGUPDATE); - // Battery status register, part 1 - printf( - "bq27220: CHGINH: %d, FC: %d, OTD: %d, OTC: %d, SLEEP: %d, OCVFAIL: %d, OCVCOMP: %d, FD: %d\r\n", - battery_status.CHGINH, - battery_status.FC, - battery_status.OTD, - battery_status.OTC, - battery_status.SLEEP, - battery_status.OCVFAIL, - battery_status.OCVCOMP, - battery_status.FD); - // Battery status register, part 2 - printf( - "bq27220: DSG: %d, SYSDWN: %d, TDA: %d, BATTPRES: %d, AUTH_GD: %d, OCVGD: %d, TCA: %d, RSVD: %d\r\n", - battery_status.DSG, - battery_status.SYSDWN, - battery_status.TDA, - battery_status.BATTPRES, - battery_status.AUTH_GD, - battery_status.OCVGD, - battery_status.TCA, - battery_status.RSVD); - // Voltage and current info - printf( - "bq27220: Full capacity: %dmAh, Design capacity: %dmAh, Remaining capacity: %dmAh, State of Charge: %d%%, State of health: %d%%\r\n", - bq27220_get_full_charge_capacity(&furi_hal_i2c_handle_power), - bq27220_get_design_capacity(&furi_hal_i2c_handle_power), - bq27220_get_remaining_capacity(&furi_hal_i2c_handle_power), - bq27220_get_state_of_charge(&furi_hal_i2c_handle_power), - bq27220_get_state_of_health(&furi_hal_i2c_handle_power)); - printf( - "bq27220: Voltage: %dmV, Current: %dmA, Temperature: %dC\r\n", - bq27220_get_voltage(&furi_hal_i2c_handle_power), - bq27220_get_current(&furi_hal_i2c_handle_power), - (int)furi_hal_power_get_battery_temperature_internal(FuriHalPowerICFuelGauge)); - } - - printf( - "bq25896: VBUS: %d, VSYS: %d, VBAT: %d, Current: %d, NTC: %ldm%%\r\n", - bq25896_get_vbus_voltage(&furi_hal_i2c_handle_power), - bq25896_get_vsys_voltage(&furi_hal_i2c_handle_power), - bq25896_get_vbat_voltage(&furi_hal_i2c_handle_power), - bq25896_get_vbat_current(&furi_hal_i2c_handle_power), - bq25896_get_ntc_mpct(&furi_hal_i2c_handle_power)); - - furi_hal_i2c_release(&furi_hal_i2c_handle_power); -} - void furi_hal_power_enable_external_3_3v() { furi_hal_gpio_write(&periph_power, 1); } @@ -526,57 +456,227 @@ void furi_hal_power_suppress_charge_exit() { } } -void furi_hal_power_info_get(FuriHalPowerInfoCallback out, void* context) { +void furi_hal_power_info_get(PropertyValueCallback out, char sep, void* context) { furi_assert(out); - FuriString* value; - value = furi_string_alloc(); + FuriString* value = furi_string_alloc(); + FuriString* key = furi_string_alloc(); - // Power Info version - out("power_info_major", "1", false, context); - out("power_info_minor", "0", false, context); + PropertyValueContext property_context = { + .key = key, .value = value, .out = out, .sep = sep, .last = false, .context = context}; + + if(sep == '.') { + property_value_out(&property_context, NULL, 2, "format", "major", "2"); + property_value_out(&property_context, NULL, 2, "format", "minor", "0"); + } else { + property_value_out(&property_context, NULL, 3, "power", "info", "major", "1"); + property_value_out(&property_context, NULL, 3, "power", "info", "minor", "0"); + } uint8_t charge = furi_hal_power_get_pct(); + property_value_out(&property_context, "%u", 2, "charge", "level", charge); - furi_string_printf(value, "%u", charge); - out("charge_level", furi_string_get_cstr(value), false, context); - + const char* charge_state; if(furi_hal_power_is_charging()) { if(charge < 100) { - furi_string_printf(value, "charging"); + charge_state = "charging"; } else { - furi_string_printf(value, "charged"); + charge_state = "charged"; } } else { - furi_string_printf(value, "discharging"); + charge_state = "discharging"; } - out("charge_state", furi_string_get_cstr(value), false, context); + property_value_out(&property_context, NULL, 2, "charge", "state", charge_state); uint16_t voltage = (uint16_t)(furi_hal_power_get_battery_voltage(FuriHalPowerICFuelGauge) * 1000.f); - furi_string_printf(value, "%u", voltage); - out("battery_voltage", furi_string_get_cstr(value), false, context); - + property_value_out(&property_context, "%u", 2, "battery", "voltage", voltage); int16_t current = (int16_t)(furi_hal_power_get_battery_current(FuriHalPowerICFuelGauge) * 1000.f); - furi_string_printf(value, "%d", current); - out("battery_current", furi_string_get_cstr(value), false, context); - + property_value_out(&property_context, "%d", 2, "battery", "current", current); int16_t temperature = (int16_t)furi_hal_power_get_battery_temperature(FuriHalPowerICFuelGauge); - furi_string_printf(value, "%d", temperature); - out("gauge_temp", furi_string_get_cstr(value), false, context); - - furi_string_printf(value, "%u", furi_hal_power_get_bat_health_pct()); - out("battery_health", furi_string_get_cstr(value), false, context); - - furi_string_printf(value, "%lu", furi_hal_power_get_battery_remaining_capacity()); - out("capacity_remain", furi_string_get_cstr(value), false, context); - - furi_string_printf(value, "%lu", furi_hal_power_get_battery_full_capacity()); - out("capacity_full", furi_string_get_cstr(value), false, context); - - furi_string_printf(value, "%lu", furi_hal_power_get_battery_design_capacity()); - out("capacity_design", furi_string_get_cstr(value), true, context); + property_value_out(&property_context, "%d", 2, "battery", "temp", temperature); + property_value_out( + &property_context, "%u", 2, "battery", "health", furi_hal_power_get_bat_health_pct()); + property_value_out( + &property_context, + "%lu", + 2, + "capacity", + "remain", + furi_hal_power_get_battery_remaining_capacity()); + property_value_out( + &property_context, + "%lu", + 2, + "capacity", + "full", + furi_hal_power_get_battery_full_capacity()); + property_context.last = true; + property_value_out( + &property_context, + "%lu", + 2, + "capacity", + "design", + furi_hal_power_get_battery_design_capacity()); + furi_string_free(key); furi_string_free(value); } + +void furi_hal_power_debug_get(PropertyValueCallback out, void* context) { + furi_assert(out); + + FuriString* value = furi_string_alloc(); + FuriString* key = furi_string_alloc(); + + PropertyValueContext property_context = { + .key = key, .value = value, .out = out, .sep = '.', .last = false, .context = context}; + + BatteryStatus battery_status; + OperationStatus operation_status; + + furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); + + // Power Debug version + property_value_out(&property_context, NULL, 2, "format", "major", "1"); + property_value_out(&property_context, NULL, 2, "format", "minor", "0"); + + property_value_out( + &property_context, + "%d", + 2, + "charger", + "vbus", + bq25896_get_vbus_voltage(&furi_hal_i2c_handle_power)); + property_value_out( + &property_context, + "%d", + 2, + "charger", + "vsys", + bq25896_get_vsys_voltage(&furi_hal_i2c_handle_power)); + property_value_out( + &property_context, + "%d", + 2, + "charger", + "vbat", + bq25896_get_vbat_voltage(&furi_hal_i2c_handle_power)); + property_value_out( + &property_context, + "%d", + 2, + "charger", + "current", + bq25896_get_vbat_current(&furi_hal_i2c_handle_power)); + + const uint32_t ntc_mpct = bq25896_get_ntc_mpct(&furi_hal_i2c_handle_power); + + if(bq27220_get_battery_status(&furi_hal_i2c_handle_power, &battery_status) != BQ27220_ERROR && + bq27220_get_operation_status(&furi_hal_i2c_handle_power, &operation_status) != + BQ27220_ERROR) { + property_value_out(&property_context, "%lu", 2, "charger", "ntc", ntc_mpct); + property_value_out(&property_context, "%d", 2, "gauge", "calmd", operation_status.CALMD); + property_value_out(&property_context, "%d", 2, "gauge", "sec", operation_status.SEC); + property_value_out(&property_context, "%d", 2, "gauge", "edv2", operation_status.EDV2); + property_value_out(&property_context, "%d", 2, "gauge", "vdq", operation_status.VDQ); + property_value_out( + &property_context, "%d", 2, "gauge", "initcomp", operation_status.INITCOMP); + property_value_out(&property_context, "%d", 2, "gauge", "smth", operation_status.SMTH); + property_value_out(&property_context, "%d", 2, "gauge", "btpint", operation_status.BTPINT); + property_value_out( + &property_context, "%d", 2, "gauge", "cfgupdate", operation_status.CFGUPDATE); + + // Battery status register, part 1 + property_value_out(&property_context, "%d", 2, "gauge", "chginh", battery_status.CHGINH); + property_value_out(&property_context, "%d", 2, "gauge", "fc", battery_status.FC); + property_value_out(&property_context, "%d", 2, "gauge", "otd", battery_status.OTD); + property_value_out(&property_context, "%d", 2, "gauge", "otc", battery_status.OTC); + property_value_out(&property_context, "%d", 2, "gauge", "sleep", battery_status.SLEEP); + property_value_out(&property_context, "%d", 2, "gauge", "ocvfail", battery_status.OCVFAIL); + property_value_out(&property_context, "%d", 2, "gauge", "ocvcomp", battery_status.OCVCOMP); + property_value_out(&property_context, "%d", 2, "gauge", "fd", battery_status.FD); + + // Battery status register, part 2 + property_value_out(&property_context, "%d", 2, "gauge", "dsg", battery_status.DSG); + property_value_out(&property_context, "%d", 2, "gauge", "sysdwn", battery_status.SYSDWN); + property_value_out(&property_context, "%d", 2, "gauge", "tda", battery_status.TDA); + property_value_out( + &property_context, "%d", 2, "gauge", "battpres", battery_status.BATTPRES); + property_value_out(&property_context, "%d", 2, "gauge", "authgd", battery_status.AUTH_GD); + property_value_out(&property_context, "%d", 2, "gauge", "ocvgd", battery_status.OCVGD); + property_value_out(&property_context, "%d", 2, "gauge", "tca", battery_status.TCA); + property_value_out(&property_context, "%d", 2, "gauge", "rsvd", battery_status.RSVD); + + // Voltage and current info + property_value_out( + &property_context, + "%d", + 3, + "gauge", + "capacity", + "full", + bq27220_get_full_charge_capacity(&furi_hal_i2c_handle_power)); + property_value_out( + &property_context, + "%d", + 3, + "gauge", + "capacity", + "design", + bq27220_get_design_capacity(&furi_hal_i2c_handle_power)); + property_value_out( + &property_context, + "%d", + 3, + "gauge", + "capacity", + "remain", + bq27220_get_remaining_capacity(&furi_hal_i2c_handle_power)); + property_value_out( + &property_context, + "%d", + 3, + "gauge", + "state", + "charge", + bq27220_get_state_of_charge(&furi_hal_i2c_handle_power)); + property_value_out( + &property_context, + "%d", + 3, + "gauge", + "state", + "health", + bq27220_get_state_of_health(&furi_hal_i2c_handle_power)); + property_value_out( + &property_context, + "%d", + 2, + "gauge", + "voltage", + bq27220_get_voltage(&furi_hal_i2c_handle_power)); + property_value_out( + &property_context, + "%d", + 2, + "gauge", + "current", + bq27220_get_current(&furi_hal_i2c_handle_power)); + + property_context.last = true; + const int battery_temp = + (int)furi_hal_power_get_battery_temperature_internal(FuriHalPowerICFuelGauge); + property_value_out(&property_context, "%d", 2, "gauge", "temperature", battery_temp); + } else { + property_context.last = true; + property_value_out(&property_context, "%lu", 2, "charger", "ntc", ntc_mpct); + } + + furi_string_free(key); + furi_string_free(value); + + furi_hal_i2c_release(&furi_hal_i2c_handle_power); +} diff --git a/firmware/targets/furi_hal_include/furi_hal_info.h b/firmware/targets/furi_hal_include/furi_hal_info.h index 4a335f2a..fa3267f5 100644 --- a/firmware/targets/furi_hal_include/furi_hal_info.h +++ b/firmware/targets/furi_hal_include/furi_hal_info.h @@ -7,27 +7,20 @@ #include #include +#include +#include #ifdef __cplusplus extern "C" { #endif -/** Callback type called every time another key-value pair of device information is ready - * - * @param key[in] device information type identifier - * @param value[in] device information value - * @param last[in] whether the passed key-value pair is the last one - * @param context[in] to pass to callback - */ -typedef void ( - *FuriHalInfoValueCallback)(const char* key, const char* value, bool last, void* context); - /** Get device information * * @param[in] callback callback to provide with new data + * @param[in] sep category separator character * @param[in] context context to pass to callback */ -void furi_hal_info_get(FuriHalInfoValueCallback callback, void* context); +void furi_hal_info_get(PropertyValueCallback callback, char sep, void* context); #ifdef __cplusplus } diff --git a/firmware/targets/furi_hal_include/furi_hal_power.h b/firmware/targets/furi_hal_include/furi_hal_power.h index e94877af..a78d09fe 100644 --- a/firmware/targets/furi_hal_include/furi_hal_power.h +++ b/firmware/targets/furi_hal_include/furi_hal_power.h @@ -7,6 +7,8 @@ #include #include +#include +#include #ifdef __cplusplus extern "C" { @@ -167,10 +169,6 @@ float furi_hal_power_get_battery_temperature(FuriHalPowerIC ic); */ float furi_hal_power_get_usb_voltage(); -/** Get power system component state - */ -void furi_hal_power_dump_state(); - /** Enable 3.3v on external gpio and sd card */ void furi_hal_power_enable_external_3_3v(); @@ -189,22 +187,20 @@ void furi_hal_power_suppress_charge_enter(); */ void furi_hal_power_suppress_charge_exit(); -/** Callback type called by furi_hal_power_info_get every time another key-value pair of information is ready - * - * @param key[in] power information type identifier - * @param value[in] power information value - * @param last[in] whether the passed key-value pair is the last one - * @param context[in] to pass to callback - */ -typedef void ( - *FuriHalPowerInfoCallback)(const char* key, const char* value, bool last, void* context); - /** Get power information + * + * @param[in] callback callback to provide with new data + * @param[in] sep category separator character + * @param[in] context context to pass to callback + */ +void furi_hal_power_info_get(PropertyValueCallback callback, char sep, void* context); + +/** Get power debug information * * @param[in] callback callback to provide with new data * @param[in] context context to pass to callback */ -void furi_hal_power_info_get(FuriHalPowerInfoCallback callback, void* context); +void furi_hal_power_debug_get(PropertyValueCallback callback, void* context); #ifdef __cplusplus } diff --git a/lib/toolbox/property.c b/lib/toolbox/property.c new file mode 100644 index 00000000..c258cdd6 --- /dev/null +++ b/lib/toolbox/property.c @@ -0,0 +1,33 @@ +#include "property.h" + +#include + +void property_value_out(PropertyValueContext* ctx, const char* fmt, unsigned int nparts, ...) { + furi_assert(ctx); + furi_string_reset(ctx->key); + + va_list args; + va_start(args, nparts); + + for(size_t i = 0; i < nparts; ++i) { + const char* keypart = va_arg(args, const char*); + furi_string_cat(ctx->key, keypart); + if(i < nparts - 1) { + furi_string_push_back(ctx->key, ctx->sep); + } + } + + const char* value_str; + + if(fmt) { + furi_string_vprintf(ctx->value, fmt, args); + value_str = furi_string_get_cstr(ctx->value); + } else { + // C string passthrough (no formatting) + value_str = va_arg(args, const char*); + } + + va_end(args); + + ctx->out(furi_string_get_cstr(ctx->key), value_str, ctx->last, ctx->context); +} diff --git a/lib/toolbox/property.h b/lib/toolbox/property.h new file mode 100644 index 00000000..524d8ff1 --- /dev/null +++ b/lib/toolbox/property.h @@ -0,0 +1,39 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +/** Callback type called every time another key-value pair of device information is ready + * + * @param key[in] device information type identifier + * @param value[in] device information value + * @param last[in] whether the passed key-value pair is the last one + * @param context[in] to pass to callback + */ +typedef void (*PropertyValueCallback)(const char* key, const char* value, bool last, void* context); + +typedef struct { + FuriString* key; /**< key string buffer, must be initialised before use */ + FuriString* value; /**< value string buffer, must be initialised before use */ + PropertyValueCallback out; /**< output callback function */ + char sep; /**< separator character between key parts */ + bool last; /**< flag to indicate last element */ + void* context; /**< user-defined context, passed through to out callback */ +} PropertyValueContext; + +/** Builds key and value strings and outputs them via a callback function + * + * @param ctx[in] local property context + * @param fmt[in] value format, set to NULL to bypass formatting + * @param nparts[in] number of key parts (separated by character) + * @param ...[in] list of key parts followed by value + */ +void property_value_out(PropertyValueContext* ctx, const char* fmt, unsigned int nparts, ...); + +#ifdef __cplusplus +} +#endif From 297f185ef4f8060f581be4307946ebf198f411dc Mon Sep 17 00:00:00 2001 From: Sergey Gavrilov Date: Tue, 29 Nov 2022 22:50:55 +1000 Subject: [PATCH 22/25] Blocking USB driver API (#2009) * invalidate memmgt thread dict * Core: rollback memmgt thread dict invalidation * Dialogs: move api lock to toolbox * HAL: blocking usb API * HAL usb: fix api return data * HAL usb: api optimization * api lock: test results * Fix build errors * DAP Link: fix imports * Crash when malloc in ISR * Fix dap-link copypaste error * Moar memory management crashes. * Crash when malloc in IRQ, not ISR * USB-UART: Blocking VCP mode switch Co-authored-by: nminaylov Co-authored-by: Aleksandr Kutuzov --- applications/main/gpio/gpio_app_i.h | 1 + applications/main/gpio/gpio_custom_event.h | 1 + .../gpio/scenes/gpio_scene_usb_uart_config.c | 78 ++-- applications/main/gpio/usb_uart_bridge.c | 6 + applications/plugins/dap_link/dap_link.c | 1 - .../plugins/dap_link/usb/dap_v2_usb.c | 17 - .../plugins/dap_link/usb/dap_v2_usb.h | 2 - applications/services/dialogs/dialogs.c | 4 +- applications/services/dialogs/dialogs_api.c | 10 +- .../services/dialogs/dialogs_api_lock.h | 18 - .../services/dialogs/dialogs_message.h | 2 +- .../dialogs/dialogs_module_file_browser.c | 12 +- .../services/dialogs/dialogs_module_message.c | 12 +- .../targets/f7/furi_hal/furi_hal_memory.c | 4 + firmware/targets/f7/furi_hal/furi_hal_usb.c | 427 ++++++++++++------ furi/core/memmgr_heap.c | 8 + lib/toolbox/api_lock.h | 43 ++ 17 files changed, 418 insertions(+), 228 deletions(-) delete mode 100644 applications/services/dialogs/dialogs_api_lock.h create mode 100644 lib/toolbox/api_lock.h diff --git a/applications/main/gpio/gpio_app_i.h b/applications/main/gpio/gpio_app_i.h index 85c5c332..8f805891 100644 --- a/applications/main/gpio/gpio_app_i.h +++ b/applications/main/gpio/gpio_app_i.h @@ -29,6 +29,7 @@ struct GpioApp { GpioTest* gpio_test; GpioUsbUart* gpio_usb_uart; UsbUartBridge* usb_uart_bridge; + UsbUartConfig* usb_uart_cfg; }; typedef enum { diff --git a/applications/main/gpio/gpio_custom_event.h b/applications/main/gpio/gpio_custom_event.h index 2bf3e5a8..72b8fecc 100644 --- a/applications/main/gpio/gpio_custom_event.h +++ b/applications/main/gpio/gpio_custom_event.h @@ -9,4 +9,5 @@ typedef enum { GpioCustomEventErrorBack, GpioUsbUartEventConfig, + GpioUsbUartEventConfigSet, } GpioCustomEvent; diff --git a/applications/main/gpio/scenes/gpio_scene_usb_uart_config.c b/applications/main/gpio/scenes/gpio_scene_usb_uart_config.c index c114d79a..55b04ed6 100644 --- a/applications/main/gpio/scenes/gpio_scene_usb_uart_config.c +++ b/applications/main/gpio/scenes/gpio_scene_usb_uart_config.c @@ -9,8 +9,6 @@ typedef enum { UsbUartLineIndexFlow, } LineIndex; -static UsbUartConfig* cfg_set; - static const char* vcp_ch[] = {"0 (CLI)", "1"}; static const char* uart_ch[] = {"13,14", "15,16"}; static const char* flow_pins[] = {"None", "2,3", "6,7", "16,15"}; @@ -28,8 +26,14 @@ static const uint32_t baudrate_list[] = { }; bool gpio_scene_usb_uart_cfg_on_event(void* context, SceneManagerEvent event) { - UNUSED(context); - UNUSED(event); + GpioApp* app = context; + furi_assert(app); + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GpioUsbUartEventConfigSet) { + usb_uart_set_config(app->usb_uart_bridge, app->usb_uart_cfg); + return true; + } + } return false; } @@ -38,55 +42,59 @@ void line_ensure_flow_invariant(GpioApp* app) { // selected. This function enforces that invariant by resetting flow_pins // to None if it is configured to 16,15 when LPUART is selected. - uint8_t available_flow_pins = cfg_set->uart_ch == FuriHalUartIdLPUART1 ? 3 : 4; + uint8_t available_flow_pins = app->usb_uart_cfg->uart_ch == FuriHalUartIdLPUART1 ? 3 : 4; VariableItem* item = app->var_item_flow; variable_item_set_values_count(item, available_flow_pins); - if(cfg_set->flow_pins >= available_flow_pins) { - cfg_set->flow_pins = 0; - usb_uart_set_config(app->usb_uart_bridge, cfg_set); + if(app->usb_uart_cfg->flow_pins >= available_flow_pins) { + app->usb_uart_cfg->flow_pins = 0; - variable_item_set_current_value_index(item, cfg_set->flow_pins); - variable_item_set_current_value_text(item, flow_pins[cfg_set->flow_pins]); + variable_item_set_current_value_index(item, app->usb_uart_cfg->flow_pins); + variable_item_set_current_value_text(item, flow_pins[app->usb_uart_cfg->flow_pins]); } } static void line_vcp_cb(VariableItem* item) { GpioApp* app = variable_item_get_context(item); + furi_assert(app); uint8_t index = variable_item_get_current_value_index(item); variable_item_set_current_value_text(item, vcp_ch[index]); - cfg_set->vcp_ch = index; - usb_uart_set_config(app->usb_uart_bridge, cfg_set); + app->usb_uart_cfg->vcp_ch = index; + view_dispatcher_send_custom_event(app->view_dispatcher, GpioUsbUartEventConfigSet); } static void line_port_cb(VariableItem* item) { GpioApp* app = variable_item_get_context(item); + furi_assert(app); uint8_t index = variable_item_get_current_value_index(item); variable_item_set_current_value_text(item, uart_ch[index]); if(index == 0) - cfg_set->uart_ch = FuriHalUartIdUSART1; + app->usb_uart_cfg->uart_ch = FuriHalUartIdUSART1; else if(index == 1) - cfg_set->uart_ch = FuriHalUartIdLPUART1; - usb_uart_set_config(app->usb_uart_bridge, cfg_set); + app->usb_uart_cfg->uart_ch = FuriHalUartIdLPUART1; + line_ensure_flow_invariant(app); + view_dispatcher_send_custom_event(app->view_dispatcher, GpioUsbUartEventConfigSet); } static void line_flow_cb(VariableItem* item) { GpioApp* app = variable_item_get_context(item); + furi_assert(app); uint8_t index = variable_item_get_current_value_index(item); variable_item_set_current_value_text(item, flow_pins[index]); - cfg_set->flow_pins = index; - usb_uart_set_config(app->usb_uart_bridge, cfg_set); + app->usb_uart_cfg->flow_pins = index; + view_dispatcher_send_custom_event(app->view_dispatcher, GpioUsbUartEventConfigSet); } static void line_baudrate_cb(VariableItem* item) { GpioApp* app = variable_item_get_context(item); + furi_assert(app); uint8_t index = variable_item_get_current_value_index(item); char br_text[8]; @@ -94,28 +102,29 @@ static void line_baudrate_cb(VariableItem* item) { if(index > 0) { snprintf(br_text, 7, "%lu", baudrate_list[index - 1]); variable_item_set_current_value_text(item, br_text); - cfg_set->baudrate = baudrate_list[index - 1]; + app->usb_uart_cfg->baudrate = baudrate_list[index - 1]; } else { variable_item_set_current_value_text(item, baudrate_mode[index]); - cfg_set->baudrate = 0; + app->usb_uart_cfg->baudrate = 0; } - cfg_set->baudrate_mode = index; - usb_uart_set_config(app->usb_uart_bridge, cfg_set); + app->usb_uart_cfg->baudrate_mode = index; + view_dispatcher_send_custom_event(app->view_dispatcher, GpioUsbUartEventConfigSet); } void gpio_scene_usb_uart_cfg_on_enter(void* context) { GpioApp* app = context; + furi_assert(app); VariableItemList* var_item_list = app->var_item_list; - cfg_set = malloc(sizeof(UsbUartConfig)); - usb_uart_get_config(app->usb_uart_bridge, cfg_set); + app->usb_uart_cfg = malloc(sizeof(UsbUartConfig)); + usb_uart_get_config(app->usb_uart_bridge, app->usb_uart_cfg); VariableItem* item; char br_text[8]; item = variable_item_list_add(var_item_list, "USB Channel", 2, line_vcp_cb, app); - variable_item_set_current_value_index(item, cfg_set->vcp_ch); - variable_item_set_current_value_text(item, vcp_ch[cfg_set->vcp_ch]); + variable_item_set_current_value_index(item, app->usb_uart_cfg->vcp_ch); + variable_item_set_current_value_text(item, vcp_ch[app->usb_uart_cfg->vcp_ch]); item = variable_item_list_add( var_item_list, @@ -123,22 +132,23 @@ void gpio_scene_usb_uart_cfg_on_enter(void* context) { sizeof(baudrate_list) / sizeof(baudrate_list[0]) + 1, line_baudrate_cb, app); - variable_item_set_current_value_index(item, cfg_set->baudrate_mode); - if(cfg_set->baudrate_mode > 0) { - snprintf(br_text, 7, "%lu", baudrate_list[cfg_set->baudrate_mode - 1]); + variable_item_set_current_value_index(item, app->usb_uart_cfg->baudrate_mode); + if(app->usb_uart_cfg->baudrate_mode > 0) { + snprintf(br_text, 7, "%lu", baudrate_list[app->usb_uart_cfg->baudrate_mode - 1]); variable_item_set_current_value_text(item, br_text); } else { - variable_item_set_current_value_text(item, baudrate_mode[cfg_set->baudrate_mode]); + variable_item_set_current_value_text( + item, baudrate_mode[app->usb_uart_cfg->baudrate_mode]); } item = variable_item_list_add(var_item_list, "UART Pins", 2, line_port_cb, app); - variable_item_set_current_value_index(item, cfg_set->uart_ch); - variable_item_set_current_value_text(item, uart_ch[cfg_set->uart_ch]); + variable_item_set_current_value_index(item, app->usb_uart_cfg->uart_ch); + variable_item_set_current_value_text(item, uart_ch[app->usb_uart_cfg->uart_ch]); item = variable_item_list_add( var_item_list, "RTS/DTR Pins", COUNT_OF(flow_pins), line_flow_cb, app); - variable_item_set_current_value_index(item, cfg_set->flow_pins); - variable_item_set_current_value_text(item, flow_pins[cfg_set->flow_pins]); + variable_item_set_current_value_index(item, app->usb_uart_cfg->flow_pins); + variable_item_set_current_value_text(item, flow_pins[app->usb_uart_cfg->flow_pins]); app->var_item_flow = item; line_ensure_flow_invariant(app); @@ -155,5 +165,5 @@ void gpio_scene_usb_uart_cfg_on_exit(void* context) { GpioAppViewUsbUartCfg, variable_item_list_get_selected_item_index(app->var_item_list)); variable_item_list_reset(app->var_item_list); - free(cfg_set); + free(app->usb_uart_cfg); } diff --git a/applications/main/gpio/usb_uart_bridge.c b/applications/main/gpio/usb_uart_bridge.c index 927eedb0..1a82dbdc 100644 --- a/applications/main/gpio/usb_uart_bridge.c +++ b/applications/main/gpio/usb_uart_bridge.c @@ -3,6 +3,7 @@ #include #include "usb_cdc.h" #include "cli/cli_vcp.h" +#include #include "cli/cli.h" #define USB_CDC_PKT_LEN CDC_DATA_SZ @@ -51,6 +52,8 @@ struct UsbUartBridge { UsbUartState st; + FuriApiLock cfg_lock; + uint8_t rx_buf[USB_CDC_PKT_LEN]; }; @@ -244,6 +247,7 @@ static int32_t usb_uart_worker(void* context) { usb_uart->cfg.flow_pins = usb_uart->cfg_new.flow_pins; events |= WorkerEvtCtrlLineSet; } + api_lock_unlock(usb_uart->cfg_lock); } if(events & WorkerEvtLineCfgSet) { if(usb_uart->cfg.baudrate == 0) @@ -352,8 +356,10 @@ void usb_uart_disable(UsbUartBridge* usb_uart) { void usb_uart_set_config(UsbUartBridge* usb_uart, UsbUartConfig* cfg) { furi_assert(usb_uart); furi_assert(cfg); + usb_uart->cfg_lock = api_lock_alloc_locked(); memcpy(&(usb_uart->cfg_new), cfg, sizeof(UsbUartConfig)); furi_thread_flags_set(furi_thread_get_id(usb_uart->thread), WorkerEvtCfgChange); + api_lock_wait_unlock_and_free(usb_uart->cfg_lock); } void usb_uart_get_config(UsbUartBridge* usb_uart, UsbUartConfig* cfg) { diff --git a/applications/plugins/dap_link/dap_link.c b/applications/plugins/dap_link/dap_link.c index 5c30e85c..eafb435e 100644 --- a/applications/plugins/dap_link/dap_link.c +++ b/applications/plugins/dap_link/dap_link.c @@ -247,7 +247,6 @@ static int32_t dap_process(void* p) { // deinit usb furi_hal_usb_set_config(usb_config_prev, NULL); - dap_common_wait_for_deinit(); dap_common_usb_free_name(); dap_deinit_gpio(swd_pins_prev); return 0; diff --git a/applications/plugins/dap_link/usb/dap_v2_usb.c b/applications/plugins/dap_link/usb/dap_v2_usb.c index 0c303a3b..b42df283 100644 --- a/applications/plugins/dap_link/usb/dap_v2_usb.c +++ b/applications/plugins/dap_link/usb/dap_v2_usb.c @@ -618,23 +618,12 @@ static void hid_init(usbd_device* dev, FuriHalUsbInterface* intf, void* ctx) { if(dap_state.semaphore_v2 == NULL) dap_state.semaphore_v2 = furi_semaphore_alloc(1, 1); if(dap_state.semaphore_cdc == NULL) dap_state.semaphore_cdc = furi_semaphore_alloc(1, 1); - usb_hid.dev_descr->idVendor = DAP_HID_VID; - usb_hid.dev_descr->idProduct = DAP_HID_PID; - usbd_reg_config(dev, hid_ep_config); usbd_reg_control(dev, hid_control); usbd_connect(dev, true); } -static bool deinit_flag = false; - -void dap_common_wait_for_deinit() { - while(!deinit_flag) { - furi_delay_ms(50); - } -} - static void hid_deinit(usbd_device* dev) { dap_state.usb_dev = NULL; @@ -647,12 +636,6 @@ static void hid_deinit(usbd_device* dev) { usbd_reg_config(dev, NULL); usbd_reg_control(dev, NULL); - - free(usb_hid.str_manuf_descr); - free(usb_hid.str_prod_descr); - - FURI_SW_MEMBARRIER(); - deinit_flag = true; } static void hid_on_wakeup(usbd_device* dev) { diff --git a/applications/plugins/dap_link/usb/dap_v2_usb.h b/applications/plugins/dap_link/usb/dap_v2_usb.h index 2a0e8605..3f1534ff 100644 --- a/applications/plugins/dap_link/usb/dap_v2_usb.h +++ b/applications/plugins/dap_link/usb/dap_v2_usb.h @@ -51,5 +51,3 @@ void dap_common_usb_set_state_callback(DapStateCallback callback); void dap_common_usb_alloc_name(const char* name); void dap_common_usb_free_name(); - -void dap_common_wait_for_deinit(); \ No newline at end of file diff --git a/applications/services/dialogs/dialogs.c b/applications/services/dialogs/dialogs.c index e2db4a0f..3c658888 100644 --- a/applications/services/dialogs/dialogs.c +++ b/applications/services/dialogs/dialogs.c @@ -1,6 +1,6 @@ #include "dialogs/dialogs_message.h" #include "dialogs_i.h" -#include "dialogs_api_lock.h" +#include #include "dialogs_module_file_browser.h" #include "dialogs_module_message.h" @@ -35,7 +35,7 @@ static void dialogs_app_process_message(DialogsApp* app, DialogsAppMessage* mess dialogs_app_process_module_message(&message->data->dialog); break; } - API_LOCK_UNLOCK(message->lock); + api_lock_unlock(message->lock); } int32_t dialogs_srv(void* p) { diff --git a/applications/services/dialogs/dialogs_api.c b/applications/services/dialogs/dialogs_api.c index ee959a33..c1de5999 100644 --- a/applications/services/dialogs/dialogs_api.c +++ b/applications/services/dialogs/dialogs_api.c @@ -1,6 +1,6 @@ #include "dialogs/dialogs_message.h" #include "dialogs_i.h" -#include "dialogs_api_lock.h" +#include #include /****************** File browser ******************/ @@ -10,7 +10,7 @@ bool dialog_file_browser_show( FuriString* result_path, FuriString* path, const DialogsFileBrowserOptions* options) { - FuriApiLock lock = API_LOCK_INIT_LOCKED(); + FuriApiLock lock = api_lock_alloc_locked(); furi_check(lock != NULL); DialogsAppData data = { @@ -35,7 +35,7 @@ bool dialog_file_browser_show( furi_check( furi_message_queue_put(context->message_queue, &message, FuriWaitForever) == FuriStatusOk); - API_LOCK_WAIT_UNTIL_UNLOCK_AND_FREE(lock); + api_lock_wait_unlock_and_free(lock); return return_data.bool_value; } @@ -43,7 +43,7 @@ bool dialog_file_browser_show( /****************** Message ******************/ DialogMessageButton dialog_message_show(DialogsApp* context, const DialogMessage* dialog_message) { - FuriApiLock lock = API_LOCK_INIT_LOCKED(); + FuriApiLock lock = api_lock_alloc_locked(); furi_check(lock != NULL); DialogsAppData data = { @@ -61,7 +61,7 @@ DialogMessageButton dialog_message_show(DialogsApp* context, const DialogMessage furi_check( furi_message_queue_put(context->message_queue, &message, FuriWaitForever) == FuriStatusOk); - API_LOCK_WAIT_UNTIL_UNLOCK_AND_FREE(lock); + api_lock_wait_unlock_and_free(lock); return return_data.dialog_value; } diff --git a/applications/services/dialogs/dialogs_api_lock.h b/applications/services/dialogs/dialogs_api_lock.h deleted file mode 100644 index a165803f..00000000 --- a/applications/services/dialogs/dialogs_api_lock.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -typedef FuriEventFlag* FuriApiLock; - -#define API_LOCK_EVENT (1U << 0) - -#define API_LOCK_INIT_LOCKED() furi_event_flag_alloc(); - -#define API_LOCK_WAIT_UNTIL_UNLOCK(_lock) \ - furi_event_flag_wait(_lock, API_LOCK_EVENT, FuriFlagWaitAny, FuriWaitForever); - -#define API_LOCK_FREE(_lock) furi_event_flag_free(_lock); - -#define API_LOCK_UNLOCK(_lock) furi_event_flag_set(_lock, API_LOCK_EVENT); - -#define API_LOCK_WAIT_UNTIL_UNLOCK_AND_FREE(_lock) \ - API_LOCK_WAIT_UNTIL_UNLOCK(_lock); \ - API_LOCK_FREE(_lock); diff --git a/applications/services/dialogs/dialogs_message.h b/applications/services/dialogs/dialogs_message.h index 91e040ce..d01c5aa9 100644 --- a/applications/services/dialogs/dialogs_message.h +++ b/applications/services/dialogs/dialogs_message.h @@ -1,7 +1,7 @@ #pragma once #include #include "dialogs_i.h" -#include "dialogs_api_lock.h" +#include #ifdef __cplusplus extern "C" { diff --git a/applications/services/dialogs/dialogs_module_file_browser.c b/applications/services/dialogs/dialogs_module_file_browser.c index 166fd111..7e67d6c6 100644 --- a/applications/services/dialogs/dialogs_module_file_browser.c +++ b/applications/services/dialogs/dialogs_module_file_browser.c @@ -1,5 +1,5 @@ #include "dialogs_i.h" -#include "dialogs_api_lock.h" +#include #include "gui/modules/file_browser.h" typedef struct { @@ -11,14 +11,14 @@ static void dialogs_app_file_browser_back_callback(void* context) { furi_assert(context); DialogsAppFileBrowserContext* file_browser_context = context; file_browser_context->result = false; - API_LOCK_UNLOCK(file_browser_context->lock); + api_lock_unlock(file_browser_context->lock); } static void dialogs_app_file_browser_callback(void* context) { furi_assert(context); DialogsAppFileBrowserContext* file_browser_context = context; file_browser_context->result = true; - API_LOCK_UNLOCK(file_browser_context->lock); + api_lock_unlock(file_browser_context->lock); } bool dialogs_app_process_module_file_browser(const DialogsAppMessageDataFileBrowser* data) { @@ -27,7 +27,7 @@ bool dialogs_app_process_module_file_browser(const DialogsAppMessageDataFileBrow DialogsAppFileBrowserContext* file_browser_context = malloc(sizeof(DialogsAppFileBrowserContext)); - file_browser_context->lock = API_LOCK_INIT_LOCKED(); + file_browser_context->lock = api_lock_alloc_locked(); ViewHolder* view_holder = view_holder_alloc(); view_holder_attach_to_gui(view_holder, gui); @@ -44,7 +44,7 @@ bool dialogs_app_process_module_file_browser(const DialogsAppMessageDataFileBrow view_holder_set_view(view_holder, file_browser_get_view(file_browser)); view_holder_start(view_holder); - API_LOCK_WAIT_UNTIL_UNLOCK(file_browser_context->lock); + api_lock_wait_unlock(file_browser_context->lock); ret = file_browser_context->result; @@ -52,7 +52,7 @@ bool dialogs_app_process_module_file_browser(const DialogsAppMessageDataFileBrow view_holder_free(view_holder); file_browser_stop(file_browser); file_browser_free(file_browser); - API_LOCK_FREE(file_browser_context->lock); + api_lock_free(file_browser_context->lock); free(file_browser_context); furi_record_close(RECORD_GUI); diff --git a/applications/services/dialogs/dialogs_module_message.c b/applications/services/dialogs/dialogs_module_message.c index 8d1c3ba7..879ba9ba 100644 --- a/applications/services/dialogs/dialogs_module_message.c +++ b/applications/services/dialogs/dialogs_module_message.c @@ -1,5 +1,5 @@ #include "dialogs_i.h" -#include "dialogs_api_lock.h" +#include #include typedef struct { @@ -30,7 +30,7 @@ static void dialogs_app_message_back_callback(void* context) { furi_assert(context); DialogsAppMessageContext* message_context = context; message_context->result = DialogMessageButtonBack; - API_LOCK_UNLOCK(message_context->lock); + api_lock_unlock(message_context->lock); } static void dialogs_app_message_callback(DialogExResult result, void* context) { @@ -49,7 +49,7 @@ static void dialogs_app_message_callback(DialogExResult result, void* context) { default: break; } - API_LOCK_UNLOCK(message_context->lock); + api_lock_unlock(message_context->lock); } DialogMessageButton dialogs_app_process_module_message(const DialogsAppMessageDataDialog* data) { @@ -57,7 +57,7 @@ DialogMessageButton dialogs_app_process_module_message(const DialogsAppMessageDa Gui* gui = furi_record_open(RECORD_GUI); const DialogMessage* message = data->message; DialogsAppMessageContext* message_context = malloc(sizeof(DialogsAppMessageContext)); - message_context->lock = API_LOCK_INIT_LOCKED(); + message_context->lock = api_lock_alloc_locked(); ViewHolder* view_holder = view_holder_alloc(); view_holder_attach_to_gui(view_holder, gui); @@ -87,14 +87,14 @@ DialogMessageButton dialogs_app_process_module_message(const DialogsAppMessageDa view_holder_set_view(view_holder, dialog_ex_get_view(dialog_ex)); view_holder_start(view_holder); - API_LOCK_WAIT_UNTIL_UNLOCK(message_context->lock); + api_lock_wait_unlock(message_context->lock); ret = message_context->result; view_holder_stop(view_holder); view_holder_free(view_holder); dialog_ex_free(dialog_ex); - API_LOCK_FREE(message_context->lock); + api_lock_free(message_context->lock); free(message_context); furi_record_close(RECORD_GUI); diff --git a/firmware/targets/f7/furi_hal/furi_hal_memory.c b/firmware/targets/f7/furi_hal/furi_hal_memory.c index 9cf2c312..ec71e666 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_memory.c +++ b/firmware/targets/f7/furi_hal/furi_hal_memory.c @@ -81,6 +81,10 @@ void furi_hal_memory_init() { } void* furi_hal_memory_alloc(size_t size) { + if(FURI_IS_IRQ_MODE()) { + furi_crash("memmgt in ISR"); + } + if(furi_hal_memory == NULL) { return NULL; } diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb.c b/firmware/targets/f7/furi_hal/furi_hal_usb.c index 1eaeffd6..e740155f 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_usb.c +++ b/firmware/targets/f7/furi_hal/furi_hal_usb.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "usb.h" @@ -11,35 +12,67 @@ #define USB_RECONNECT_DELAY 500 +typedef enum { + UsbApiEventTypeSetConfig, + UsbApiEventTypeGetConfig, + UsbApiEventTypeLock, + UsbApiEventTypeUnlock, + UsbApiEventTypeIsLocked, + UsbApiEventTypeEnable, + UsbApiEventTypeDisable, + UsbApiEventTypeReinit, + UsbApiEventTypeSetStateCallback, +} UsbApiEventType; + +typedef struct { + FuriHalUsbStateCallback callback; + void* context; +} UsbApiEventDataStateCallback; + +typedef struct { + FuriHalUsbInterface* interface; + void* context; +} UsbApiEventDataInterface; + +typedef union { + UsbApiEventDataStateCallback state_callback; + UsbApiEventDataInterface interface; +} UsbApiEventData; + +typedef union { + bool bool_value; + void* void_value; +} UsbApiEventReturnData; + +typedef struct { + FuriApiLock lock; + UsbApiEventType type; + UsbApiEventData data; + UsbApiEventReturnData* return_data; +} UsbApiEventMessage; + typedef struct { FuriThread* thread; + FuriMessageQueue* queue; bool enabled; bool connected; bool mode_lock; - FuriHalUsbInterface* if_cur; - FuriHalUsbInterface* if_next; - void* if_ctx; + bool request_pending; + FuriHalUsbInterface* interface; + void* interface_context; FuriHalUsbStateCallback callback; - void* cb_ctx; + void* callback_context; } UsbSrv; typedef enum { - EventModeChange = (1 << 0), - EventEnable = (1 << 1), - EventDisable = (1 << 2), - EventReinit = (1 << 3), - - EventReset = (1 << 4), - EventRequest = (1 << 5), - - EventModeChangeStart = (1 << 6), + UsbEventReset = (1 << 0), + UsbEventRequest = (1 << 1), + UsbEventMessage = (1 << 2), } UsbEvent; -#define USB_SRV_ALL_EVENTS \ - (EventModeChange | EventEnable | EventDisable | EventReinit | EventReset | EventRequest | \ - EventModeChangeStart) +#define USB_SRV_ALL_EVENTS (UsbEventReset | UsbEventRequest | UsbEventMessage) -static UsbSrv usb; +PLACE_IN_SECTION("MB_MEM2") static UsbSrv usb = {0}; static const struct usb_string_descriptor dev_lang_desc = USB_ARRAY_DESC(USB_LANGID_ENG_US); @@ -74,12 +107,13 @@ void furi_hal_usb_init(void) { // Reset callback will be enabled after first mode change to avoid getting false reset events usb.enabled = false; - usb.if_cur = NULL; + usb.interface = NULL; NVIC_SetPriority(USB_LP_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0)); NVIC_SetPriority(USB_HP_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 15, 0)); NVIC_EnableIRQ(USB_LP_IRQn); NVIC_EnableIRQ(USB_HP_IRQn); + usb.queue = furi_message_queue_alloc(1, sizeof(UsbApiEventMessage)); usb.thread = furi_thread_alloc_ex("UsbDriver", 1024, furi_hal_usb_thread, NULL); furi_thread_mark_as_service(usb.thread); furi_thread_start(usb.thread); @@ -87,53 +121,119 @@ void furi_hal_usb_init(void) { FURI_LOG_I(TAG, "Init OK"); } -bool furi_hal_usb_set_config(FuriHalUsbInterface* new_if, void* ctx) { - if(usb.mode_lock) { - return false; - } +static void furi_hal_usb_send_message(UsbApiEventMessage* message) { + furi_message_queue_put(usb.queue, message, FuriWaitForever); + furi_thread_flags_set(furi_thread_get_id(usb.thread), UsbEventMessage); + api_lock_wait_unlock_and_free(message->lock); +} - usb.if_next = new_if; - usb.if_ctx = ctx; - if(usb.thread == NULL) { - // Service thread hasn't started yet, so just save interface mode - return true; - } - furi_assert(usb.thread); - furi_thread_flags_set(furi_thread_get_id(usb.thread), EventModeChange); - return true; +bool furi_hal_usb_set_config(FuriHalUsbInterface* new_if, void* ctx) { + UsbApiEventReturnData return_data = { + .bool_value = false, + }; + + UsbApiEventMessage msg = { + .lock = api_lock_alloc_locked(), + .type = UsbApiEventTypeSetConfig, + .data.interface = + { + .interface = new_if, + .context = ctx, + }, + .return_data = &return_data, + }; + + furi_hal_usb_send_message(&msg); + return return_data.bool_value; } FuriHalUsbInterface* furi_hal_usb_get_config() { - return usb.if_cur; + UsbApiEventReturnData return_data = { + .void_value = NULL, + }; + + UsbApiEventMessage msg = { + .lock = api_lock_alloc_locked(), + .type = UsbApiEventTypeGetConfig, + .return_data = &return_data, + }; + + furi_hal_usb_send_message(&msg); + return return_data.void_value; } void furi_hal_usb_lock() { - FURI_LOG_I(TAG, "Mode lock"); - usb.mode_lock = true; + UsbApiEventMessage msg = { + .lock = api_lock_alloc_locked(), + .type = UsbApiEventTypeLock, + }; + + furi_hal_usb_send_message(&msg); } void furi_hal_usb_unlock() { - FURI_LOG_I(TAG, "Mode unlock"); - usb.mode_lock = false; + UsbApiEventMessage msg = { + .lock = api_lock_alloc_locked(), + .type = UsbApiEventTypeUnlock, + }; + + furi_hal_usb_send_message(&msg); } bool furi_hal_usb_is_locked() { - return usb.mode_lock; + UsbApiEventReturnData return_data = { + .bool_value = false, + }; + + UsbApiEventMessage msg = { + .lock = api_lock_alloc_locked(), + .type = UsbApiEventTypeIsLocked, + .return_data = &return_data, + }; + + furi_hal_usb_send_message(&msg); + return return_data.bool_value; } void furi_hal_usb_disable() { - furi_assert(usb.thread); - furi_thread_flags_set(furi_thread_get_id(usb.thread), EventDisable); + UsbApiEventMessage msg = { + .lock = api_lock_alloc_locked(), + .type = UsbApiEventTypeDisable, + }; + + furi_hal_usb_send_message(&msg); } void furi_hal_usb_enable() { - furi_assert(usb.thread); - furi_thread_flags_set(furi_thread_get_id(usb.thread), EventEnable); + UsbApiEventMessage msg = { + .lock = api_lock_alloc_locked(), + .type = UsbApiEventTypeEnable, + }; + + furi_hal_usb_send_message(&msg); } void furi_hal_usb_reinit() { - furi_assert(usb.thread); - furi_thread_flags_set(furi_thread_get_id(usb.thread), EventReinit); + UsbApiEventMessage msg = { + .lock = api_lock_alloc_locked(), + .type = UsbApiEventTypeReinit, + }; + + furi_hal_usb_send_message(&msg); +} + +void furi_hal_usb_set_state_callback(FuriHalUsbStateCallback cb, void* ctx) { + UsbApiEventMessage msg = { + .lock = api_lock_alloc_locked(), + .type = UsbApiEventTypeSetStateCallback, + .data.state_callback = + { + .callback = cb, + .context = ctx, + }, + }; + + furi_hal_usb_send_message(&msg); } /* Get device / configuration descriptors */ @@ -142,29 +242,29 @@ static usbd_respond usb_descriptor_get(usbd_ctlreq* req, void** address, uint16_ const uint8_t dnumber = req->wValue & 0xFF; const void* desc; uint16_t len = 0; - if(usb.if_cur == NULL) return usbd_fail; + if(usb.interface == NULL) return usbd_fail; switch(dtype) { case USB_DTYPE_DEVICE: - furi_thread_flags_set(furi_thread_get_id(usb.thread), EventRequest); + furi_thread_flags_set(furi_thread_get_id(usb.thread), UsbEventRequest); if(usb.callback != NULL) { - usb.callback(FuriHalUsbStateEventDescriptorRequest, usb.cb_ctx); + usb.callback(FuriHalUsbStateEventDescriptorRequest, usb.callback_context); } - desc = usb.if_cur->dev_descr; + desc = usb.interface->dev_descr; break; case USB_DTYPE_CONFIGURATION: - desc = usb.if_cur->cfg_descr; - len = ((struct usb_string_descriptor*)(usb.if_cur->cfg_descr))->wString[0]; + desc = usb.interface->cfg_descr; + len = ((struct usb_string_descriptor*)(usb.interface->cfg_descr))->wString[0]; break; case USB_DTYPE_STRING: if(dnumber == UsbDevLang) { desc = &dev_lang_desc; - } else if((dnumber == UsbDevManuf) && (usb.if_cur->str_manuf_descr != NULL)) { - desc = usb.if_cur->str_manuf_descr; - } else if((dnumber == UsbDevProduct) && (usb.if_cur->str_prod_descr != NULL)) { - desc = usb.if_cur->str_prod_descr; - } else if((dnumber == UsbDevSerial) && (usb.if_cur->str_serial_descr != NULL)) { - desc = usb.if_cur->str_serial_descr; + } else if((dnumber == UsbDevManuf) && (usb.interface->str_manuf_descr != NULL)) { + desc = usb.interface->str_manuf_descr; + } else if((dnumber == UsbDevProduct) && (usb.interface->str_prod_descr != NULL)) { + desc = usb.interface->str_prod_descr; + } else if((dnumber == UsbDevSerial) && (usb.interface->str_serial_descr != NULL)) { + desc = usb.interface->str_serial_descr; } else return usbd_fail; break; @@ -181,18 +281,13 @@ static usbd_respond usb_descriptor_get(usbd_ctlreq* req, void** address, uint16_ return usbd_ack; } -void furi_hal_usb_set_state_callback(FuriHalUsbStateCallback cb, void* ctx) { - usb.callback = cb; - usb.cb_ctx = ctx; -} - static void reset_evt(usbd_device* dev, uint8_t event, uint8_t ep) { UNUSED(dev); UNUSED(event); UNUSED(ep); - furi_thread_flags_set(furi_thread_get_id(usb.thread), EventReset); + furi_thread_flags_set(furi_thread_get_id(usb.thread), UsbEventReset); if(usb.callback != NULL) { - usb.callback(FuriHalUsbStateEventReset, usb.cb_ctx); + usb.callback(FuriHalUsbStateEventReset, usb.callback_context); } } @@ -200,14 +295,14 @@ static void susp_evt(usbd_device* dev, uint8_t event, uint8_t ep) { UNUSED(dev); UNUSED(event); UNUSED(ep); - if((usb.if_cur != NULL) && (usb.connected == true)) { + if((usb.interface != NULL) && (usb.connected == true)) { usb.connected = false; - usb.if_cur->suspend(&udev); + usb.interface->suspend(&udev); furi_hal_power_insomnia_exit(); } if(usb.callback != NULL) { - usb.callback(FuriHalUsbStateEventSuspend, usb.cb_ctx); + usb.callback(FuriHalUsbStateEventSuspend, usb.callback_context); } } @@ -215,101 +310,161 @@ static void wkup_evt(usbd_device* dev, uint8_t event, uint8_t ep) { UNUSED(dev); UNUSED(event); UNUSED(ep); - if((usb.if_cur != NULL) && (usb.connected == false)) { + if((usb.interface != NULL) && (usb.connected == false)) { usb.connected = true; - usb.if_cur->wakeup(&udev); + usb.interface->wakeup(&udev); furi_hal_power_insomnia_enter(); } if(usb.callback != NULL) { - usb.callback(FuriHalUsbStateEventWakeup, usb.cb_ctx); + usb.callback(FuriHalUsbStateEventWakeup, usb.callback_context); } } +static void usb_process_mode_start(FuriHalUsbInterface* interface, void* context) { + if(usb.interface != NULL) { + usb.interface->deinit(&udev); + } + + __disable_irq(); + usb.interface = interface; + usb.interface_context = context; + __enable_irq(); + + if(interface != NULL) { + interface->init(&udev, interface, context); + usbd_reg_event(&udev, usbd_evt_reset, reset_evt); + FURI_LOG_I(TAG, "USB Mode change done"); + usb.enabled = true; + } +} + +static void usb_process_mode_change(FuriHalUsbInterface* interface, void* context) { + if(interface != usb.interface) { + if(usb.enabled) { + // Disable current interface + susp_evt(&udev, 0, 0); + usbd_connect(&udev, false); + usb.enabled = false; + furi_delay_ms(USB_RECONNECT_DELAY); + } + usb_process_mode_start(interface, context); + } +} + +static void usb_process_mode_reinit() { + // Temporary disable callback to avoid getting false reset events + usbd_reg_event(&udev, usbd_evt_reset, NULL); + FURI_LOG_I(TAG, "USB Reinit"); + susp_evt(&udev, 0, 0); + usbd_connect(&udev, false); + usb.enabled = false; + + usbd_enable(&udev, false); + usbd_enable(&udev, true); + + furi_delay_ms(USB_RECONNECT_DELAY); + usb_process_mode_start(usb.interface, usb.interface_context); +} + +static bool usb_process_set_config(FuriHalUsbInterface* interface, void* context) { + if(usb.mode_lock) { + return false; + } else { + usb_process_mode_change(interface, context); + return true; + } +} + +static void usb_process_enable(bool enable) { + if(enable) { + if((!usb.enabled) && (usb.interface != NULL)) { + usbd_connect(&udev, true); + usb.enabled = true; + FURI_LOG_I(TAG, "USB Enable"); + } + } else { + if(usb.enabled) { + susp_evt(&udev, 0, 0); + usbd_connect(&udev, false); + usb.enabled = false; + usb.request_pending = false; + FURI_LOG_I(TAG, "USB Disable"); + } + } +} + +static void usb_process_message(UsbApiEventMessage* message) { + switch(message->type) { + case UsbApiEventTypeSetConfig: + message->return_data->bool_value = usb_process_set_config( + message->data.interface.interface, message->data.interface.context); + break; + case UsbApiEventTypeGetConfig: + message->return_data->void_value = usb.interface; + break; + case UsbApiEventTypeLock: + FURI_LOG_I(TAG, "Mode lock"); + usb.mode_lock = true; + break; + case UsbApiEventTypeUnlock: + FURI_LOG_I(TAG, "Mode unlock"); + usb.mode_lock = false; + break; + case UsbApiEventTypeIsLocked: + message->return_data->bool_value = usb.mode_lock; + break; + case UsbApiEventTypeDisable: + usb_process_enable(false); + break; + case UsbApiEventTypeEnable: + usb_process_enable(true); + break; + case UsbApiEventTypeReinit: + usb_process_mode_reinit(); + break; + case UsbApiEventTypeSetStateCallback: + usb.callback = message->data.state_callback.callback; + usb.callback_context = message->data.state_callback.context; + break; + } + + api_lock_unlock(message->lock); +} + static int32_t furi_hal_usb_thread(void* context) { UNUSED(context); - bool usb_request_pending = false; uint8_t usb_wait_time = 0; - FuriHalUsbInterface* if_new = NULL; - FuriHalUsbInterface* if_ctx_new = NULL; - if(usb.if_next != NULL) { - furi_thread_flags_set(furi_thread_get_id(usb.thread), EventModeChange); + if(furi_message_queue_get_count(usb.queue) > 0) { + furi_thread_flags_set(furi_thread_get_id(usb.thread), UsbEventMessage); } while(true) { uint32_t flags = furi_thread_flags_wait(USB_SRV_ALL_EVENTS, FuriFlagWaitAny, 500); + + { + UsbApiEventMessage message; + if(furi_message_queue_get(usb.queue, &message, 0) == FuriStatusOk) { + usb_process_message(&message); + } + } + if((flags & FuriFlagError) == 0) { - if(flags & EventModeChange) { - if(usb.if_next != usb.if_cur) { - if_new = usb.if_next; - if_ctx_new = usb.if_ctx; - if(usb.enabled) { // Disable current interface - susp_evt(&udev, 0, 0); - usbd_connect(&udev, false); - usb.enabled = false; - furi_delay_ms(USB_RECONNECT_DELAY); - } - flags |= EventModeChangeStart; - } - } - if(flags & EventReinit) { - // Temporary disable callback to avoid getting false reset events - usbd_reg_event(&udev, usbd_evt_reset, NULL); - FURI_LOG_I(TAG, "USB Reinit"); - susp_evt(&udev, 0, 0); - usbd_connect(&udev, false); - usb.enabled = false; - - usbd_enable(&udev, false); - usbd_enable(&udev, true); - - if_new = usb.if_cur; - furi_delay_ms(USB_RECONNECT_DELAY); - flags |= EventModeChangeStart; - } - if(flags & EventModeChangeStart) { // Second stage of mode change process - if(usb.if_cur != NULL) { - usb.if_cur->deinit(&udev); - } - if(if_new != NULL) { - if_new->init(&udev, if_new, if_ctx_new); - usbd_reg_event(&udev, usbd_evt_reset, reset_evt); - FURI_LOG_I(TAG, "USB Mode change done"); - usb.enabled = true; - } - usb.if_cur = if_new; - } - if(flags & EventEnable) { - if((!usb.enabled) && (usb.if_cur != NULL)) { - usbd_connect(&udev, true); - usb.enabled = true; - FURI_LOG_I(TAG, "USB Enable"); - } - } - if(flags & EventDisable) { + if(flags & UsbEventReset) { if(usb.enabled) { - susp_evt(&udev, 0, 0); - usbd_connect(&udev, false); - usb.enabled = false; - usb_request_pending = false; - FURI_LOG_I(TAG, "USB Disable"); - } - } - if(flags & EventReset) { - if(usb.enabled) { - usb_request_pending = true; + usb.request_pending = true; usb_wait_time = 0; } } - if(flags & EventRequest) { - usb_request_pending = false; + if(flags & UsbEventRequest) { + usb.request_pending = false; } - } else if(usb_request_pending) { + } else if(usb.request_pending) { usb_wait_time++; if(usb_wait_time > 4) { - furi_hal_usb_reinit(); - usb_request_pending = false; + usb_process_mode_reinit(); + usb.request_pending = false; } } } diff --git a/furi/core/memmgr_heap.c b/furi/core/memmgr_heap.c index ac51b4a2..01153fe5 100644 --- a/furi/core/memmgr_heap.c +++ b/furi/core/memmgr_heap.c @@ -340,6 +340,10 @@ void* pvPortMalloc(size_t xWantedSize) { void* pvReturn = NULL; size_t to_wipe = xWantedSize; + if(FURI_IS_IRQ_MODE()) { + furi_crash("memmgt in ISR"); + } + #ifdef HEAP_PRINT_DEBUG BlockLink_t* print_heap_block = NULL; #endif @@ -486,6 +490,10 @@ void vPortFree(void* pv) { uint8_t* puc = (uint8_t*)pv; BlockLink_t* pxLink; + if(FURI_IS_IRQ_MODE()) { + furi_crash("memmgt in ISR"); + } + if(pv != NULL) { /* The memory being freed will have an BlockLink_t structure immediately before it. */ diff --git a/lib/toolbox/api_lock.h b/lib/toolbox/api_lock.h new file mode 100644 index 00000000..5902a492 --- /dev/null +++ b/lib/toolbox/api_lock.h @@ -0,0 +1,43 @@ +#pragma once +#include + +/* +Testing 10000 api calls + +No lock + Time diff: 445269.218750 us + Time per call: 44.526920 us + +furi_thread_flags + Time diff: 430279.875000 us // lol wtf? smaller than no lock? + Time per call: 43.027988 us // I tested it many times, it's always smaller + +FuriEventFlag + Time diff: 831523.625000 us + Time per call: 83.152359 us + +FuriSemaphore + Time diff: 999807.125000 us + Time per call: 99.980713 us + +FuriMutex + Time diff: 1071417.500000 us + Time per call: 107.141747 us +*/ + +typedef FuriEventFlag* FuriApiLock; + +#define API_LOCK_EVENT (1U << 0) + +#define api_lock_alloc_locked() furi_event_flag_alloc() + +#define api_lock_wait_unlock(_lock) \ + furi_event_flag_wait(_lock, API_LOCK_EVENT, FuriFlagWaitAny, FuriWaitForever) + +#define api_lock_free(_lock) furi_event_flag_free(_lock) + +#define api_lock_unlock(_lock) furi_event_flag_set(_lock, API_LOCK_EVENT) + +#define api_lock_wait_unlock_and_free(_lock) \ + api_lock_wait_unlock(_lock); \ + api_lock_free(_lock); From b70395eba9161c26807494c6db8f1ca22cf77ee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9D=D0=B8=D0=BA=D0=B8=D1=82=D0=B0=20=D0=A2=D0=B8=D0=BC?= =?UTF-8?q?=D0=BE=D1=84=D0=B5=D0=B5=D0=B2?= Date: Tue, 29 Nov 2022 16:10:02 +0300 Subject: [PATCH 23/25] Allow "Detect reader" for unsaved card (#2045) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Allow "Detect reader" for unsaved card * Add missed detect reader deed Co-authored-by: あく --- .../nfc/scenes/nfc_scene_mf_classic_menu.c | 20 +++++++++++++------ .../main/nfc/scenes/nfc_scene_saved_menu.c | 1 + 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c index a5bb10dd..5fbdabe3 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c @@ -4,6 +4,7 @@ enum SubmenuIndex { SubmenuIndexSave, SubmenuIndexEmulate, + SubmenuIndexDetectReader, SubmenuIndexInfo, }; @@ -21,6 +22,14 @@ void nfc_scene_mf_classic_menu_on_enter(void* context) { submenu, "Save", SubmenuIndexSave, nfc_scene_mf_classic_menu_submenu_callback, nfc); submenu_add_item( submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_mf_classic_menu_submenu_callback, nfc); + if(!mf_classic_is_card_read(&nfc->dev->dev_data.mf_classic_data)) { + submenu_add_item( + submenu, + "Detect reader", + SubmenuIndexDetectReader, + nfc_scene_mf_classic_menu_submenu_callback, + nfc); + } submenu_add_item( submenu, "Info", SubmenuIndexInfo, nfc_scene_mf_classic_menu_submenu_callback, nfc); @@ -35,17 +44,14 @@ bool nfc_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event) bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfClassicMenu, event.event); if(event.event == SubmenuIndexSave) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMfClassicMenu, SubmenuIndexSave); nfc->dev->format = NfcDeviceSaveFormatMifareClassic; // Clear device name nfc_device_set_name(nfc->dev, ""); scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); consumed = true; } else if(event.event == SubmenuIndexEmulate) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMfClassicMenu, SubmenuIndexEmulate); scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate); if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { DOLPHIN_DEED(DolphinDeedNfcAddEmulate); @@ -53,9 +59,11 @@ bool nfc_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event) DOLPHIN_DEED(DolphinDeedNfcEmulate); } consumed = true; + } else if(event.event == SubmenuIndexDetectReader) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader); + DOLPHIN_DEED(DolphinDeedNfcDetectReader); + consumed = true; } else if(event.event == SubmenuIndexInfo) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMfClassicMenu, SubmenuIndexInfo); scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); consumed = true; } diff --git a/applications/main/nfc/scenes/nfc_scene_saved_menu.c b/applications/main/nfc/scenes/nfc_scene_saved_menu.c index e0839d66..04c686fb 100644 --- a/applications/main/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_saved_menu.c @@ -123,6 +123,7 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { consumed = true; } else if(event.event == SubmenuIndexDetectReader) { scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader); + DOLPHIN_DEED(DolphinDeedNfcDetectReader); consumed = true; } else if(event.event == SubmenuIndexWrite) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicWrite); From 0ab14c37c96083d7818640d2a4c24a02be4fc0cf Mon Sep 17 00:00:00 2001 From: Danil Kalashnikov Date: Tue, 29 Nov 2022 20:31:32 +0700 Subject: [PATCH 24/25] fbt: add missing Force flag when moving toolchain from temp path (#2044) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- scripts/toolchain/windows-toolchain-download.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/toolchain/windows-toolchain-download.ps1 b/scripts/toolchain/windows-toolchain-download.ps1 index c96bb119..05ea4be2 100644 --- a/scripts/toolchain/windows-toolchain-download.ps1 +++ b/scripts/toolchain/windows-toolchain-download.ps1 @@ -36,11 +36,11 @@ Add-Type -Assembly "System.IO.Compression.Filesystem" # Expand-Archive -LiteralPath "$toolchain_zip_temp_path" -DestinationPath "$download_dir" Write-Host -NoNewline "moving.." -Move-Item -LiteralPath "$toolchain_dist_temp_path" -Destination "$toolchain_target_path" +Move-Item -LiteralPath "$toolchain_dist_temp_path" -Destination "$toolchain_target_path" -Force Write-Host "done!" Write-Host -NoNewline "Cleaning up temporary files.." Remove-Item -LiteralPath "$toolchain_zip_temp_path" -Force Write-Host "done!" -# dasdasd \ No newline at end of file +# dasdasd From 2a6a3a1bf7ba1ecb42b8cbfc1b1856a54f2878b7 Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Wed, 30 Nov 2022 15:41:23 +0400 Subject: [PATCH 25/25] [FL-2955], [FL-2953] SubGhz: fix RAW "Send never ends" (#1979) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * SubGhz: fix RAW "Send never ends" * SubGhz: delete comments * SubGhz: RAW file parsing speed increase * SubGhz: fix level_duration_is_wait * SubGhz: modification furi_hal_subghz_async_tx_refill * SubGhz: furi_hal_subghz_stop_async_rx * SubGhz: hal unit test and better async tx yield handling * FuriHal: proper async tx end in subghz, vibro on power off * FuriHal: variable naming in subghz * SubGhz,FuriHal: extreme timings in subghz hal unit tests, remove memset in async tx buffer fill routine * FuriHal: small refinements in subghz Co-authored-by: あく --- .../debug/unit_tests/subghz/subghz_test.c | 145 ++++++++++++++++++ firmware/targets/f7/furi_hal/furi_hal_power.c | 5 +- .../targets/f7/furi_hal/furi_hal_subghz.c | 77 +++++----- .../furi_hal_include/furi_hal_subghz.h | 5 + lib/subghz/subghz_file_encoder_worker.c | 16 +- 5 files changed, 204 insertions(+), 44 deletions(-) diff --git a/applications/debug/unit_tests/subghz/subghz_test.c b/applications/debug/unit_tests/subghz/subghz_test.c index 3052448b..fe834c60 100644 --- a/applications/debug/unit_tests/subghz/subghz_test.c +++ b/applications/debug/unit_tests/subghz/subghz_test.c @@ -209,6 +209,149 @@ MU_TEST(subghz_keystore_test) { "Test keystore error"); } +typedef enum { + SubGhzHalAsyncTxTestTypeNormal, + SubGhzHalAsyncTxTestTypeInvalidStart, + SubGhzHalAsyncTxTestTypeInvalidMid, + SubGhzHalAsyncTxTestTypeInvalidEnd, + SubGhzHalAsyncTxTestTypeResetStart, + SubGhzHalAsyncTxTestTypeResetMid, + SubGhzHalAsyncTxTestTypeResetEnd, +} SubGhzHalAsyncTxTestType; + +typedef struct { + SubGhzHalAsyncTxTestType type; + size_t pos; +} SubGhzHalAsyncTxTest; + +#define SUBGHZ_HAL_TEST_DURATION 1 + +static LevelDuration subghz_hal_async_tx_test_yield(void* context) { + SubGhzHalAsyncTxTest* test = context; + bool is_odd = test->pos % 2; + + if(test->type == SubGhzHalAsyncTxTestTypeNormal) { + if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) { + test->pos++; + return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION); + } else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) { + test->pos++; + return level_duration_reset(); + } else { + furi_crash("Yield after reset"); + } + } else if(test->type == SubGhzHalAsyncTxTestTypeInvalidStart) { + if(test->pos == 0) { + test->pos++; + return level_duration_make(!is_odd, SUBGHZ_HAL_TEST_DURATION); + } else if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) { + test->pos++; + return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION); + } else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) { + test->pos++; + return level_duration_reset(); + } else { + furi_crash("Yield after reset"); + } + } else if(test->type == SubGhzHalAsyncTxTestTypeInvalidMid) { + if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF / 2) { + test->pos++; + return level_duration_make(!is_odd, SUBGHZ_HAL_TEST_DURATION); + } else if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) { + test->pos++; + return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION); + } else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) { + test->pos++; + return level_duration_reset(); + } else { + furi_crash("Yield after reset"); + } + } else if(test->type == SubGhzHalAsyncTxTestTypeInvalidEnd) { + if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL - 1) { + test->pos++; + return level_duration_make(!is_odd, SUBGHZ_HAL_TEST_DURATION); + } else if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) { + test->pos++; + return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION); + } else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) { + test->pos++; + return level_duration_reset(); + } else { + furi_crash("Yield after reset"); + } + } else if(test->type == SubGhzHalAsyncTxTestTypeResetStart) { + if(test->pos == 0) { + test->pos++; + return level_duration_reset(); + } else { + furi_crash("Yield after reset"); + } + } else if(test->type == SubGhzHalAsyncTxTestTypeResetMid) { + if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF / 2) { + test->pos++; + return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION); + } else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF / 2) { + test->pos++; + return level_duration_reset(); + } else { + furi_crash("Yield after reset"); + } + } else if(test->type == SubGhzHalAsyncTxTestTypeResetEnd) { + if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL - 1) { + test->pos++; + return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION); + } else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL - 1) { + test->pos++; + return level_duration_reset(); + } else { + furi_crash("Yield after reset"); + } + } else { + furi_crash("Programming error"); + } +} + +bool subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestType type) { + SubGhzHalAsyncTxTest test = {0}; + test.type = type; + furi_hal_subghz_reset(); + furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); + furi_hal_subghz_set_frequency_and_path(433920000); + + furi_hal_subghz_start_async_tx(subghz_hal_async_tx_test_yield, &test); + while(!furi_hal_subghz_is_async_tx_complete()) { + furi_delay_ms(10); + } + furi_hal_subghz_stop_async_tx(); + furi_hal_subghz_sleep(); + + return true; +} + +MU_TEST(subghz_hal_async_tx_test) { + mu_assert( + subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestTypeNormal), + "Test furi_hal_async_tx normal"); + mu_assert( + subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestTypeInvalidStart), + "Test furi_hal_async_tx invalid start"); + mu_assert( + subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestTypeInvalidMid), + "Test furi_hal_async_tx invalid mid"); + mu_assert( + subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestTypeInvalidEnd), + "Test furi_hal_async_tx invalid end"); + mu_assert( + subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestTypeResetStart), + "Test furi_hal_async_tx reset start"); + mu_assert( + subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestTypeResetMid), + "Test furi_hal_async_tx reset mid"); + mu_assert( + subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestTypeResetEnd), + "Test furi_hal_async_tx reset end"); +} + //test decoders MU_TEST(subghz_decoder_came_atomo_test) { mu_assert( @@ -579,6 +722,8 @@ MU_TEST_SUITE(subghz) { subghz_test_init(); MU_RUN_TEST(subghz_keystore_test); + MU_RUN_TEST(subghz_hal_async_tx_test); + MU_RUN_TEST(subghz_decoder_came_atomo_test); MU_RUN_TEST(subghz_decoder_came_test); MU_RUN_TEST(subghz_decoder_came_twee_test); diff --git a/firmware/targets/f7/furi_hal/furi_hal_power.c b/firmware/targets/f7/furi_hal/furi_hal_power.c index 88e191e9..ddb05690 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_power.c +++ b/firmware/targets/f7/furi_hal/furi_hal_power.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -308,11 +309,13 @@ void furi_hal_power_shutdown() { void furi_hal_power_off() { // Crutch: shutting down with ext 3V3 off is causing LSE to stop furi_hal_power_enable_external_3_3v(); - furi_delay_us(1000); + furi_hal_vibro_on(true); + furi_delay_us(50000); // Send poweroff to charger furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); bq25896_poweroff(&furi_hal_i2c_handle_power); furi_hal_i2c_release(&furi_hal_i2c_handle_power); + furi_hal_vibro_on(false); } void furi_hal_power_reset() { diff --git a/firmware/targets/f7/furi_hal/furi_hal_subghz.c b/firmware/targets/f7/furi_hal/furi_hal_subghz.c index 5eeb4e9a..726b2d7f 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_subghz.c +++ b/firmware/targets/f7/furi_hal/furi_hal_subghz.c @@ -488,13 +488,9 @@ void furi_hal_subghz_stop_async_rx() { furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); } -#define API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL (256) -#define API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF (API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL / 2) -#define API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME 333 - typedef struct { uint32_t* buffer; - bool flip_flop; + LevelDuration carry_ld; FuriHalSubGhzAsyncTxCallback callback; void* callback_context; uint64_t duty_high; @@ -504,37 +500,48 @@ typedef struct { static FuriHalSubGhzAsyncTx furi_hal_subghz_async_tx = {0}; static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) { + furi_assert(furi_hal_subghz.state == SubGhzStateAsyncTx); while(samples > 0) { bool is_odd = samples % 2; - LevelDuration ld = - furi_hal_subghz_async_tx.callback(furi_hal_subghz_async_tx.callback_context); + LevelDuration ld; + if(level_duration_is_reset(furi_hal_subghz_async_tx.carry_ld)) { + ld = furi_hal_subghz_async_tx.callback(furi_hal_subghz_async_tx.callback_context); + } else { + ld = furi_hal_subghz_async_tx.carry_ld; + furi_hal_subghz_async_tx.carry_ld = level_duration_reset(); + } if(level_duration_is_wait(ld)) { - return; + *buffer = API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME; + buffer++; + samples--; } else if(level_duration_is_reset(ld)) { - // One more even sample required to end at low level - if(is_odd) { - *buffer = API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME; - buffer++; - samples--; - furi_hal_subghz_async_tx.duty_low += API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME; - } + *buffer = 0; + buffer++; + samples--; + LL_DMA_DisableIT_HT(DMA1, LL_DMA_CHANNEL_1); + LL_DMA_DisableIT_TC(DMA1, LL_DMA_CHANNEL_1); + LL_TIM_EnableIT_UPDATE(TIM2); break; } else { - // Inject guard time if level is incorrect bool level = level_duration_get_level(ld); - if(is_odd == level) { + + // Inject guard time if level is incorrect + if(is_odd != level) { *buffer = API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME; buffer++; samples--; - if(!level) { + if(is_odd) { furi_hal_subghz_async_tx.duty_high += API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME; } else { furi_hal_subghz_async_tx.duty_low += API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME; } - // This code must be invoked only once: when encoder starts with low level. - // Otherwise whole thing will crash. - furi_check(samples > 0); + + // Special case: prevent buffer overflow if sample is last + if(samples == 0) { + furi_hal_subghz_async_tx.carry_ld = ld; + break; + } } uint32_t duration = level_duration_get_duration(ld); @@ -543,22 +550,17 @@ static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) { buffer++; samples--; - if(level) { + if(is_odd) { furi_hal_subghz_async_tx.duty_high += duration; } else { furi_hal_subghz_async_tx.duty_low += duration; } } } - - memset(buffer, 0, samples * sizeof(uint32_t)); } static void furi_hal_subghz_async_tx_dma_isr() { - furi_assert( - furi_hal_subghz.state == SubGhzStateAsyncTx || - furi_hal_subghz.state == SubGhzStateAsyncTxEnd || - furi_hal_subghz.state == SubGhzStateAsyncTxLast); + furi_assert(furi_hal_subghz.state == SubGhzStateAsyncTx); if(LL_DMA_IsActiveFlag_HT1(DMA1)) { LL_DMA_ClearFlag_HT1(DMA1); furi_hal_subghz_async_tx_refill( @@ -578,11 +580,14 @@ static void furi_hal_subghz_async_tx_timer_isr() { if(LL_TIM_GetAutoReload(TIM2) == 0) { if(furi_hal_subghz.state == SubGhzStateAsyncTx) { furi_hal_subghz.state = SubGhzStateAsyncTxLast; + LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1); + } else if(furi_hal_subghz.state == SubGhzStateAsyncTxLast) { + furi_hal_subghz.state = SubGhzStateAsyncTxEnd; //forcibly pulls the pin to the ground so that there is no carrier furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullDown, GpioSpeedLow); - } else { - furi_hal_subghz.state = SubGhzStateAsyncTxEnd; LL_TIM_DisableCounter(TIM2); + } else { + furi_crash(NULL); } } } @@ -605,8 +610,6 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* furi_hal_subghz_async_tx.buffer = malloc(API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * sizeof(uint32_t)); - furi_hal_subghz_async_tx_refill( - furi_hal_subghz_async_tx.buffer, API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL); // Connect CC1101_GD0 to TIM2 as output furi_hal_gpio_init_ex( @@ -647,14 +650,16 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_DISABLE; TIM_OC_InitStruct.OCNState = LL_TIM_OCSTATE_DISABLE; TIM_OC_InitStruct.CompareValue = 0; - TIM_OC_InitStruct.OCPolarity = LL_TIM_OCPOLARITY_HIGH; + TIM_OC_InitStruct.OCPolarity = LL_TIM_OCPOLARITY_LOW; LL_TIM_OC_Init(TIM2, LL_TIM_CHANNEL_CH2, &TIM_OC_InitStruct); LL_TIM_OC_DisableFast(TIM2, LL_TIM_CHANNEL_CH2); LL_TIM_DisableMasterSlaveMode(TIM2); furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, furi_hal_subghz_async_tx_timer_isr, NULL); - LL_TIM_EnableIT_UPDATE(TIM2); + furi_hal_subghz_async_tx_refill( + furi_hal_subghz_async_tx.buffer, API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL); + LL_TIM_EnableDMAReq_UPDATE(TIM2); LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2); @@ -673,8 +678,8 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* &SUBGHZ_DEBUG_CC1101_PIN, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); const GpioPin* gpio = &SUBGHZ_DEBUG_CC1101_PIN; - subghz_debug_gpio_buff[0] = gpio->pin; - subghz_debug_gpio_buff[1] = (uint32_t)gpio->pin << GPIO_NUMBER; + subghz_debug_gpio_buff[0] = (uint32_t)gpio->pin << GPIO_NUMBER; + subghz_debug_gpio_buff[1] = gpio->pin; dma_config.MemoryOrM2MDstAddress = (uint32_t)subghz_debug_gpio_buff; dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (gpio->port->BSRR); diff --git a/firmware/targets/furi_hal_include/furi_hal_subghz.h b/firmware/targets/furi_hal_include/furi_hal_subghz.h index d610b01b..1f99386c 100644 --- a/firmware/targets/furi_hal_include/furi_hal_subghz.h +++ b/firmware/targets/furi_hal_include/furi_hal_subghz.h @@ -14,6 +14,11 @@ extern "C" { #endif +/** Low level buffer dimensions and guard times */ +#define API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL (256) +#define API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF (API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL / 2) +#define API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME 999 + /** Radio Presets */ typedef enum { FuriHalSubGhzPresetIDLE, /**< default configuration */ diff --git a/lib/subghz/subghz_file_encoder_worker.c b/lib/subghz/subghz_file_encoder_worker.c index f987430d..abc33188 100644 --- a/lib/subghz/subghz_file_encoder_worker.c +++ b/lib/subghz/subghz_file_encoder_worker.c @@ -18,6 +18,7 @@ struct SubGhzFileEncoderWorker { volatile bool worker_running; volatile bool worker_stoping; bool level; + bool is_storage_slow; FuriString* str_data; FuriString* file_path; @@ -86,7 +87,7 @@ LevelDuration subghz_file_encoder_worker_get_level_duration(void* context) { if(ret == sizeof(int32_t)) { LevelDuration level_duration = {.level = LEVEL_DURATION_RESET}; if(duration < 0) { - level_duration = level_duration_make(false, duration * -1); + level_duration = level_duration_make(false, -duration); } else if(duration > 0) { level_duration = level_duration_make(true, duration); } else if(duration == 0) { @@ -96,7 +97,7 @@ LevelDuration subghz_file_encoder_worker_get_level_duration(void* context) { } return level_duration; } else { - FURI_LOG_E(TAG, "Slow flash read"); + instance->is_storage_slow = true; return level_duration_wait(); } } @@ -110,6 +111,7 @@ static int32_t subghz_file_encoder_worker_thread(void* context) { SubGhzFileEncoderWorker* instance = context; FURI_LOG_I(TAG, "Worker start"); bool res = false; + instance->is_storage_slow = false; Stream* stream = flipper_format_get_raw_stream(instance->flipper_format); do { if(!flipper_format_file_open_existing( @@ -139,21 +141,21 @@ static int32_t subghz_file_encoder_worker_thread(void* context) { furi_string_trim(instance->str_data); if(!subghz_file_encoder_worker_data_parse( instance, furi_string_get_cstr(instance->str_data))) { - //to stop DMA correctly subghz_file_encoder_worker_add_level_duration(instance, LEVEL_DURATION_RESET); - subghz_file_encoder_worker_add_level_duration(instance, LEVEL_DURATION_RESET); - break; } } else { - subghz_file_encoder_worker_add_level_duration(instance, LEVEL_DURATION_RESET); subghz_file_encoder_worker_add_level_duration(instance, LEVEL_DURATION_RESET); break; } + } else { + furi_delay_ms(1); } - furi_delay_ms(5); } //waiting for the end of the transfer + if(instance->is_storage_slow) { + FURI_LOG_E(TAG, "Storage is slow"); + } FURI_LOG_I(TAG, "End read file"); while(!furi_hal_subghz_is_async_tx_complete() && instance->worker_running) { furi_delay_ms(5);