/************************************************************************************************** Filename: rangeext.c Revised: $Date: 2007-08-02 09:20:10 -0700 (Thu,02 Aug 2007) $ Revision: $Revision: 15001 $ Description: This module implements the Range Extender functionality and contains the init and event loop functions Copyright 2009 Texas Instruments Incorporated. All rights reserved. IMPORTANT: Your use of this Software is limited to those specific rights granted under the terms of a software license agreement between the user who downloaded the software, his/her employer (which must be your employer) and Texas Instruments Incorporated (the "License"). You may not use this Software unless you agree to abide by the terms of the License. The License limits your use, and you acknowledge, that the Software may not be modified, copied or distributed unless embedded on a Texas Instruments microcontroller or used solely and exclusively in conjunction with a Texas Instruments radio frequency transceiver, which is integrated into your product. Other than for the foregoing purpose, you may not use, reproduce, copy, prepare derivative works of, modify, distribute, perform, display or sell this Software and/or its documentation for any purpose. YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE PROVIDED “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. Should you have any questions regarding your right to use this Software, contact Texas Instruments Incorporated at www.TI.com. **************************************************************************************************/ /********************************************************************* This application is designed for the test purpose of the SE profile which exploits the following clusters for a Range Extender configuration: General Basic General Alarms General Time General Key Establishment Key control: SW1: Join Network SW2: Not Used SW3: Not Used SW4: Not Used *********************************************************************/ /********************************************************************* * INCLUDES */ #include "OSAL.h" #include "OSAL_Clock.h" #include "ZDApp.h" #include "AddrMgr.h" #include "se.h" #include "rangeext.h" #include "zcl_general.h" #include "zcl_key_establish.h" #include "onboard.h" /* HAL */ #include "hal_lcd.h" #include "hal_led.h" #include "hal_key.h" /********************************************************************* * MACROS */ // There is no attribute in the Mandatory Reportable Attribute list for now #define zcl_MandatoryReportableAttribute( a ) ( a == NULL ) /********************************************************************* * CONSTANTS */ /********************************************************************* * TYPEDEFS */ /********************************************************************* * GLOBAL VARIABLES */ /********************************************************************* * GLOBAL FUNCTIONS */ /********************************************************************* * LOCAL VARIABLES */ static uint8 rangeExtTaskID; // osal task id for range ext device static devStates_t rangeExtNwkState; // network state variable static uint8 rangeExtTransID; // transaction id static afAddrType_t ESPAddr; // ESP destination address static uint8 linkKeyStatus; // status variable from get link key function /********************************************************************* * LOCAL FUNCTIONS */ static void rangeext_HandleKeys( uint8 shift, uint8 keys ); #if defined ( ZCL_KEY_ESTABLISH ) static uint8 rangeext_KeyEstablish_ReturnLinkKey( uint16 shortAddr ); #endif // ZCL_KEY_ESTABLISH #if defined ( ZCL_ALARMS ) static void rangeext_ProcessAlarmCmd( uint8 srcEP, afAddrType_t *dstAddr, uint16 clusterID, zclFrameHdr_t *hdr, uint8 len, uint8 *data ); #endif // ZCL_ALARMS static void rangeext_ProcessIdentifyTimeChange( void ); /*************************************************************************/ /*** Application Callback Functions ***/ /*************************************************************************/ // Foundation Callback functions static uint8 rangeext_ValidateAttrDataCB( zclAttrRec_t *pAttr, zclWriteRec_t *pAttrInfo ); // General Cluster Callback functions static void rangeext_BasicResetCB( void ); static void rangeext_IdentifyCB( zclIdentify_t *pCmd ); static void rangeext_IdentifyQueryRspCB( zclIdentifyQueryRsp_t *pRsp ); static void rangeext_AlarmCB( zclAlarm_t *pAlarm ); /************************************************************************/ /*** Functions to process ZCL Foundation ***/ /*** incoming Command/Response messages ***/ /************************************************************************/ static void rangeext_ProcessZCLMsg( zclIncomingMsg_t *msg ); #if defined ( ZCL_READ ) static uint8 rangeext_ProcessInReadRspCmd( zclIncomingMsg_t *pInMsg ); #endif // ZCL_READ #if defined ( ZCL_WRITE ) static uint8 rangeext_ProcessInWriteRspCmd( zclIncomingMsg_t *pInMsg ); #endif // ZCL_WRITE static uint8 rangeext_ProcessInDefaultRspCmd( zclIncomingMsg_t *pInMsg ); #if defined ( ZCL_DISCOVER ) static uint8 rangeext_ProcessInDiscRspCmd( zclIncomingMsg_t *pInMsg ); #endif // ZCL_DISCOVER /********************************************************************* * ZCL General Clusters Callback table */ static zclGeneral_AppCallbacks_t rangeext_GenCmdCallbacks = { rangeext_BasicResetCB, // Basic Cluster Reset command rangeext_IdentifyCB, // Identify command rangeext_IdentifyQueryRspCB, // Identify Query Response command NULL, // On/Off cluster commands NULL, // Level Control Move to Level command NULL, // Level Control Move command NULL, // Level Control Step command NULL, // Level Control Stop command NULL, // Group Response commands NULL, // Scene Store Request command NULL, // Scene Recall Request command NULL, // Scene Response command rangeext_AlarmCB, // Alarm (Response) command NULL, // RSSI Location command NULL, // RSSI Location Response command }; /********************************************************************* * @fn rangeext_Init * * @brief Initialization function for the ZCL App Application. * * @param uint8 task_id - range extender task id * * @return none */ void rangeext_Init( uint8 task_id ) { rangeExtTaskID = task_id; // setup ESP destination address ESPAddr.addrMode = (afAddrMode_t)Addr16Bit; ESPAddr.endPoint = RANGEEXT_ENDPOINT; ESPAddr.addr.shortAddr = 0; // register SE endpoint zclSE_Init( &rangeExtSimpleDesc ); // Register the ZCL General Cluster Library callback functions zclGeneral_RegisterCmdCallbacks( RANGEEXT_ENDPOINT, &rangeext_GenCmdCallbacks ); // Register the application's attribute list zcl_registerAttrList( RANGEEXT_ENDPOINT, RANGEEXT_MAX_ATTRIBUTES, rangeExtAttrs ); // Register the application's cluster option list zcl_registerClusterOptionList( RANGEEXT_ENDPOINT, RANGEEXT_MAX_OPTIONS, rangeExtOptions ); // Register the application's attribute data validation callback function zcl_registerValidateAttrData( rangeext_ValidateAttrDataCB ); // Register the Application to receive the unprocessed Foundation command/response messages zcl_registerForMsg( rangeExtTaskID ); // Register for all key events - This app will handle all key events RegisterForKeys( rangeExtTaskID ); } /********************************************************************* * @fn rangeext_event_loop * * @brief Event Loop Processor for rangeext. * * @param uint8 task_id - the osal task id * @param uint16 events - the event bitmask * * @return none */ uint16 rangeext_event_loop( uint8 task_id, uint16 events ) { afIncomingMSGPacket_t *MSGpkt; if ( events & SYS_EVENT_MSG ) { while ( (MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( rangeExtTaskID )) ) { switch ( MSGpkt->hdr.event ) { case ZCL_INCOMING_MSG: // Incoming ZCL foundation command/response messages rangeext_ProcessZCLMsg( (zclIncomingMsg_t *)MSGpkt ); break; case KEY_CHANGE: rangeext_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys ); break; case ZDO_STATE_CHANGE: rangeExtNwkState = (devStates_t)(MSGpkt->hdr.status); if (ZG_SECURE_ENABLED) { if ( rangeExtNwkState == DEV_ROUTER ) { // check to see if link key had already been established linkKeyStatus = rangeext_KeyEstablish_ReturnLinkKey(ESPAddr.addr.shortAddr); if (linkKeyStatus != ZSuccess) { // send out key establishment request osal_set_event( rangeExtTaskID, RANGEEXT_KEY_ESTABLISHMENT_REQUEST_EVT); } } } break; default: break; } // Release the memory osal_msg_deallocate( (uint8 *)MSGpkt ); } // return unprocessed events return (events ^ SYS_EVENT_MSG); } // event to intiate key establishment request if ( events & RANGEEXT_KEY_ESTABLISHMENT_REQUEST_EVT ) { zclGeneral_KeyEstablish_InitiateKeyEstablishment(rangeExtTaskID, &ESPAddr, rangeExtTransID); return ( events ^ RANGEEXT_KEY_ESTABLISHMENT_REQUEST_EVT ); } // handle processing of identify timeout event triggered by an identify command if ( events & RANGEEXT_IDENTIFY_TIMEOUT_EVT ) { if ( rangeExtIdentifyTime > 0 ) { rangeExtIdentifyTime--; } rangeext_ProcessIdentifyTimeChange(); return ( events ^ RANGEEXT_IDENTIFY_TIMEOUT_EVT ); } // Discard unknown events return 0; } /********************************************************************* * @fn rangeext_ProcessIdentifyTimeChange * * @brief Called to blink led for specified IdentifyTime attribute value * * @param none * * @return none */ static void rangeext_ProcessIdentifyTimeChange( void ) { if ( rangeExtIdentifyTime > 0 ) { osal_start_timerEx( rangeExtTaskID, RANGEEXT_IDENTIFY_TIMEOUT_EVT, 1000 ); HalLedBlink ( HAL_LED_4, 0xFF, HAL_LED_DEFAULT_DUTY_CYCLE, HAL_LED_DEFAULT_FLASH_TIME ); } else { HalLedSet ( HAL_LED_4, HAL_LED_MODE_OFF ); osal_stop_timerEx( rangeExtTaskID, RANGEEXT_IDENTIFY_TIMEOUT_EVT ); } } #if defined ( ZCL_KEY_ESTABLISH ) /********************************************************************* * @fn rangeext_KeyEstablish_ReturnLinkKey * * @brief This function get the requested link key * * @param shortAddr - short address of the partner. * * @return none */ static uint8 rangeext_KeyEstablish_ReturnLinkKey( uint16 shortAddr ) { APSME_LinkKeyData_t* keyData; uint8 status = ZFailure; AddrMgrEntry_t entry; // Look up the long address of the device entry.user = ADDRMGR_USER_DEFAULT; entry.nwkAddr = shortAddr; if ( AddrMgrEntryLookupNwk( &entry ) ) { // check for APS link key data APSME_LinkKeyDataGet( entry.extAddr, &keyData ); if ( (keyData != NULL) && (keyData->key != NULL) ) { status = ZSuccess; } } else { // It's an unknown device status = ZInvalidParameter; } return status; } #endif // ZCL_KEY_ESTABLISH /********************************************************************* * @fn rangeext_HandleKeys * * @brief Handles all key events for this device. * * @param shift - true if in shift/alt. * @param keys - bit field for key events. Valid entries: * HAL_KEY_SW_4 * HAL_KEY_SW_3 * HAL_KEY_SW_2 * HAL_KEY_SW_1 * * @return none */ static void rangeext_HandleKeys( uint8 shift, uint8 keys ) { // Shift is used to make each button/switch dual purpose. if ( shift ) { if ( keys & HAL_KEY_SW_1 ) { } if ( keys & HAL_KEY_SW_2 ) { } if ( keys & HAL_KEY_SW_3 ) { } if ( keys & HAL_KEY_SW_4 ) { } } else { if ( keys & HAL_KEY_SW_1 ) { ZDOInitDevice(0); // join the network } if ( keys & HAL_KEY_SW_2 ) { } if ( keys & HAL_KEY_SW_3 ) { } if ( keys & HAL_KEY_SW_4 ) { } } } /********************************************************************* * @fn rangeext_ValidateAttrDataCB * * @brief Check to see if the supplied value for the attribute data * is within the specified range of the attribute. * * @param pAttr - pointer to attribute * @param pAttrInfo - pointer to attribute info * * @return TRUE if data valid. FALSE otherwise. */ static uint8 rangeext_ValidateAttrDataCB( zclAttrRec_t *pAttr, zclWriteRec_t *pAttrInfo ) { uint8 valid = TRUE; switch ( pAttrInfo->dataType ) { case ZCL_DATATYPE_BOOLEAN: if ( ( *(pAttrInfo->attrData) != 0 ) && ( *(pAttrInfo->attrData) != 1 ) ) valid = FALSE; break; default: break; } return ( valid ); } /********************************************************************* * @fn rangeext_BasicResetCB * * @brief Callback from the ZCL General Cluster Library to set all * the attributes of all the clusters to their factory defaults * * @param none * * @return none */ static void rangeext_BasicResetCB( void ) { // user should handle setting attributes to factory defaults here } /********************************************************************* * @fn rangeext_IdentifyCB * * @brief Callback from the ZCL General Cluster Library when * it received an Identity Command for this application. * * @param pCmd - pointer to structure for identify command * * @return none */ static void rangeext_IdentifyCB( zclIdentify_t *pCmd ) { rangeExtIdentifyTime = pCmd->identifyTime; rangeext_ProcessIdentifyTimeChange(); } /********************************************************************* * @fn rangeext_IdentifyQueryRspCB * * @brief Callback from the ZCL General Cluster Library when * it received an Identity Query Response Command for this application. * * @param pRsp - pointer to structure for identify query response * * @return none */ static void rangeext_IdentifyQueryRspCB( zclIdentifyQueryRsp_t *pRsp ) { // add user code here } /********************************************************************* * @fn rangeext_AlarmCB * * @brief Callback from the ZCL General Cluster Library when * it received an Alarm request or response command for * this application. * * @param pAlarm - pointer to structure for alarm command * * @return none */ static void rangeext_AlarmCB( zclAlarm_t *pAlarm ) { // add user code here } /****************************************************************************** * * Functions for processing ZCL Foundation incoming Command/Response messages * *****************************************************************************/ /********************************************************************* * @fn rangeext_ProcessZCLMsg * * @brief Process ZCL Foundation incoming message * * @param pInMsg - message to process * * @return none */ static void rangeext_ProcessZCLMsg( zclIncomingMsg_t *pInMsg ) { switch ( pInMsg->zclHdr.commandID ) { #if defined ( ZCL_READ ) case ZCL_CMD_READ_RSP: rangeext_ProcessInReadRspCmd( pInMsg ); break; #endif // ZCL_READ #if defined ( ZCL_WRITE ) case ZCL_CMD_WRITE_RSP: rangeext_ProcessInWriteRspCmd( pInMsg ); break; #endif // ZCL_WRITE case ZCL_CMD_DEFAULT_RSP: rangeext_ProcessInDefaultRspCmd( pInMsg ); break; #if defined ( ZCL_DISCOVER ) case ZCL_CMD_DISCOVER_RSP: rangeext_ProcessInDiscRspCmd( pInMsg ); break; #endif // ZCL_DISCOVER default: break; } if ( pInMsg->attrCmd != NULL ) { // free the parsed command osal_mem_free( pInMsg->attrCmd ); pInMsg->attrCmd = NULL; } } #if defined ( ZCL_READ ) /********************************************************************* * @fn rangeext_ProcessInReadRspCmd * * @brief Process the "Profile" Read Response Command * * @param pInMsg - incoming message to process * * @return none */ static uint8 rangeext_ProcessInReadRspCmd( zclIncomingMsg_t *pInMsg ) { zclReadRspCmd_t *readRspCmd; uint8 i; readRspCmd = (zclReadRspCmd_t *)pInMsg->attrCmd; for (i = 0; i < readRspCmd->numAttr; i++) { // Notify the originator of the results of the original read attributes // attempt and, for each successfull request, the value of the requested // attribute } return TRUE; } #endif // ZCL_READ #if defined ( ZCL_WRITE ) /********************************************************************* * @fn rangeext_ProcessInWriteRspCmd * * @brief Process the "Profile" Write Response Command * * @param pInMsg - incoming message to process * * @return none */ static uint8 rangeext_ProcessInWriteRspCmd( zclIncomingMsg_t *pInMsg ) { zclWriteRspCmd_t *writeRspCmd; uint8 i; writeRspCmd = (zclWriteRspCmd_t *)pInMsg->attrCmd; for (i = 0; i < writeRspCmd->numAttr; i++) { // Notify the device of the results of the its original write attributes // command. } return TRUE; } #endif // ZCL_WRITE /********************************************************************* * @fn rangeext_ProcessInDefaultRspCmd * * @brief Process the "Profile" Default Response Command * * @param pInMsg - incoming message to process * * @return none */ static uint8 rangeext_ProcessInDefaultRspCmd( zclIncomingMsg_t *pInMsg ) { // zclDefaultRspCmd_t *defaultRspCmd = (zclDefaultRspCmd_t *)pInMsg->attrCmd; // Device is notified of the Default Response command. return TRUE; } #if defined ( ZCL_DISCOVER ) /********************************************************************* * @fn rangeext_ProcessInDiscRspCmd * * @brief Process the "Profile" Discover Response Command * * @param pInMsg - incoming message to process * * @return none */ static uint8 rangeext_ProcessInDiscRspCmd( zclIncomingMsg_t *pInMsg ) { zclDiscoverRspCmd_t *discoverRspCmd; uint8 i; discoverRspCmd = (zclDiscoverRspCmd_t *)pInMsg->attrCmd; for ( i = 0; i < discoverRspCmd->numAttr; i++ ) { // Device is notified of the result of its attribute discovery command. } return TRUE; } #endif // ZCL_DISCOVER /**************************************************************************** ****************************************************************************/