Cameron Reid
/
SmartThings_Switch
Mbed switch for Samsung SmartThings using Xbee
Diff: Main.cpp
- Revision:
- 0:1431a301c379
- Child:
- 1:80fe03be2832
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Main.cpp Thu Sep 15 10:15:59 2016 +0000 @@ -0,0 +1,524 @@ +#include "mbed.h" +#include "C12832.h" + +#define AppV 0x01 +#define HarV 0x01 + +C12832 lcd(p5, p7, p6, p8, p11); //configure LCD +RawSerial xbee(p9,p10); //Set Serial to XBee +Serial pc(USBTX, USBRX); //Set Serial to PC. +DigitalOut led2 (LED2); //configure onboard LEDs +DigitalOut led1 (LED1); +DigitalOut LED (LED4); +volatile char x,y,z,len,sum; //some useful internal variables +volatile int length, size, check; +volatile int flag; +char packet[60]; +char PacketAddr[10]; +char Opacket[60]; +char AI[8] = {0x7E,0x00,0x04,0x08,0x21,0x41,0x49,0x4C}; //create AT command to querey network joined? +char MY[8] = {0x7E,0x00,0x04,0x08,0x21,0x4D,0x59,0x30}; //create AT command to get my network ID. +char SL[8] = {0x7E,0x00,0x04,0x08,0x21,0x53,0x4C,0x37}; //create AT command to get 64bit LSB. +char SH[8] = {0x7E,0x00,0x04,0x08,0x21,0x53,0x48,0x3B}; //create AT command to get 64bit MSB. +char CB[8] = {0x7E,0x00,0x04,0x08,0x21,0x43,0x42,0x51}; //Create AT command to leave network. +char LNw[2]; +char Addr[8]; +char pay[101]; +char Buffer[101]; +char EP, DEP, SEP, seqNum, cmdID, frmType; +char atID[2]; +char Clu[2]; +char Pro[2]; +char Man[3] = {'A','R','M'}; //Product manufacturer +char Dev[10] = {'N','X','P','L','P','C','1','7','6','8'}; //Device Name + +void packet_interupt(); //Create subroutine to deal with incoming packet. +void Psend(char API_packet[]); //Create subroutine to send API commands +void PBuild(char FrameAddr[], char sEP, char dEP, char Profile[], char Cluster[], char Payload[], char PaySize); //function to create packets to send. +void Builder(); //Get usefull infromation from packets. +void checksum(); //Create the checksum for the packet. +void DevAnnc(); //function to send the device announce command. +void SimpleDesc(); //Function to create the Simple description packet +void ActiveEPReq(); //Function to create the Active end point request. +void ClusterBasic(); //Function to create the Cluster Basic. +void OnOff(); //Function to process on off commands. +void DefRes(char success, char endpoint); //Function to create the response for the on off command. + +int main(){ + lcd.cls(); //clear lcd screen. + lcd.locate(0,1); //locate the cursor. + lcd.printf(" Joining network..."); //Print to lcd screen + + //xbee.attach(&packet_interupt, Serial::RxIrq); //attach interupt when recieving serial information. + + while(packet[5] != 0){ //While Xbee has not joined a network + wait(1); //Wait 0.1 second. + Psend(AI); //Send network joined status again. + pc.printf("%x," , packet[5]); //Serially print netowrk status. + check = 0; + while(check == 0){ + while (!xbee.readable()) + {} + if (xbee.readable()) //If data is available. + packet_interupt(); //Read data. + } + } + lcd.cls(); //Clear lcd screen. + lcd.locate(0,1); //Locate the cursor. + lcd.printf(" Connected"); //Print to lcd screen. + + wait(1); //Wait 0.1 seconds. + Psend(MY); //Send AT command to get the 16bit network address. + check = 0; + while( check == 0){ //Wait for packet. + while (!xbee.readable()) //Wait till something is available on the Serial port. + {} + if (xbee.readable()) // if data is available + packet_interupt(); //Read data. + LNw[0] = packet[5]; //Transfer 16 bit address payload. + pc.printf("%x",packet[5]); //Serially print result. + LNw[1] = packet[6]; //Transfer 16 bit address payload. + pc.printf("%x \n",packet[6]); //Serially print result. + } + + Psend(SH); //Send AT command to get the 64bit address MSB. + check = 0; + while (check == 0){ //Wait for packet. + while (!xbee.readable()) //Wait till something is available on the Serial port. + {} + if (xbee.readable()) //If data is available + packet_interupt(); //Read data. + Addr[0] = packet[5]; //Transfer 64 bit address payload. + pc.printf("%x",packet[5]); //Serially print result. + Addr[1] = packet[6]; //Transfer 64 bit address payload. + pc.printf("%x",packet[6]); //Serially print result. + Addr[2] = packet[7]; //Transfer 64 bit address payload. + pc.printf("%x",packet[7]); //Serially print result. + Addr[3] = packet[8]; //Transfer 64 bit address payload. + pc.printf("%x \n",packet[8]); //Serially print result. + } + + Psend(SL); //Send AT command to get the 64bit address LSB. + check = 0; + while (check == 0){ //Wait for packet. + while (!xbee.readable()) //Wait till something is available on the Serial port. + {} + if (xbee.readable()) //If data is available + packet_interupt(); //Read data. + Addr[4] = packet[5]; //Transfer 64 bit address payload. + pc.printf("%x",packet[5]); //Serially print result. + Addr[5] = packet[6]; //Transfer 64 bit address payload. + pc.printf("%x",packet[6]); //Serially print result. + Addr[6] = packet[7]; //Transfer 64 bit address payload. + pc.printf("%x",packet[7]); //Serially print result. + Addr[7] = packet[8]; //Transfer 64 bit address payload. + pc.printf("%x \n",packet[8]); //Serially print result. + } + wait(1); //Wait 0.1 seconds. + DevAnnc(); //Send Device Announce. + +while(1) { +lcd.locate(0,21); //Locate LCD cursor. +lcd.printf("Packets recieved = %d", z); //Print to LCD display. +check = 0; +while(check == 0){ //Wait for packet. + while(!xbee.readable()) //Wait till something is available on the Serial port. + {} + if (xbee.readable()) //If data is available. + packet_interupt(); //Read data. +} + if (packet[16] == 0x00){ //If packet profile = 16. + if (packet[14] == 0x04){ //If packet cluster = 14. + lcd.locate(0,11); //Locate LCD cursor. + lcd.printf(" simple dec"); + SimpleDesc(); //Process Simple Desciption request. + } + else if (packet[14] ==0x05){ //If packet cluster = 15. + lcd.locate(0,11); //Locate LCD display + lcd.printf(" Active EP req"); + ActiveEPReq(); //Process active EP Request. + } + else{ + lcd.locate(0,11); //Locate LCD cursor. + lcd.printf(" Unknown Packet"); //Print to lcd screen. + } + } + else{ //Else if packet profile is not = 00. + if (packet[14] == 0x00){ //If packet Cluster = 00. + lcd.locate(0,11); //Locate LCD cursor. + lcd.printf(" Cluster Basic"); + ClusterBasic(); //Process Cluster Basic request. + } + else if (packet[14] ==0x06){ //Else if packet profile is not = 06. + lcd.locate(0,11); //Locate LCD cursor. + lcd.printf(" on/off "); + OnOff(); //Process On/Off. + } + else{ + lcd.locate(0,11); //Locate the cursor. + lcd.printf(" Unknown Packet"); //Print to lcd screen. + } + } + +} //end of while(1) +} + +/********************************* Packet interupt *************************************** +When a new Xbee packet is revieved it is sent to this function to be processed. + +*****************************************************************************************/ +void packet_interupt() //packet interupt begins when incoming data sensed on the rx line. +{ +if (xbee.readable()) //If data is available + x=xbee.getc(); //Get data +if (x==0x7E){ //Test for start of Frame. + led2 =1; //Set indicator LED2 to on. + z ++; //Increment packet counter. + pc.printf("packet Recieved"); //Serially print to PC. + memset(packet, 0, sizeof(packet)); //Clear packet buffer. + while(xbee.readable() == 0); //If data is available. + x =xbee.getc(); //Get data MSB length. + while(xbee.readable() == 0); //If data is available. + len=xbee.getc(); //Get data LSB length. + x=0; //Counter to 0. + sum = 0; //Set checksum calculator to 0. + while(x < (len +1)){ //Fill packet variable with entire API packet. + while (xbee.readable()==0); //If data is available. + packet[x]=xbee.getc(); //Get data and place it in the data array. + sum = (sum + packet[x]); //Add value to checksum calculation. + x++; + } + sum = (0xFF - ( sum & 0xFF)); //Finish calculating the checksum. + if (packet[x] == sum ){ //If the checksum and the calculated checksum are equal. + pc.printf(" checksum good \n"); + if (packet[0] == 0x91){ //If packet ID = 0x91 + Builder(); //Extract packet information + check = 1; + } + else if(packet[0] == 0x88) //Else if packet ID = 0x88. + check = 1; + else + memset(packet, 0, sizeof(packet)); //Clear array + } + else{ + pc.printf(" checksum bad \n"); + memset(packet, 0, sizeof(packet)); //Clear array + } + led2 = 0; //Set indicator LED2 to off. + } +} +/************************************* Builder ****************************************** +Extract all the important inforamtion from the packet and assoicate it to the relevant variable. +*****************************************************************************************/ +void Builder() +{ + x = 0; //Set the counter to 0. + while (x < 10){ //send the command + PacketAddr[x] = packet[(x+1)]; //Copy the packets 16 and 64bit address. + x ++; + } + DEP = packet[11]; //Get the source endpoint. + SEP = packet[12]; //Get the destination endpoint. + Clu[0] = packet[13]; //Get Cluster ID MSB. + Clu[1] = packet[14]; //Get Cluster ID LSB. + Pro[0] = packet[15]; //Get profile ID MSB. + Pro[1] = packet[16]; //Get profile ID LSB. + x = 0; //Set counter to 0. + while ((x+18) < len){ + pay[x] = packet[(x+18)]; //Copy packet payload. + pc.printf(" %x," ,packet[x+18]); //Print packet contents to PC. + x++; + } + pc.printf(" \n"); +} +/************************************ PBuild ****************************************** +Organise the information from other functions into the correct packet format. + +*****************************************************************************************/ +void PBuild(char FrameAddr[], char sEP, char dEP, char Profile[], char Cluster[], char Payload[],char PaySize) +{ + size = 0; //Set size to 0. + x = 0; //Set counter to 0. + memset(Opacket, 0, sizeof(Opacket)); //Clear output buffer. + + size = 20 +(PaySize); //Find out the size of the out going packet. + + Opacket[0] = 0x7E; //Packet start bit. + Opacket[1] = 0x00; //Packet length MSB. + Opacket[2] = size; //Packet length LSB. + Opacket[3] = 0x11; //Packet Type + Opacket[4] = 0x00; //No response needed. + Opacket[5] = FrameAddr[0]; //64 bit address High + Opacket[6] = FrameAddr[1]; + Opacket[7] = FrameAddr[2]; + Opacket[8] = FrameAddr[3]; + Opacket[9] = FrameAddr[4]; //64 bit address Low + Opacket[10] = FrameAddr[5]; + Opacket[11] = FrameAddr[6]; + Opacket[12] = FrameAddr[7]; + Opacket[13] = FrameAddr[8]; //16 bit PAN address + Opacket[14] = FrameAddr[9]; + Opacket[15] = sEP; //Source Endpoint + Opacket[16] = dEP; //Destinaton Endpoint + Opacket[17] = Cluster[0]; //Cluster ID + Opacket[18] = Cluster[1]; + Opacket[19] = Profile[0]; //Profile ID + Opacket[20] = Profile[1]; + Opacket[21] = 0x00; //Broadcast radius + Opacket[22] = 0x00; //Trasmit option bitfield + while (x < PaySize){ + Opacket[(23 + x)] = Payload[x]; //Copy packet payload + x ++; + } + + checksum(); //Create the check sum. + Psend(Opacket); //Send the packet. +} +/************************************ Checksum ****************************************** +Create the checksum for outgoing packets. + +*****************************************************************************************/ +void checksum() +{ + y = 0; //Set Alternatie counter to 0 + sum = 0; + while (y < (Opacket[2])){ //Create the checksum. + sum = (sum + Opacket[y + 3]); + y++; + } + Opacket[23 + x] = (0xFF - ( sum & 0xFF)); +} +/************************************* Psend ******************************************** +Send the packet out serially to the Xbee module. + +*****************************************************************************************/ +void Psend(char API_packet[]) +{ + led1 = 1; //Set onboard LED1 on for diagnostics + pc.printf("sending packet"); + length = (API_packet[2] + 4); //Calaculate packet length using packet length identifier and add the start byte, 2 byte length and checksum. + x = 0; + while (x < length){ //Send the command + xbee.putc(API_packet[x]); + pc.printf("%x," ,API_packet[x]); + x ++; + } + led1 = 0; //Set diagnostics LED1 to off + pc.printf("\n"); +} +/********************************* Device Announce ************************************** +Send a Device announce packet when joining or re joining and network. +For more informaion see ZigBee spec page 109 +*****************************************************************************************/ +void DevAnnc() +{ + char AnncFrame[16] = {0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFE}; + char AnncPayload[12]; //Create char array for payload. + char DevClu[2] = {0x00, 0x13}; //Create char array for Cluster ID. + char DevPro[2] = {0x00, 0x00}; //Create char array for Profile ID. + AnncPayload[0] = 0x22; //Set seqence ID to 0x22. + AnncPayload[1] = LNw[1]; //Copy 16bit PAN address little endian. + AnncPayload[2] = LNw[0]; + AnncPayload[3] = Addr[7]; //Copy 64bit address little endian. + AnncPayload[4] = Addr[6]; + AnncPayload[5] = Addr[5]; + AnncPayload[6] = Addr[4]; + AnncPayload[7] = Addr[3]; + AnncPayload[8] = Addr[2]; + AnncPayload[9] = Addr[1]; + AnncPayload[10] = Addr[0]; + AnncPayload[11] = 0x8C; //Set device parameters. + + PBuild(AnncFrame,0x00,0x00,DevPro,DevClu, AnncPayload, 12); //Send packet to builder. +} +/******************************** Simple Description ************************************ +Send a response to a Simple Description Request. +For more informaion see ZigBee spec page 159. +*****************************************************************************************/ +void SimpleDesc() +{ + EP = pay[3]; //Get endpoint from payload. + char DescClu[2] = {0x80,0x04}; //Create char array for cluster ID. + char DescPro[2] = {0x00,0x00}; //Create char array for profile ID. + + if( EP == 0x76){ //If Endpoint = 38. + memset(Buffer, 0, sizeof(Buffer)); //Clear array + Buffer[0] = pay[0]; //Set Transcation Seq number to match inbound packets seq number + Buffer[1] = 0x00; //Status $00 = success Table 2.93 on page 159 of ZBSpec + Buffer[2] = pay[1]; //Set Network address little endian order + Buffer[3] = pay[2]; + Buffer[4] = 0x0E; //Length in bytes of the Simple Descriptor to Follow + Buffer[5] = 0x76; //Endpoint of the simple descriptor Table 2.38 on page 88 of ZBSpec + Buffer[6] = 0x04; //Application Profile ID 2 Bytes Little endian. $0104 = Home Automation Profile + Buffer[7] = 0x01; + Buffer[8] = 0x02; //Device type 2 Bytes Little endian, $0002 = On/Off Output see page 42 of ZigBee Home Automation Profile + Buffer[9] = 0x00; + Buffer[10] = 0x00; //App Dev Version 4bits + reserved 4bits + Buffer[11] = 0x02; //Input cluster count in this case we only have $02 input clusters + Buffer[12] = 0x00; //Input cluster list 2 bytes each little endian. $0000 = Basic Cluster + Buffer[13] = 0x00; + Buffer[14] = 0x06; //Output cluster 2 bytes each little endian. $0006 = On / Off Cluster + Buffer[15] = 0x00; + Buffer[16] = 0x00; //Output cluster list. No output cluster. + PBuild(PacketAddr,0x00,0x00,DescPro,DescClu, Buffer, 0x11); + } + + else{ + memset(Buffer, 0, sizeof(Buffer)); //Clear array. + Buffer[0] = pay[0]; //Set Transcation Seq number to match inbound packets seq number. + Buffer[1] = 0x82; //Status $82 = Invalid_EP page 212 of ZigBee Specification. + Buffer[2] = pay[1]; //Set Network address little endian order. + Buffer[3] = pay[2]; + Buffer[4] = 0x00; //Length in bytes of simple descriptor to follow. + PBuild(PacketAddr,0x00,0x00,DescPro,DescClu, Buffer, 0x05); + } +} +/******************************** Active EP Request ************************************ +Send a response to and Active EP Request. +For more informaion see ZigBee spec page 161. +*****************************************************************************************/ +void ActiveEPReq() +{ + char EPReqClu[2] = {0x80, 0x05}; //Create char array for Cluster. + char EPReqPro[2] = {0x00, 0x00}; //Create char array for Profile. + memset(Buffer, 0, sizeof(Buffer)); //Clear array. + Buffer[0] = pay[0]; //Set Transcation Seq number to match inbound packets seq number. + Buffer[1] = 0x00; //Status $00 = success Table 2.93 on page 159 of ZBSpec. + Buffer[2] = pay[1]; //Set Network address little endian order. + Buffer[3] = pay[2]; + Buffer[4] = 0x01; //Active end point count in this case 1. + Buffer[5] = 0x76; //Endpoint 38. + PBuild(PacketAddr,0x00,0x00,EPReqPro,EPReqClu, Buffer, 0x06); +} +/********************************** Cluster Basic *************************************** +Process a Basic Cluster request. +For more informaion see ZigBee cluster library page 78 +*****************************************************************************************/ +void ClusterBasic() +{ + cmdID = 0; //Set command ID to 0. + seqNum = 0; //Set seqence number to 0. + memset(Buffer, 0, sizeof(Buffer)); //Clear array. + memset(atID, 0, sizeof(atID)); //Clear array. + + seqNum = pay[1]; //Copy seqence number from payload. + cmdID = pay[2]; //Copy command ID from payload. + atID[0] = pay[3]; //Copy attribute ID LSB from payload. + atID[1] = pay[4]; //Copy attribute ID MSB from payload. + + if ((cmdID == 0x00) && (atID[0] == 0x01) && (atID[1] == 0x00)){ //If Application version is requested. + Buffer[0] = 0x18; //Frame control direction is server to client. + Buffer[1] = seqNum; //Reply with seqence number from request. + Buffer[2] = 0x01; //Command indetifier = 1, Read attribute response. + Buffer[3] = 0x01; //Attribute Identfier (2 bytes) field being reported. + Buffer[4] = 0x00; + Buffer[5] = 0x00; //status 00 success. + Buffer[6] = 0x20; //Attribute data type 0x20 = unsigned 8 bit integer. + Buffer[7] = AppV; //Application version. + PBuild(PacketAddr,SEP,DEP,Pro,Clu, Buffer, 0x08); //Send data to packet builder. + } + + if ((cmdID == 0x00) && (atID[0] == 0x03) && (atID[1] == 0x00)){ //If Hardware version is requeted. + Buffer[0] = 0x18; //Frame control direction is server to client. + Buffer[1] = seqNum; //Reply with seqence number from request. + Buffer[2] = 0x01; //Command indetifier = 1, Read attribute response. + Buffer[3] = 0x03; //Attribute Identfier (2 bytes) field being reported. + Buffer[4] = 0x00; + Buffer[5] = 0x00; //status 00 success. + Buffer[6] = 0x20; //Attribute data type 0x20 = unsigned 8 bit integer. + Buffer[7] = HarV; //Hardware version. + PBuild(PacketAddr,SEP,DEP,Pro,Clu, Buffer, 0x08); //Send data to packet builder. + } + + if ((cmdID == 0x00) && (atID[0] == 0x04) && (atID[1] == 0x00)){ //If device Manufacturer is requested + Buffer[0] = 0x18; //Frame control direction is server to client. + Buffer[1] = seqNum; //Reply with seqence number from request. + Buffer[2] = 0x01; //Command indetifier = 1, Read attribute response. + Buffer[3] = 0x04; //Attribute Identfier (2 bytes) field being reported. + Buffer[4] = 0x00; + Buffer[5] = 0x00; //status 00 success. + Buffer[6] = 0x42; //Attribute data type 0x42 = character string. + Buffer[7] = sizeof(Man); //Size of string to follow. + x = 0; + while( x < (sizeof(Man))){ //Send sting byte by byte. + Buffer[(x+8)] = Man[x]; + x++; + } + PBuild(PacketAddr,SEP,DEP,Pro,Clu, Buffer, (0x08 + Buffer[7])); //Send data to packet builder. + } + + if ((cmdID == 0x00) && (atID[0] == 0x05) && (atID[1] == 0x00)){ //If Device devoloper is requested. + Buffer[0] = 0x18; //Frame control direction is server to client. + Buffer[1] = seqNum; //Reply with seqence number from request. + Buffer[2] = 0x01; //Command indetifier = 1, Read attribute response. + Buffer[3] = 0x05; //Attribute Identfier (2 bytes) field being reported. + Buffer[4] = 0x00; + Buffer[5] = 0x00; //status 00 success. + Buffer[6] = 0x42; //Attribute data type 0x42 = character string. + Buffer[7] = sizeof(Dev) ; //Size of string to follow. + x = 0; + while( x < (sizeof(Dev))){ //Send sting byte by byte. + Buffer[(x+8)] = Dev[x]; + x++; + } + PBuild(PacketAddr,SEP,DEP,Pro,Clu, Buffer, (0x08 + Buffer[7])); //Send data to packet builder. + } +} +/******************************** Switch Cluster ************************************ +Process and respond to a Switch cluster command. +For more informaion see ZigBee Cluster library page 125. +*****************************************************************************************/ +void OnOff() +{ + cmdID = 0; //Set command ID to 0. + seqNum = 0; //Set seqence number to 0. + frmType = 0; //Set frame type to 0. + memset(Buffer, 0, sizeof(Buffer)); //Clear array + memset(atID, 0, sizeof(atID)); //Clear array + + frmType = pay[0]; //Get frame type from payload. + frmType = frmType & 0x03; //Bitwise & with 0x03 to make sure you are looking at the first 2 bits. + seqNum = pay[1]; //Get Seqence Number for payload. + cmdID = pay[2]; //Get command ID from payload. + atID[0] = pay[3]; //Get attribute ID MSB. + atID[1] = pay[4]; //Get attribute ID LSB. + + if ((frmType == 0x00) && (cmdID == 0x00) && (atID[1] == 0x00)){ //If Command to check status is sent. + Buffer[0] = 0x18; //Frame control direction is server to client. + Buffer[1] = seqNum; //Reply with seqence number from request. + Buffer[2] = 0x01; //Command indetifier = 1, Read attribute response. + Buffer[3] = 0x00; //Attribute Identfier (2 bytes) field being reported. + Buffer[4] = 0x00; + Buffer[5] = 0x00; //Status 00 = success. + Buffer[6] = 0x10; //Attribute data type 10 = boolean. + Buffer[7] = LED; //Read LED state. + PBuild(PacketAddr,SEP,DEP,Pro,Clu, Buffer, 0x08); //Send to packet builder. + } + + if ((frmType == 0x01) && (cmdID == 0x00) && (atID[1] == 0x00)){ //command to turn off LED. + LED = 0; //Turn LED off. + DefRes( 0x00, 0x76); //Create response. + } + + if ((frmType == 0x01) && (cmdID == 0x01) && (atID[1] == 0x00)){ //Command to turn on LED. + LED = 1; //Turn LED on. + DefRes(0x00, 0x76); //Create response. + } + if ((frmType == 0x01) && (cmdID == 0x02) && (atID[1] == 0x00)){ //Command to toggle LED. + LED = !LED; //Toggle LED + DefRes(0x00, 0x76); //Create response. + } +} +/********************************* Default Response ************************************* +Create a default response. + +*****************************************************************************************/ +void DefRes(char success, char endpoint) +{ + Buffer[0] = 0x18; //Frame control direction is server to client. + Buffer[1] = seqNum; //Reply with seqence number from request. + Buffer[2] = 0x0B; //Command identifier 0x08 = default response. + Buffer[3] = cmdID; //reply with the command ID sne to you. + Buffer[4] = success; //Send sucess 00 + PBuild(PacketAddr,endpoint,DEP,Pro,Clu, Buffer, 0x05); //Send to packet builder. +} \ No newline at end of file