Design Article
ZigBee applications - Part 6: Profiles
Drew Gislason
8/10/2010 3:28 AM EDT
When the command is sent over-the-air, it looks like the following. This decode depicts command 0x01 which instructs the iPod to skip forward one song:
Frame 18 (Length = 28 bytes)
IEEE 802.15.4
Frame Control: 0x8861
Sequence Number: 205
Destination PAN Identifier: 0x1aaa
Destination Address: 0x0000
Source Address: 0x796f
Frame Check Sequence: Correct
ZigBee NWK
Frame Control: 0x0048
Destination Address: 0x0000
Source Address: 0x796f
Radius = 10
Sequence Number = 219
ZigBee APS
Frame Control: 0x00
Destination Endpoint: 0x01
Cluster Identifier: (0x0001)
Profile Identifier: (0xc035)
Source Endpoint: 0x01
Counter: 0x4d
Unknown APS Data: 01
Note the profile ID in the ZigBee APS frame (0xc035). This is a private profile assigned to San Juan Software by the ZigBee Alliance. In this profile, cluster 0x0001 means the "iPod" cluster. This cluster is defined to contain a single command byte in the payload, called "APS Data." The commands mirror the features available to the iPod controller.
• Play/Pause (cmd 0x00)
• Skip Forward (cmd 0x01)
• Skip Backward (cmd 0x02)
• Volume Up (cmd 0x03)
• Volume Down (cmd 0x04)
The data indication on the iPod Controller simply takes this command byte in and passes it along to the function SendiPodRemoteCommand(), which sends a corresponding command string over the serial port at 19,200 baud. The serial port is connected to the iPod via the 2-wire interface:
void BeeAppDataIndication(void)
{
apsdeToAfMessage_t *pMsg;
zbApsdeDataIndication_t *pIndication;
while(MSG_Pending(&gAppDataIndicationQueue))
{
/* Get a message from a queue */
pMsg = MSG_DeQueue(&gAppDataIndicationQueue);
pIndication = & (pMsg- > msgData.dataIndication);
/* is the cluster for the application */
if(pIndication- > aClusterId == appDataCluster)
SendiPodRemoteCommand(pIndication- > pAsdu[0]);
/* Free memory allocated by data indication */
MSG_Free(pMsg);
}
}
void SendiPodRemoteCommand(iPodRemoteCommand_t cmd)
{
uint8_t *pCmdPtr;
switch(cmd) {
case gPlayPause_c:
pCmdPtr = PlayPause;
break;
case gSkipForward_c:
pCmdPtr = SkipForward;
break;
case gSkipReverse_c:
pCmdPtr = SkipReverse;
break;
case gVolumeDown_c:
pCmdPtr = VolumeDown;
break;
case gVolumeUp_c:
pCmdPtr = VolumeUp;
break;
default:
pCmdPtr = ButtonRelease;
break;
}
/* send command-all commands are the same size */
(void)UartX_Transmit(pCmdPtr, sizeof(PlayPause), NULL);
while (!UartX_TxCompleteFlag);
/* delay 100 microseconds before sending button release */
DELAY_100US();
/* Button release must always be sent after a command */
UartX_Transmit(ButtonRelease, sizeof(ButtonRelease), NULL);
while (!UartX_TxCompleteFlag);
}
On the sending end, the application simply creates a data request with the command-byte associated with the particular button:
void BeeAppHandleKeys(key_event_t keyEvent)
{
switch(keyEvent) {
/* play/pause */
case gKBD_EventSW1_c:
SendiPodRemoteCommandOTA(gPlayPause_c);
break;
/* skip one song forward */
case gKBD_EventSW2_c:
SendiPodRemoteCommandOTA(gSkipForward_c);
break;
/* skip one song reverse */
case gKBD_EventLongSW2_c:
SendiPodRemoteCommandOTA(gSkipReverse_c);
break;
/* volume down */
case gKBD_EventSW3_c:
SendiPodRemoteCommandOTA(gVolumeDown_c);
break;
/* volume up */
case gKBD_EventSW4_c:
SendiPodRemoteCommandOTA(gVolumeUp_c);
break;
}
}
void SendiPodRemoteCommandOTA(iPodRemoteCommand_t cmd)
{
afAddrInfo_t addrInfo;
uint8_t TransmitBuffer[1];
/* copy iPod command to TransmitBuffer */
TransmitBuffer[0] = cmd;
/* set up address information */
addrInfo.dstAddrMode = gZbAddrMode16Bit_c;
Set2Bytes(addrInfo.dstAddr.aNwkAddr, 0x0000);
addrInfo.dstEndPoint = appEndPoint;
addrInfo.srcEndPoint = appEndPoint;
Copy2Bytes(addrInfo.aClusterId, appDataCluster);
addrInfo.txOptions = gApsTxOptionNone_c;
addrInfo.radiusCounter = afDefaultRadius_c;
/* send the data request */
(void)AF_DataRequest( & addrInfo, sizeof(TransmitBuffer), TransmitBuffer, NULL);
}
Notice the data request is sent to node 0x0000. In a private profile the main application could be on node 0x0000, the ZigBee Coordinator, such as a gateway to the PC, or in this case, the iPod controller, making node discovery unnecessary.
The application uses appEndPoint for both the source and destination endpoints. Using a fixed endpoint makes private profiles a little easier, as no endpoint discovery is required. The cluster in this example is appDataCluster, the first cluster in the output cluster list.
|
Manufacturer Specific Profile IDs are obtained from the ZigBee Alliance.
MSPs can use fixed endpoints and cluster IDs to make service discovery unnecessary. |
Next: Device IDs


Tim.Gillman
8/30/2010 1:39 AM EDT
To find out more about ZigBee and Wireless Sensor Networking, go to Drew's website: www.sanjuansw.com
Sign in to Reply