datasheets.com EBN.com EDN.com EETimes.com Embedded.com PlanetAnalog.com TechOnline.com  
Events
UBM Tech
UBM Tech

Design Article

ZigBee applications - Part 6: Profiles

Drew Gislason

8/10/2010 3:28 AM EDT

Example: iPod Controller (cont.)

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



Please sign in to post comment

Navigate to related information

Datasheets.com Parts Search

185 million searchable parts
(please enter a part number or hit search to begin)