From f7dd9043d4f24ccb6d2aee85b245abdb7114a92d Mon Sep 17 00:00:00 2001 From: Martin Peach Date: Sun, 6 Nov 2011 15:53:11 +0000 Subject: Externs to pack and unpack Xbee messages in API modes 1 or 2. Interfaces with an Xbee via [comport]. svn path=/trunk/externals/mrpeach/; revision=15708 --- xbee/packxbee-help.pd | 521 +++++++++++++++++++++++++++++++++++++++ xbee/packxbee.c | 655 ++++++++++++++++++++++++++++++++++++++++++++++++++ xbee/pdxbee.h | 41 ++++ xbee/unpackxbee.c | 452 ++++++++++++++++++++++++++++++++++ 4 files changed, 1669 insertions(+) create mode 100644 xbee/packxbee-help.pd create mode 100644 xbee/packxbee.c create mode 100644 xbee/pdxbee.h create mode 100644 xbee/unpackxbee.c diff --git a/xbee/packxbee-help.pd b/xbee/packxbee-help.pd new file mode 100644 index 0000000..2949d19 --- /dev/null +++ b/xbee/packxbee-help.pd @@ -0,0 +1,521 @@ +#N canvas 502 3 994 313 10; +#X declare -lib mrpeach; +#X msg 80 53 AT DH 0x0013A200; +#X text 193 52 set upper 32 bits of destination address; +#X msg 103 76 AT DL 0x407694DB; +#X msg 128 101 AT MY; +#X text 80 9 get upper 32 bits of destination address; +#X text 97 31 get loweer 32 bits of destination address; +#X msg 37 10 AT DH; +#X msg 60 33 AT DL; +#X msg 148 121 AT MP; +#X text 171 99 get our 16-bit address (Read Only); +#X msg 171 144 AT NC; +#X text 210 141 get number of remaining children (Read Only); +#X msg 193 166 AT SH; +#X text 232 163 get serial number high 32 bits (Read Only); +#X text 253 184 get serial number low 32 bits (Read Only); +#X msg 214 187 AT SL; +#X msg 234 207 AT NI diddley; +#X text 321 204 set node identifier string; +#X msg 254 227 AT NI; +#X text 299 225 get node identifier string; +#X text 527 50 prefix hexadecimal parameters with 0x; +#X msg 274 247 AT NP; +#X text 319 245 get maximum payload; +#X msg 294 267 AT DD; +#X text 336 264 get device type identifier; +#X text 191 119 get endpoint parent's 16-bit address (Read Only); +#X msg 328 301 AT CH; +#X text 366 300 get operating channel; +#X msg 348 321 AT ID; +#X text 386 320 get 64-bit PAN ID; +#X text 529 342 set 64-bit PAN ID; +#X msg 390 363 AT ID 0x0; +#X text 458 362 set coordinator chosen 64-bit PAN ID; +#X msg 370 343 AT ID 0xFEEAFEEBFEECFEED; +#X text 210 74 set lower 32 bits of destination address; +#X msg 412 385 AT OP; +#X text 455 383 get operating 64-bit PAN ID; +#X msg 432 405 AT NH; +#X msg 452 425 AT NH 0xFF; +#X text 528 443 set maximum unicast hops (float arg); +#X text 525 423 set maximum unicast hops (symbol arg); +#X text 475 403 get maximum unicast hops (no arg); +#X msg 492 465 AT BH; +#X text 535 463 get maximum broadcastcast hops (no arg); +#X text 585 483 set maximum broadcast hops (symbol arg); +#X msg 512 485 AT BH 0x1E; +#X msg 532 505 AT BH 3; +#X text 585 502 set maximum broadcast hops (float arg); +#X msg 552 525 AT OI; +#X text 595 523 get operating 16-bit PAN ID; +#X msg 472 445 AT NH 2; +#X msg 573 546 AT NT; +#X text 616 544 get node discovery timeout; +#X text 662 564 set node discovery timeout; +#X msg 593 566 AT NT 0xFF; +#X msg 613 586 AT NO; +#X msg 633 606 AT NO 3; +#X text 656 584 get node discovery options; +#X text 684 604 set node discovery options; +#X msg 654 627 AT SC; +#X msg 673 646 AT SC 0xFFFF; +#X text 697 625 get scan channel bitmask; +#X text 754 645 set scan channels; +#X msg 692 665 AT SD; +#X msg 711 684 AT SD 3; +#X text 735 663 get scan duration; +#X text 762 683 set scan duration; +#X text 66 300 get zigbee stack profile; +#X text 94 320 set zigbee stack profile; +#X msg 28 301 AT ZS; +#X msg 47 320 AT ZS 0; +#X msg 68 341 AT NJ; +#X msg 88 361 AT NJ 0xFF; +#X text 106 340 get node join time; +#X text 161 360 set node join time; +#X obj 412 700 s topackxbee; +#X obj 583 690 r topackxbee; +#X msg 108 381 AT JV; +#X text 146 380 get channel verification; +#X text 181 400 set channel verification; +#X msg 128 401 AT JV 1; +#X obj 237 720 comport 23 9600; +#X text 203 437 get power level; +#X msg 165 438 AT PL; +#X msg 185 458 AT PM; +#X text 223 457 get power mode; +#X msg 205 478 AT DB; +#X msg 225 498 AT PP; +#X text 263 497 get peak power dBm; +#X text 243 477 get received signal strength -dBm; +#X text 283 517 get API mode; +#X msg 245 518 AT AP; +#X msg 325 598 AT AO; +#X text 363 597 get API options; +#X msg 345 618 AT BD; +#X text 383 617 get interface data rate; +#X msg 365 638 AT NB; +#X text 403 637 get interface parity; +#X msg 385 658 AT SB; +#X text 423 657 get interface stop bits; +#X msg 405 678 AT RO; +#X text 443 677 get packetization timeout; +#X obj 1082 736 s topackxbee; +#X msg 954 593 AT D7; +#X msg 936 575 AT D6; +#X msg 708 347 AT IR; +#X text 746 346 get IO sample rate; +#X msg 728 367 AT IC; +#X text 766 366 get IO digital change detection; +#X msg 748 387 AT P0; +#X text 786 386 get PWM0 function; +#X msg 768 407 AT P1; +#X text 806 406 get PWM1 function; +#X msg 788 427 AT P2; +#X text 826 426 get PWM2 function; +#X msg 808 447 AT P3; +#X text 846 446 get PWM3 function; +#X msg 828 467 AT D0; +#X text 872 466 get AD0/DIO0 function; +#X msg 846 485 AT D1; +#X msg 864 503 AT D2; +#X text 908 502 get AD2/DIO2 function; +#X text 890 484 get AD1/DIO1 function; +#X msg 882 521 AT D3; +#X msg 900 539 AT D4; +#X msg 918 557 AT D5; +#X text 926 520 get AD3/DIO3 function; +#X text 944 538 get DIO4 function; +#X text 962 556 get DIO5 function; +#X text 974 574 get DIO6 configuration; +#X text 992 592 get DIO7 configuration; +#X msg 972 611 AT D8; +#X text 1010 610 get DIO8 configuration; +#X msg 991 630 AT LT; +#X text 1026 628 get Associate LED blink time 10ms; +#X msg 1009 648 AT PR; +#X text 1044 646 get pullup resistors; +#X text 1067 664 get supply voltage 1200/1024mV; +#X msg 1028 667 AT %V; +#X msg 1048 687 AT V+; +#X text 1087 684 get supply voltage threshold 1200/1024mV; +#X msg 1068 707 AT TP; +#X text 1107 704 get temperature C; +#X obj 1277 662 s topackxbee; +#X msg 979 349 AT VR; +#X text 1018 346 get firmware version; +#X msg 999 369 AT HV; +#X text 1038 366 get hardware version; +#X msg 1019 389 AT AI; +#X text 1058 386 get association indication; +#X msg 1039 409 AT CC; +#X text 1078 406 get AT command sequence character; +#X msg 1069 439 AT ND; +#X text 1108 436 node discover; +#X text 1187 457 resolve destination node; +#X msg 1089 459 AT DN jellybaby; +#X msg 1109 479 AT IS; +#X msg 1129 499 AT 1S; +#X text 1157 477 force sample; +#X text 1167 497 force xbee sample; +#X msg 143 705 devices; +#X msg 11 546 API 1; +#X msg 33 568 API 2; +#X obj 86 636 s topackxbee; +#X text 50 545 set API mode 1; +#X text 74 569 set API mode 2 (escaped characters); +#X text 55 583 mode 2 is the default setting; +#X text 314 537 set API mode; +#X msg 265 538 AT AP 1; +#X text 334 557 set API mode; +#X msg 285 558 AT AP 2; +#X msg 1162 532 AT AC; +#X text 1202 530 apply changes; +#X msg 1182 552 AT WR; +#X text 1222 550 write parameters to non-volatile memory; +#X msg 1202 572 AT RE; +#X text 1242 570 restore defaults; +#X msg 1222 592 AT FR; +#X text 1262 590 software reset; +#X msg 1242 612 AT NR; +#X text 1282 610 network reset; +#X msg 1262 632 AT CB 1; +#X text 1312 630 commisioning pushbutton; +#X text 1115 515 ***DANGEROUS***; +#X text 14 704 list available ports; +#X obj 792 320 s topackxbee; +#X text 640 79 queue set interface data rate; +#X msg 566 79 ATQ BD 7; +#X msg 184 652 baud 115200; +#X msg 208 676 baud 9600; +#X text 660 99 queue set interface data rate; +#X msg 586 99 ATQ BD 3; +#X msg 150 750 verbosity \$1; +#X obj 96 735 hradio 15 1 0 3 empty empty verbosity 0 -8 0 10 -4034 +-1 -1 0; +#X msg 713 226 verbosity \$1; +#X obj 659 211 hradio 15 1 0 3 empty empty verbosity 0 -8 0 10 -4034 +-1 -1 0; +#X msg 656 169 TX 0x0013A200406ADE1E 0x79D6 0 0 64; +#X obj 237 739 t f f; +#X obj 237 793 print data; +#N canvas 4 353 1019 577 status 1; +#X obj 73 16 inlet; +#X floatatom 184 218 5 0 0 0 - - -; +#X obj 264 97 print unpack5; +#X obj 73 50 route AT_Command_Response; +#X obj 73 82 list split 3; +#X obj 184 142 route ND; +#X obj 184 120 list trim; +#X symbolatom 201 234 7 0 0 0 - - -; +#X symbolatom 219 251 17 0 0 0 - - -; +#X obj 73 120 unpack 0 0 0; +#X floatatom 73 144 5 0 0 0 - - -; +#X floatatom 107 164 5 0 0 0 - - -; +#X floatatom 142 184 5 0 0 0 - - -; +#X text -1 144 packet type; +#X text 39 164 packet ID; +#X text 64 183 data length; +#X text 71 215 AT command status; +#X text 155 233 addr16; +#X text 175 249 addr64; +#X obj 428 65 route ZigBee_Transmit_Status; +#X floatatom 428 105 5 0 0 0 - - -; +#X floatatom 449 123 5 0 0 0 - - -; +#X text 354 105 packet type; +#X text 381 123 packet ID; +#X symbolatom 470 140 7 0 0 0 - - -; +#X text 427 139 addr16; +#X floatatom 533 192 5 0 0 0 - - -; +#X floatatom 512 175 5 0 0 0 - - -; +#X floatatom 491 158 5 0 0 0 - - -; +#X text 360 156 transmit retry count; +#X text 411 173 delivery status; +#X text 427 190 discovery status; +#X symbolatom 236 268 32 0 0 0 - - -; +#X symbolatom 254 286 7 0 0 0 - - -; +#X symbolatom 307 339 7 0 0 0 - - -; +#X symbolatom 325 357 7 0 0 0 - - -; +#X obj 184 196 unpack 0 s s s s 0 0 s s; +#X floatatom 272 304 5 0 0 0 - - -; +#X floatatom 289 321 5 0 0 0 - - -; +#X text 139 267 Node Identifier; +#X text 207 285 parent; +#X text 197 301 device type; +#X text 209 319 source event; +#X text 252 337 profile; +#X text 247 355 manufacturer; +#X obj 229 162 print unpack7; +#X obj 428 85 unpack 0 0 s 0 0 0; +#X obj 616 80 route ZigBee_Receive_Packet; +#X obj 775 100 print someotherpacket; +#X symbolatom 685 177 7 0 0 0 - - -; +#X symbolatom 662 159 17 0 0 0 - - -; +#X text 639 176 addr16; +#X text 618 157 addr64; +#X floatatom 616 123 5 0 0 0 - - -; +#X text 542 123 packet type; +#X floatatom 709 195 5 0 0 0 - - -; +#X text 610 193 receive options; +#X obj 709 245 tgl 15 0 empty empty acknowledged 17 7 0 10 -4034 -1 +-1 0 1; +#X obj 749 265 tgl 15 0 empty empty broadcast 17 7 0 10 -4034 -1 -1 +0 1; +#X obj 789 285 tgl 15 0 empty empty encrypted 17 7 0 10 -4034 -1 -1 +0 1; +#X obj 829 305 tgl 15 0 empty empty from_end_device 17 7 0 10 -4034 +-1 -1 0 1; +#X obj 709 209 & 1; +#X obj 749 209 & 2; +#X obj 789 209 & 32; +#X obj 829 209 & 64; +#X obj 616 101 unpack 0 0 s s 0; +#X floatatom 639 140 5 0 0 0 - - -; +#X text 565 140 data length; +#X obj 511 214 select 0 2 21 33 34 35 36 37; +#X symbolatom 511 411 32 0 0 0 - - -; +#X msg 511 238 set success; +#X msg 676 396 set unknown; +#X msg 531 257 set CCA_failurs; +#X msg 572 297 set Network_ACK_Failure; +#X msg 552 277 set Invalid_Destination_Endpoint; +#X msg 593 317 set Not_Joined_To_Network; +#X msg 612 337 set Self-Addresed; +#X msg 634 356 set Address_Not_Found; +#X msg 655 376 set Route_Not_Found; +#X text 408 410 delivery status:; +#X symbolatom 532 547 32 0 0 0 - - -; +#X msg 613 532 set unknown; +#X obj 532 435 select 0 1 2 3; +#X msg 532 456 set No_Discovery_Overhead; +#X msg 552 475 set Address_Discovery; +#X msg 573 494 set Route_Discovery; +#X msg 593 513 set Address_And_Route_Discovery; +#X text 428 545 discovery status:; +#X connect 0 0 3 0; +#X connect 3 0 4 0; +#X connect 3 1 19 0; +#X connect 4 0 9 0; +#X connect 4 1 6 0; +#X connect 4 2 2 0; +#X connect 5 0 36 0; +#X connect 5 1 45 0; +#X connect 6 0 5 0; +#X connect 9 0 10 0; +#X connect 9 1 11 0; +#X connect 9 2 12 0; +#X connect 19 0 46 0; +#X connect 19 1 47 0; +#X connect 36 0 1 0; +#X connect 36 1 7 0; +#X connect 36 2 8 0; +#X connect 36 3 32 0; +#X connect 36 4 33 0; +#X connect 36 5 37 0; +#X connect 36 6 38 0; +#X connect 36 7 34 0; +#X connect 36 8 35 0; +#X connect 46 0 20 0; +#X connect 46 1 21 0; +#X connect 46 2 24 0; +#X connect 46 3 28 0; +#X connect 46 4 27 0; +#X connect 46 4 68 0; +#X connect 46 5 26 0; +#X connect 46 5 82 0; +#X connect 47 0 65 0; +#X connect 47 1 48 0; +#X connect 55 0 61 0; +#X connect 55 0 62 0; +#X connect 55 0 63 0; +#X connect 55 0 64 0; +#X connect 61 0 57 0; +#X connect 62 0 58 0; +#X connect 63 0 59 0; +#X connect 64 0 60 0; +#X connect 65 0 53 0; +#X connect 65 1 66 0; +#X connect 65 2 50 0; +#X connect 65 3 49 0; +#X connect 65 4 55 0; +#X connect 68 0 70 0; +#X connect 68 1 72 0; +#X connect 68 2 74 0; +#X connect 68 3 73 0; +#X connect 68 4 75 0; +#X connect 68 5 76 0; +#X connect 68 6 77 0; +#X connect 68 7 78 0; +#X connect 68 8 71 0; +#X connect 70 0 69 0; +#X connect 71 0 69 0; +#X connect 72 0 69 0; +#X connect 73 0 69 0; +#X connect 74 0 69 0; +#X connect 75 0 69 0; +#X connect 76 0 69 0; +#X connect 77 0 69 0; +#X connect 78 0 69 0; +#X connect 81 0 80 0; +#X connect 82 0 83 0; +#X connect 82 1 84 0; +#X connect 82 2 85 0; +#X connect 82 3 86 0; +#X connect 82 4 81 0; +#X connect 83 0 80 0; +#X connect 84 0 80 0; +#X connect 85 0 80 0; +#X connect 86 0 80 0; +#X restore 317 780 pd status; +#X obj 385 754 spigot; +#X obj 385 776 print raw; +#X obj 418 730 tgl 15 0 empty empty print_raw 17 7 0 10 -4034 -1 -1 +0 1; +#X obj 709 771 print packed; +#X obj 717 754 spigot; +#X obj 750 730 tgl 15 0 empty empty print_packed 17 7 0 10 -4034 -1 +-1 0 1; +#X obj 717 705 packxbee 2; +#X obj 237 765 unpackxbee 2; +#X msg 742 255 RAT 0x0013A200406ADE1E 0x79D6 0 AT SH; +#X msg 762 275 RAT 0x0013A200406ADE1E 0x79D6 0 AT SL; +#X msg 636 149 TX 0x0013A20040769444 0xFFFE 0 0 1 2 3 4; +#X msg 836 196 RAT 0x0013A20040769698 0xDA23 0 AT SL; +#X obj 412 2 import mrpeach; +#X text 891 135 data packet: 64-bit_destination 16-bit_destination +broadcast_radius options data; +#X msg 617 130 TX 0x0013A20040769698 0xFFFE 0 0 136 \$1; +#X obj 898 97 hsl 128 15 0 127 0 0 empty empty empty -2 -8 0 10 -262144 +-1 -1 8100 1; +#X obj 895 116 nbx 5 14 -1e+037 1e+037 0 0 empty empty empty 0 -8 0 +10 -262144 -1 -1 81 256; +#X obj 931 47 metro 2000; +#X obj 925 74 f; +#X obj 968 74 + 1; +#X obj 942 16 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 +1; +#X obj 1012 72 % 128; +#X connect 0 0 206 0; +#X connect 2 0 206 0; +#X connect 3 0 206 0; +#X connect 6 0 206 0; +#X connect 7 0 206 0; +#X connect 8 0 206 0; +#X connect 10 0 206 0; +#X connect 12 0 206 0; +#X connect 15 0 206 0; +#X connect 16 0 206 0; +#X connect 18 0 206 0; +#X connect 21 0 206 0; +#X connect 23 0 206 0; +#X connect 26 0 206 0; +#X connect 28 0 206 0; +#X connect 31 0 206 0; +#X connect 33 0 206 0; +#X connect 35 0 206 0; +#X connect 37 0 206 0; +#X connect 38 0 206 0; +#X connect 42 0 206 0; +#X connect 45 0 206 0; +#X connect 46 0 206 0; +#X connect 48 0 206 0; +#X connect 50 0 206 0; +#X connect 51 0 206 0; +#X connect 54 0 206 0; +#X connect 55 0 206 0; +#X connect 56 0 206 0; +#X connect 59 0 206 0; +#X connect 60 0 206 0; +#X connect 63 0 206 0; +#X connect 64 0 206 0; +#X connect 69 0 75 0; +#X connect 70 0 75 0; +#X connect 71 0 75 0; +#X connect 72 0 75 0; +#X connect 76 0 206 0; +#X connect 77 0 75 0; +#X connect 80 0 75 0; +#X connect 81 0 197 0; +#X connect 83 0 75 0; +#X connect 84 0 75 0; +#X connect 86 0 75 0; +#X connect 87 0 75 0; +#X connect 91 0 75 0; +#X connect 92 0 75 0; +#X connect 94 0 75 0; +#X connect 96 0 75 0; +#X connect 98 0 75 0; +#X connect 100 0 75 0; +#X connect 103 0 102 0; +#X connect 104 0 102 0; +#X connect 105 0 102 0; +#X connect 107 0 102 0; +#X connect 109 0 102 0; +#X connect 111 0 102 0; +#X connect 113 0 102 0; +#X connect 115 0 102 0; +#X connect 117 0 102 0; +#X connect 119 0 102 0; +#X connect 120 0 102 0; +#X connect 123 0 102 0; +#X connect 124 0 102 0; +#X connect 125 0 102 0; +#X connect 131 0 102 0; +#X connect 133 0 102 0; +#X connect 135 0 102 0; +#X connect 138 0 102 0; +#X connect 139 0 102 0; +#X connect 141 0 102 0; +#X connect 144 0 143 0; +#X connect 146 0 143 0; +#X connect 148 0 143 0; +#X connect 150 0 143 0; +#X connect 152 0 143 0; +#X connect 155 0 143 0; +#X connect 156 0 143 0; +#X connect 157 0 143 0; +#X connect 160 0 81 0; +#X connect 161 0 163 0; +#X connect 162 0 163 0; +#X connect 168 0 75 0; +#X connect 170 0 75 0; +#X connect 171 0 143 0; +#X connect 173 0 143 0; +#X connect 175 0 143 0; +#X connect 177 0 143 0; +#X connect 179 0 143 0; +#X connect 181 0 143 0; +#X connect 187 0 185 0; +#X connect 188 0 81 0; +#X connect 189 0 81 0; +#X connect 191 0 185 0; +#X connect 192 0 207 0; +#X connect 193 0 192 0; +#X connect 194 0 185 0; +#X connect 195 0 194 0; +#X connect 196 0 185 0; +#X connect 197 0 207 0; +#X connect 197 1 200 0; +#X connect 200 0 201 0; +#X connect 202 0 200 1; +#X connect 204 0 203 0; +#X connect 205 0 204 1; +#X connect 206 0 81 0; +#X connect 206 0 204 0; +#X connect 207 0 198 0; +#X connect 207 1 199 0; +#X connect 208 0 185 0; +#X connect 209 0 185 0; +#X connect 210 0 185 0; +#X connect 211 0 185 0; +#X connect 214 0 185 0; +#X connect 215 0 216 0; +#X connect 216 0 214 0; +#X connect 217 0 218 0; +#X connect 218 0 219 0; +#X connect 218 0 215 0; +#X connect 219 0 221 0; +#X connect 220 0 217 0; +#X connect 221 0 218 1; diff --git a/xbee/packxbee.c b/xbee/packxbee.c new file mode 100644 index 0000000..37ea476 --- /dev/null +++ b/xbee/packxbee.c @@ -0,0 +1,655 @@ +/* packxbee outputs a list of floats which are the bytes making up an xbee api packet. */ +/* The packet can then be sent through [comport]. */ +/* Started by Martin Peach 20110731 */ +/* Information taken from "XBeeŽ/XBee-PROŽ ZB RF Modules" (document 90000976_G, 11/15/2010)*/ +/* by Digi International Inc. http://www.digi.com */ + +#include +//#include +#include "m_pd.h" +#include "pdxbee.h" + +static t_class *packxbee_class; + + +typedef struct _packxbee +{ + t_object x_obj; + t_outlet *x_listout; + int x_api_mode; + unsigned char x_frameID; + unsigned char x_frameType; + int x_verbosity; + t_atom x_outbuf[MAX_XBEE_PACKET_LENGTH]; +} t_packxbee; + +static void *packxbee_new(t_floatarg f); +static int packxbee_outbuf_add(t_packxbee *x, int index, unsigned char val); +static void packxbee_AT(t_packxbee *x, t_symbol *s, int argc, t_atom *argv); +static void packxbee_RAT(t_packxbee *x, t_symbol *s, int argc, t_atom *argv); +static void packxbee_ATQ(t_packxbee *x, t_symbol *s, int argc, t_atom *argv); +static void packxbee_TX(t_packxbee *x, t_symbol *s, int argc, t_atom *argv); +static void packxbee_pack_remote_frame(t_packxbee *x, t_symbol *s, int argc, t_atom *argv); +static void packxbee_pack_frame(t_packxbee *x, t_symbol *s, int argc, t_atom *argv); +static void packxbee_API(t_packxbee *x, t_float api); +static void packxbee_verbosity(t_packxbee *x, t_float verbosity_level); +static void packxbee_free(t_packxbee *x); +void packxbee_setup(void); + +static void *packxbee_new(t_floatarg f) +{ + int i; + + t_packxbee *x = (t_packxbee *)pd_new(packxbee_class); + if (x) + { + x->x_listout = outlet_new(&x->x_obj, &s_list); + if (1 == f) x->x_api_mode = 1; + else x->x_api_mode = 2; /* default to escaped mode */ + x->x_verbosity = 2; /* debug level */ + for(i = 0; i < MAX_XBEE_PACKET_LENGTH; ++i) x->x_outbuf[i].a_type = A_FLOAT; /* init output atoms as floats */ + } + return (x); +} + +static void packxbee_API(t_packxbee *x, t_float api) +{ + if ((api == 1) || (api ==2)) x->x_api_mode = api; + else error ("packxbee: api mode must be 1 or 2"); +} + +static void packxbee_verbosity(t_packxbee *x, t_float verbosity_level) +{ + if (verbosity_level >= 0) x->x_verbosity = verbosity_level; + else error ("packxbee: verbosity_level must be positive"); +} + +static int packxbee_outbuf_add(t_packxbee *x, int index, unsigned char val) +{ + int i = index; + +/* if API mode is 2 all characters after the first are escaped if they are one of the sacred texts */ +/* to escape the character prefix it with XSCAPE and XOR it with 0x20 */ + if + ( + (2 == x->x_api_mode) + && + ( + ((0 < index)&&(XFRAME == val)) + ||(XSCAPE == val) + ||(XON == val) + ||(XOFF == val) + ) + ) + { /* escape the character */ + x->x_outbuf[i].a_w.w_float = XSCAPE; + ++i; + x->x_outbuf[i].a_w.w_float = val ^ 0x20; + ++i; + } + else + { /* otherwise just put it in the buffer */ + x->x_outbuf[i++].a_w.w_float = val; + } + return i; +} + +/* send a packet given a 64-bit address, a 16-bit address, broadcast radius, options, followed by raw data */ +static void packxbee_TX(t_packxbee *x, t_symbol *s, int argc, t_atom *argv) +{ + unsigned char floatstring[256]; /* longer than the longest hex number with each character escaped plus the header and checksum overhead */ + unsigned long long dest64; + unsigned int dest16; + int result; + char checksum = 0xFF; + unsigned char broadcast_radius, options; + t_float f; + int d, i, j, k; + int length = 0; + unsigned char c; + + if (argc < 5) + { + error("packxbee_TX: not enough parameters"); + return; + } + /* first arg is dest64, a symbol starting with "0x" */ + if (argv[0].a_type != A_SYMBOL) + { + error("packxbee_TX: first argument is not a symbol"); + return; + } + if ((argv[0].a_w.w_symbol->s_name[0] != '0')||(argv[0].a_w.w_symbol->s_name[1] != 'x')) + { + error("packxbee_TX: first argument is not a hex string beginning with \"0x\""); + return; + } + result = sscanf(argv[0].a_w.w_symbol->s_name, "0x%I64X", &dest64); + if (result == 0) + { + error("packxbee_TX: first argument is not a hex string"); + return; + } + if (x->x_verbosity > 0) post ("packxbee_TX: dest64:0x%I64X", dest64); + /* second arg is dest16 also a symbol starting with "0x" */ + if (argv[1].a_type != A_SYMBOL) + { + error("packxbee_TX: second argument is not a symbol"); + return; + } + if ((argv[1].a_w.w_symbol->s_name[0] != '0')||(argv[1].a_w.w_symbol->s_name[1] != 'x')) + { + error("packxbee_TX: second argument is not a hex string beginning with \"0x\""); + return; + } + result = sscanf(argv[1].a_w.w_symbol->s_name, "0x%X", &dest16); + if (result == 0) + { + error("packxbee_TX: second argument is not a hex string"); + return; + } + if (x->x_verbosity > 0) post ("packxbee_TX: dest16: 0x%X", dest16); + /* broadcast radius is a single byte as a float */ + if (argv[2].a_type != A_FLOAT) + { + error("packxbee_TX: third argument is not a float"); + return; + } + f = argv[2].a_w.w_float; + if (x->x_verbosity > 0) post("packxbee_TX float parameter %f", f); + d = ((unsigned int)f)&0x0FF; + if (f != d) + { + post ("packxbee_TX third argument not a positive integer from 0 to 255"); + return; + } + else broadcast_radius = d; + if (x->x_verbosity > 0) post("packxbee_TX: broadcast_radius: %d", d); + + /* options is a single byte as a float */ + if (argv[3].a_type != A_FLOAT) + { + error("packxbee_TX: fourth argument is not a float"); + return; + } + f = argv[3].a_w.w_float; + if (x->x_verbosity > 0) post("packxbee_TX float parameter %f", f); + d = ((unsigned int)f)&0x0FF; + if (f != d) + { + post ("packxbee_TX fourth argument not a positive integer from 0 to 255"); + return; + } + else options = d; + if (x->x_verbosity > 0) post("packxbee_TX: options: %d", d); + + x->x_frameType = ZigBee_Transmit_Request;/* because we're building a queued AT frame */ + floatstring[0] = XFRAME; /* as usual */ + floatstring[1] = 0; /* length MSB */ + floatstring[2] = 0;/* length LSB */ + floatstring[3] = x->x_frameType; + checksum -= x->x_frameType; + if (0 == x->x_frameID) x->x_frameID++; + checksum -= x->x_frameID; /* frame ID */ + floatstring[4] = x->x_frameID++; + /* raw 8 byte address in big-endian order: */ + floatstring[5] = (dest64>>56)&0x0FF; + checksum -= floatstring[5]; + floatstring[6] = (dest64>>48)&0x0FF; + checksum -= floatstring[6]; + floatstring[7] = (dest64>>40)&0x0FF; + checksum -= floatstring[7]; + floatstring[8] = (dest64>>32)&0x0FF; + checksum -= floatstring[8]; + floatstring[9] = (dest64>>24)&0x0FF; + checksum -= floatstring[9]; + floatstring[10] = (dest64>>16)&0x0FF; + checksum -= floatstring[10]; + floatstring[11] = (dest64>>8)&0x0FF; + checksum -= floatstring[11]; + floatstring[12] = (dest64)&0x0FF; + checksum -= floatstring[12]; + + floatstring[13] = (dest16>>8)&0x0FF; + checksum -= floatstring[13]; + floatstring[14] = (dest16)&0x0FF; + checksum -= floatstring[14]; + + floatstring[15] = broadcast_radius; + checksum -= floatstring[15]; + floatstring[16] = options; + checksum -= floatstring[16]; + /* the rest is payload */ + i = 17; + for (k = 4; k < argc; ++k) + { + if (A_FLOAT == argv[k].a_type) + { + f = argv[k].a_w.w_float; + if (x->x_verbosity > 0) post("packxbee_TX float parameter %f", f); + d = ((unsigned int)f)&0x0FF; + if (f != d) + { + post ("packxbee_TX %dth argument not a positive integer from 0 to 255", k+1); + return; + } + floatstring[i++] = d; + checksum -= d; + } + else if (A_SYMBOL == argv[k].a_type) + { + if (x->x_verbosity > 0) post("packxbee_TX symbol parameter %s", argv[k].a_w.w_symbol->s_name); + j = i; + i += sprintf(&floatstring[i], "%s", argv[k].a_w.w_symbol->s_name); + for (;j < i; ++j) checksum -= floatstring[j]; + } + else + { + error("packxbee_TX %dth argument neither a float nor a symbol", k); + return; + } + } + length = i-3; + floatstring[LENGTH_LSB_INDEX] = length & 0x0FF; + floatstring[LENGTH_MSB_INDEX] = length >> 8; + floatstring[i++] = checksum; + k = j = 0; /* j indexes the outbuf, k indexes the floatbuf, i is the length of floatbuf */ + for (k = 0; k < i; ++k) j = packxbee_outbuf_add(x, j, floatstring[k]); + outlet_list(x->x_listout, &s_list, j, x->x_outbuf); + if(x->x_verbosity > 1) + { + for (k = 0; k < j; ++k) + { + c = (unsigned char)atom_getfloat(&x->x_outbuf[k]); + post("buf[%d]: %d [0x%02X]", k, c, c); + } + } +} + +/* format a queued AT packet and send it through x_listout as a list of floats */ +static void packxbee_ATQ(t_packxbee *x, t_symbol *s, int argc, t_atom *argv) +{ + x->x_frameType = AT_Command_Queue_Parameter_Value;/* we're building a queued AT frame */ + packxbee_pack_frame(x, s, argc, argv); +} + +/* format an AT packet and send it through x_listout as a list of floats */ +static void packxbee_AT(t_packxbee *x, t_symbol *s, int argc, t_atom *argv) +{ + x->x_frameType = AT_Command;/* we're building an AT frame */ + packxbee_pack_frame(x, s, argc, argv); +} + +/* format a remote AT packet and send it through x_listout as a list of floats */ +static void packxbee_RAT(t_packxbee *x, t_symbol *s, int argc, t_atom *argv) +{ + x->x_frameType = Remote_Command_Request;/* we're building a remote AT frame */ + if (argc < 3) + { + error("packxbee_RAT: not enough parameters"); + return; + } + packxbee_pack_remote_frame(x, s, argc, argv); +} + +static void packxbee_pack_remote_frame(t_packxbee *x, t_symbol *s, int argc, t_atom *argv) +{ + int i, j, k, maxdigits, d; + char checksum = 0xFF; + unsigned char floatstring[256]; /* longer than the longest hex number with each character escaped plus the header and checksum overhead */ + int length = 0; + int usefloatstring = 0; + unsigned char c, digits; + long param; + t_float f; + + unsigned long long dest64; + unsigned int dest16; + int result; + unsigned char options; + + + if (x->x_verbosity > 0) post("packxbee_AT s is %s, argc is %d", s->s_name, argc); + if (argc >= 4) /* we must have addr64, addr16, option byte, and an AT command */ + { + /* first arg is dest64, a symbol starting with "0x" */ + if (argv[0].a_type != A_SYMBOL) + { + error("packxbee_pack_remote_frame: first argument is not a symbol"); + return; + } + if ((argv[0].a_w.w_symbol->s_name[0] != '0')||(argv[0].a_w.w_symbol->s_name[1] != 'x')) + { + error("packxbee_pack_remote_frame: first argument is not a hex string beginning with \"0x\""); + return; + } + result = sscanf(argv[0].a_w.w_symbol->s_name, "0x%I64X", &dest64); + if (result == 0) + { + error("packxbee_pack_remote_frame: first argument is not a hex string"); + return; + } + if (x->x_verbosity > 0) post ("packxbee_pack_remote_frame: dest64:0x%I64X", dest64); + /* second arg is dest16 also a symbol starting with "0x" */ + if (argv[1].a_type != A_SYMBOL) + { + error("packxbee_pack_remote_frame: second argument is not a symbol"); + return; + } + if ((argv[1].a_w.w_symbol->s_name[0] != '0')||(argv[1].a_w.w_symbol->s_name[1] != 'x')) + { + error("packxbee_pack_remote_frame: second argument is not a hex string beginning with \"0x\""); + return; + } + result = sscanf(argv[1].a_w.w_symbol->s_name, "0x%X", &dest16); + if (result == 0) + { + error("packxbee_pack_remote_frame: second argument is not a hex string"); + return; + } + if (x->x_verbosity > 0) post ("packxbee_pack_remote_frame: dest16: 0x%X", dest16); + /* options is a single byte as a float */ + if (argv[2].a_type != A_FLOAT) + { + error("packxbee_pack_remote_frame: third argument is not a float"); + return; + } + f = argv[2].a_w.w_float; + if (x->x_verbosity > 0) post("packxbee_pack_remote_frame float parameter %f", f); + d = ((unsigned int)f)&0x0FF; + if (f != d) + { + post ("packxbee_pack_remote_frame third argument not a positive integer from 0 to 255"); + return; + } + else options = d; + if (x->x_verbosity > 0) post("packxbee_pack_remote_frame: options: %d", d); + if (argv[3].a_type != A_SYMBOL) + { + post ("packxbee_pack_remote_frame: argument 4 must be an AT command"); + return; + } + if (x->x_verbosity > 0) post ("packxbee_pack_remote_frame: argument 4 is %s", argv[3].a_w.w_symbol->s_name); + if (2 != strlen(argv[3].a_w.w_symbol->s_name)) + { + post ("packxbee_pack_remote_frame: argument 4 must be a two-character AT command"); + return; + } + if (((argv[3].a_w.w_symbol->s_name[0] < 0x20) || (argv[3].a_w.w_symbol->s_name[0] > 0x7F)) + || ((argv[3].a_w.w_symbol->s_name[1] < 0x20) || (argv[3].a_w.w_symbol->s_name[1] > 0x7F))) + { + post ("packxbee_pack_remote_frame: argument 4 must be printable ascii"); + return; + } + /* parameters seem valid, now build the frame */ + i = 0; + floatstring[i++] = XFRAME; /* as usual */ + floatstring[i++] = 0; /* length MSB */ + floatstring[i++] = 0;/* length LSB */ + floatstring[i++] = x->x_frameType; + checksum -= x->x_frameType; + if (0 == x->x_frameID) x->x_frameID++; /* never use zero as frame ID */ + floatstring[i] = x->x_frameID++; + checksum -= floatstring[i++]; + + /* raw 8 byte address in big-endian order: */ + floatstring[i] = (dest64>>56)&0x0FF; + checksum -= floatstring[i++]; + floatstring[i] = (dest64>>48)&0x0FF; + checksum -= floatstring[i++]; + floatstring[i] = (dest64>>40)&0x0FF; + checksum -= floatstring[i++]; + floatstring[i] = (dest64>>32)&0x0FF; + checksum -= floatstring[i++]; + floatstring[i] = (dest64>>24)&0x0FF; + checksum -= floatstring[i++]; + floatstring[i] = (dest64>>16)&0x0FF; + checksum -= floatstring[i++]; + floatstring[i] = (dest64>>8)&0x0FF; + checksum -= floatstring[i++]; + floatstring[i] = (dest64)&0x0FF; + checksum -= floatstring[i++]; + + floatstring[i] = (dest16>>8)&0x0FF; + checksum -= floatstring[i++]; + floatstring[i] = (dest16)&0x0FF; + checksum -= floatstring[i++]; + + floatstring[i] = options; + checksum -= floatstring[i++]; + + c = argv[3].a_w.w_symbol->s_name[0];/* the first character of the AT command */ + floatstring[i] = c; + checksum -= floatstring[i++]; + c = argv[3].a_w.w_symbol->s_name[1];/* the second character of the AT command */ + floatstring[i] = c; + checksum -= floatstring[i++]; + j = i; /* save i in j so we can calculate checksum on any further parameters */ + /* parameters if any */ + if (argc >= 5) + { /* some parameters */ + if (argv[4].a_type == A_SYMBOL) + { + if (x->x_verbosity > 0) post("packxbee_pack_remote_frame symbol parameter %s", argv[4].a_w.w_symbol->s_name); + if (('0' == argv[4].a_w.w_symbol->s_name[0])&&(('x' == argv[4].a_w.w_symbol->s_name[1]))) + { /* this is a hexadecimal number: strip the "0x" and copy the rest to the buffer as ascii digits */ + i += sprintf(&floatstring[i], "%s", &argv[4].a_w.w_symbol->s_name[2]); + } + else // if ((0 == strncmp("NI", argv[0].a_w.w_symbol->s_name, 2))||(0 == strncmp("DN", argv[0].a_w.w_symbol->s_name, 2))) + { /* we hope it's just an ascii string for the NI command */ + for (k = 0; (k < 20); ++k) /* no more than 20 characters in a node identifier */ + { + c = argv[4].a_w.w_symbol->s_name[k]; + if (0 == c) break; + //checksum -= c; + floatstring[i++] = c; + } + } + } + else if (argv[4].a_type == A_FLOAT) + { + f = argv[4].a_w.w_float; + if (x->x_verbosity > 0) post("packxbee_pack_remote_frame float parameter %f", f); + d = ((unsigned int)f)&0x0FF; + if (f != d) + { + post ("packxbee_pack_remote_frame parameter not a positive integer from 0 to 255"); + } + else + { + // put the significant part of the raw value into floatstring in big endian order + if (0 != ((d>>24) & 0x0FF)) digits = 4; + else if (0 != ((d>>16) & 0x0FF)) digits = 3; + else if (0 != ((d>>8) & 0x0FF)) digits = 2; + else digits = 1; + if (4 == digits) floatstring[i++] = (d>>24) & 0x0FF; + if (3 <= digits) floatstring[i++] = (d>>16) & 0x0FF; + if (2 <= digits) floatstring[i++] = (d>>8) & 0x0FF; + floatstring[i++] = d & 0x0FF; + } + } + else + { + post("packxbee_pack_remote_frame parameter not symbol or float: ignoring"); + } + maxdigits = 32; /* the longest possible hex string is for the encryption key */ + /* we leave it up to the user to send the correct values */ + if (j != i) + { /* update the checksum */ + for (; ((j < maxdigits)&&(j < i)); ++j) + { + c = floatstring[j]; + if (0 == c) break; + checksum -= c; + } + } + } /* argc >= 5 */ + } /* argc >= 4 */ + else + { + error("packxbee_pack_remote_frame: not enough parameters"); + return; + } + length = i-3; + floatstring[LENGTH_LSB_INDEX] = length & 0x0FF; + floatstring[LENGTH_MSB_INDEX] = length >> 8; + floatstring[i++] = checksum; + k = j = 0; /* j indexes the outbuf, k indexes the floatbuf, i is the length of floatbuf */ + for (k = 0; k < i; ++k) j = packxbee_outbuf_add(x, j, floatstring[k]); + outlet_list(x->x_listout, &s_list, j, x->x_outbuf); + if(x->x_verbosity > 1) + { + for (k = 0; k < j; ++k) + { + c = (unsigned char)atom_getfloat(&x->x_outbuf[k]); + post("buf[%d]: %d [0x%02X]", k, c, c); + } + } +} + +static void packxbee_pack_frame(t_packxbee *x, t_symbol *s, int argc, t_atom *argv) +{ + int i, j, k, maxdigits, d; + char checksum = 0xFF; + unsigned char floatstring[256]; /* longer than the longest hex number with each character escaped plus the header and checksum overhead */ + int length = 0; + int usefloatstring = 0; + unsigned char c, digits; + long param; + t_float f; + + if (x->x_verbosity > 0) post("packxbee_AT s is %s, argc is %d", s->s_name, argc); + if (argc >= 1) + { + if (argv[0].a_type != A_SYMBOL) + { + post ("packxbee_AT: argument 1 must be an AT command"); + return; + } + if (x->x_verbosity > 0) post ("packxbee_AT: argument 1 is %s", argv[0].a_w.w_symbol->s_name); + if (2 != strlen(argv[0].a_w.w_symbol->s_name)) + { + post ("packxbee_AT: argument 1 must be a two-character AT command"); + return; + } + if (((argv[0].a_w.w_symbol->s_name[0] < 0x20) || (argv[0].a_w.w_symbol->s_name[0] > 0x7F)) + || ((argv[0].a_w.w_symbol->s_name[1] < 0x20) || (argv[0].a_w.w_symbol->s_name[1] > 0x7F))) + { + post ("packxbee_AT: argument 1 must be printable ascii"); + return; + } + i = 0; + floatstring[i++] = XFRAME; /* as usual */ + floatstring[i++] = 0; /* length MSB */ + floatstring[i++] = 0;/* length LSB */ + floatstring[i] = x->x_frameType; + checksum -= floatstring[i++]; + if (0 == x->x_frameID) x->x_frameID++; + floatstring[i] = x->x_frameID++; + checksum -= floatstring[i++]; + c = argv[0].a_w.w_symbol->s_name[0];/* the first character of the AT command */ + floatstring[i] = c; + checksum -= floatstring[i++]; + c = argv[0].a_w.w_symbol->s_name[1];/* the second character of the AT command */ + floatstring[i] = c; + checksum -= floatstring[i++]; + j = i; /* store i in j to see if anything gets added later and we need to update the checksum */ + /* parameters if any */ + if (argc >= 2) + { /* some parameters */ + if (argv[1].a_type == A_SYMBOL) + { + if (x->x_verbosity > 0) post("packxbee_AT symbol parameter %s", argv[1].a_w.w_symbol->s_name); + if (('0' == argv[1].a_w.w_symbol->s_name[0])&&(('x' == argv[1].a_w.w_symbol->s_name[1]))) + { /* this is a hexadecimal number: strip the "0x" and copy the rest to the buffer as ascii digits */ + i += sprintf(&floatstring[i], "%s", &argv[1].a_w.w_symbol->s_name[2]); + } + else // if ((0 == strncmp("NI", argv[0].a_w.w_symbol->s_name, 2))||(0 == strncmp("DN", argv[0].a_w.w_symbol->s_name, 2))) + { /* we hope it's just an ascii string for the NI command */ + for (k = 0; (k < 20); ++k) /* no more than 20 characters in a node identifier */ + { + c = argv[1].a_w.w_symbol->s_name[k]; + if (0 == c) break; +// checksum -= c; + floatstring[i++] = c; + } + } + } + else if (argv[1].a_type == A_FLOAT) + { + f = argv[1].a_w.w_float; + if (x->x_verbosity > 0) post("packxbee_AT float parameter %f", f); + d = ((unsigned int)f)&0x0FF; + if (f != d) + { + post ("packxbee_AT parameter not a positive integer from 0 to 255"); + } + else + { + // put the significant part of the raw value into floatstring in big endian order + if (0 != ((d>>24) & 0x0FF)) digits = 4; + else if (0 != ((d>>16) & 0x0FF)) digits = 3; + else if (0 != ((d>>8) & 0x0FF)) digits = 2; + else digits = 1; + if (4 == digits) floatstring[i++] = (d>>24) & 0x0FF; + if (3 <= digits) floatstring[i++] = (d>>16) & 0x0FF; + if (2 <= digits) floatstring[i++] = (d>>8) & 0x0FF; + floatstring[i++] = d & 0x0FF; + } + } + else + { + post("packxbee_AT parameter not symbol or float: ignoring"); + } + maxdigits = 32; /* the longest possible hex string is for the encryption key */ + /* we leave it up to the user to send the correct values */ + /* if anything was added to floatstring, calculate the checksum on it */ + /* update the checksum */ + if (j != i) + { + for (; ((j < maxdigits)&&(j < i)); ++j) + { + c = floatstring[j]; + if (0 == c) break; + checksum -= c; + } + } + } /* argc >= 2 */ + } /* argc >= 1 */ + length = i-3; + floatstring[LENGTH_LSB_INDEX] = length & 0x0FF; + floatstring[LENGTH_MSB_INDEX] = length >> 8; + floatstring[i++] = checksum; + k = j = 0; /* j indexes the outbuf, k indexes the floatbuf, i is the length of floatbuf */ + for (k = 0; k < i; ++k) j = packxbee_outbuf_add(x, j, floatstring[k]); + outlet_list(x->x_listout, &s_list, j, x->x_outbuf); + if(x->x_verbosity > 1) + { + for (k = 0; k < j; ++k) + { + c = (unsigned char)atom_getfloat(&x->x_outbuf[k]); + post("buf[%d]: %d [0x%02X]", k, c, c); + } + } +} + +static void packxbee_free(t_packxbee *x) +{ + /* free any memory we allocated */ + /* stop any callbacks */ +} + +void packxbee_setup(void) +{ + packxbee_class = class_new(gensym("packxbee"), (t_newmethod)packxbee_new, + (t_method)packxbee_free, + sizeof(t_packxbee), 0, A_DEFFLOAT, 0); + class_addmethod(packxbee_class, (t_method)packxbee_AT, gensym("AT"), A_GIMME, 0); + class_addmethod(packxbee_class, (t_method)packxbee_ATQ, gensym("ATQ"), A_GIMME, 0); + class_addmethod(packxbee_class, (t_method)packxbee_RAT, gensym("RAT"), A_GIMME, 0); + class_addmethod(packxbee_class, (t_method)packxbee_TX, gensym("TX"), A_GIMME, 0); + class_addmethod(packxbee_class, (t_method)packxbee_API, gensym("API"), A_DEFFLOAT, 0); + class_addmethod(packxbee_class, (t_method)packxbee_verbosity, gensym("verbosity"), A_DEFFLOAT, 0); +} + +/* fin packxbee.c*/ diff --git a/xbee/pdxbee.h b/xbee/pdxbee.h new file mode 100644 index 0000000..d3023c3 --- /dev/null +++ b/xbee/pdxbee.h @@ -0,0 +1,41 @@ +#ifndef _PDXBEE +#define _PDXBEE + +// MAX_XBEE_PACKET_LENGTH is around 80 +#define MAX_XBEE_PACKET_LENGTH 128 + +#define LENGTH_MSB_INDEX 1 /* offset in x_outbuf */ +#define LENGTH_LSB_INDEX 2 /* offset in x_outbuf */ +#define FRAME_TYPE_INDEX 3 /* offset in x_outbuf */ +#define FRAME_ID_INDEX 4 /* offset in x_outbuf */ +#define AT_COMMAND_INDEX 5 /* offset in x_outbuf */ +#define AT_PARAMETER_INDEX 6 /* offset in x_outbuf */ + +/* API Frame Names and Values */ + +#define AT_Command 0x08 +#define AT_Command_Queue_Parameter_Value 0x09 +#define ZigBee_Transmit_Request 0x10 +#define Explicit_Addressing_ZigBee_Command_Frame 0x11 +#define Remote_Command_Request 0x17 +#define Create_Source_Route 0x21 +#define AT_Command_Response 0x88 +#define Modem_Status 0x8A +#define ZigBee_Transmit_Status 0x8B +#define ZigBee_Receive_Packet 0x90 +#define ZigBee_Explicit_Rx_Indicator 0x91 +#define ZigBee_IO_Data_Sample_Rx_Indicator 0x92 +#define XBee_Sensor_Read_Indicator 0x94 +#define Node_Identification_Indicator 0x95 +#define Remote_Command_Response 0x97 +#define Over_the_Air_Firmware_Update_Status 0xA0 +#define Route_Record_Indicator 0xA1 +#define Many_to_One_Route_Request_Indicator 0xA3 + +/* if API mode is 2 all characters after the first are escaped if they are one of */ +#define XFRAME 0x7E /* Frame Delimiter */ +#define XSCAPE 0x7D /* Escape */ +#define XON 0x11 /* XON */ +#define XOFF 0x13 /* XOFF */ +/* to escape the character prefix it with XSCAPE and XOR it with 0x20 */ +#endif /* _PDXBEE */ diff --git a/xbee/unpackxbee.c b/xbee/unpackxbee.c new file mode 100644 index 0000000..35f36e3 --- /dev/null +++ b/xbee/unpackxbee.c @@ -0,0 +1,452 @@ +/* unpackxbee outputs a list of floats which are the bytes making up an xbee api packet. */ +/* The packet can then be sent through [comport]. */ +/* Started by Martin Peach 20110731 */ +/* Information taken from "XBeeŽ/XBee-PROŽ ZB RF Modules" (document 90000976_G, 11/15/2010)*/ +/* by Digi International Inc. http://www.digi.com */ + +#include +//#include +#include "m_pd.h" +#include "pdxbee.h" + +static t_class *unpackxbee_class; + + +typedef struct _unpackxbee +{ + t_object x_obj; + t_outlet *x_status_out; + t_outlet *x_payload_out; + int x_api_mode; + unsigned char x_frame_ID; + unsigned char x_frame_type; + unsigned int x_frame_length; + int x_verbosity; + unsigned char x_message[MAX_XBEE_PACKET_LENGTH]; + int x_message_index; + int x_escaped; + t_atom x_outbuf[MAX_XBEE_PACKET_LENGTH]; + t_atom x_statusbuf[32]; /* some number bigger than we will ever reach */ +} t_unpackxbee; + +static void *unpackxbee_new(t_floatarg f); +static void unpackxbee_input(t_unpackxbee *x, t_symbol *s, int argc, t_atom *argv); +static void unpackxbee_API(t_unpackxbee *x, t_float api); +static void unpackxbee_verbosity(t_unpackxbee *x, t_float verbosity_level); +static void unpackxbee_free(t_unpackxbee *x); +void unpackxbee_setup(void); + +static void *unpackxbee_new(t_floatarg f) +{ + int i; + + t_unpackxbee *x = (t_unpackxbee *)pd_new(unpackxbee_class); + if (x) + { + x->x_payload_out = outlet_new(&x->x_obj, &s_list); /* the first outlet on the left */ + x->x_status_out = outlet_new(&x->x_obj, &s_list); + + if (1 == f) x->x_api_mode = 1; + else x->x_api_mode = 2; /* default to escaped mode */ + x->x_verbosity = 2; /* debug level */ + for(i = 0; i < MAX_XBEE_PACKET_LENGTH; ++i) x->x_outbuf[i].a_type = A_FLOAT; /* init output atoms as floats */ + } + return (x); +} + +static void unpackxbee_API(t_unpackxbee *x, t_float api) +{ + if ((api == 1) || (api ==2)) x->x_api_mode = api; + else error ("unpackxbee: api mode must be 1 or 2"); +} + +static void unpackxbee_verbosity(t_unpackxbee *x, t_float verbosity_level) +{ + if (verbosity_level >= 0) x->x_verbosity = verbosity_level; + else error ("packxbee: verbosity_level must be positive"); +} + +int unpackxbee_add(t_unpackxbee *x, unsigned char d) +{ + if (XFRAME == d) + { + if (x->x_verbosity > 1) post ("frame start"); + x->x_message_index = 0; + x->x_frame_length = 0; + x->x_frame_type = 0; + x->x_escaped = 0; + } + if (2 == x->x_api_mode) + { + if (XSCAPE == d) + { + x->x_escaped = 1; /* we need to xor the next character with 0x20 */ + return 0; /* don't store the escape character */ + } + else if (1 == x->x_escaped) + { + d ^= 0x20; /* xor with 0x20 to restore the original character */ + x->x_escaped = 0; /* don't do it again */ + } + } + if (LENGTH_LSB_INDEX == x->x_message_index) /* length is a bigendian pair */ + { + x->x_frame_length = (x->x_message[LENGTH_MSB_INDEX]<<8) + d; + if (x->x_verbosity > 1) post ("frame length %d", x->x_frame_length); + } + else if (FRAME_TYPE_INDEX == x->x_message_index) + { + x->x_frame_type = d; + if (x->x_verbosity > 1) post ("frame type 0x%02X", x->x_frame_type); + } + else if (FRAME_ID_INDEX == x->x_message_index) + { /* this is part of the payload and may not be valid in some frame types */ + x->x_frame_ID = d; + if (x->x_verbosity > 1) post ("frame ID %d", x->x_frame_ID); + } + x->x_message[x->x_message_index++] = d; /* add the unescaped character to the output list */ + return 1; +} + +static void unpackxbee_input(t_unpackxbee *x, t_symbol *s, int argc, t_atom *argv) +{ + int i , j, k; + t_float f; + unsigned int d, checksum = 0; + unsigned char c; + t_symbol *type_selector; + int statuslength = 0, payloadstart = 0; + char atbuf[64]; + unsigned char floatstring[256]; /* longer than the longest hex number with each character escaped plus the header and checksum overhead */ + unsigned long long addr64; + unsigned int addr16; + + if (x->x_verbosity > 1) post("unpackxbee_input: s is %s, argc is %d", s->s_name, argc); + for (i = 0; i < argc; ++i) + { + if (A_FLOAT == argv[i].a_type) + { + f = argv[i].a_w.w_float; + d = ((unsigned int)f)&0x0FF; + if (x->x_verbosity > 1) post("unpackxbee_input: argv[%d] is %f int is %d", i, f, d); + if (f != d) + { + post ("unpackxbee_input not a positive integer from 0 to 255"); + } + else unpackxbee_add(x, d); + } + else + post("unpackxbee_input: item %d is not a float", i+1); + } + if ((x->x_frame_length > 0)&&(x->x_frame_length + 4 == x->x_message_index)) + { /* end of frame reached */ + k = x->x_frame_length+4; /* total packet length is payload + 1 start 2 length 1 checksum*/ + if(x->x_verbosity > 1) + { + post("frame end"); + for (j = 0; j < k; ++j) + { + c = x->x_message[j]; + post("unpackxbee buf[%d]: %d [0x%02X]", j, c, c); + } + } + for (j = 3; j < k; ++j) + { + checksum += x->x_message[j]; + } + checksum &= 0x0FF; + if (checksum != 0xFF) + { + post("unpackxbee: wrong checksum; dropping packet"); + return; + } + if(x->x_verbosity > 1) post("unpackxbee checksum %d [0x%02X]", checksum, checksum); + switch(x->x_frame_type) + { + case AT_Command: + type_selector = gensym("AT_Command"); + break; + case AT_Command_Queue_Parameter_Value: + type_selector = gensym("AT_Command_Queue_Parameter_Value"); + break; + case ZigBee_Transmit_Request: + type_selector = gensym("ZigBee_Transmit_Request"); + break; + case Explicit_Addressing_ZigBee_Command_Frame: + type_selector = gensym("Explicit_Addressing_ZigBee_Command_Frame"); + break; + case Remote_Command_Request: + type_selector = gensym("Remote_Command_Request"); + break; + case Create_Source_Route: + type_selector = gensym("Create_Source_Route"); + break; + case AT_Command_Response: + type_selector = gensym("AT_Command_Response"); + break; + case Modem_Status: + type_selector = gensym("Modem_Status"); + break; + case ZigBee_Transmit_Status: + type_selector = gensym("ZigBee_Transmit_Status"); + break; + case ZigBee_Receive_Packet: + type_selector = gensym("ZigBee_Receive_Packet"); + break; + case ZigBee_Explicit_Rx_Indicator: + type_selector = gensym("ZigBee_Explicit_Rx_Indicator"); + break; + case ZigBee_IO_Data_Sample_Rx_Indicator: + type_selector = gensym("ZigBee_IO_Data_Sample_Rx_Indicator"); + break; + case XBee_Sensor_Read_Indicator: + type_selector = gensym("XBee_Sensor_Read_Indicator"); + break; + case Node_Identification_Indicator: + type_selector = gensym("Node_Identification_Indicator"); + break; + case Remote_Command_Response: + type_selector = gensym("Remote_Command_Response"); + break; + case Over_the_Air_Firmware_Update_Status: + type_selector = gensym("Over_the_Air_Firmware_Update_Status"); + break; + case Route_Record_Indicator: + type_selector = gensym("Route_Record_Indicator"); + break; + case Many_to_One_Route_Request_Indicator: + type_selector = gensym("Many_to_One_Route_Request_Indicator"); + break; + default: + type_selector = gensym("unknown"); + } + statuslength = 0; + SETFLOAT(&x->x_statusbuf[statuslength], x->x_frame_type); + statuslength++; + if + ( + (AT_Command_Response == x->x_frame_type) + ||(AT_Command == x->x_frame_type) + ||(AT_Command_Queue_Parameter_Value == x->x_frame_type) + ) + { + if (x->x_verbosity > 1) + post("AT_Command_Response AT_Command AT_Command_Queue_Parameter_Value statuslength %d", statuslength); + SETFLOAT(&x->x_statusbuf[statuslength], x->x_frame_ID); + statuslength++; + /* data doesn't include 1byte frame type 1byte ID 2byte AT command 1byte AT command status = 5bytes */ + SETFLOAT(&x->x_statusbuf[statuslength], x->x_frame_length-5); + statuslength++; + atbuf[0] = x->x_message[5]; /* the AT command string */ + atbuf[1] = x->x_message[6]; + atbuf[2] = '\0'; + SETSYMBOL(&x->x_statusbuf[statuslength], gensym(atbuf)); + statuslength++; + SETFLOAT(&x->x_statusbuf[statuslength], x->x_message[7]);/* AT command status */ + statuslength++; + if ((0 == x->x_message[7]) && ('N' == x->x_message[5]) && ('D' == x->x_message[6])) + { /* a succesful node discover response: output the addresses as symbols */ +/* +buf[0]: 126 [0x7E] ND packet start +buf[1]: 0 [0x00] Length MSB +buf[2]: 25 [0x19] Length LSB +buf[3]: 136 [0x88] AT response +buf[4]: 5 [0x05] packet ID +buf[5]: 78 [0x4E] N +buf[6]: 68 [0x44] D +buf[7]: 0 [0x00] status +*/ + addr16 = (x->x_message[8]<<8) + x->x_message[9]; + sprintf(floatstring, "0x%X", addr16); + SETSYMBOL(&x->x_statusbuf[statuslength], gensym(floatstring)); + statuslength++; +/* +buf[8]: 121 [0x79] MY +buf[9]: 214 [0xD6] +*/ +/* now switch endianness */ + + addr64 = x->x_message[10]; + addr64 <<= 8; + addr64 |= x->x_message[11]; + addr64 <<= 8; + addr64 |= x->x_message[12]; + addr64 <<= 8; + addr64 |= x->x_message[13]; + addr64 <<= 8; + addr64 |= x->x_message[14]; + addr64 <<= 8; + addr64 |= x->x_message[15]; + addr64 <<= 8; + addr64 |= x->x_message[16]; + addr64 <<= 8; + addr64 |= x->x_message[17]; + sprintf(floatstring, "0x%I64X", addr64); + SETSYMBOL(&x->x_statusbuf[statuslength], gensym(floatstring)); /* addr64 */ + statuslength++; +/* +buf[10]: 0 [0x00] SH +buf[11]: 19 [0x13] +buf[12]: 162 [0xA2] +buf[13]: 0 [0x00] +buf[14]: 64 [0x40] SL +buf[15]: 106 [0x6A] +buf[16]: 222 [0xDE] +buf[17]: 30 [0x1E] +*/ + for (j = 0, i = 18; i < k; ++i, ++j) + { + floatstring[j] = x->x_message[i]; + if (0 == floatstring[j]) + { + i++; + break;/* Node Identifier should be a null-terminated ascii string */ + } + } + SETSYMBOL(&x->x_statusbuf[statuslength], gensym(floatstring)); /* Node Identifier */ + statuslength++; +/* +buf[18]: 32 [0x20] NI +buf[19]: 0 [0x00] +*/ + addr16 = (x->x_message[i]<<8) + x->x_message[i+1]; + sprintf(floatstring, "0x%X", addr16); + i += 2; + SETSYMBOL(&x->x_statusbuf[statuslength], gensym(floatstring)); /* parent addr16 */ + statuslength++; +/* +buf[20]: 255 [0xFF] parent +buf[21]: 254 [0xFE] +*/ + SETFLOAT(&x->x_statusbuf[statuslength], x->x_message[i++]);/* Device Type */ + statuslength++; +/* +buf[22]: 1 [0x01] device type +*/ + SETFLOAT(&x->x_statusbuf[statuslength], x->x_message[i++]);/* Source Event */ + statuslength++; +/* +buf[23]: 0 [0x00] source event +*/ + addr16 = x->x_message[i++]<<8; + addr16 |= x->x_message[i++]; + sprintf(floatstring, "0x%X", addr16); + SETSYMBOL(&x->x_statusbuf[statuslength], gensym(floatstring)); /* Profile ID */ + statuslength++; +/* +buf[24]: 193 [0xC1] Profile ID +buf[25]: 5 [0x05] +*/ + addr16 = (x->x_message[i]<<8) + x->x_message[i+1]; + sprintf(floatstring, "0x%X", addr16); + i += 2; + SETSYMBOL(&x->x_statusbuf[statuslength], gensym(floatstring)); /* Manufacturer ID */ + statuslength++; +/* +buf[26]: 16 [0x10] Manufacturer ID +buf[27]: 30 [0x1E] +*/ + +/* +buf[28]: 36 [0x24] checksum +*/ + payloadstart = 0;/* no payload */ + } + else + { + payloadstart = 8; + } + } + else if (ZigBee_Transmit_Status == x->x_frame_type) + { + if (x->x_verbosity > 1) + post("ZigBee_Transmit_Status statuslength %d", statuslength); + SETFLOAT(&x->x_statusbuf[statuslength], x->x_frame_ID); + statuslength++; + sprintf(atbuf, "0x%X", (x->x_message[5]<<8) + x->x_message[6]); /* the 16-bit address as a symbol */ + SETSYMBOL(&x->x_statusbuf[statuslength], gensym(atbuf)); + statuslength++; + SETFLOAT(&x->x_statusbuf[statuslength], x->x_message[7]);/* Transmit Retry Count */ + statuslength++; + SETFLOAT(&x->x_statusbuf[statuslength], x->x_message[8]);/* Delivery Status */ + statuslength++; + SETFLOAT(&x->x_statusbuf[statuslength], x->x_message[9]);/* Discovery Status */ + statuslength++; + payloadstart = 0; /* no payload */ + } + else if (ZigBee_Receive_Packet == x->x_frame_type) + { + if (x->x_verbosity > 1) + post("ZigBee_Receive_Packet statuslength %d", statuslength); + /* data doesn't include 1byte frametype, 8byte addr64, 2byte addr16, 1byte options = 12bytes*/ + SETFLOAT(&x->x_statusbuf[statuslength], x->x_frame_length-12); + statuslength++; + /* frame type */ + /* 64-bit source address */ + i = 4; + addr64 = x->x_message[i++]; + addr64 <<= 8; + addr64 |= x->x_message[i++]; + addr64 <<= 8; + addr64 |= x->x_message[i++]; + addr64 <<= 8; + addr64 |= x->x_message[i++]; + addr64 <<= 8; + addr64 |= x->x_message[i++]; + addr64 <<= 8; + addr64 |= x->x_message[i++]; + addr64 <<= 8; + addr64 |= x->x_message[i++]; + addr64 <<= 8; + addr64 |= x->x_message[i++]; + sprintf(floatstring, "0x%I64X", addr64); + SETSYMBOL(&x->x_statusbuf[statuslength], gensym(floatstring)); /* addr64 */ + statuslength++; + /* 16-bit source address */ + addr16 = x->x_message[i++]<<8; + addr16 |= x->x_message[i++]; + sprintf(floatstring, "0x%X", addr16); + SETSYMBOL(&x->x_statusbuf[statuslength], gensym(floatstring)); /* addr16 */ + statuslength++; + /* receive options byte */ + SETFLOAT(&x->x_statusbuf[statuslength], x->x_message[i++]);/* 1 2 32 64 */ + statuslength++; + /* data */ + payloadstart = i; + } + else + { + if (x->x_verbosity > 1) + post("some other packet statuslength %d", statuslength); + SETFLOAT(&x->x_statusbuf[statuslength], x->x_frame_ID);/* may not be valid */ + statuslength++; + SETFLOAT(&x->x_statusbuf[statuslength], x->x_frame_length-2);/* payload doesn't include frame type and ID */ + statuslength++; + payloadstart = 5; + } + outlet_anything(x->x_status_out, type_selector, statuslength, x->x_statusbuf); + if (payloadstart > 0) + { + for (j = 0, i = payloadstart; i < k-1; ++j, ++i) + SETFLOAT(&x->x_outbuf[j], x->x_message[i]); /* the payload */ + if (j > 0) + outlet_list(x->x_payload_out, &s_list, j, x->x_outbuf); + } + } +} + +static void unpackxbee_free(t_unpackxbee *x) +{ +} + +void unpackxbee_setup(void) +{ + unpackxbee_class = class_new(gensym("unpackxbee"), (t_newmethod)unpackxbee_new, + (t_method)unpackxbee_free, + sizeof(t_unpackxbee), 0, A_DEFFLOAT, 0); + class_addanything(unpackxbee_class, (t_method)unpackxbee_input); + class_addmethod(unpackxbee_class, (t_method)unpackxbee_API, gensym("API"), A_DEFFLOAT, 0); + class_addmethod(unpackxbee_class, (t_method)unpackxbee_verbosity, gensym("verbosity"), A_DEFFLOAT, 0); +} + +/* fin unpackxbee.c*/ -- cgit v1.2.1