diff --git a/applications/unit_tests/subghz/subghz_test.c b/applications/unit_tests/subghz/subghz_test.c index 680f199a..fea407ed 100644 --- a/applications/unit_tests/subghz/subghz_test.c +++ b/applications/unit_tests/subghz/subghz_test.c @@ -13,7 +13,7 @@ #define CAME_ATOMO_DIR_NAME "/ext/subghz/assets/came_atomo" #define NICE_FLOR_S_DIR_NAME "/ext/subghz/assets/nice_flor_s" #define TEST_RANDOM_DIR_NAME "/ext/unit_tests/subghz/test_random_raw.sub" -#define TEST_RANDOM_COUNT_PARSE 113 +#define TEST_RANDOM_COUNT_PARSE 119 #define TEST_TIMEOUT 10000 static SubGhzEnvironment* environment_handler; @@ -361,6 +361,13 @@ MU_TEST(subghz_decoder_holtek_test) { "Test decoder " SUBGHZ_PROTOCOL_HOLTEK_NAME " error\r\n"); } +MU_TEST(subghz_decoder_power_smart_test) { + mu_assert( + subghz_decoder_test( + "/ext/unit_tests/subghz/power_smart_raw.sub", SUBGHZ_PROTOCOL_POWER_SMART_NAME), + "Test decoder " SUBGHZ_PROTOCOL_POWER_SMART_NAME " error\r\n"); +} + //test encoders MU_TEST(subghz_encoder_princeton_test) { mu_assert( @@ -428,6 +435,12 @@ MU_TEST(subghz_encoder_secplus_v2_test) { "Test encoder " SUBGHZ_PROTOCOL_SECPLUS_V2_NAME " error\r\n"); } +MU_TEST(subghz_encoder_power_smart_test) { + mu_assert( + subghz_encoder_test("/ext/unit_tests/subghz/power_smart.sub"), + "Test encoder " SUBGHZ_PROTOCOL_POWER_SMART_NAME " error\r\n"); +} + MU_TEST(subghz_random_test) { mu_assert(subghz_decode_random_test(TEST_RANDOM_DIR_NAME), "Random test error\r\n"); } @@ -459,6 +472,7 @@ MU_TEST_SUITE(subghz) { MU_RUN_TEST(subghz_decoder_secplus_v1_test); MU_RUN_TEST(subghz_decoder_secplus_v2_test); MU_RUN_TEST(subghz_decoder_holtek_test); + MU_RUN_TEST(subghz_decoder_power_smart_test); MU_RUN_TEST(subghz_encoder_princeton_test); MU_RUN_TEST(subghz_encoder_came_test); @@ -471,6 +485,7 @@ MU_TEST_SUITE(subghz) { MU_RUN_TEST(subghz_encoder_holtek_test); MU_RUN_TEST(subghz_encoder_secplus_v1_test); MU_RUN_TEST(subghz_encoder_secplus_v2_test); + MU_RUN_TEST(subghz_encoder_power_smart_test); MU_RUN_TEST(subghz_random_test); subghz_test_deinit(); diff --git a/assets/unit_tests/subghz/power_smart.sub b/assets/unit_tests/subghz/power_smart.sub new file mode 100644 index 00000000..445458b8 --- /dev/null +++ b/assets/unit_tests/subghz/power_smart.sub @@ -0,0 +1,7 @@ +Filetype: Flipper SubGhz Key File +Version: 1 +Frequency: 433420000 +Preset: FuriHalSubGhzPresetOok650Async +Protocol: Power Smart +Bit: 64 +Key: FD C1 36 AC AA 3E C9 52 diff --git a/assets/unit_tests/subghz/power_smart_raw.sub b/assets/unit_tests/subghz/power_smart_raw.sub new file mode 100644 index 00000000..0aafc87c --- /dev/null +++ b/assets/unit_tests/subghz/power_smart_raw.sub @@ -0,0 +1,7 @@ +Filetype: Flipper SubGhz RAW File +Version: 1 +Frequency: 433420000 +Preset: FuriHalSubGhzPresetOok270Async +Protocol: RAW +RAW_Data: -68 521674 -200 213 -258 217 -218 217 -246 193 -242 211 -466 451 -450 225 -212 211 -242 211 -238 243 -200 223 -254 419 -226 221 -432 251 -212 467 -240 203 -450 449 -246 205 -238 217 -218 217 -444 439 -478 431 -230 211 -462 247 -214 435 -454 449 -456 441 -442 471 -448 449 -246 205 -238 215 -220 217 -244 201 -254 217 -430 235 -220 461 -198 223 -442 275 -212 429 -458 245 -212 203 -228 253 -218 431 -448 451 -442 235 -218 463 -426 485 -214 209 -234 221 -254 219 -214 207 -228 253 -428 459 -418 245 -216 243 -194 241 -212 241 -212 211 -244 441 -228 215 -460 217 -244 435 -236 235 -440 439 -246 213 -208 229 -256 217 -430 445 -450 445 -236 253 -420 225 -232 429 -450 465 -448 439 -448 449 -454 453 -230 225 -214 241 -212 211 -242 211 -244 237 -442 237 -218 429 -230 221 -442 241 -246 425 -458 245 -212 203 -228 255 -218 427 -448 451 -446 235 -256 425 -462 417 -244 251 -208 201 -256 217 -218 209 -232 255 -420 451 -448 217 -242 211 -238 209 -234 221 -256 217 -218 437 -238 217 -464 203 -256 419 -226 223 -464 441 -244 213 -240 197 -254 219 -430 445 -452 479 -204 253 -420 225 -222 463 -452 449 -450 449 -452 447 -450 451 -238 215 -220 217 -244 199 -256 217 -218 207 -440 241 -254 423 -238 217 -462 197 -224 471 -448 225 -220 213 -242 211 -212 465 -446 449 -456 245 -214 437 -456 449 -232 233 -216 219 -254 207 -204 253 -218 219 -440 451 -456 237 -216 217 -254 209 -202 253 -218 219 -210 437 -244 253 -422 237 -218 423 -226 247 -430 451 -242 203 -228 253 -220 217 -442 449 -454 449 -240 217 -430 237 -218 461 -426 453 -450 465 -448 451 -440 443 -246 215 -250 201 -224 255 -218 215 -208 227 -442 239 -208 457 -238 219 -464 201 -256 425 -464 201 -256 217 -210 241 -216 451 -426 445 -486 207 -236 441 -430 479 -194 223 -256 217 -218 209 -234 253 -218 217 -438 449 -454 239 -216 217 -256 207 -202 255 -218 217 -210 439 -244 253 -424 235 -218 457 -224 229 -436 449 -230 221 -214 211 -242 211 -468 447 -450 449 -250 207 -454 239 -218 431 -446 451 -448 443 -486 447 -448 431 -240 207 -232 223 -254 219 -216 209 -230 253 -426 233 -234 433 -244 213 -432 237 -218 463 -446 221 -212 211 -242 239 -208 457 -456 451 -456 223 -212 467 -450 453 -204 253 -218 211 -240 215 -218 255 -208 201 -442 479 -452 203 -254 217 -212 241 -216 217 -256 207 -202 439 -240 245 -430 237 -218 463 -240 217 -428 465 -202 253 -218 213 -234 219 +RAW_Data: -444 443 -452 455 -244 213 -440 237 -254 427 -450 429 -480 417 -454 477 -430 445 -244 217 -250 203 -224 253 -220 215 -206 221 -462 217 -212 467 -234 231 -440 239 -220 427 -446 219 -242 211 -244 237 -206 451 -458 451 -458 203 -254 427 -450 441 -246 213 -242 193 -244 211 -242 211 -212 241 -442 451 -454 245 -214 241 -198 255 -218 217 -210 225 -212 461 -246 213 -440 225 -242 435 -240 209 -456 457 -246 211 -204 229 -254 219 -428 445 -452 445 -238 253 -426 231 -232 435 -448 455 -448 439 -446 449 -456 451 -230 223 -214 241 -212 211 -242 211 -244 237 -442 237 -218 427 -232 221 -442 239 -246 427 -458 245 -212 205 -228 253 -220 427 -446 471 -442 237 -216 451 -462 411 -244 251 -216 205 -222 211 -242 211 -242 211 -480 453 -418 245 -252 207 -202 253 -218 219 -210 229 -256 425 -232 221 -430 251 -212 469 -204 235 -446 441 -246 213 -242 193 -244 211 -464 451 -456 441 -248 215 -450 201 -256 427 -452 457 -450 455 -450 439 -446 451 -238 217 -256 207 -202 255 -218 217 -210 231 -442 237 -244 423 -240 217 -464 203 -254 419 -454 227 -210 243 -212 241 -212 477 -418 453 -484 199 -226 431 -267004 97 -422 97 -164 65 -490 97 -2222 559 -66 163 -64 295 -100 497 -100 263 -98 361 -460 793 -66 1803 -100 339 -68 1733 diff --git a/assets/unit_tests/subghz/test_random_raw.sub b/assets/unit_tests/subghz/test_random_raw.sub index 9d1cdd67..df36e125 100644 --- a/assets/unit_tests/subghz/test_random_raw.sub +++ b/assets/unit_tests/subghz/test_random_raw.sub @@ -100,3 +100,6 @@ RAW_Data: -202 531 -66 531 -66 1093 -66 1389 -66 1551 -134 2699 -66 1291 -132 65 RAW_Data: -132 2291 -66 3057 -68 2521 -166 333 -134 503 -400 3235 -66 2329 -68 995 -100 333 -100 97 -166 1757 -100 397 -100 165 -66 2755 -132 297 -134 163 -100 565 -100 1793 -100 1813 -162 1293 -98 97 -66 999 -66 1763 -68 261 -68 2391 -100 765 -364 859 -100 1855 -98 1399 -230 463 -134 301 -198 397 -100 961 -68 431 -134 695 -202 133 -100 365 -66 925 -98 165 -66 365 -132 663 -98 4573 -134 1479 -66 1019 -66 629 -66 233 -68 201 -66 569 -66 295 -134 1755 -296 3199 -100 3261 -168 3373 -132 1425 -100 759 -66 895 -98 201 -100 265 -166 99 -66 695 -66 1091 -66 855 -168 299 -100 229 -164 589 -66 521 -66 655 -134 329 -98 493 -200 429 -66 929 -66 673 -100 953 -66 823 -66 1283 -66 1979 -68 233 -66 1547 -164 589 -132 597 -66 131 -66 265 -100 761 -200 759 -66 689 -332 263 -100 1227 -68 1067 -164 2945 -100 959 -100 995 -100 399 -100 1193 -100 625 -66 399 -66 3021 -134 393 -66 4805 -66 1095 -68 231 -332 399 -166 1663 -68 561 -66 927 -98 1085 -164 1155 -98 627 -66 265 -132 263 -130 2211 -66 2159 -66 1029 -264 2669 -66 295 -66 8747 -100 329 -232 625 -134 429 -68 1329 -168 1355 -98 987 -66 1545 -98 1015 -98 699 -134 133 -134 1263 -66 4687 -166 8299 -66 1349 -434 933 -906 443 -452 949 -894 441 -480 909 -486 907 -456 947 -448 949 -434 969 -454 931 -460 941 -448 933 -450 979 -450 945 -450 935 -458 935 -486 927 -456 947 -450 951 -482 945 -428 975 -446 967 -452 955 -458 945 -912 485 -434 971 -902 481 -450 949 -926 451 -478 941 -920 481 -450 949 -920 473 -450 955 -916 471 -452 981 -918 449 -486 945 -910 483 -924 473 -15780 479 -450 967 -948 449 -482 943 -944 485 -468 941 -484 979 -446 1001 -444 999 -446 967 -484 969 -482 979 -478 947 -484 985 -470 973 -458 983 -492 971 -458 979 -494 971 -458 983 -494 973 -458 981 -498 975 -458 1013 -466 973 -952 475 -458 973 -950 489 -450 1011 -916 481 -478 1001 -918 481 -478 1001 -916 481 -478 1001 -920 483 -480 983 -946 479 -458 1013 -932 485 -952 479 -16040 493 -476 1009 -912 515 -464 1007 -910 517 -464 1007 -450 1001 -488 1001 -484 1011 -450 1019 -458 1039 -450 1031 -454 1005 -484 1009 -458 1015 -476 1009 -478 1035 -462 1015 -468 1007 -480 1001 -486 1015 -460 1041 -450 1017 -484 1019 -482 1009 -952 477 -494 1003 -944 485 -478 1013 -944 519 -482 1013 -942 487 -482 1013 -946 487 -484 1015 -944 487 -484 1015 -946 519 -454 1019 -942 505 -952 487 -16238 517 -468 1007 -942 521 -482 1011 -944 519 RAW_Data: -450 1019 -482 1035 -480 1033 -460 1047 -476 1017 -484 1007 -484 1051 -484 1027 -452 1039 -478 1035 -458 1049 -480 1017 -480 1035 -480 1035 -472 1047 -484 1027 -454 1039 -480 1033 -488 1031 -488 1009 -962 521 -486 1017 -966 485 -490 1015 -139210 229 -98 461 -364 165 -334 131 -168 2121 -66 1049 -66 1215 -166 297 -136 1449 -100 3877 -100 1495 -234 331 -64 1345 -262 393 -100 529 -132 2921 -164 1223 -132 1807 -66 765 -66 397 -98 3405 -132 2123 -230 231 -66 2541 -100 2489 -98 4397 -132 461 -98 293 -64 991 -66 1125 -166 401 -100 131 -100 99 -100 265 -100 2555 -100 499 -98 1361 -134 265 -166 895 -100 2253 -100 1057 -100 129 -296 1147 -198 197 -66 1163 -66 1935 -98 1675 -66 1103 -100 891 -100 989 -164 1019 -66 2967 -68 1293 -166 3161 -66 133 -264 1065 -100 731 -66 1693 -66 529 -100 165 -68 865 -66 825 -232 1117 -196 2401 -66 3051 -296 229 -132 1843 -132 1687 -68 1119 -68 299 -68 97 -66 4741 -66 197 -200 2319 -100 1097 -66 3765 -66 131 -100 695 -132 2753 -66 2287 -100 1129 -68 331 -98 1433 -132 893 -100 465 -100 801 -66 529 -66 1515 -264 393 -98 263 -66 1831 -166 3533 -100 633 -100 1051 -100 331 -98 795 -134 959 -132 1229 -100 627 -132 2517 -66 165 -98 131 -66 2301 -166 163 -134 465 -66 2767 -66 1019 -66 401 -134 397 -232 893 -66 397 -66 833 -66 199 -66 303 -66 2775 -66 2069 -98 1841 -100 399 -66 793 -98 2793 -68 3769 -100 867 -66 861 -100 399 -66 1859 -100 631 -132 755 -100 689 -66 163 -64 2045 -64 2191 -102 1127 -68 727 -68 625 -164 1381 -66 1153 -132 1115 -98 1017 -100 491 -100 593 -132 991 -98 1415 -98 4813 -66 331 -98 131 -102 1847 -98 197 -68 263 -100 3265 -66 431 -100 493 -98 435 -134 133 -68 1185 -134 395 -100 131 -66 399 -134 767 -134 1125 -66 429 -198 3185 -100 2261 -66 523 -230 2475 -168 1297 -66 3243 -66 1853 -100 1657 -66 459 -66 827 -100 263 -66 303 -234 197 -166 1167 -100 2299 -66 1329 -68 461 -100 763 -132 3819 -366 757 -66 591 -164 621 -98 1445 -100 2155 -100 231 -100 631 -68 1161 -66 131 -166 67 -98 1915 -166 1891 -66 1261 -68 999 -164 165 -132 133 -168 2695 -68 1055 -198 97 -98 229 -66 229 -66 1215 -66 885 -100 303 -132 297 -164 619 -198 459 -64 989 -66 229 -66 597 -134 693 -64 1255 -100 65 -132 331 -66 199 -98 529 -100 2831 -98 1259 -66 4855 -100 1163 -166 299 -66 395 -98 3141 -66 1319 -66 2139 -100 161 -132 261 -130 821 -200 263 -134 931 -330 65 -98 99 -134 793 RAW_Data: -66 597 -100 231 -68 167 -66 1659 -100 733 -66 1631 -100 165 -66 199 -66 233 -166 165 -100 1925 -68 595 -198 1785 -134 2177 -134 131 -66 1049 -98 3087 -132 195 -64 589 -66 397 -134 329 -66 2565 -164 327 -100 689 -64 1775 -100 5183 -132 1187 -66 329 -66 395 -132 165 -98 261 -98 1247 -64 1217 -66 927 -66 997 -66 199 -98 1419 -66 531 -166 1231 -66 697 -100 97 -66 563 -66 161 -264 3205 -200 525 -98 293 -100 291 -100 133 -66 759 -66 659 -100 983 -64 523 -130 431 -166 919 -66 1097 -100 1757 -66 1119 -66 917 -98 2647 -166 1247 -66 165 -264 1189 -100 899 -134 597 -68 2323 -66 1893 -66 1095 -100 533 -64 965 -100 1817 -130 1215 -66 1879 -64 821 -164 1117 -132 263 -132 131 -66 557 -66 431 -132 661 -100 1183 -98 629 -100 1679 -132 259 -66 623 -98 431 -66 399 -164 923 -100 297 -66 165 -166 2521 -198 99 -66 431 -132 1225 -66 1063 -68 131 -136 631 -66 163 -100 99 -298 965 -68 465 -68 465 -298 2545 -134 2639 -230 1489 -66 299 -66 1991 -234 65 -132 693 -134 429 -102 101 -68 461 -66 3333 -64 1229 -68 333 -66 265 -66 885 -64 3163 -100 467 -66 2651 -164 1221 -100 1527 -66 1259 -134 431 -232 1259 -100 6029 -164 297 -98 1151 -66 1415 -100 5289 -66 2467 -100 493 -132 495 -200 1121 -66 129 -66 757 -166 327 -130 5477 -66 1227 -230 395 -100 265 -132 497 -132 1133 -132 361 -100 1051 -164 3089 -132 1583 -100 65 -68 2315 -100 529 -132 2157 -68 1257 -66 1975 -98 427 -98 1347 -66 719 -164 857 -66 165 -66 1029 -132 297 -132 467 -100 731 -130 1985 -98 199 -166 899 -100 1391 -166 3425 -100 261 -132 721 -66 4845 -98 1193 -68 1225 -66 721 -100 1015 -64 983 -66 557 -130 693 -98 99 -64 1091 -98 197 -100 2321 -66 431 -134 727 -66 467 -102 891 -98 167 -134 2619 -66 393 -64 97 -100 589 -98 1583 -164 301 -68 1481 -98 295 -98 959 -66 365 -98 1253 -66 231 -100 1255 -132 1813 -132 1645 -100 361 -132 395 -100 427 -164 1197 -98 1001 -100 861 -66 1161 -98 195 -100 197 -66 1429 -66 663 -66 1427 -98 665 -66 699 -100 663 -66 855 -196 161 -100 361 -98 823 -66 227 -66 621 -132 1853 -230 461 -230 623 -100 557 -98 229 -98 133 -134 1291 -66 533 -166 627 -134 195 -134 593 -64 591 -66 1019 -66 1049 -262 297 -100 2921 -66 133 -66 963 -134 165 -100 +RAW_Data: -68 521674 -200 213 -258 217 -218 217 -246 193 -242 211 -466 451 -450 225 -212 211 -242 211 -238 243 -200 223 -254 419 -226 221 -432 251 -212 467 -240 203 -450 449 -246 205 -238 217 -218 217 -444 439 -478 431 -230 211 -462 247 -214 435 -454 449 -456 441 -442 471 -448 449 -246 205 -238 215 -220 217 -244 201 -254 217 -430 235 -220 461 -198 223 -442 275 -212 429 -458 245 -212 203 -228 253 -218 431 -448 451 -442 235 -218 463 -426 485 -214 209 -234 221 -254 219 -214 207 -228 253 -428 459 -418 245 -216 243 -194 241 -212 241 -212 211 -244 441 -228 215 -460 217 -244 435 -236 235 -440 439 -246 213 -208 229 -256 217 -430 445 -450 445 -236 253 -420 225 -232 429 -450 465 -448 439 -448 449 -454 453 -230 225 -214 241 -212 211 -242 211 -244 237 -442 237 -218 429 -230 221 -442 241 -246 425 -458 245 -212 203 -228 255 -218 427 -448 451 -446 235 -256 425 -462 417 -244 251 -208 201 -256 217 -218 209 -232 255 -420 451 -448 217 -242 211 -238 209 -234 221 -256 217 -218 437 -238 217 -464 203 -256 419 -226 223 -464 441 -244 213 -240 197 -254 219 -430 445 -452 479 -204 253 -420 225 -222 463 -452 449 -450 449 -452 447 -450 451 -238 215 -220 217 -244 199 -256 217 -218 207 -440 241 -254 423 -238 217 -462 197 -224 471 -448 225 -220 213 -242 211 -212 465 -446 449 -456 245 -214 437 -456 449 -232 233 -216 219 -254 207 -204 253 -218 219 -440 451 -456 237 -216 217 -254 209 -202 253 -218 219 -210 437 -244 253 -422 237 -218 423 -226 247 -430 451 -242 203 -228 253 -220 217 -442 449 -454 449 -240 217 -430 237 -218 461 -426 453 -450 465 -448 451 -440 443 -246 215 -250 201 -224 255 -218 215 -208 227 -442 239 -208 457 -238 219 -464 201 -256 425 -464 201 -256 217 -210 241 -216 451 -426 445 -486 207 -236 441 -430 479 -194 223 -256 217 -218 209 -234 253 -218 217 -438 449 -454 239 -216 217 -256 207 -202 255 -218 217 -210 439 -244 253 -424 235 -218 457 -224 229 -436 449 -230 221 -214 211 -242 211 -468 447 -450 449 -250 207 -454 239 -218 431 -446 451 -448 443 -486 447 -448 431 -240 207 -232 223 -254 219 -216 209 -230 253 -426 233 -234 433 -244 213 -432 237 -218 463 -446 221 -212 211 -242 239 -208 457 -456 451 -456 223 -212 467 -450 453 -204 253 -218 211 -240 215 -218 255 -208 201 -442 479 -452 203 -254 217 -212 241 -216 217 -256 207 -202 439 -240 245 -430 237 -218 463 -240 217 -428 465 -202 253 -218 213 -234 219 +RAW_Data: -444 443 -452 455 -244 213 -440 237 -254 427 -450 429 -480 417 -454 477 -430 445 -244 217 -250 203 -224 253 -220 215 -206 221 -462 217 -212 467 -234 231 -440 239 -220 427 -446 219 -242 211 -244 237 -206 451 -458 451 -458 203 -254 427 -450 441 -246 213 -242 193 -244 211 -242 211 -212 241 -442 451 -454 245 -214 241 -198 255 -218 217 -210 225 -212 461 -246 213 -440 225 -242 435 -240 209 -456 457 -246 211 -204 229 -254 219 -428 445 -452 445 -238 253 -426 231 -232 435 -448 455 -448 439 -446 449 -456 451 -230 223 -214 241 -212 211 -242 211 -244 237 -442 237 -218 427 -232 221 -442 239 -246 427 -458 245 -212 205 -228 253 -220 427 -446 471 -442 237 -216 451 -462 411 -244 251 -216 205 -222 211 -242 211 -242 211 -480 453 -418 245 -252 207 -202 253 -218 219 -210 229 -256 425 -232 221 -430 251 -212 469 -204 235 -446 441 -246 213 -242 193 -244 211 -464 451 -456 441 -248 215 -450 201 -256 427 -452 457 -450 455 -450 439 -446 451 -238 217 -256 207 -202 255 -218 217 -210 231 -442 237 -244 423 -240 217 -464 203 -254 419 -454 227 -210 243 -212 241 -212 477 -418 453 -484 199 -226 431 -267004 97 -422 97 -164 65 -490 97 -2222 559 -66 163 -64 295 -100 497 -100 263 -98 361 -460 793 -66 1803 -100 339 -68 1733 + diff --git a/lib/subghz/protocols/power_smart.c b/lib/subghz/protocols/power_smart.c new file mode 100644 index 00000000..0dc81f2a --- /dev/null +++ b/lib/subghz/protocols/power_smart.c @@ -0,0 +1,380 @@ +#include "power_smart.h" +#include +#include +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/encoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" + +#define TAG "SubGhzProtocolPowerSmart" +#define POWER_SMART_PACKET_HEADER 0xFD000000AA000000 +#define POWER_SMART_PACKET_HEADER_MASK 0xFF000000FF000000 + +#define CHANNEL_PATTERN "%c%c%c%c%c%c" +#define CNT_TO_CHANNEL(dip) \ + (dip & 0x0001 ? '*' : '-'), (dip & 0x0002 ? '*' : '-'), (dip & 0x0004 ? '*' : '-'), \ + (dip & 0x0008 ? '*' : '-'), (dip & 0x0010 ? '*' : '-'), (dip & 0x0020 ? '*' : '-') + +static const SubGhzBlockConst subghz_protocol_power_smart_const = { + .te_short = 225, + .te_long = 450, + .te_delta = 100, + .min_count_bit_for_found = 64, +}; + +struct SubGhzProtocolDecoderPowerSmart { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + SubGhzBlockGeneric generic; + ManchesterState manchester_saved_state; + uint16_t header_count; +}; + +struct SubGhzProtocolEncoderPowerSmart { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + SubGhzBlockGeneric generic; +}; + +typedef enum { + PowerSmartDecoderStepReset = 0, + PowerSmartDecoderFoundHeader, + PowerSmartDecoderStepDecoderData, +} PowerSmartDecoderStep; + +const SubGhzProtocolDecoder subghz_protocol_power_smart_decoder = { + .alloc = subghz_protocol_decoder_power_smart_alloc, + .free = subghz_protocol_decoder_power_smart_free, + + .feed = subghz_protocol_decoder_power_smart_feed, + .reset = subghz_protocol_decoder_power_smart_reset, + + .get_hash_data = subghz_protocol_decoder_power_smart_get_hash_data, + .serialize = subghz_protocol_decoder_power_smart_serialize, + .deserialize = subghz_protocol_decoder_power_smart_deserialize, + .get_string = subghz_protocol_decoder_power_smart_get_string, +}; + +const SubGhzProtocolEncoder subghz_protocol_power_smart_encoder = { + .alloc = subghz_protocol_encoder_power_smart_alloc, + .free = subghz_protocol_encoder_power_smart_free, + + .deserialize = subghz_protocol_encoder_power_smart_deserialize, + .stop = subghz_protocol_encoder_power_smart_stop, + .yield = subghz_protocol_encoder_power_smart_yield, +}; + +const SubGhzProtocol subghz_protocol_power_smart = { + .name = SUBGHZ_PROTOCOL_POWER_SMART_NAME, + .type = SubGhzProtocolTypeStatic, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | + SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, + + .decoder = &subghz_protocol_power_smart_decoder, + .encoder = &subghz_protocol_power_smart_encoder, +}; + +void* subghz_protocol_encoder_power_smart_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolEncoderPowerSmart* instance = malloc(sizeof(SubGhzProtocolEncoderPowerSmart)); + + instance->base.protocol = &subghz_protocol_power_smart; + instance->generic.protocol_name = instance->base.protocol->name; + + instance->encoder.repeat = 10; + instance->encoder.size_upload = 1024; + instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); + instance->encoder.is_runing = false; + return instance; +} + +void subghz_protocol_encoder_power_smart_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderPowerSmart* instance = context; + free(instance->encoder.upload); + free(instance); +} + +static LevelDuration + subghz_protocol_encoder_power_smart_add_duration_to_upload(ManchesterEncoderResult result) { + LevelDuration data = {.duration = 0, .level = 0}; + switch(result) { + case ManchesterEncoderResultShortLow: + data.duration = subghz_protocol_power_smart_const.te_short; + data.level = false; + break; + case ManchesterEncoderResultLongLow: + data.duration = subghz_protocol_power_smart_const.te_long; + data.level = false; + break; + case ManchesterEncoderResultLongHigh: + data.duration = subghz_protocol_power_smart_const.te_long; + data.level = true; + break; + case ManchesterEncoderResultShortHigh: + data.duration = subghz_protocol_power_smart_const.te_short; + data.level = true; + break; + + default: + furi_crash("SubGhz: ManchesterEncoderResult is incorrect."); + break; + } + return level_duration_make(data.level, data.duration); +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderPowerSmart instance + */ +static void + subghz_protocol_encoder_power_smart_get_upload(SubGhzProtocolEncoderPowerSmart* instance) { + furi_assert(instance); + size_t index = 0; + + ManchesterEncoderState enc_state; + manchester_encoder_reset(&enc_state); + ManchesterEncoderResult result; + + for(int i = 8; i > 0; i--) { + for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) { + if(!manchester_encoder_advance( + &enc_state, !bit_read(instance->generic.data, i - 1), &result)) { + instance->encoder.upload[index++] = + subghz_protocol_encoder_power_smart_add_duration_to_upload(result); + manchester_encoder_advance( + &enc_state, !bit_read(instance->generic.data, i - 1), &result); + } + instance->encoder.upload[index++] = + subghz_protocol_encoder_power_smart_add_duration_to_upload(result); + } + } + instance->encoder.upload[index] = subghz_protocol_encoder_power_smart_add_duration_to_upload( + manchester_encoder_finish(&enc_state)); + if(level_duration_get_level(instance->encoder.upload[index])) { + index++; + } + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_power_smart_const.te_long * 1111); + instance->encoder.size_upload = index; +} + +/** + * Analysis of received data + * @param instance Pointer to a SubGhzBlockGeneric* instance + */ +static void subghz_protocol_power_smart_remote_controller(SubGhzBlockGeneric* instance) { + /* + * Protocol: Manchester encoding, symbol rate ~2222. + * Packet Format: + * 0xFDXXXXYYAAZZZZWW where 0xFD and 0xAA sync word + * XXXX = ~ZZZZ, YY=(~WW)-1 + * Example: + * SYNC1 K1 CHANNEL DATA1 K2 DATA2 SYNC2 ~K1 ~CHANNEL ~DATA2 ~K2 (~DATA2)-1 + * 0xFD2137ACAADEC852 => 11111101 0 010000 10011011 1 10101100 10101010 1 1011110 1100100 0 01010010 + * 0xFDA137ACAA5EC852 => 11111101 1 010000 10011011 1 10101100 10101010 0 1011110 1100100 0 01010010 + * 0xFDA136ACAA5EC952 => 11111101 1 010000 10011011 0 10101100 10101010 0 1011110 1100100 1 01010010 + * + * Key: + * K1K2 + * 0 0 - key_unknown + * 0 1 - key_down + * 1 0 - key_up + * 1 1 - key_stop + * + */ + + instance->btn = ((instance->data >> 54) & 0x02) | ((instance->data >> 40) & 0x1); + instance->serial = ((instance->data >> 33) & 0x3FFF00) | ((instance->data >> 32) & 0xFF); + instance->cnt = ((instance->data >> 49) & 0x3F); +} + +bool subghz_protocol_encoder_power_smart_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderPowerSmart* instance = context; + bool res = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + FURI_LOG_E(TAG, "Deserialize error"); + break; + } + + //optional parameter parameter + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + subghz_protocol_power_smart_remote_controller(&instance->generic); + subghz_protocol_encoder_power_smart_get_upload(instance); + instance->encoder.is_runing = true; + + res = true; + } while(false); + + return res; +} + +void subghz_protocol_encoder_power_smart_stop(void* context) { + SubGhzProtocolEncoderPowerSmart* instance = context; + instance->encoder.is_runing = false; +} + +LevelDuration subghz_protocol_encoder_power_smart_yield(void* context) { + SubGhzProtocolEncoderPowerSmart* instance = context; + + if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { + instance->encoder.is_runing = 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_power_smart_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolDecoderPowerSmart* instance = malloc(sizeof(SubGhzProtocolDecoderPowerSmart)); + instance->base.protocol = &subghz_protocol_power_smart; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void subghz_protocol_decoder_power_smart_free(void* context) { + furi_assert(context); + SubGhzProtocolDecoderPowerSmart* instance = context; + free(instance); +} + +void subghz_protocol_decoder_power_smart_reset(void* context) { + furi_assert(context); + SubGhzProtocolDecoderPowerSmart* instance = context; + manchester_advance( + instance->manchester_saved_state, + ManchesterEventReset, + &instance->manchester_saved_state, + NULL); +} + +bool subghz_protocol_power_smart_chek_valid(uint64_t packet) { + uint32_t data_1 = (uint32_t)((packet >> 40) & 0xFFFF); + uint32_t data_2 = (uint32_t)((~packet >> 8) & 0xFFFF); + uint8_t data_3 = (uint8_t)(packet >> 32) & 0xFF; + uint8_t data_4 = (uint8_t)(((~packet) & 0xFF) - 1); + return (data_1 == data_2) && (data_3 == data_4); +} + +void subghz_protocol_decoder_power_smart_feed( + void* context, + bool level, + volatile uint32_t duration) { + furi_assert(context); + SubGhzProtocolDecoderPowerSmart* instance = context; + ManchesterEvent event = ManchesterEventReset; + if(!level) { + if(DURATION_DIFF(duration, subghz_protocol_power_smart_const.te_short) < + subghz_protocol_power_smart_const.te_delta) { + event = ManchesterEventShortLow; + } else if( + DURATION_DIFF(duration, subghz_protocol_power_smart_const.te_long) < + subghz_protocol_power_smart_const.te_delta * 2) { + event = ManchesterEventLongLow; + } + } else { + if(DURATION_DIFF(duration, subghz_protocol_power_smart_const.te_short) < + subghz_protocol_power_smart_const.te_delta) { + event = ManchesterEventShortHigh; + } else if( + DURATION_DIFF(duration, subghz_protocol_power_smart_const.te_long) < + subghz_protocol_power_smart_const.te_delta * 2) { + event = ManchesterEventLongHigh; + } + } + if(event != ManchesterEventReset) { + bool data; + bool data_ok = manchester_advance( + instance->manchester_saved_state, event, &instance->manchester_saved_state, &data); + + if(data_ok) { + instance->decoder.decode_data = (instance->decoder.decode_data << 1) | !data; + } + if((instance->decoder.decode_data & POWER_SMART_PACKET_HEADER_MASK) == + POWER_SMART_PACKET_HEADER) { + if(subghz_protocol_power_smart_chek_valid(instance->decoder.decode_data)) { + instance->decoder.decode_data = instance->decoder.decode_data; + instance->generic.data = instance->decoder.decode_data; + instance->generic.data_count_bit = + subghz_protocol_power_smart_const.min_count_bit_for_found; + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + } + } + } else { + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + manchester_advance( + instance->manchester_saved_state, + ManchesterEventReset, + &instance->manchester_saved_state, + NULL); + } +} + +static const char* subghz_protocol_power_smart_get_name_button(uint8_t btn) { + btn &= 0x3; + const char* name_btn[0x4] = {"Unknown", "Down", "Up", "Stop"}; + return name_btn[btn]; +} + +uint8_t subghz_protocol_decoder_power_smart_get_hash_data(void* context) { + furi_assert(context); + SubGhzProtocolDecoderPowerSmart* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +bool subghz_protocol_decoder_power_smart_serialize( + void* context, + FlipperFormat* flipper_format, + uint32_t frequency, + FuriHalSubGhzPreset preset) { + furi_assert(context); + SubGhzProtocolDecoderPowerSmart* instance = context; + return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset); +} + +bool subghz_protocol_decoder_power_smart_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolDecoderPowerSmart* instance = context; + return subghz_block_generic_deserialize(&instance->generic, flipper_format); +} + +void subghz_protocol_decoder_power_smart_get_string(void* context, string_t output) { + furi_assert(context); + SubGhzProtocolDecoderPowerSmart* instance = context; + subghz_protocol_power_smart_remote_controller(&instance->generic); + + string_cat_printf( + output, + "%s %db\r\n" + "Key:0x%lX%08lX\r\n" + "Sn:0x%07lX \r\n" + "Btn:%s\r\n" + "Channel:" CHANNEL_PATTERN "\r\n", + instance->generic.protocol_name, + instance->generic.data_count_bit, + (uint32_t)(instance->generic.data >> 32), + (uint32_t)(instance->generic.data & 0xFFFFFFFF), + instance->generic.serial, + subghz_protocol_power_smart_get_name_button(instance->generic.btn), + CNT_TO_CHANNEL(instance->generic.cnt)); +} diff --git a/lib/subghz/protocols/power_smart.h b/lib/subghz/protocols/power_smart.h new file mode 100644 index 00000000..346fe537 --- /dev/null +++ b/lib/subghz/protocols/power_smart.h @@ -0,0 +1,109 @@ +#pragma once + +#include "base.h" + +#define SUBGHZ_PROTOCOL_POWER_SMART_NAME "Power Smart" + +typedef struct SubGhzProtocolDecoderPowerSmart SubGhzProtocolDecoderPowerSmart; +typedef struct SubGhzProtocolEncoderPowerSmart SubGhzProtocolEncoderPowerSmart; + +extern const SubGhzProtocolDecoder subghz_protocol_power_smart_decoder; +extern const SubGhzProtocolEncoder subghz_protocol_power_smart_encoder; +extern const SubGhzProtocol subghz_protocol_power_smart; + +/** + * Allocate SubGhzProtocolEncoderPowerSmart. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderPowerSmart* pointer to a SubGhzProtocolEncoderPowerSmart instance + */ +void* subghz_protocol_encoder_power_smart_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderPowerSmart. + * @param context Pointer to a SubGhzProtocolEncoderPowerSmart instance + */ +void subghz_protocol_encoder_power_smart_free(void* context); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderPowerSmart instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_encoder_power_smart_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderPowerSmart instance + */ +void subghz_protocol_encoder_power_smart_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderPowerSmart instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_power_smart_yield(void* context); + +/** + * Allocate SubGhzProtocolDecoderPowerSmart. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolDecoderPowerSmart* pointer to a SubGhzProtocolDecoderPowerSmart instance + */ +void* subghz_protocol_decoder_power_smart_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolDecoderPowerSmart. + * @param context Pointer to a SubGhzProtocolDecoderPowerSmart instance + */ +void subghz_protocol_decoder_power_smart_free(void* context); + +/** + * Reset decoder SubGhzProtocolDecoderPowerSmart. + * @param context Pointer to a SubGhzProtocolDecoderPowerSmart instance + */ +void subghz_protocol_decoder_power_smart_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a SubGhzProtocolDecoderPowerSmart instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void subghz_protocol_decoder_power_smart_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a SubGhzProtocolDecoderPowerSmart instance + * @return hash Hash sum + */ +uint8_t subghz_protocol_decoder_power_smart_get_hash_data(void* context); + +/** + * Serialize data SubGhzProtocolDecoderPowerSmart. + * @param context Pointer to a SubGhzProtocolDecoderPowerSmart instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param frequency The frequency at which the signal was received, Hz + * @param preset The modulation on which the signal was received, FuriHalSubGhzPreset + * @return true On success + */ +bool subghz_protocol_decoder_power_smart_serialize( + void* context, + FlipperFormat* flipper_format, + uint32_t frequency, + FuriHalSubGhzPreset preset); + +/** + * Deserialize data SubGhzProtocolDecoderPowerSmart. + * @param context Pointer to a SubGhzProtocolDecoderPowerSmart instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_decoder_power_smart_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a SubGhzProtocolDecoderPowerSmart instance + * @param output Resulting text + */ +void subghz_protocol_decoder_power_smart_get_string(void* context, string_t output); diff --git a/lib/subghz/protocols/registry.c b/lib/subghz/protocols/registry.c index 668e6ad5..5a09ee8c 100644 --- a/lib/subghz/protocols/registry.c +++ b/lib/subghz/protocols/registry.c @@ -1,15 +1,15 @@ #include "registry.h" const SubGhzProtocol* subghz_protocol_registry[] = { - &subghz_protocol_gate_tx, &subghz_protocol_keeloq, &subghz_protocol_star_line, - &subghz_protocol_nice_flo, &subghz_protocol_came, &subghz_protocol_faac_slh, - &subghz_protocol_nice_flor_s, &subghz_protocol_came_twee, &subghz_protocol_came_atomo, - &subghz_protocol_nero_sketch, &subghz_protocol_ido, &subghz_protocol_kia, - &subghz_protocol_hormann, &subghz_protocol_nero_radio, &subghz_protocol_somfy_telis, - &subghz_protocol_somfy_keytis, &subghz_protocol_scher_khan, &subghz_protocol_princeton, - &subghz_protocol_raw, &subghz_protocol_linear, &subghz_protocol_secplus_v2, - &subghz_protocol_secplus_v1, &subghz_protocol_megacode, &subghz_protocol_holtek, - &subghz_protocol_chamb_code, + &subghz_protocol_gate_tx, &subghz_protocol_keeloq, &subghz_protocol_star_line, + &subghz_protocol_nice_flo, &subghz_protocol_came, &subghz_protocol_faac_slh, + &subghz_protocol_nice_flor_s, &subghz_protocol_came_twee, &subghz_protocol_came_atomo, + &subghz_protocol_nero_sketch, &subghz_protocol_ido, &subghz_protocol_kia, + &subghz_protocol_hormann, &subghz_protocol_nero_radio, &subghz_protocol_somfy_telis, + &subghz_protocol_somfy_keytis, &subghz_protocol_scher_khan, &subghz_protocol_princeton, + &subghz_protocol_raw, &subghz_protocol_linear, &subghz_protocol_secplus_v2, + &subghz_protocol_secplus_v1, &subghz_protocol_megacode, &subghz_protocol_holtek, + &subghz_protocol_chamb_code, &subghz_protocol_power_smart, }; diff --git a/lib/subghz/protocols/registry.h b/lib/subghz/protocols/registry.h index 39322380..d64b0cdd 100644 --- a/lib/subghz/protocols/registry.h +++ b/lib/subghz/protocols/registry.h @@ -27,6 +27,7 @@ #include "megacode.h" #include "holtek.h" #include "chamberlain_code.h" +#include "power_smart.h" /** * Registration by name SubGhzProtocol.