aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Peach <mrpeach@users.sourceforge.net>2011-11-06 15:53:11 +0000
committerMartin Peach <mrpeach@users.sourceforge.net>2011-11-06 15:53:11 +0000
commitf7dd9043d4f24ccb6d2aee85b245abdb7114a92d (patch)
tree42497d9473466fc32304c4dc6b9935d92bcee155
parent8cbbe4d6259efc1366b67929d16e32bd3c36c753 (diff)
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
-rw-r--r--xbee/packxbee-help.pd521
-rw-r--r--xbee/packxbee.c655
-rw-r--r--xbee/pdxbee.h41
-rw-r--r--xbee/unpackxbee.c452
4 files changed, 1669 insertions, 0 deletions
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 <stdio.h>
+//#include <string.h>
+#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 <stdio.h>
+//#include <string.h>
+#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*/