smart-green-house/project_ZigBee/Components/stack/zcl/zcl_general.c

3398 lines
100 KiB
C
Raw Normal View History

2023-10-28 18:00:47 +08:00
/**************************************************************************************************
Filename: zcl_general.c
Revised: $Date: 2011-12-14 16:30:16 -0800 (Wed, 14 Dec 2011) $
Revision: $Revision: 28678 $
Description: Zigbee Cluster Library - General. This application receives all
ZCL messages and initially parses them before passing to application.
Copyright 2006-2011 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 <EFBFBD>AS IS<EFBFBD> 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.
**************************************************************************************************/
/*********************************************************************
* INCLUDES
*/
#include "ZComDef.h"
#include "OSAL.h"
#include "OSAL_Nv.h"
#include "zcl.h"
#include "zcl_general.h"
#include "ZDApp.h"
#if defined ( INTER_PAN )
#include "stub_aps.h"
#endif
/*********************************************************************
* MACROS
*/
#define locationTypeAbsolute( a ) ( (a) & LOCATION_TYPE_ABSOLUTE )
#define locationType2D( a ) ( (a) & LOCATION_TYPE_2_D )
#define locationTypeCoordinateSystem( a ) ( (a) & LOCATION_TYPE_COORDINATE_SYSTEM )
#ifdef ZCL_SCENES
#define zclGeneral_ScenesRemaingCapacity() ( ZCL_GEN_MAX_SCENES - zclGeneral_CountAllScenes() )
#endif // ZCL_SCENES
/*********************************************************************
* CONSTANTS
*/
/*********************************************************************
* TYPEDEFS
*/
typedef struct zclGenCBRec
{
struct zclGenCBRec *next;
uint8 endpoint; // Used to link it into the endpoint descriptor
zclGeneral_AppCallbacks_t *CBs; // Pointer to Callback function
} zclGenCBRec_t;
typedef struct zclGenSceneItem
{
struct zclGenSceneItem *next;
uint8 endpoint; // Used to link it into the endpoint descriptor
zclGeneral_Scene_t scene; // Scene info
} zclGenSceneItem_t;
typedef struct zclGenAlarmItem
{
struct zclGenAlarmItem *next;
uint8 endpoint; // Used to link it into the endpoint descriptor
zclGeneral_Alarm_t alarm; // Alarm info
} zclGenAlarmItem_t;
// Scene NV types
typedef struct
{
uint16 numRecs;
} nvGenScenesHdr_t;
typedef struct zclGenSceneNVItem
{
uint8 endpoint;
zclGeneral_Scene_t scene;
} zclGenSceneNVItem_t;
/*********************************************************************
* GLOBAL VARIABLES
*/
/*********************************************************************
* GLOBAL FUNCTIONS
*/
/*********************************************************************
* LOCAL VARIABLES
*/
static zclGenCBRec_t *zclGenCBs = (zclGenCBRec_t *)NULL;
static uint8 zclGenPluginRegisted = FALSE;
#ifdef ZCL_SCENES
static zclGenSceneItem_t *zclGenSceneTable = (zclGenSceneItem_t *)NULL;
#endif // ZCL_SCENES
#ifdef ZCL_ALARMS
static zclGenAlarmItem_t *zclGenAlarmTable = (zclGenAlarmItem_t *)NULL;
#endif // ZCL_ALARMS
/*********************************************************************
* LOCAL FUNCTIONS
*/
static ZStatus_t zclGeneral_HdlIncoming( zclIncoming_t *pInMsg );
static ZStatus_t zclGeneral_HdlInSpecificCommands( zclIncoming_t *pInMsg );
static zclGeneral_AppCallbacks_t *zclGeneral_FindCallbacks( uint8 endpoint );
// Device Configuration and Installation clusters
#ifdef ZCL_BASIC
static ZStatus_t zclGeneral_ProcessInBasic( zclIncoming_t *pInMsg, zclGeneral_AppCallbacks_t *pCBs );
#endif // ZCL_BASIC
#ifdef ZCL_IDENTIFY
static ZStatus_t zclGeneral_ProcessInIdentity( zclIncoming_t *pInMsg, zclGeneral_AppCallbacks_t *pCBs );
#endif // ZCL_IDENTIFY
// Groups and Scenes clusters
#ifdef ZCL_GROUPS
static ZStatus_t zclGeneral_ProcessInGroupsServer( zclIncoming_t *pInMsg );
static ZStatus_t zclGeneral_ProcessInGroupsClient( zclIncoming_t *pInMsg, zclGeneral_AppCallbacks_t *pCBs );
static ZStatus_t zclGeneral_AddGroup( uint8 endPoint, aps_Group_t *group, uint8 *pData );
#endif // ZCL_GROUPS
#ifdef ZCL_SCENES
static ZStatus_t zclGeneral_ProcessInScenesServer( zclIncoming_t *pInMsg, zclGeneral_AppCallbacks_t *pCBs );
static ZStatus_t zclGeneral_ProcessInScenesClient( zclIncoming_t *pInMsg, zclGeneral_AppCallbacks_t *pCBs );
#endif // ZCL_SCENES
// On/Off and Level Control Configuration clusters
#ifdef ZCL_ON_OFF
static ZStatus_t zclGeneral_ProcessInOnOff( zclIncoming_t *pInMsg, zclGeneral_AppCallbacks_t *pCBs );
#endif // ZCL_ONOFF
#ifdef ZCL_LEVEL_CTRL
static ZStatus_t zclGeneral_ProcessInLevelControl( zclIncoming_t *pInMsg, zclGeneral_AppCallbacks_t *pCBs );
#endif // ZCL_LEVEL_CTRL
// Alarms cluster
#ifdef ZCL_ALARMS
static ZStatus_t zclGeneral_ProcessInAlarmsServer( zclIncoming_t *pInMsg, zclGeneral_AppCallbacks_t *pCBs );
static ZStatus_t zclGeneral_ProcessInAlarmsClient( zclIncoming_t *pInMsg, zclGeneral_AppCallbacks_t *pCBs );
#endif // ZCL_ALARMS
// Location cluster
#ifdef ZCL_LOCATION
static ZStatus_t zclGeneral_ProcessInLocationServer( zclIncoming_t *pInMsg, zclGeneral_AppCallbacks_t *pCBs );
static ZStatus_t zclGeneral_ProcessInLocationClient( zclIncoming_t *pInMsg, zclGeneral_AppCallbacks_t *pCBs );
#endif // ZCL_LOCATION
#ifdef ZCL_SCENES
static uint8 zclGeneral_ScenesInitNV( void );
static void zclGeneral_ScenesSetDefaultNV( void );
static void zclGeneral_ScenesWriteNV( void );
static uint16 zclGeneral_ScenesRestoreFromNV( void );
#endif // ZCL_SCENES
/*********************************************************************
* @fn zclGeneral_RegisterCmdCallbacks
*
* @brief Register an applications command callbacks
*
* @param endpoint - application's endpoint
* @param callbacks - pointer to the callback record.
*
* @return ZMemError if not able to allocate
*/
ZStatus_t zclGeneral_RegisterCmdCallbacks( uint8 endpoint, zclGeneral_AppCallbacks_t *callbacks )
{
zclGenCBRec_t *pNewItem;
zclGenCBRec_t *pLoop;
// Register as a ZCL Plugin
if ( zclGenPluginRegisted == FALSE )
{
zcl_registerPlugin( ZCL_CLUSTER_ID_GEN_BASIC,
ZCL_CLUSTER_ID_GEN_MULTISTATE_VALUE_BASIC,
zclGeneral_HdlIncoming );
#ifdef ZCL_SCENES
// Initialize NV items
zclGeneral_ScenesInitNV();
// Restore the Scene table
zclGeneral_ScenesRestoreFromNV();
#endif // ZCL_SCENES
zclGenPluginRegisted = TRUE;
}
// Fill in the new profile list
pNewItem = osal_mem_alloc( sizeof( zclGenCBRec_t ) );
if ( pNewItem == NULL )
return (ZMemError);
pNewItem->next = (zclGenCBRec_t *)NULL;
pNewItem->endpoint = endpoint;
pNewItem->CBs = callbacks;
// Find spot in list
if ( zclGenCBs == NULL )
{
zclGenCBs = pNewItem;
}
else
{
// Look for end of list
pLoop = zclGenCBs;
while ( pLoop->next != NULL )
pLoop = pLoop->next;
// Put new item at end of list
pLoop->next = pNewItem;
}
return ( ZSuccess );
}
#ifdef ZCL_IDENTIFY
/*********************************************************************
* @fn zclGeneral_SendIdentify
*
* @brief Call to send out an Identify Command
*
* @param srcEP - Sending application's endpoint
* @param dstAddr - where you want the message to go
* @param identifyTime - how long the device will continue to identify itself (in seconds)
* @param seqNum - identification number for the transaction
*
* @return ZStatus_t
*/
ZStatus_t zclGeneral_SendIdentify( uint8 srcEP, afAddrType_t *dstAddr,
uint16 identifyTime, uint8 disableDefaultRsp, uint8 seqNum )
{
uint8 buf[2];
buf[0] = LO_UINT16( identifyTime );
buf[1] = HI_UINT16( identifyTime );
return zcl_SendCommand( srcEP, dstAddr, ZCL_CLUSTER_ID_GEN_IDENTIFY,
COMMAND_IDENTIFY, TRUE, ZCL_FRAME_CLIENT_SERVER_DIR,
disableDefaultRsp, 0, seqNum, 2, buf );
}
/*********************************************************************
* @fn zclGeneral_SendIdentifyQueryResponse
*
* @brief Call to send out an Identify Query Response Command
*
* @param srcEP - Sending application's endpoint
* @param dstAddr - where you want the message to go
* @param timeout - how long the device will continue to identify itself (in seconds)
* @param seqNum - identification number for the transaction
*
* @return ZStatus_t
*/
ZStatus_t zclGeneral_SendIdentifyQueryResponse( uint8 srcEP, afAddrType_t *dstAddr,
uint16 timeout, uint8 disableDefaultRsp, uint8 seqNum )
{
uint8 buf[2];
buf[0] = LO_UINT16( timeout );
buf[1] = HI_UINT16( timeout );
return zcl_SendCommand( srcEP, dstAddr, ZCL_CLUSTER_ID_GEN_IDENTIFY,
COMMAND_IDENTIFY_QUERY_RSP, TRUE,
ZCL_FRAME_SERVER_CLIENT_DIR, disableDefaultRsp, 0, seqNum, 2, buf );
}
#endif // ZCL_IDENTIFY
#ifdef ZCL_GROUPS
/*********************************************************************
* @fn zclGeneral_SendGroupRequest
*
* @brief Send a Group Request to a device. You can also use the
* appropriate macro.
*
* @param srcEP - Sending Apps endpoint
* @param dstAddr - where to send the request
* @param cmd - one of the following:
* COMMAND_GROUP_VIEW
* COMMAND_GROUP_REMOVE
* @param groupID -
*
* @return ZStatus_t
*/
ZStatus_t zclGeneral_SendGroupRequest( uint8 srcEP, afAddrType_t *dstAddr,
uint8 cmd, uint16 groupID, uint8 disableDefaultRsp, uint8 seqNum )
{
uint8 buf[2];
buf[0] = LO_UINT16( groupID );
buf[1] = HI_UINT16( groupID );
return ( zcl_SendCommand( srcEP, dstAddr, ZCL_CLUSTER_ID_GEN_GROUPS,
cmd, TRUE, ZCL_FRAME_CLIENT_SERVER_DIR,
disableDefaultRsp, 0, seqNum, 2, buf ) );
}
/*********************************************************************
* @fn zclGeneral_SendAddGroupRequest
*
* @brief Send the Add Group Request to a device
*
* @param srcEP - Sending Apps endpoint
* @param dstAddr - where to send the request
* @param cmd - one of the following:
* COMMAND_GROUP_ADD
* COMMAND_GROUP_ADD_IF_IDENTIFYING
* @param groupID - pointer to the group structure
* @param groupName - pointer to Group Name. This is a Zigbee
* string data type, so the first byte is the length of the
* name (in bytes), then the name.
*
* @return ZStatus_t
*/
ZStatus_t zclGeneral_SendAddGroupRequest( uint8 srcEP, afAddrType_t *dstAddr,
uint8 cmd, uint16 groupID, uint8 *groupName,
uint8 disableDefaultRsp, uint8 seqNum )
{
uint8 *buf;
uint8 *pBuf;
uint8 len;
ZStatus_t status;
len = 2; // Group ID
len += groupName[0] + 1; // String + 1 for length
buf = osal_mem_alloc( len );
if ( buf )
{
pBuf = buf;
*pBuf++ = LO_UINT16( groupID );
*pBuf++ = HI_UINT16( groupID );
*pBuf++ = groupName[0]; // string length
osal_memcpy( pBuf, &(groupName[1]), groupName[0] );
status = zcl_SendCommand( srcEP, dstAddr, ZCL_CLUSTER_ID_GEN_GROUPS,
cmd, TRUE, ZCL_FRAME_CLIENT_SERVER_DIR,
disableDefaultRsp, 0, seqNum, len, buf );
osal_mem_free( buf );
}
else
status = ZMemError;
return ( status );
}
/*********************************************************************
* @fn zclGeneral_SendGroupGetMembershipRequest
*
* @brief Send a Get Group Membership (Resposne) Command to a device
*
* @param srcEP - Sending Apps endpoint
* @param dstAddr - where to send the request
* @param cmd - one of the following:
* COMMAND_GROUP_GET_MEMBERSHIP
* COMMAND_GROUP_GET_MEMBERSHIP_RSP
* @param groupID - pointer to the group structure
* @param groupName - pointer to Group Name. This is a Zigbee
* string data type, so the first byte is the length of the
* name (in bytes), then the name.
*
* @return ZStatus_t
*/
ZStatus_t zclGeneral_SendGroupGetMembershipRequest( uint8 srcEP, afAddrType_t *dstAddr,
uint8 cmd, uint8 rspCmd, uint8 direction, uint8 capacity,
uint8 grpCnt, uint16 *grpList, uint8 disableDefaultRsp, uint8 seqNum )
{
uint8 *buf;
uint8 *pBuf;
uint8 len = 0;
uint8 i;
ZStatus_t status;
if ( rspCmd )
len++; // Capacity
len++; // Group Count
len += sizeof ( uint16 ) * grpCnt; // Group List
buf = osal_mem_alloc( len );
if ( buf )
{
pBuf = buf;
if ( rspCmd )
*pBuf++ = capacity;
*pBuf++ = grpCnt;
for ( i = 0; i < grpCnt; i++ )
{
*pBuf++ = LO_UINT16( grpList[i] );
*pBuf++ = HI_UINT16( grpList[i] );
}
status = zcl_SendCommand( srcEP, dstAddr, ZCL_CLUSTER_ID_GEN_GROUPS,
cmd, TRUE, direction,
disableDefaultRsp, 0, seqNum, len, buf );
osal_mem_free( buf );
}
else
status = ZMemError;
return ( status );
}
/*********************************************************************
* @fn zclGeneral_SendGroupResponse
*
* @brief Send Group Response (not Group View Response)
*
* @param srcEP - Sending application's endpoint
* @param dstAddr - where you want the message to go
* @param cmd - either COMMAND_GROUP_ADD_RSP or COMMAND_GROUP_REMOVE_RSP
* @param status - group command status
* @param groupID - what group
*
* @return ZStatus_t
*/
ZStatus_t zclGeneral_SendGroupResponse( uint8 srcEP, afAddrType_t *dstAddr,
uint8 cmd, uint8 status, uint16 groupID,
uint8 disableDefaultRsp, uint8 seqNum )
{
uint8 buf[3];
buf[0] = status;
buf[1] = LO_UINT16( groupID );
buf[2] = HI_UINT16( groupID );
return zcl_SendCommand( srcEP, dstAddr, ZCL_CLUSTER_ID_GEN_GROUPS,
cmd, TRUE, ZCL_FRAME_SERVER_CLIENT_DIR,
disableDefaultRsp, 0, seqNum, 3, buf );
}
/*********************************************************************
* @fn zclGeneral_SendGroupViewResponse
*
* @brief Call to send Group Response Command
*
* @param srcEP - Sending application's endpoint
* @param dstAddr - where you want the message to go
* @param cmd - either COMMAND_GROUP_ADD_RSP or COMMAND_GROUP_REMOVE_RSP
* @param status - group command status
* @param grp - group info
*
* @return ZStatus_t
*/
ZStatus_t zclGeneral_SendGroupViewResponse( uint8 srcEP, afAddrType_t *dstAddr,
uint8 status, aps_Group_t *grp, uint8 disableDefaultRsp, uint8 seqNum )
{
uint8 *buf;
uint8 len;
ZStatus_t stat;
len = 1 + 2; // Status + Group ID
if ( status == ZCL_STATUS_SUCCESS )
len += grp->name[0] + 1; // String + 1 for length
buf = osal_mem_alloc( len );
if ( buf )
{
buf[0] = status;
buf[1] = LO_UINT16( grp->ID );
buf[2] = HI_UINT16( grp->ID );
if ( status == ZCL_STATUS_SUCCESS )
{
buf[3] = grp->name[0]; // string length
osal_memcpy( &buf[4], (&grp->name[1]), grp->name[0] );
}
stat = zcl_SendCommand( srcEP, dstAddr, ZCL_CLUSTER_ID_GEN_GROUPS,
COMMAND_GROUP_VIEW_RSP, TRUE, ZCL_FRAME_SERVER_CLIENT_DIR,
disableDefaultRsp, 0, seqNum, len, buf );
osal_mem_free( buf );
}
else
stat = ZMemError;
return ( stat );
}
#endif // ZCL_GROUPS
#ifdef ZCL_SCENES
/*********************************************************************
* @fn zclGeneral_SendAddScene
*
* @brief Send the Add Scene Request to a device
*
* @param srcEP - Sending Apps endpoint
* @param dstAddr - where to send the request
* @param scene - pointer to the scene structure
*
* @return ZStatus_t
*/
ZStatus_t zclGeneral_SendAddScene( uint8 srcEP, afAddrType_t *dstAddr,
zclGeneral_Scene_t *scene, uint8 disableDefaultRsp, uint8 seqNum )
{
uint8 *buf;
uint8 *pBuf;
uint8 len;
ZStatus_t status;
len = 2 + 1 + 2; // Group ID + Scene ID + transition time
len += scene->name[0] + 1; // String + 1 for length
// Add something for the extension field length
len += scene->extLen;
buf = osal_mem_alloc( len );
if ( buf )
{
pBuf = buf;
*pBuf++ = LO_UINT16( scene->groupID );
*pBuf++ = HI_UINT16( scene->groupID );
*pBuf++ = scene->ID;
*pBuf++ = LO_UINT16( scene->transTime );
*pBuf++ = HI_UINT16( scene->transTime );
*pBuf++ = scene->name[0]; // string length
osal_memcpy( pBuf, &(scene->name[1]), scene->name[0] );
pBuf += scene->name[0]; // move pass name
// Add the extension fields
if ( scene->extLen > 0 )
osal_memcpy( pBuf, scene->extField, scene->extLen );
status = zcl_SendCommand( srcEP, dstAddr, ZCL_CLUSTER_ID_GEN_SCENES,
COMMAND_SCENE_ADD, TRUE, ZCL_FRAME_CLIENT_SERVER_DIR,
disableDefaultRsp, 0, seqNum, len, buf );
osal_mem_free( buf );
}
else
status = ZMemError;
return ( status );
}
/*********************************************************************
* @fn zclGeneral_SendSceneRequest
*
* @brief Send a Scene Request to a device. You can also use the
* appropriate macro.
*
* @param srcEP - Sending Apps endpoint
* @param dstAddr - where to send the request
* @param cmd - one of the following:
* COMMAND_SCENE_VIEW
* COMMAND_SCENE_REMOVE
* COMMAND_SCENE_REMOVE_ALL
* COMMAND_SCENE_STORE
* COMMAND_SCENE_RECALL
* COMMAND_SCENE_GET_MEMBERSHIP
* @param groupID - group ID
* @param sceneID - scene ID (not applicable to COMMAND_SCENE_REMOVE_ALL and
* COMMAND_SCENE_GET_MEMBERSHIP)
* @return ZStatus_t
*/
ZStatus_t zclGeneral_SendSceneRequest( uint8 srcEP, afAddrType_t *dstAddr,
uint8 cmd, uint16 groupID, uint8 sceneID,
uint8 disableDefaultRsp, uint8 seqNum )
{
uint8 buf[3];
uint8 len = 2;
buf[0] = LO_UINT16( groupID );
buf[1] = HI_UINT16( groupID );
if ( cmd != COMMAND_SCENE_REMOVE_ALL && cmd != COMMAND_SCENE_GET_MEMBERSHIP )
{
buf[2] = sceneID;
len++;
}
return ( zcl_SendCommand( srcEP, dstAddr, ZCL_CLUSTER_ID_GEN_SCENES,
cmd, TRUE, ZCL_FRAME_CLIENT_SERVER_DIR,
disableDefaultRsp, 0, seqNum, len, buf ) );
}
/*********************************************************************
* @fn zclGeneral_SendSceneResponse
*
* @brief Send Group Response (not Group View Response)
*
* @param srcEP - Sending application's endpoint
* @param dstAddr - where you want the message to go
* @param cmd - either COMMAND_SCENE_ADD_RSP, COMMAND_SCENE_REMOVE_RSP
* COMMAND_SCENE_STORE_RSP, or COMMAND_SCENE_REMOVE_ALL_RSP
* @param status - scene command status
* @param groupID - what group
* @param sceneID - what scene (not applicable to COMMAND_SCENE_REMOVE_ALL_RSP)
*
* @return ZStatus_t
*/
ZStatus_t zclGeneral_SendSceneResponse( uint8 srcEP, afAddrType_t *dstAddr,
uint8 cmd, uint8 status, uint16 groupID,
uint8 sceneID, uint8 disableDefaultRsp, uint8 seqNum )
{
uint8 buf[4];
uint8 len = 1 + 2; // Status + Group ID
buf[0] = status;
buf[1] = LO_UINT16( groupID );
buf[2] = HI_UINT16( groupID );
if ( cmd != COMMAND_SCENE_REMOVE_ALL_RSP )
{
buf[3] = sceneID;
len++;
}
return zcl_SendCommand( srcEP, dstAddr, ZCL_CLUSTER_ID_GEN_SCENES,
cmd, TRUE, ZCL_FRAME_SERVER_CLIENT_DIR,
disableDefaultRsp, 0, seqNum, len, buf );
}
/*********************************************************************
* @fn zclGeneral_SendSceneViewResponse
*
* @brief Call to send Scene Response Command
*
* @param srcEP - Sending application's endpoint
* @param dstAddr - where you want the message to go
* @param status - scene command status
* @param scene - scene info
*
* @return ZStatus_t
*/
ZStatus_t zclGeneral_SendSceneViewResponse( uint8 srcEP, afAddrType_t *dstAddr,
uint8 status, zclGeneral_Scene_t *scene,
uint8 disableDefaultRsp, uint8 seqNum )
{
uint8 *buf;
uint8 *pBuf;
uint8 len = 1 + 2 + 1; // Status + Group ID + Scene ID
ZStatus_t stat;
if ( status == ZCL_STATUS_SUCCESS )
{
len += 2; // Transition Time
len += scene->name[0] + 1; // string + 1 for length
// Add something for the extension field length
len += scene->extLen;
}
buf = osal_mem_alloc( len );
if ( buf )
{
pBuf = buf;
*pBuf++ = status;
*pBuf++ = LO_UINT16( scene->groupID );
*pBuf++ = HI_UINT16( scene->groupID );
*pBuf++ = scene->ID;
if ( status == ZCL_STATUS_SUCCESS )
{
*pBuf++ = LO_UINT16( scene->transTime );
*pBuf++ = HI_UINT16( scene->transTime );
*pBuf++ = scene->name[0]; // string length
if ( scene->name[0] != 0 )
{
osal_memcpy( pBuf, &(scene->name[1]), scene->name[0] );
pBuf += scene->name[0]; // move pass name
}
// Add the extension fields
if ( scene->extLen > 0 )
osal_memcpy( pBuf, scene->extField, scene->extLen );
}
stat = zcl_SendCommand( srcEP, dstAddr, ZCL_CLUSTER_ID_GEN_SCENES,
COMMAND_SCENE_VIEW_RSP, TRUE, ZCL_FRAME_SERVER_CLIENT_DIR,
disableDefaultRsp, 0, seqNum, len, buf );
osal_mem_free( buf );
}
else
stat = ZMemError;
return ( stat );
}
/*********************************************************************
* @fn zclGeneral_SendSceneGetMembershipResponse
*
* @brief Call to send Scene Get Membership Response Command
*
* @param srcEP - Sending application's endpoint
* @param dstAddr - where you want the message to go
* @param status - scene command status
* @param capacity - remaining capacity of the scene table
* @param sceneCnt - number of scenes in the scene list
* @param sceneList - list of scene IDs
* @param groupID - group ID that scene belongs to
* @param seqNum - sequence number
*
* @return ZStatus_t
*/
ZStatus_t zclGeneral_SendSceneGetMembershipResponse( uint8 srcEP, afAddrType_t *dstAddr,
uint8 status, uint8 capacity, uint8 sceneCnt, uint8 *sceneList,
uint16 groupID, uint8 disableDefaultRsp, uint8 seqNum )
{
uint8 *buf;
uint8 *pBuf;
uint8 len = 1 + 1 + 2; // Status + Capacity + Group ID;
uint8 i;
ZStatus_t stat;
if ( status == ZCL_STATUS_SUCCESS )
{
len++; // Scene Count
len += sceneCnt; // Scene List (Scene ID is a single octet)
}
buf = osal_mem_alloc( len );
if ( buf )
{
pBuf = buf;
*pBuf++ = status;
*pBuf++ = capacity;
*pBuf++ = LO_UINT16( groupID );
*pBuf++ = HI_UINT16( groupID );
if ( status == ZCL_STATUS_SUCCESS )
{
*pBuf++ = sceneCnt;
for ( i = 0; i < sceneCnt; i++ )
*pBuf++ = sceneList[i];
}
stat = zcl_SendCommand( srcEP, dstAddr, ZCL_CLUSTER_ID_GEN_SCENES,
COMMAND_SCENE_GET_MEMBERSHIP_RSP, TRUE,
ZCL_FRAME_SERVER_CLIENT_DIR, disableDefaultRsp, 0, seqNum, len, buf );
osal_mem_free( buf );
}
else
stat = ZMemError;
return ( stat );
}
#endif // ZCL_SCENES
#ifdef ZCL_LEVEL_CTRL
/*********************************************************************
* @fn zclGeneral_SendLevelControlMoveToLevelRequest
*
* @brief Call to send out a Level Control Request. You can also use
* the appropriate macro.
*
* @param srcEP - Sending application's endpoint
* @param dstAddr - where you want the message to go
* @param cmd - one of the following:
* COMMAND_LEVEL_MOVE_TO_LEVEL or
* COMMAND_LEVEL_MOVE_TO_LEVEL_WITH_ON_OFF
* @param level - what level to move to
* @param transitionTime - how long to take to get to the level (in seconds)
*
* @return ZStatus_t
*/
ZStatus_t zclGeneral_SendLevelControlMoveToLevelRequest( uint8 srcEP, afAddrType_t *dstAddr,
uint8 cmd, uint8 level, uint16 transTime,
uint8 disableDefaultRsp, uint8 seqNum )
{
uint8 buf[3];
buf[0] = level;
buf[1] = LO_UINT16( transTime );
buf[2] = HI_UINT16( transTime );
return zcl_SendCommand( srcEP, dstAddr, ZCL_CLUSTER_ID_GEN_LEVEL_CONTROL,
cmd, TRUE, ZCL_FRAME_CLIENT_SERVER_DIR,
disableDefaultRsp, 0, seqNum, 3, buf );
}
/*********************************************************************
* @fn zclGeneral_SendLevelControlMoveRequest
*
* @brief Call to send out a Level Control Request. You can also use
* the appropriate macro.
*
* @param srcEP - Sending application's endpoint
* @param dstAddr - where you want the message to go
* @param cmd - one of the following:
* COMMAND_LEVEL_MOVE or
* COMMAND_LEVEL_MOVE_WITH_ON_OFF
* @param moveMode - LEVEL_MOVE_UP or
* LEVEL_MOVE_DOWN
* @param rate - number of steps to take per second
*
* @return ZStatus_t
*/
ZStatus_t zclGeneral_SendLevelControlMoveRequest( uint8 srcEP, afAddrType_t *dstAddr,
uint8 cmd, uint8 moveMode, uint8 rate,
uint8 disableDefaultRsp, uint8 seqNum )
{
uint8 buf[2];
buf[0] = moveMode;
buf[1] = rate;
return zcl_SendCommand( srcEP, dstAddr, ZCL_CLUSTER_ID_GEN_LEVEL_CONTROL,
cmd, TRUE, ZCL_FRAME_CLIENT_SERVER_DIR,
disableDefaultRsp, 0, seqNum, 2, buf );
}
/*********************************************************************
* @fn zclGeneral_SendLevelControlStepRequest
*
* @brief Call to send out a Level Control Request. You can also use
* the appropriate macro.
*
* @param srcEP - Sending application's endpoint
* @param dstAddr - where you want the message to go
* @param cmd - one of the following:
* COMMAND_LEVEL_STEP
* COMMAND_LEVEL_STEP_WITH_ON_OFF
* @param stepMode - LEVEL_STEP_UP or
* LEVEL_STEP_DOWN
* @param amount - number of levels to step
* @param transitionTime - time, in 1/10ths of a second, to take to perform the step
*
* @return ZStatus_t
*/
ZStatus_t zclGeneral_SendLevelControlStepRequest( uint8 srcEP, afAddrType_t *dstAddr,
uint8 cmd, uint8 stepMode, uint8 stepSize, uint16 transTime,
uint8 disableDefaultRsp, uint8 seqNum )
{
uint8 buf[4];
buf[0] = stepMode;
buf[1] = stepSize;
buf[2] = LO_UINT16( transTime );
buf[3] = HI_UINT16( transTime );
return zcl_SendCommand( srcEP, dstAddr, ZCL_CLUSTER_ID_GEN_LEVEL_CONTROL,
cmd, TRUE, ZCL_FRAME_CLIENT_SERVER_DIR,
disableDefaultRsp, 0, seqNum, 4, buf );
}
#endif // ZCL_LEVEL_CTRL
#ifdef ZCL_ALARMS
/*********************************************************************
* @fn zclGeneral_SendAlarmRequest
*
* @brief Call to send out an Alarm Request Command
*
* @param srcEP - Sending application's endpoint
* @param dstAddr - where you want the message to go
* @param cmd - either COMMAND_ALARMS_RESET or COMMAND_ALARMS_ALARM
* @param alarmCode - code for the cause of the alarm
* @param clusterID - cluster whose attribute generate the alarm
*
* @return ZStatus_t
*/
ZStatus_t zclGeneral_SendAlarmRequest( uint8 srcEP, afAddrType_t *dstAddr,
uint8 cmd, uint8 alarmCode, uint16 clusterID,
uint8 disableDefaultRsp, uint8 seqNum )
{
uint8 buf[3];
buf[0] = alarmCode;
buf[1] = LO_UINT16( clusterID );
buf[2] = HI_UINT16( clusterID );
return zcl_SendCommand( srcEP, dstAddr, ZCL_CLUSTER_ID_GEN_ALARMS,
cmd, TRUE, ZCL_FRAME_CLIENT_SERVER_DIR,
disableDefaultRsp, 0, seqNum, 3, buf );
}
/*********************************************************************
* @fn zclGeneral_SendAlarmGetRespnose
*
* @brief Call to send out an Alarm Get Response Command
*
* @param srcEP - Sending application's endpoint
* @param dstAddr - where you want the message to go
* @param status - SUCCESS or NOT_FOUND
* @param alarmCode - code for the cause of the alarm
* @param clusterID - cluster whose attribute generate the alarm
* @param timeStamp - time at which the alarm occured
*
* @return ZStatus_t
*/
ZStatus_t zclGeneral_SendAlarmGetRespnose( uint8 srcEP, afAddrType_t *dstAddr,
uint8 status, uint8 alarmCode, uint16 clusterID,
uint32 timeStamp, uint8 disableDefaultRsp, uint8 seqNum )
{
uint8 buf[8];
uint8 len = 1; // Status
buf[0] = status;
if ( status == ZCL_STATUS_SUCCESS )
{
len += 1 + 2 + 4; // Alarm code + Cluster ID + Time stamp
buf[1] = alarmCode;
buf[2] = LO_UINT16( clusterID );
buf[3] = HI_UINT16( clusterID );
osal_buffer_uint32( &buf[4], timeStamp );
}
return zcl_SendCommand( srcEP, dstAddr, ZCL_CLUSTER_ID_GEN_ALARMS,
COMMAND_ALARMS_GET_RSP, TRUE, ZCL_FRAME_SERVER_CLIENT_DIR,
disableDefaultRsp, 0, seqNum, len, buf );
}
#ifdef SE_UK_EXT
/*********************************************************************
* @fn zclGeneral_SendAlarmGetEventLog
*
* @brief Call to send out an Alarm Get Event Log Command
*
* @param srcEP - Sending application's endpoint
* @param dstAddr - where you want the message to go
* @param pEventLog - pointer to Get Event Log Command
* @param disableDefaultRsp - disable default response
* @param seqNum - ZCL sequence number
*
* @return ZStatus_t
*/
ZStatus_t zclGeneral_SendAlarmGetEventLog( uint8 srcEP, afAddrType_t *dstAddr,
zclGetEventLog_t *pEventLog,
uint8 disableDefaultRsp, uint8 seqNum )
{
uint8 buf[10];
buf[0] = pEventLog->logID;
osal_buffer_uint32( &buf[1], pEventLog->startTime );
osal_buffer_uint32( &buf[5], pEventLog->endTime );
buf[9] = pEventLog->numEvents;
return zcl_SendCommand( srcEP, dstAddr, ZCL_CLUSTER_ID_GEN_ALARMS,
COMMAND_ALARMS_GET_EVENT_LOG, TRUE, ZCL_FRAME_SERVER_CLIENT_DIR,
disableDefaultRsp, 0, seqNum, 10, buf );
}
/*********************************************************************
* @fn zclGeneral_SendAlarmPublishEventLog
*
* @brief Call to send out an Alarm Publish Event Log Command
*
* @param srcEP - Sending application's endpoint
* @param dstAddr - where you want the message to go
* @param pEventLog - pointer to Publish Event Log Command
* @param disableDefaultRsp - disable default response
* @param seqNum - ZCL sequence number
*
* @return ZStatus_t
*/
ZStatus_t zclGeneral_SendAlarmPublishEventLog( uint8 srcEP, afAddrType_t *dstAddr,
zclPublishEventLog_t *pEventLog,
uint8 disableDefaultRsp, uint8 seqNum )
{
uint8 *buf;
uint8 *pBuf;
uint8 bufLen;
// Log ID + Command Index + Total Commands + (numSubLogs * ( Event ID + Event Time))
bufLen = 1 + 1 + 1 + (pEventLog->numSubLogs * (1 + 4));
buf = osal_mem_alloc( bufLen );
if ( buf == NULL )
{
return (ZMemError);
}
pBuf = buf;
*pBuf++ = pEventLog->logID;
*pBuf++ = pEventLog->cmdIndex;
*pBuf++ = pEventLog->totalCmds;
for ( uint8 i = 0; i < pEventLog->numSubLogs; i++ )
{
zclEventLogPayload_t *pLogs = &(pEventLog->pLogs[i]);
*pBuf++ = pLogs->eventId;
pBuf = osal_buffer_uint32( pBuf, pLogs->eventTime );
}
return zcl_SendCommand( srcEP, dstAddr, ZCL_CLUSTER_ID_GEN_ALARMS,
COMMAND_ALARMS_PUBLISH_EVENT_LOG, TRUE, ZCL_FRAME_CLIENT_SERVER_DIR,
disableDefaultRsp, 0, seqNum, bufLen, buf );
}
#endif // SE_UK_EXT
#endif // ZCL_ALARMS
#ifdef ZCL_LOCATION
/*********************************************************************
* @fn zclGeneral_SendLocationSetAbsolute
*
* @brief Call to send out a Set Absolute Location Command
*
* @param srcEP - Sending application's endpoint
* @param dstAddr - where you want the message to go
* @param absLoc - absolute location info
*
* @return ZStatus_t
*/
ZStatus_t zclGeneral_SendLocationSetAbsolute( uint8 srcEP, afAddrType_t *dstAddr,
zclLocationAbsolute_t *absLoc,
uint8 disableDefaultRsp, uint8 seqNum )
{
uint8 buf[10]; // 5 fields (2 octects each)
buf[0] = LO_UINT16( absLoc->coordinate1 );
buf[1] = HI_UINT16( absLoc->coordinate1 );
buf[2] = LO_UINT16( absLoc->coordinate2 );
buf[3] = HI_UINT16( absLoc->coordinate2 );
buf[4] = LO_UINT16( absLoc->coordinate3 );
buf[5] = HI_UINT16( absLoc->coordinate3 );
buf[6] = LO_UINT16( absLoc->power );
buf[7] = HI_UINT16( absLoc->power );
buf[8] = LO_UINT16( absLoc->pathLossExponent );
buf[9] = HI_UINT16( absLoc->pathLossExponent );
return zcl_SendCommand( srcEP, dstAddr, ZCL_CLUSTER_ID_GEN_LOCATION,
COMMAND_LOCATION_SET_ABSOLUTE, TRUE,
ZCL_FRAME_CLIENT_SERVER_DIR, disableDefaultRsp, 0, seqNum, 10, buf );
}
/*********************************************************************
* @fn zclGeneral_SendLocationSetDevCfg
*
* @brief Call to send out a Set Device Configuration Command
*
* @param srcEP - Sending application's endpoint
* @param dstAddr - where you want the message to go
* @param devCfg - device configuration info
*
* @return ZStatus_t
*/
ZStatus_t zclGeneral_SendLocationSetDevCfg( uint8 srcEP, afAddrType_t *dstAddr,
zclLocationDevCfg_t *devCfg,
uint8 disableDefaultRsp, uint8 seqNum )
{
uint8 buf[9]; // 4 fields (2 octects each) + 1 field with 1 octect
buf[0] = LO_UINT16( devCfg->power );
buf[1] = HI_UINT16( devCfg->power );
buf[2] = LO_UINT16( devCfg->pathLossExponent );
buf[3] = HI_UINT16( devCfg->pathLossExponent );
buf[4] = LO_UINT16( devCfg->calcPeriod );
buf[5] = HI_UINT16( devCfg->calcPeriod );
buf[6] = devCfg->numMeasurements;
buf[7] = LO_UINT16( devCfg->reportPeriod );
buf[8] = HI_UINT16( devCfg->reportPeriod );
return zcl_SendCommand( srcEP, dstAddr, ZCL_CLUSTER_ID_GEN_LOCATION,
COMMAND_LOCATION_SET_DEV_CFG, TRUE,
ZCL_FRAME_CLIENT_SERVER_DIR, disableDefaultRsp, 0, seqNum, 9, buf );
}
/*********************************************************************
* @fn zclGeneral_SendLocationGetDevCfg
*
* @brief Call to send out a Get Device Configuration Command
*
* @param srcEP - Sending application's endpoint
* @param dstAddr - where you want the message to go
* @param targetAddr - device for which location parameters are being requested
*
* @return ZStatus_t
*/
ZStatus_t zclGeneral_SendLocationGetDevCfg( uint8 srcEP, afAddrType_t *dstAddr,
uint8 *targetAddr, uint8 disableDefaultRsp, uint8 seqNum )
{
uint8 buf[8];
osal_cpyExtAddr( buf, targetAddr );
return zcl_SendCommand( srcEP, dstAddr, ZCL_CLUSTER_ID_GEN_LOCATION,
COMMAND_LOCATION_GET_DEV_CFG, TRUE,
ZCL_FRAME_CLIENT_SERVER_DIR, disableDefaultRsp, 0, seqNum, 8, buf );
}
/*********************************************************************
* @fn zclGeneral_SendLocationGetData
*
* @brief Call to send out a Get Location Data Command
*
* @param srcEP - Sending application's endpoint
* @param dstAddr - where you want the message to go
* @param locaData - location information and channel parameters that are requested.
*
* @return ZStatus_t
*/
ZStatus_t zclGeneral_SendLocationGetData( uint8 srcEP, afAddrType_t *dstAddr,
zclLocationGetData_t *locData,
uint8 disableDefaultRsp, uint8 seqNum )
{
uint8 buf[10]; // bitmap (1) + number responses (1) + IEEE Address (8)
uint8 *pBuf = buf;
uint8 len = 2; // bitmap + number responses
*pBuf = locData->absoluteOnly;
*pBuf |= locData->recalculate << 1;
*pBuf |= locData->brdcastIndicator << 2;
*pBuf |= locData->brdcastResponse << 3;
*pBuf |= locData->compactResponse << 4;
pBuf++; // move past the bitmap field
*pBuf++ = locData->numResponses;
if ( locData->brdcastIndicator == 0 )
{
osal_cpyExtAddr( pBuf, locData->targetAddr );
len += 8; // ieee addr
}
return zcl_SendCommand( srcEP, dstAddr, ZCL_CLUSTER_ID_GEN_LOCATION,
COMMAND_LOCATION_GET_DATA, TRUE,
ZCL_FRAME_CLIENT_SERVER_DIR, disableDefaultRsp, 0, seqNum, len, buf );
}
/*********************************************************************
* @fn zclGeneral_SendLocationDevCfgResponse
*
* @brief Call to send out a Device Configuration Response Command
*
* @param srcEP - Sending application's endpoint
* @param dstAddr - where you want the message to go
* @param devCfg - device's location parameters that are requested
*
* @return ZStatus_t
*/
ZStatus_t zclGeneral_SendLocationDevCfgResponse( uint8 srcEP, afAddrType_t *dstAddr,
zclLocationDevCfgRsp_t *devCfg,
uint8 disableDefaultRsp, uint8 seqNum )
{
uint8 buf[10]; // 4 fields (2 octects each) + 2 fields (1 octect each)
uint8 len = 1; // Status
buf[0] = devCfg->status;
if ( devCfg->status == ZCL_STATUS_SUCCESS )
{
buf[1] = LO_UINT16( devCfg->data.power );
buf[2] = HI_UINT16( devCfg->data.power );
buf[3] = LO_UINT16( devCfg->data.pathLossExponent );
buf[4] = HI_UINT16( devCfg->data.pathLossExponent );
buf[5] = LO_UINT16( devCfg->data.calcPeriod );
buf[6] = HI_UINT16( devCfg->data.calcPeriod );
buf[7] = devCfg->data.numMeasurements;
buf[8] = LO_UINT16( devCfg->data.reportPeriod );
buf[9] = HI_UINT16( devCfg->data.reportPeriod );
len += 9;
}
return zcl_SendCommand( srcEP, dstAddr, ZCL_CLUSTER_ID_GEN_LOCATION,
COMMAND_LOCATION_DEV_CFG_RSP, TRUE,
ZCL_FRAME_SERVER_CLIENT_DIR, disableDefaultRsp, 0, seqNum, len, buf );
}
/*********************************************************************
* @fn zclGeneral_SendLocationData
*
* @brief Call to send out location data
*
* @param srcEP - Sending application's endpoint
* @param dstAddr - where you want the message to go
* @param status - indicates whether response to request was successful or not
* @param locData - location information and channel parameters being sent
*
* @return ZStatus_t
*/
ZStatus_t zclGeneral_SendLocationData( uint8 srcEP, afAddrType_t *dstAddr, uint8 cmd,
uint8 status, zclLocationData_t *locData,
uint8 disableDefaultRsp, uint8 seqNum )
{
uint8 buf[16];
uint8 *pBuf = buf;
uint8 len = 0;
if ( cmd == COMMAND_LOCATION_DATA_RSP )
{
// Only response command includes a status field
*pBuf++ = status;
len++;
}
if ( cmd != COMMAND_LOCATION_DATA_RSP || status == ZCL_STATUS_SUCCESS )
{
// Notification or Response with successful status
*pBuf++ = locData->type;
*pBuf++ = LO_UINT16( locData->absLoc.coordinate1 );
*pBuf++ = HI_UINT16( locData->absLoc.coordinate1 );
*pBuf++ = LO_UINT16( locData->absLoc.coordinate2 );
*pBuf++ = HI_UINT16( locData->absLoc.coordinate2 );
len += 5;
if ( locationType2D(locData->type) == 0 )
{
// 2D location doesn't have coordinate 3
*pBuf++ = LO_UINT16( locData->absLoc.coordinate3 );
*pBuf++ = HI_UINT16( locData->absLoc.coordinate3 );
len += 2;
}
if ( cmd != COMMAND_LOCATION_COMPACT_DATA_NOTIF )
{
// Compact notification doesn't include these fields
*pBuf++ = LO_UINT16( locData->absLoc.power );
*pBuf++ = HI_UINT16( locData->absLoc.power );
*pBuf++ = LO_UINT16( locData->absLoc.pathLossExponent );
*pBuf++ = HI_UINT16( locData->absLoc.pathLossExponent );
len += 4;
}
if ( locationTypeAbsolute(locData->type) == 0 )
{
// Absolute location doesn't include these fields
if ( cmd != COMMAND_LOCATION_COMPACT_DATA_NOTIF )
{
// Compact notification doesn't include this field
*pBuf++ = locData->calcLoc.locationMethod;
len++;
}
*pBuf++ = locData->calcLoc.qualityMeasure;
*pBuf++ = LO_UINT16( locData->calcLoc.locationAge );
*pBuf++ = HI_UINT16( locData->calcLoc.locationAge );
len += 3;
}
}
return zcl_SendCommand( srcEP, dstAddr, ZCL_CLUSTER_ID_GEN_LOCATION,
cmd, TRUE, ZCL_FRAME_SERVER_CLIENT_DIR,
disableDefaultRsp, 0, seqNum, len, buf );
}
#endif // ZCL_LOCATION
/*********************************************************************
* @fn zclGeneral_FindCallbacks
*
* @brief Find the callbacks for an endpoint
*
* @param endpoint - endpoint to find the application callbacks for
*
* @return pointer to the callbacks
*/
static zclGeneral_AppCallbacks_t *zclGeneral_FindCallbacks( uint8 endpoint )
{
zclGenCBRec_t *pCBs;
pCBs = zclGenCBs;
while ( pCBs )
{
if ( pCBs->endpoint == endpoint )
return ( pCBs->CBs );
pCBs = pCBs->next;
}
return ( (zclGeneral_AppCallbacks_t *)NULL );
}
/*********************************************************************
* @fn zclGeneral_HdlIncoming
*
* @brief Callback from ZCL to process incoming Commands specific
* to this cluster library or Profile commands for attributes
* that aren't in the attribute list
*
*
* @param pInMsg - pointer to the incoming message
*
* @return ZStatus_t
*/
static ZStatus_t zclGeneral_HdlIncoming( zclIncoming_t *pInMsg )
{
ZStatus_t stat = ZSuccess;
#if defined ( INTER_PAN )
if ( StubAPS_InterPan( pInMsg->msg->srcAddr.panId, pInMsg->msg->srcAddr.endPoint ) )
return ( stat ); // Cluster not supported thru Inter-PAN
#endif
if ( zcl_ClusterCmd( pInMsg->hdr.fc.type ) )
{
// Is this a manufacturer specific command?
if ( pInMsg->hdr.fc.manuSpecific == 0 )
{
stat = zclGeneral_HdlInSpecificCommands( pInMsg );
}
else
{
// We don't support any manufacturer specific command.
stat = ZFailure;
}
}
else
{
// Handle all the normal (Read, Write...) commands -- should never get here
stat = ZFailure;
}
return ( stat );
}
/*********************************************************************
* @fn zclGeneral_HdlInSpecificCommands
*
* @brief Callback from ZCL to process incoming Commands specific
* to this cluster library
* @param pInMsg - pointer to the incoming message
*
* @return ZStatus_t
*/
static ZStatus_t zclGeneral_HdlInSpecificCommands( zclIncoming_t *pInMsg )
{
ZStatus_t stat;
zclGeneral_AppCallbacks_t *pCBs;
// make sure endpoint exists
pCBs = zclGeneral_FindCallbacks( pInMsg->msg->endPoint );
if ( pCBs == NULL )
return ( ZFailure );
switch ( pInMsg->msg->clusterId )
{
#ifdef ZCL_BASIC
case ZCL_CLUSTER_ID_GEN_BASIC:
stat = zclGeneral_ProcessInBasic( pInMsg, pCBs );
break;
#endif // ZCL_BASIC
#ifdef ZCL_IDENTIFY
case ZCL_CLUSTER_ID_GEN_IDENTIFY:
stat = zclGeneral_ProcessInIdentity( pInMsg, pCBs );
break;
#endif // ZCL_IDENTIFY
#ifdef ZCL_GROUPS
case ZCL_CLUSTER_ID_GEN_GROUPS:
if ( zcl_ServerCmd( pInMsg->hdr.fc.direction ) )
stat = zclGeneral_ProcessInGroupsServer( pInMsg );
else
stat = zclGeneral_ProcessInGroupsClient( pInMsg, pCBs );
break;
#endif // ZCL_GROUPS
#ifdef ZCL_SCENES
case ZCL_CLUSTER_ID_GEN_SCENES:
if ( zcl_ServerCmd( pInMsg->hdr.fc.direction ) )
stat = zclGeneral_ProcessInScenesServer( pInMsg, pCBs );
else
stat = zclGeneral_ProcessInScenesClient( pInMsg, pCBs );
break;
#endif // ZCL_SCENES
#ifdef ZCL_ON_OFF
case ZCL_CLUSTER_ID_GEN_ON_OFF:
stat = zclGeneral_ProcessInOnOff( pInMsg, pCBs );
break;
#endif // ZCL_ON_OFF
#ifdef ZCL_LEVEL_CTRL
case ZCL_CLUSTER_ID_GEN_LEVEL_CONTROL:
stat = zclGeneral_ProcessInLevelControl( pInMsg, pCBs );
break;
#endif // ZCL_LEVEL_CTRL
#ifdef ZCL_ALARMS
case ZCL_CLUSTER_ID_GEN_ALARMS:
if ( zcl_ServerCmd( pInMsg->hdr.fc.direction ) )
stat = zclGeneral_ProcessInAlarmsServer( pInMsg, pCBs );
else
stat = zclGeneral_ProcessInAlarmsClient( pInMsg, pCBs );
break;
#endif // ZCL_ALARMS
#ifdef ZCL_LOCATION
case ZCL_CLUSTER_ID_GEN_LOCATION:
if ( zcl_ServerCmd( pInMsg->hdr.fc.direction ) )
stat = zclGeneral_ProcessInLocationServer( pInMsg, pCBs );
else
stat = zclGeneral_ProcessInLocationClient( pInMsg, pCBs );
break;
#endif // ZCL_LOCATION
case ZCL_CLUSTER_ID_GEN_POWER_CFG:
case ZCL_CLUSTER_ID_GEN_DEVICE_TEMP_CONFIG:
case ZCL_CLUSTER_ID_GEN_ON_OFF_SWITCH_CONFIG:
case ZCL_CLUSTER_ID_GEN_TIME:
default:
stat = ZFailure;
break;
}
return ( stat );
}
#ifdef ZCL_BASIC
/*********************************************************************
* @fn zclGeneral_ProcessInBasic
*
* @brief Process in the received Basic Command.
*
* @param pInMsg - pointer to the incoming message
*
* @return ZStatus_t
*/
static ZStatus_t zclGeneral_ProcessInBasic( zclIncoming_t *pInMsg,
zclGeneral_AppCallbacks_t *pCBs )
{
if ( zcl_ServerCmd( pInMsg->hdr.fc.direction ) )
{
if ( pInMsg->hdr.commandID > COMMAND_BASIC_RESET_FACT_DEFAULT )
return ( ZFailure ); // Error ignore the command
if ( pCBs->pfnBasicReset )
pCBs->pfnBasicReset();
}
// no Client command
return ( ZSuccess );
}
#endif // ZCL_BASIC
#ifdef ZCL_IDENTIFY
/*********************************************************************
* @fn zclGeneral_ProcessInIdentity
*
* @brief Process in the received Identity Command.
*
* @param pInMsg - pointer to the incoming message
*
* @return ZStatus_t
*/
static ZStatus_t zclGeneral_ProcessInIdentity( zclIncoming_t *pInMsg,
zclGeneral_AppCallbacks_t *pCBs )
{
if ( zcl_ServerCmd( pInMsg->hdr.fc.direction ) )
{
if ( pInMsg->hdr.commandID > COMMAND_IDENTIFY_QUERY )
return ( ZFailure ); // Error ignore the command
if ( pInMsg->hdr.commandID == COMMAND_IDENTIFY )
{
if ( pCBs->pfnIdentify )
{
zclIdentify_t cmd;
cmd.srcAddr = &(pInMsg->msg->srcAddr);
cmd.identifyTime = BUILD_UINT16( pInMsg->pData[0], pInMsg->pData[1] );
pCBs->pfnIdentify( &cmd );
}
}
else
{
zclAttrRec_t attrRec;
uint16 identifyTime = 0;
// Retrieve Identify Time
if ( zclFindAttrRec( pInMsg->msg->endPoint, pInMsg->msg->clusterId, ATTRID_IDENTIFY_TIME, &attrRec ) )
zclReadAttrData( (uint8 *)&identifyTime, &attrRec, NULL );
// Is device identifying itself?
if ( identifyTime > 0 )
{
zclGeneral_SendIdentifyQueryResponse( pInMsg->msg->endPoint, &pInMsg->msg->srcAddr,
identifyTime, true, pInMsg->hdr.transSeqNum );
}
return ( ZCL_STATUS_CMD_HAS_RSP );
}
}
else // Client Command
{
if ( pInMsg->hdr.commandID > COMMAND_IDENTIFY_QUERY_RSP )
return ( ZFailure ); // Error ignore the command
if ( pCBs->pfnIdentifyQueryRsp )
{
zclIdentifyQueryRsp_t rsp;
rsp.srcAddr = &(pInMsg->msg->srcAddr);
rsp.timeout = BUILD_UINT16( pInMsg->pData[0], pInMsg->pData[1] );
pCBs->pfnIdentifyQueryRsp( &rsp );
}
}
return ( ZSuccess );
}
#endif // ZCL_IDENTIFY
#ifdef ZCL_GROUPS
/*********************************************************************
* @fn zclGeneral_AddGroup
*
* @brief Add a Group.
*
* @param endPoint - application endpoint
* @param group - group to be added
* @param pData - pointer to the group info
*
* @return ZStatus_t
*/
static ZStatus_t zclGeneral_AddGroup( uint8 endPoint, aps_Group_t *group, uint8 *pData )
{
zclAttrRec_t attrRec;
uint8 nameLen;
uint8 nameSupport = FALSE;
pData += 2; // Move past group ID
nameLen = *pData++;
// Retrieve Name Support attribute
if ( zclFindAttrRec( endPoint, ZCL_CLUSTER_ID_GEN_GROUPS, ATTRID_GROUP_NAME_SUPPORT, &attrRec ) )
zclReadAttrData( &nameSupport, &attrRec, NULL );
if ( nameSupport )
{
if ( nameLen > (APS_GROUP_NAME_LEN-1) )
nameLen = (APS_GROUP_NAME_LEN-1);
group->name[0] = nameLen;
osal_memcpy( &(group->name[1]), pData, nameLen );
}
return ( aps_AddGroup( endPoint, group ) );
}
/*********************************************************************
* @fn zclGeneral_ProcessInGroupsServer
*
* @brief Process in the received Groups Command.
*
* @param pInMsg - pointer to the incoming message
*
* @return ZStatus_t
*/
static ZStatus_t zclGeneral_ProcessInGroupsServer( zclIncoming_t *pInMsg )
{
zclAttrRec_t attrRec;
aps_Group_t group;
aps_Group_t *pGroup;
uint8 *pData;
uint8 status;
uint8 grpCnt;
uint8 grpRspCnt = 0;
uint16 *grpList;
uint16 identifyTime = 0;
uint8 i;
ZStatus_t stat = ZSuccess;
osal_memset( (uint8*)&group, 0, sizeof( aps_Group_t ) );
pData = pInMsg->pData;
group.ID = BUILD_UINT16( pData[0], pData[1] );
switch ( pInMsg->hdr.commandID )
{
case COMMAND_GROUP_ADD:
status = zclGeneral_AddGroup( pInMsg->msg->endPoint, &group, pData );
if ( status != ZSuccess )
{
if ( status == ZApsDuplicateEntry )
status = ZCL_STATUS_DUPLICATE_EXISTS;
else
status = ZCL_STATUS_INSUFFICIENT_SPACE;
}
zclGeneral_SendGroupAddResponse( pInMsg->msg->endPoint, &pInMsg->msg->srcAddr,
status, group.ID, true, pInMsg->hdr.transSeqNum );
stat = ZCL_STATUS_CMD_HAS_RSP;
break;
case COMMAND_GROUP_VIEW:
pGroup = aps_FindGroup( pInMsg->msg->endPoint, group.ID );
if ( pGroup )
{
status = ZCL_STATUS_SUCCESS;
}
else
{
// Group not found
status = ZCL_STATUS_NOT_FOUND;
pGroup = &group;
}
zclGeneral_SendGroupViewResponse( pInMsg->msg->endPoint, &pInMsg->msg->srcAddr,
status, pGroup, true, pInMsg->hdr.transSeqNum );
stat = ZCL_STATUS_CMD_HAS_RSP;
break;
case COMMAND_GROUP_GET_MEMBERSHIP:
grpCnt = *pData++;
// Allocate space for the group list
grpList = osal_mem_alloc( sizeof( uint16 ) * APS_MAX_GROUPS );
if ( grpList != NULL )
{
if ( grpCnt == 0 )
{
// Find out all the groups of which the endpoint is a member.
grpRspCnt = aps_FindAllGroupsForEndpoint( pInMsg->msg->endPoint, grpList );
}
else
{
// Find out the groups (in the list) of which the endpoint is a member.
for ( i = 0; i < grpCnt; i++ )
{
group.ID = BUILD_UINT16( pData[0], pData[1] );
pData += 2;
if ( aps_FindGroup( pInMsg->msg->endPoint, group.ID ) )
grpList[grpRspCnt++] = group.ID;
}
}
if ( grpCnt == 0 || grpRspCnt != 0 )
{
zclGeneral_SendGroupGetMembershipResponse( pInMsg->msg->endPoint, &pInMsg->msg->srcAddr,
aps_GroupsRemaingCapacity(), grpRspCnt,
grpList, true, pInMsg->hdr.transSeqNum );
}
osal_mem_free( grpList );
}
else
{
// Couldn't allocate space for the group list -- send a Default Response command back.
zclDefaultRspCmd_t defaultRspCmd;
defaultRspCmd.commandID = pInMsg->hdr.commandID;
defaultRspCmd.statusCode = ZCL_STATUS_INSUFFICIENT_SPACE;
zcl_SendDefaultRspCmd( pInMsg->msg->endPoint, &(pInMsg->msg->srcAddr),
pInMsg->msg->clusterId, &defaultRspCmd,
ZCL_FRAME_SERVER_CLIENT_DIR, true, 0, pInMsg->hdr.transSeqNum );
}
stat = ZCL_STATUS_CMD_HAS_RSP;
break;
case COMMAND_GROUP_REMOVE:
if ( aps_RemoveGroup( pInMsg->msg->endPoint, group.ID ) )
status = ZCL_STATUS_SUCCESS;
else
status = ZCL_STATUS_NOT_FOUND;
zclGeneral_SendGroupRemoveResponse( pInMsg->msg->endPoint, &pInMsg->msg->srcAddr,
status, group.ID, true, pInMsg->hdr.transSeqNum );
stat = ZCL_STATUS_CMD_HAS_RSP;
break;
case COMMAND_GROUP_REMOVE_ALL:
aps_RemoveAllGroup( pInMsg->msg->endPoint );
break;
case COMMAND_GROUP_ADD_IF_IDENTIFYING:
// Retrieve Identify Time
if ( zclFindAttrRec( pInMsg->msg->endPoint, ZCL_CLUSTER_ID_GEN_IDENTIFY, ATTRID_IDENTIFY_TIME, &attrRec ) )
zclReadAttrData( (uint8 *)&identifyTime, &attrRec, NULL );
// Is device identifying itself?
if ( identifyTime > 0 )
zclGeneral_AddGroup( pInMsg->msg->endPoint, &group, pData );
break;
default:
stat = ZFailure;
break;
}
return ( stat );
}
/*********************************************************************
* @fn zclGeneral_ProcessInGroupsClient
*
* @brief Process in the received Groups Command.
*
* @param pInMsg - pointer to the incoming message
*
* @return ZStatus_t
*/
static ZStatus_t zclGeneral_ProcessInGroupsClient( zclIncoming_t *pInMsg,
zclGeneral_AppCallbacks_t *pCBs )
{
aps_Group_t group;
uint8 *pData = pInMsg->pData;
uint8 grpCnt;
uint8 nameLen;
zclGroupRsp_t rsp;
uint8 i;
ZStatus_t stat = ZSuccess;
osal_memset( (uint8*)&group, 0, sizeof( aps_Group_t ) );
osal_memset( (uint8*)&rsp, 0, sizeof( zclGroupRsp_t ) );
switch ( pInMsg->hdr.commandID )
{
case COMMAND_GROUP_ADD_RSP:
case COMMAND_GROUP_VIEW_RSP:
case COMMAND_GROUP_REMOVE_RSP:
rsp.status = *pData++;
group.ID = BUILD_UINT16( pData[0], pData[1] );
if ( rsp.status == ZCL_STATUS_SUCCESS && pInMsg->hdr.commandID == COMMAND_GROUP_VIEW_RSP )
{
pData += 2; // Move past ID
nameLen = *pData++;
if ( nameLen > (APS_GROUP_NAME_LEN-1) )
nameLen = (APS_GROUP_NAME_LEN-1);
group.name[0] = nameLen;
osal_memcpy( &(group.name[1]), pData, nameLen );
rsp.grpName = group.name;
}
if ( pCBs->pfnGroupRsp )
{
rsp.srcAddr = &(pInMsg->msg->srcAddr);
rsp.cmdID = pInMsg->hdr.commandID;
rsp.grpCnt = 1;
rsp.grpList = &group.ID;
rsp.capacity = 0;
pCBs->pfnGroupRsp( &rsp );
}
break;
case COMMAND_GROUP_GET_MEMBERSHIP_RSP:
{
uint16 *grpList = NULL;
rsp.capacity = *pData++;
grpCnt = *pData++;
if ( grpCnt > 0 )
{
// Allocate space for the group list
grpList = osal_mem_alloc( sizeof( uint16 ) * grpCnt );
if ( grpList != NULL )
{
rsp.grpCnt = grpCnt;
for ( i = 0; i < grpCnt; i++ )
{
grpList[i] = BUILD_UINT16( pData[0], pData[1] );
pData += 2;
}
}
}
if ( pCBs->pfnGroupRsp )
{
rsp.srcAddr = &(pInMsg->msg->srcAddr);
rsp.cmdID = pInMsg->hdr.commandID;
rsp.grpList = grpList;
pCBs->pfnGroupRsp( &rsp );
}
if ( grpList != NULL )
{
osal_mem_free( grpList );
}
}
break;
default:
stat = ZFailure;
break;
}
return ( stat );
}
#endif // ZCL_GROUPS
#ifdef ZCL_SCENES
/*********************************************************************
* @fn zclGeneral_AddScene
*
* @brief Add a scene for an endpoint
*
* @param endpoint -
* @param scene - new scene item
*
* @return ZStatus_t
*/
ZStatus_t zclGeneral_AddScene( uint8 endpoint, zclGeneral_Scene_t *scene )
{
zclGenSceneItem_t *pNewItem;
zclGenSceneItem_t *pLoop;
// Fill in the new profile list
pNewItem = osal_mem_alloc( sizeof( zclGenSceneItem_t ) );
if ( pNewItem == NULL )
return ( ZMemError );
// Fill in the plugin record.
pNewItem->next = (zclGenSceneItem_t *)NULL;
pNewItem->endpoint = endpoint;
osal_memcpy( (uint8*)&(pNewItem->scene), (uint8*)scene, sizeof ( zclGeneral_Scene_t ));
// Find spot in list
if ( zclGenSceneTable == NULL )
{
zclGenSceneTable = pNewItem;
}
else
{
// Look for end of list
pLoop = zclGenSceneTable;
while ( pLoop->next != NULL )
pLoop = pLoop->next;
// Put new item at end of list
pLoop->next = pNewItem;
}
// Update NV
zclGeneral_ScenesWriteNV();
return ( ZSuccess );
}
/*********************************************************************
* @fn zclGeneral_FindScene
*
* @brief Find a scene with endpoint and sceneID
*
* @param endpoint -
* @param groupID - what group the scene belongs to
* @param sceneID - ID to look for scene
*
* @return a pointer to the scene information, NULL if not found
*/
zclGeneral_Scene_t *zclGeneral_FindScene( uint8 endpoint, uint16 groupID, uint8 sceneID )
{
zclGenSceneItem_t *pLoop;
// Look for end of list
pLoop = zclGenSceneTable;
while ( pLoop )
{
if ( (pLoop->endpoint == endpoint || endpoint == 0xFF)
&& pLoop->scene.groupID == groupID && pLoop->scene.ID == sceneID )
{
return ( &(pLoop->scene) );
}
pLoop = pLoop->next;
}
return ( (zclGeneral_Scene_t *)NULL );
}
/*********************************************************************
* @fn aps_FindAllScensForGroup
*
* @brief Find all the scenes with groupID
*
* @param endpoint - endpoint to look for
* @param sceneList - List to hold scene IDs (should hold APS_MAX_SCENES entries)
*
* @return number of scenes copied to sceneList
*/
uint8 zclGeneral_FindAllScenesForGroup( uint8 endpoint, uint16 groupID, uint8 *sceneList )
{
zclGenSceneItem_t *pLoop;
uint8 cnt = 0;
// Look for end of list
pLoop = zclGenSceneTable;
while ( pLoop )
{
if ( pLoop->endpoint == endpoint && pLoop->scene.groupID == groupID )
sceneList[cnt++] = pLoop->scene.ID;
pLoop = pLoop->next;
}
return ( cnt );
}
/*********************************************************************
* @fn zclGeneral_RemoveScene
*
* @brief Remove a scene with endpoint and sceneID
*
* @param endpoint -
* @param groupID - what group the scene belongs to
* @param sceneID - ID to look for scene
*
* @return TRUE if removed, FALSE if not found
*/
uint8 zclGeneral_RemoveScene( uint8 endpoint, uint16 groupID, uint8 sceneID )
{
zclGenSceneItem_t *pLoop;
zclGenSceneItem_t *pPrev;
// Look for end of list
pLoop = zclGenSceneTable;
pPrev = NULL;
while ( pLoop )
{
if ( pLoop->endpoint == endpoint
&& pLoop->scene.groupID == groupID && pLoop->scene.ID == sceneID )
{
if ( pPrev == NULL )
zclGenSceneTable = pLoop->next;
else
pPrev->next = pLoop->next;
// Free the memory
osal_mem_free( pLoop );
// Update NV
zclGeneral_ScenesWriteNV();
return ( TRUE );
}
pPrev = pLoop;
pLoop = pLoop->next;
}
return ( FALSE );
}
/*********************************************************************
* @fn zclGeneral_RemoveAllScenes
*
* @brief Remove all scenes with endpoint and group Id
*
* @param endpoint -
* @param groupID - ID to look for group
*
* @return none
*/
void zclGeneral_RemoveAllScenes( uint8 endpoint, uint16 groupID )
{
zclGenSceneItem_t *pLoop;
zclGenSceneItem_t *pPrev;
zclGenSceneItem_t *pNext;
// Look for end of list
pLoop = zclGenSceneTable;
pPrev = NULL;
while ( pLoop )
{
if ( pLoop->endpoint == endpoint && pLoop->scene.groupID == groupID )
{
if ( pPrev == NULL )
zclGenSceneTable = pLoop->next;
else
pPrev->next = pLoop->next;
pNext = pLoop->next;
// Free the memory
osal_mem_free( pLoop );
pLoop = pNext;
}
else
{
pPrev = pLoop;
pLoop = pLoop->next;
}
}
// Update NV
zclGeneral_ScenesWriteNV();
}
/*********************************************************************
* @fn zclGeneral_CountScenes
*
* @brief Count the number of scenes for an endpoint
*
* @param endpoint -
*
* @return number of scenes assigned to an endpoint
*/
uint8 zclGeneral_CountScenes( uint8 endpoint )
{
zclGenSceneItem_t *pLoop;
uint8 cnt = 0;
// Look for end of list
pLoop = zclGenSceneTable;
while ( pLoop )
{
if ( pLoop->endpoint == endpoint )
cnt++;
pLoop = pLoop->next;
}
return ( cnt );
}
/*********************************************************************
* @fn zclGeneral_CountAllScenes
*
* @brief Count the total number of scenes
*
* @param none
*
* @return number of scenes
*/
uint8 zclGeneral_CountAllScenes( void )
{
zclGenSceneItem_t *pLoop;
uint8 cnt = 0;
// Look for end of list
pLoop = zclGenSceneTable;
while ( pLoop )
{
cnt++;
pLoop = pLoop->next;
}
return ( cnt );
}
/*********************************************************************
* @fn zclGeneral_ReadSceneCountCB
*
* @brief Read the number of scenes currently in the device's
* scene table (i.e., the Scene Count attribute).
*
* Note: This function gets called only when the pointer
* 'dataPtr' to the Scene Count attribute value is
* NULL in the attribute database registered with
* the ZCL.
*
* @param clusterId - cluster that attribute belongs to
* @param attrId - attribute to be read
* @param oper - ZCL_OPER_LEN, ZCL_OPER_READ
* @param pValue - pointer to attribute value
* @param pLen - pointer to length of attribute value read
*
* @return status
*/
ZStatus_t zclGeneral_ReadSceneCountCB( uint16 clusterId, uint16 attrId,
uint8 oper, uint8 *pValue, uint16 *pLen )
{
ZStatus_t status = ZCL_STATUS_SUCCESS;
// This callback function should only be called for the Scene Count attribute
switch ( oper )
{
case ZCL_OPER_LEN:
*pLen = 1; // uint8
break;
case ZCL_OPER_READ:
*pValue = zclGeneral_CountAllScenes();
if ( pLen != NULL )
{
*pLen = 1;
}
break;
default:
status = ZCL_STATUS_SOFTWARE_FAILURE; // should never get here!
break;
}
return ( status );
}
/*********************************************************************
* @fn zclGeneral_ProcessInScenesServer
*
* @brief Process in the received Scenes Command.
*
* @param pInMsg - pointer to the incoming message
*
* @return ZStatus_t
*/
static ZStatus_t zclGeneral_ProcessInScenesServer( zclIncoming_t *pInMsg,
zclGeneral_AppCallbacks_t *pCBs )
{
zclAttrRec_t attrRec;
zclGeneral_Scene_t scene;
zclGeneral_Scene_t *pScene;
uint8 *pData = pInMsg->pData;
uint8 nameLen;
uint8 status;
uint8 sceneCnt = 0;
uint8 *sceneList = NULL;
uint8 sendRsp = FALSE;
uint8 nameSupport = FALSE;
ZStatus_t stat = ZSuccess;
osal_memset( (uint8*)&scene, 0, sizeof( zclGeneral_Scene_t ) );
scene.groupID = BUILD_UINT16( pData[0], pData[1] );
pData += 2; // Move past group ID
scene.ID = *pData++;
switch ( pInMsg->hdr.commandID )
{
case COMMAND_SCENE_ADD:
// Parse the rest of the incoming message
scene.transTime = BUILD_UINT16( pData[0], pData[1] );
pData += 2;
nameLen= *pData++; // Name length
// Retrieve Name Support attribute
if ( zclFindAttrRec( pInMsg->msg->endPoint, ZCL_CLUSTER_ID_GEN_SCENES, ATTRID_SCENES_NAME_SUPPORT, &attrRec ) )
{
zclReadAttrData( &nameSupport, &attrRec, NULL );
}
if ( nameSupport )
{
if ( nameLen > (ZCL_GEN_SCENE_NAME_LEN-1) )
{
// truncate to maximum size
scene.name[0] = ZCL_GEN_SCENE_NAME_LEN-1;
}
else
{
scene.name[0] = nameLen;
}
osal_memcpy( &(scene.name[1]), pData, scene.name[0] );
}
pData += nameLen; // move past name, use original length
scene.extLen = pInMsg->pDataLen - ( (uint16)( pData - pInMsg->pData ) );
if ( scene.extLen > 0 )
{
// Copy the extention field(s)
if ( scene.extLen > ZCL_GEN_SCENE_EXT_LEN )
{
scene.extLen = ZCL_GEN_SCENE_EXT_LEN;
}
osal_memcpy( scene.extField, pData, scene.extLen );
}
if ( scene.groupID == 0x0000 ||
aps_FindGroup( pInMsg->msg->endPoint, scene.groupID ) != NULL )
{
// Either the Scene doesn't belong to a Group (Group ID = 0x0000) or it
// does and the corresponding Group exits
pScene = zclGeneral_FindScene( pInMsg->msg->endPoint, scene.groupID, scene.ID );
if ( pScene || ( zclGeneral_CountAllScenes() < ZCL_GEN_MAX_SCENES ) )
{
status = ZCL_STATUS_SUCCESS;
if ( pScene != NULL )
{
// The Scene already exists so update it
pScene->transTime = scene.transTime;
osal_memcpy( pScene->name, scene.name, ZCL_GEN_SCENE_NAME_LEN );
// Use the new extention field(s)
osal_memcpy( pScene->extField, scene.extField, scene.extLen );
pScene->extLen = scene.extLen;
// Update NV
zclGeneral_ScenesWriteNV();
}
else
{
// The Scene doesn't exist so add it
zclGeneral_AddScene( pInMsg->msg->endPoint, &scene );
}
}
else
{
status = ZCL_STATUS_INSUFFICIENT_SPACE; // The Scene Table is full
}
}
else
{
status = ZCL_STATUS_INVALID_FIELD; // The Group is not in the Group Table
}
zclGeneral_SendSceneAddResponse( pInMsg->msg->endPoint, &pInMsg->msg->srcAddr,
status, scene.groupID, scene.ID,
true, pInMsg->hdr.transSeqNum );
stat = ZCL_STATUS_CMD_HAS_RSP;
break;
case COMMAND_SCENE_VIEW:
pScene = zclGeneral_FindScene( pInMsg->msg->endPoint, scene.groupID, scene.ID );
if ( pScene != NULL )
{
status = ZCL_STATUS_SUCCESS;
}
else
{
// Scene not found
if ( scene.groupID != 0x0000 &&
aps_FindGroup( pInMsg->msg->endPoint, scene.groupID ) == NULL )
{
status = ZCL_STATUS_INVALID_FIELD; // The Group is not in the Group Table
}
else
{
status = ZCL_STATUS_NOT_FOUND;
}
pScene = &scene;
}
zclGeneral_SendSceneViewResponse( pInMsg->msg->endPoint, &pInMsg->msg->srcAddr,
status, pScene, true, pInMsg->hdr.transSeqNum );
stat = ZCL_STATUS_CMD_HAS_RSP;
break;
case COMMAND_SCENE_REMOVE:
if ( zclGeneral_RemoveScene( pInMsg->msg->endPoint, scene.groupID, scene.ID ) )
{
status = ZCL_STATUS_SUCCESS;
}
else
{
// Scene not found
if ( aps_FindGroup( pInMsg->msg->endPoint, scene.groupID ) == NULL )
{
// The Group is not in the Group Table
status = ZCL_STATUS_INVALID_FIELD;
}
else
{
status = ZCL_STATUS_NOT_FOUND;
}
}
if ( UNICAST_MSG( pInMsg->msg ) )
{
// Addressed to this device (not to a group) - send a response back
zclGeneral_SendSceneRemoveResponse( pInMsg->msg->endPoint, &pInMsg->msg->srcAddr,
status, scene.groupID,
scene.ID, true, pInMsg->hdr.transSeqNum );
}
stat = ZCL_STATUS_CMD_HAS_RSP;
break;
case COMMAND_SCENE_REMOVE_ALL:
if ( scene.groupID == 0x0000 ||
aps_FindGroup( pInMsg->msg->endPoint, scene.groupID ) != NULL )
{
zclGeneral_RemoveAllScenes( pInMsg->msg->endPoint, scene.groupID );
status = ZCL_STATUS_SUCCESS;
}
else
{
status = ZCL_STATUS_INVALID_FIELD;
}
if ( UNICAST_MSG( pInMsg->msg ) )
{
// Addressed to this device (not to a group) - send a response back
zclGeneral_SendSceneRemoveAllResponse( pInMsg->msg->endPoint, &pInMsg->msg->srcAddr,
status, scene.groupID, true, pInMsg->hdr.transSeqNum );
}
stat = ZCL_STATUS_CMD_HAS_RSP;
break;
case COMMAND_SCENE_STORE:
if ( scene.groupID == 0x0000 ||
aps_FindGroup( pInMsg->msg->endPoint, scene.groupID ) != NULL )
{
// Either the Scene doesn't belong to a Group (Group ID = 0x0000) or it
// does and the corresponding Group exits
pScene = zclGeneral_FindScene( pInMsg->msg->endPoint, scene.groupID, scene.ID );
if ( pScene || ( zclGeneral_CountAllScenes() < ZCL_GEN_MAX_SCENES ) )
{
uint8 sceneChanged = FALSE;
status = ZCL_STATUS_SUCCESS;
if ( pScene == NULL )
{
// Haven't been added yet
pScene = &scene;
}
if ( pCBs->pfnSceneStoreReq )
{
zclSceneReq_t req;
req.srcAddr = &(pInMsg->msg->srcAddr);
req.scene = pScene;
// Get the latest Scene info
if ( pCBs->pfnSceneStoreReq( &req ) )
{
sceneChanged = TRUE;
}
}
if ( pScene == &scene )
{
// The Scene doesn't exist so add it
zclGeneral_AddScene( pInMsg->msg->endPoint, &scene );
}
else if ( sceneChanged )
{
// The Scene already exists so update only NV
zclGeneral_ScenesWriteNV();
}
}
else
{
status = ZCL_STATUS_INSUFFICIENT_SPACE; // The Scene Table is full
}
}
else
{
status = ZCL_STATUS_INVALID_FIELD; // The Group is not in the Group Table
}
if ( UNICAST_MSG( pInMsg->msg ) )
{
// Addressed to this device (not to a group) - send a response back
zclGeneral_SendSceneStoreResponse( pInMsg->msg->endPoint, &pInMsg->msg->srcAddr,
status, scene.groupID, scene.ID,
true, pInMsg->hdr.transSeqNum );
}
stat = ZCL_STATUS_CMD_HAS_RSP;
break;
case COMMAND_SCENE_RECALL:
pScene = zclGeneral_FindScene( pInMsg->msg->endPoint, scene.groupID, scene.ID );
if ( pScene && pCBs->pfnSceneRecallReq )
{
zclSceneReq_t req;
req.srcAddr = &(pInMsg->msg->srcAddr);
req.scene = pScene;
pCBs->pfnSceneRecallReq( &req );
}
// No response
break;
case COMMAND_SCENE_GET_MEMBERSHIP:
// Find all the Scenes corresponding to the Group ID
if ( scene.groupID == 0x0000 ||
aps_FindGroup( pInMsg->msg->endPoint, scene.groupID ) != NULL )
{
// Allocate space for the scene list
sceneList = osal_mem_alloc( ZCL_GEN_MAX_SCENES );
if ( sceneList != NULL )
{
sceneCnt = zclGeneral_FindAllScenesForGroup( pInMsg->msg->endPoint,
scene.groupID, sceneList );
status = ZCL_STATUS_SUCCESS;
if ( UNICAST_MSG( pInMsg->msg ) )
{
// Addressed only to this device - send a response back
sendRsp = TRUE;
}
else
{
// Addressed to the Group - ONLY send a response if an entry within the
// Scene Table corresponds to the Group ID
if ( sceneCnt != 0 )
{
sendRsp = TRUE;
}
}
}
else
{
// Couldn't allocate space for the scene list!
status = ZCL_STATUS_INSUFFICIENT_SPACE;
sendRsp = TRUE;
}
}
else
{
// The Group is not in the Group Table - send a response back
status = ZCL_STATUS_INVALID_FIELD;
sendRsp = TRUE;
}
if ( sendRsp )
{
zclGeneral_SendSceneGetMembershipResponse( pInMsg->msg->endPoint, &pInMsg->msg->srcAddr,
status, zclGeneral_ScenesRemaingCapacity(), sceneCnt, sceneList,
scene.groupID, true, pInMsg->hdr.transSeqNum );
}
if ( sceneList != NULL )
{
osal_mem_free( sceneList );
}
stat = ZCL_STATUS_CMD_HAS_RSP;
break;
default:
stat = ZFailure;
break;
}
return ( stat );
}
/*********************************************************************
* @fn zclGeneral_ProcessInScenesClient
*
* @brief Process in the received Scenes Command.
*
* @param pInMsg - pointer to the incoming message
*
* @return ZStatus_t
*/
static ZStatus_t zclGeneral_ProcessInScenesClient( zclIncoming_t *pInMsg,
zclGeneral_AppCallbacks_t *pCBs )
{
zclGeneral_Scene_t scene;
uint8 *pData = pInMsg->pData;
uint8 nameLen;
zclSceneRsp_t rsp;
uint8 i;
ZStatus_t stat = ZSuccess;
osal_memset( (uint8*)&scene, 0, sizeof( zclGeneral_Scene_t ) );
osal_memset( (uint8*)&rsp, 0, sizeof( zclSceneRsp_t ) );
// Get the status field first
rsp.status = *pData++;
if ( pInMsg->hdr.commandID == COMMAND_SCENE_GET_MEMBERSHIP_RSP )
{
rsp.capacity = *pData++;
}
scene.groupID = BUILD_UINT16( pData[0], pData[1] );
pData += 2; // Move past group ID
switch ( pInMsg->hdr.commandID )
{
case COMMAND_SCENE_VIEW_RSP:
// Parse the rest of the incoming message
scene.ID = *pData++; // Not applicable to Remove All Response command
scene.transTime = BUILD_UINT16( pData[0], pData[1] );
pData += 2;
nameLen = *pData++; // Name length
if ( nameLen > (ZCL_GEN_SCENE_NAME_LEN-1) )
{
// truncate to maximum size
scene.name[0] = ZCL_GEN_SCENE_NAME_LEN-1;
}
else
{
scene.name[0] = nameLen;
}
osal_memcpy( &(scene.name[1]), pData, scene.name[0] );
pData += nameLen; // move past name, use original length
//*** Do something with the extension field(s)
// Fall through to callback - break is left off intentionally
case COMMAND_SCENE_ADD_RSP:
case COMMAND_SCENE_REMOVE_RSP:
case COMMAND_SCENE_REMOVE_ALL_RSP:
case COMMAND_SCENE_STORE_RSP:
if ( pCBs->pfnSceneRsp )
{
rsp.srcAddr = &(pInMsg->msg->srcAddr);
rsp.cmdID = pInMsg->hdr.commandID;
rsp.scene = &scene;
pCBs->pfnSceneRsp( &rsp );
}
break;
case COMMAND_SCENE_GET_MEMBERSHIP_RSP:
{
uint8 *sceneList = NULL;
if ( rsp.status == ZCL_STATUS_SUCCESS )
{
uint8 sceneCnt = *pData++;
if ( sceneCnt > 0 )
{
// Allocate space for the scene list
sceneList = osal_mem_alloc( sceneCnt );
if ( sceneList != NULL )
{
rsp.sceneCnt = sceneCnt;
for ( i = 0; i < sceneCnt; i++ )
sceneList[i] = *pData++;
}
}
}
if ( pCBs->pfnSceneRsp )
{
rsp.srcAddr = &(pInMsg->msg->srcAddr);
rsp.cmdID = pInMsg->hdr.commandID;
rsp.sceneList = sceneList;
rsp.scene = &scene;
pCBs->pfnSceneRsp( &rsp);
}
if ( sceneList != NULL )
{
osal_mem_free( sceneList );
}
}
break;
default:
stat = ZFailure;
break;
}
return ( stat );
}
#endif // ZCL_SCENES
#ifdef ZCL_ON_OFF
/*********************************************************************
* @fn zclGeneral_ProcessInCmdOnOff
*
* @brief Process in the received On/Off Command.
*
* @param pInMsg - pointer to the incoming message
*
* @return ZStatus_t
*/
static ZStatus_t zclGeneral_ProcessInOnOff( zclIncoming_t *pInMsg,
zclGeneral_AppCallbacks_t *pCBs )
{
if ( zcl_ServerCmd( pInMsg->hdr.fc.direction ) )
{
if ( pInMsg->hdr.commandID > COMMAND_TOGGLE )
return ( ZFailure ); // Error ignore the command
if ( pCBs->pfnOnOff )
pCBs->pfnOnOff( pInMsg->hdr.commandID );
}
// no Client command
return ( ZSuccess );
}
#endif // ZCL_ON_OFF
#ifdef ZCL_LEVEL_CTRL
/*********************************************************************
* @fn zclGeneral_ProcessInLevelControl
*
* @brief Process in the received Level Control Command.
*
* @param pInMsg - pointer to the incoming message
*
* @return ZStatus_t
*/
static ZStatus_t zclGeneral_ProcessInLevelControl( zclIncoming_t *pInMsg,
zclGeneral_AppCallbacks_t *pCBs )
{
uint8 withOnOff = FALSE;
ZStatus_t stat = ZSuccess;
if ( zcl_ServerCmd( pInMsg->hdr.fc.direction ) )
{
switch ( pInMsg->hdr.commandID )
{
case COMMAND_LEVEL_MOVE_TO_LEVEL_WITH_ON_OFF:
withOnOff = TRUE;
// fall through
case COMMAND_LEVEL_MOVE_TO_LEVEL:
if ( pCBs->pfnLevelControlMoveToLevel )
{
zclLCMoveToLevel_t cmd;
cmd.level = pInMsg->pData[0];
cmd.transitionTime = BUILD_UINT16( pInMsg->pData[1], pInMsg->pData[2] );
cmd.withOnOff = withOnOff;
pCBs->pfnLevelControlMoveToLevel( &cmd );
}
break;
case COMMAND_LEVEL_MOVE_WITH_ON_OFF:
withOnOff = TRUE;
// fall through
case COMMAND_LEVEL_MOVE:
if ( pCBs->pfnLevelControlMove )
{
zclLCMove_t cmd;
cmd.moveMode = pInMsg->pData[0];
cmd.rate = pInMsg->pData[1];
cmd.withOnOff = withOnOff;
pCBs->pfnLevelControlMove( &cmd );
}
break;
case COMMAND_LEVEL_STEP_WITH_ON_OFF:
withOnOff = TRUE;
// fall through
case COMMAND_LEVEL_STEP:
if ( pCBs->pfnLevelControlStep )
{
zclLCStep_t cmd;
cmd.stepMode = pInMsg->pData[0];
cmd.amount = pInMsg->pData[1];
cmd.transitionTime = BUILD_UINT16( pInMsg->pData[2], pInMsg->pData[3] );
cmd.withOnOff = withOnOff;
pCBs->pfnLevelControlStep( &cmd );
}
break;
case COMMAND_LEVEL_STOP:
case COMMAND_LEVEL_STOP_WITH_ON_OFF:
// Both Stop commands are identical
if ( pCBs->pfnLevelControlStop )
{
pCBs->pfnLevelControlStop();
}
break;
default:
stat = ZFailure;
break;
}
}
// no Client command
return ( stat );
}
#endif // ZCL_LEVEL_CTRL
#ifdef ZCL_ALARMS
/*********************************************************************
* @fn zclGeneral_AddAlarm
*
* @brief Add an alarm for a cluster
*
* @param endpoint -
* @param alarm - new alarm item
*
* @return ZStatus_t
*/
ZStatus_t zclGeneral_AddAlarm( uint8 endpoint, zclGeneral_Alarm_t *alarm )
{
zclGenAlarmItem_t *pNewItem;
zclGenAlarmItem_t *pLoop;
// Fill in the new profile list
pNewItem = osal_mem_alloc( sizeof( zclGenAlarmItem_t ) );
if ( pNewItem == NULL )
return ( ZMemError );
// Fill in the plugin record.
pNewItem->next = (zclGenAlarmItem_t *)NULL;
pNewItem->endpoint = endpoint;
osal_memcpy( (uint8*)(&pNewItem->alarm), (uint8*)alarm, sizeof ( zclGeneral_Alarm_t ) );
// Find spot in list
if ( zclGenAlarmTable == NULL )
{
zclGenAlarmTable = pNewItem;
}
else
{
// Look for end of list
pLoop = zclGenAlarmTable;
while ( pLoop->next != NULL )
pLoop = pLoop->next;
// Put new item at end of list
pLoop->next = pNewItem;
}
return ( ZSuccess );
}
/*********************************************************************
* @fn zclGeneral_FindAlarm
*
* @brief Find an alarm with alarmCode and clusterID
*
* @param endpoint -
* @param groupID - what group the scene belongs to
* @param sceneID - ID to look for scene
*
* @return a pointer to the alarm information, NULL if not found
*/
zclGeneral_Alarm_t *zclGeneral_FindAlarm( uint8 endpoint, uint8 alarmCode, uint16 clusterID )
{
zclGenAlarmItem_t *pLoop;
// Look for the alarm
pLoop = zclGenAlarmTable;
while ( pLoop )
{
if ( pLoop->endpoint == endpoint &&
pLoop->alarm.code == alarmCode && pLoop->alarm.clusterID == clusterID )
{
return ( &(pLoop->alarm) );
}
pLoop = pLoop->next;
}
return ( (zclGeneral_Alarm_t *)NULL );
}
/*********************************************************************
* @fn zclGeneral_FindEarliestAlarm
*
* @brief Find an alarm with the earliest timestamp
*
* @param endpoint -
*
* @return a pointer to the alarm information, NULL if not found
*/
zclGeneral_Alarm_t *zclGeneral_FindEarliestAlarm( uint8 endpoint )
{
zclGenAlarmItem_t *pLoop;
zclGenAlarmItem_t earliestAlarm;
zclGenAlarmItem_t *pEarliestAlarm = &earliestAlarm;
pEarliestAlarm->alarm.timeStamp = 0xFFFFFFFF;
// Look for alarm with earliest time
pLoop = zclGenAlarmTable;
while ( pLoop )
{
if ( pLoop->endpoint == endpoint &&
pLoop->alarm.timeStamp < pEarliestAlarm->alarm.timeStamp )
{
pEarliestAlarm = pLoop;
}
pLoop = pLoop->next;
}
if ( pEarliestAlarm->alarm.timeStamp != 0xFFFFFFFF )
return ( &(pEarliestAlarm->alarm) );
// No alarm
return ( (zclGeneral_Alarm_t *)NULL );
}
/*********************************************************************
* @fn zclGeneral_ResetAlarm
*
* @brief Remove a scene with endpoint and sceneID
*
* @param endpoint -
* @param alarmCode -
* @param clusterID -
*
* @return TRUE if removed, FALSE if not found
*/
void zclGeneral_ResetAlarm( uint8 endpoint, uint8 alarmCode, uint16 clusterID )
{
zclGenAlarmItem_t *pLoop;
zclGenAlarmItem_t *pPrev;
// Look for end of list
pLoop = zclGenAlarmTable;
pPrev = NULL;
while ( pLoop )
{
if ( pLoop->endpoint == endpoint &&
pLoop->alarm.code == alarmCode && pLoop->alarm.clusterID == clusterID )
{
if ( pPrev == NULL )
zclGenAlarmTable = pLoop->next;
else
pPrev->next = pLoop->next;
// Free the memory
osal_mem_free( pLoop );
// Notify the Application so that if the alarm condition still active then
// a new notification will be generated, and a new alarm record will be
// added to the alarm log
// zclGeneral_NotifyReset( alarmCode, clusterID ); // callback function?
return;
}
pPrev = pLoop;
pLoop = pLoop->next;
}
}
/*********************************************************************
* @fn zclGeneral_ResetAllAlarms
*
* @brief Remove all alarms with endpoint
*
* @param endpoint -
* @param notifyApp -
*
* @return none
*/
void zclGeneral_ResetAllAlarms( uint8 endpoint, uint8 notifyApp )
{
zclGenAlarmItem_t *pLoop;
zclGenAlarmItem_t *pPrev;
zclGenAlarmItem_t *pNext;
// Look for end of list
pLoop = zclGenAlarmTable;
pPrev = NULL;
while ( pLoop )
{
if ( pLoop->endpoint == endpoint )
{
if ( pPrev == NULL )
zclGenAlarmTable = pLoop->next;
else
pPrev->next = pLoop->next;
pNext = pLoop->next;
// Free the memory
osal_mem_free( pLoop );
pLoop = pNext;
}
else
{
pPrev = pLoop;
pLoop = pLoop->next;
}
}
if ( notifyApp )
{
// Notify the Application so that if any alarm conditions still active then
// a new notification will be generated, and a new alarm record will be
// added to the alarm log
// zclGeneral_NotifyResetAll(); // callback function?
}
}
/*********************************************************************
* @fn zclGeneral_ProcessInAlarmsServer
*
* @brief Process in the received Alarms Command.
*
* @param pInMsg - pointer to the incoming message
*
* @return ZStatus_t
*/
static ZStatus_t zclGeneral_ProcessInAlarmsServer( zclIncoming_t *pInMsg,
zclGeneral_AppCallbacks_t *pCBs )
{
zclGeneral_Alarm_t *pAlarm;
uint8 *pData = pInMsg->pData;
ZStatus_t stat = ZSuccess;
switch ( pInMsg->hdr.commandID )
{
case COMMAND_ALARMS_RESET:
zclGeneral_ResetAlarm( pInMsg->msg->endPoint, pData[0],
BUILD_UINT16( pData[1], pData[2] ) );
break;
case COMMAND_ALARMS_RESET_ALL:
zclGeneral_ResetAllAlarms( pInMsg->msg->endPoint, TRUE );
break;
case COMMAND_ALARMS_GET:
pAlarm = zclGeneral_FindEarliestAlarm( pInMsg->msg->endPoint );
if ( pAlarm )
{
// Send a response back
zclGeneral_SendAlarmGetRespnose( pInMsg->msg->endPoint, &pInMsg->msg->srcAddr,
ZCL_STATUS_SUCCESS, pAlarm->code,
pAlarm->clusterID, pAlarm->timeStamp,
true, pInMsg->hdr.transSeqNum );
// Remove the entry from the Alarm table
zclGeneral_ResetAlarm( pInMsg->msg->endPoint, pAlarm->code, pAlarm->clusterID );
}
else
{
// Send a response back
zclGeneral_SendAlarmGetRespnose( pInMsg->msg->endPoint, &pInMsg->msg->srcAddr,
ZCL_STATUS_NOT_FOUND, 0, 0, 0,
true, pInMsg->hdr.transSeqNum );
}
stat = ZCL_STATUS_CMD_HAS_RSP;
break;
case COMMAND_ALARMS_RESET_LOG:
zclGeneral_ResetAllAlarms( pInMsg->msg->endPoint, FALSE );
break;
#ifdef SE_UK_EXT
case COMMAND_ALARMS_PUBLISH_EVENT_LOG:
if ( pCBs->pfnPublishEventLog )
{
zclPublishEventLog_t eventLog;
eventLog.logID = *pData++;
eventLog.cmdIndex = *pData++;
eventLog.totalCmds = *pData++;
// First try to find out number of Sub Log Payloads
eventLog.numSubLogs = (pInMsg->pDataLen-3)/(1+4); // event ID + event time
if ( eventLog.numSubLogs > 0 )
{
// Try to alloc space for Log Payload
eventLog.pLogs = (zclEventLogPayload_t *)osal_mem_alloc( sizeof( zclEventLogPayload_t ) *
eventLog.numSubLogs );
if ( eventLog.pLogs != NULL )
{
// Copy Log Payload
for ( uint8 i = 0; i < eventLog.numSubLogs; i++ )
{
eventLog.pLogs[i].eventId = *pData++;
eventLog.pLogs[i].eventTime = osal_build_uint32( pData, 4 );
pData += 4;
}
}
else
{
stat = ZCL_STATUS_SOFTWARE_FAILURE;
}
}
else
{
eventLog.pLogs = NULL;
}
if ( stat == ZSuccess )
{
pCBs->pfnPublishEventLog( &(pInMsg->msg->srcAddr), &eventLog );
}
if ( eventLog.pLogs != NULL )
{
osal_mem_free( eventLog.pLogs );
}
}
break;
#endif // SE_UK_EXT
default:
stat = ZFailure;
break;
}
return ( stat );
}
/*********************************************************************
* @fn zclGeneral_ProcessInAlarmsClient
*
* @brief Process in the received Alarms Command.
*
* @param pInMsg - pointer to the incoming message
*
* @return ZStatus_t
*/
static ZStatus_t zclGeneral_ProcessInAlarmsClient( zclIncoming_t *pInMsg,
zclGeneral_AppCallbacks_t *pCBs )
{
uint8 *pData = pInMsg->pData;
zclAlarm_t alarm;
ZStatus_t stat = ZSuccess;
osal_memset( (uint8*)&alarm, 0, sizeof( zclAlarm_t ) );
switch ( pInMsg->hdr.commandID )
{
case COMMAND_ALARMS_ALARM:
if ( pCBs->pfnAlarm )
{
alarm.srcAddr = &(pInMsg->msg->srcAddr);
alarm.cmdID = pInMsg->hdr.commandID;
alarm.status = *pData++;
alarm.alarmCode = *pData++;
alarm.clusterID = BUILD_UINT16( pData[0], pData[1] );
pData += 2;
alarm.timeStamp = osal_build_uint32( pData, 4 );
pCBs->pfnAlarm( &alarm );
}
break;
case COMMAND_ALARMS_GET_RSP:
if ( pCBs->pfnAlarm )
{
alarm.srcAddr = &(pInMsg->msg->srcAddr);
alarm.cmdID = pInMsg->hdr.commandID;
alarm.alarmCode = *pData++;
alarm.clusterID = BUILD_UINT16( pData[0], pData[1] );
pCBs->pfnAlarm( &alarm );
}
break;
#ifdef SE_UK_EXT
case COMMAND_ALARMS_GET_EVENT_LOG:
if ( pCBs->pfnGetEventLog )
{
zclGetEventLog_t eventLog;
eventLog.logID = *pData++;
eventLog.startTime = osal_build_uint32( pData, 4 );
pData += 4;
eventLog.endTime = osal_build_uint32( pData, 4 );
pData += 4;
eventLog.numEvents = *pData;
pCBs->pfnGetEventLog( pInMsg->msg->endPoint, &(pInMsg->msg->srcAddr),
&eventLog, pInMsg->hdr.transSeqNum );
}
break;
#endif // SE_UK_EXT
default:
stat = ZFailure;
break;
}
return ( stat );
}
#endif // ZCL_ALARMS
#ifdef ZCL_LOCATION
/*********************************************************************
* @fn zclGeneral_ProcessInLocationServer
*
* @brief Process in the received Location Command.
*
* @param pInMsg - pointer to the incoming message
*
* @return ZStatus_t
*/
static ZStatus_t zclGeneral_ProcessInLocationServer( zclIncoming_t *pInMsg,
zclGeneral_AppCallbacks_t *pCBs )
{
uint8 *pData = pInMsg->pData;
zclLocation_t cmd;
ZStatus_t stat = ZSuccess;
osal_memset( (uint8*)&cmd, 0, sizeof( zclLocation_t ) );
switch ( pInMsg->hdr.commandID )
{
case COMMAND_LOCATION_SET_ABSOLUTE:
cmd.un.absLoc.coordinate1 = BUILD_UINT16( pData[0], pData[1] );
pData += 2;
cmd.un.absLoc.coordinate2 = BUILD_UINT16( pData[0], pData[1] );
pData += 2;
cmd.un.absLoc.coordinate3 = BUILD_UINT16( pData[0], pData[1] );
pData += 2;
cmd.un.absLoc.power = BUILD_UINT16( pData[0], pData[1] );
pData += 2;
cmd.un.absLoc.pathLossExponent = BUILD_UINT16( pData[0], pData[1] );
if ( pCBs->pfnLocation )
{
cmd.srcAddr = &(pInMsg->msg->srcAddr);
cmd.cmdID = pInMsg->hdr.commandID;
// Update the absolute location info
pCBs->pfnLocation( &cmd );
}
break;
case COMMAND_LOCATION_SET_DEV_CFG:
cmd.un.devCfg.power = BUILD_UINT16( pData[0], pData[1] );
pData += 2;
cmd.un.devCfg.pathLossExponent = BUILD_UINT16( pData[0], pData[1] );
pData += 2;
cmd.un.devCfg.calcPeriod = BUILD_UINT16( pData[0], pData[1] );
pData += 2;
cmd.un.devCfg.numMeasurements = *pData++;
cmd.un.devCfg.reportPeriod = BUILD_UINT16( pData[0], pData[1] );
if ( pCBs->pfnLocation )
{
cmd.srcAddr = &(pInMsg->msg->srcAddr);
cmd.cmdID = pInMsg->hdr.commandID;
// Update the device configuration info
pCBs->pfnLocation( &cmd );
}
break;
case COMMAND_LOCATION_GET_DEV_CFG:
cmd.un.ieeeAddr = pData;
if ( pCBs->pfnLocation )
{
cmd.srcAddr = &(pInMsg->msg->srcAddr);
cmd.cmdID = pInMsg->hdr.commandID;
cmd.seqNum = pInMsg->hdr.transSeqNum;
// Retreive the Device Configuration
pCBs->pfnLocation( &cmd );
}
stat = ZCL_STATUS_CMD_HAS_RSP;
break;
case COMMAND_LOCATION_GET_DATA:
cmd.un.loc.bitmap.locByte = *pData++;
cmd.un.loc.numResponses = *pData++;
if ( cmd.un.loc.brdcastResponse == 0 ) // command is sent as a unicast
osal_cpyExtAddr( cmd.un.loc.targetAddr, pData );
if ( pCBs->pfnLocation )
{
cmd.srcAddr = &(pInMsg->msg->srcAddr);
cmd.cmdID = pInMsg->hdr.commandID;
cmd.seqNum = pInMsg->hdr.transSeqNum;
// Retreive the Location Data
pCBs->pfnLocation( &cmd );
}
stat = ZCL_STATUS_CMD_HAS_RSP;
break;
default:
stat = ZFailure;
break;
}
return ( stat );
}
/*********************************************************************
* @fn zclGeneral_ProcessInLocationDataRsp
*
* @brief Process in the received Location Command.
*
* @param pInMsg - pointer to the incoming message
*
* @return ZStatus_t
*/
static void zclGeneral_ProcessInLocationDataRsp( zclIncoming_t *pInMsg,
zclGeneral_AppCallbacks_t *pCBs )
{
uint8 *pData = pInMsg->pData;
zclLocationRsp_t rsp;
osal_memset( (uint8*)&rsp, 0, sizeof( zclLocationRsp_t ) );
if ( pCBs->pfnLocationRsp )
{
if ( pInMsg->hdr.commandID == COMMAND_LOCATION_DATA_RSP )
rsp.un.loc.status = *pData++;
if ( pInMsg->hdr.commandID != COMMAND_LOCATION_DATA_RSP ||
rsp.un.loc.status == ZCL_STATUS_SUCCESS )
{
rsp.un.loc.data.type = *pData++;
rsp.un.loc.data.absLoc.coordinate1 = BUILD_UINT16( pData[0], pData[1] );
pData += 2;
rsp.un.loc.data.absLoc.coordinate2 = BUILD_UINT16( pData[0], pData[1] );
pData += 2;
if ( locationType2D( rsp.un.loc.data.type ) == 0 )
{
rsp.un.loc.data.absLoc.coordinate3 = BUILD_UINT16( pData[0], pData[1] );
pData += 2;
}
if ( pInMsg->hdr.commandID != COMMAND_LOCATION_COMPACT_DATA_NOTIF )
{
rsp.un.loc.data.absLoc.power = BUILD_UINT16( pData[0], pData[1] );
pData += 2;
rsp.un.loc.data.absLoc.pathLossExponent = BUILD_UINT16( pData[0], pData[1] );
pData += 2;
}
if ( locationTypeAbsolute( rsp.un.loc.data.type ) == 0 )
{
if ( pInMsg->hdr.commandID != COMMAND_LOCATION_COMPACT_DATA_NOTIF )
rsp.un.loc.data.calcLoc.locationMethod = *pData++;
rsp.un.loc.data.calcLoc.qualityMeasure = *pData++;
rsp.un.loc.data.calcLoc.locationAge = BUILD_UINT16( pData[0], pData[1] );
}
}
rsp.srcAddr = &(pInMsg->msg->srcAddr);
rsp.cmdID = pInMsg->hdr.commandID;
// Notify the Application
pCBs->pfnLocationRsp( &rsp );
}
}
/*********************************************************************
* @fn zclGeneral_ProcessInLocationClient
*
* @brief Process in the received Location Command.
*
* @param pInMsg - pointer to the incoming message
*
* @return ZStatus_t
*/
static ZStatus_t zclGeneral_ProcessInLocationClient( zclIncoming_t *pInMsg,
zclGeneral_AppCallbacks_t *pCBs )
{
uint8 *pData = pInMsg->pData;
zclLocationRsp_t rsp;
ZStatus_t stat = ZSuccess;
osal_memset( (uint8*)&rsp, 0, sizeof( zclLocationRsp_t ) );
switch ( pInMsg->hdr.commandID )
{
case COMMAND_LOCATION_DEV_CFG_RSP:
if ( pCBs->pfnLocationRsp )
{
rsp.un.devCfg.status = *pData++;
if ( rsp.un.devCfg.status == ZCL_STATUS_SUCCESS )
{
rsp.un.devCfg.data.power = BUILD_UINT16( pData[0], pData[1] );
pData += 2;
rsp.un.devCfg.data.pathLossExponent = BUILD_UINT16( pData[0], pData[1] );
pData += 2;
rsp.un.devCfg.data.calcPeriod = BUILD_UINT16( pData[0], pData[1] );
pData += 2;
rsp.un.devCfg.data.numMeasurements = *pData++;
rsp.un.devCfg.data.reportPeriod = BUILD_UINT16( pData[0], pData[1] );
rsp.srcAddr = &(pInMsg->msg->srcAddr);
rsp.cmdID = pInMsg->hdr.commandID;
// Notify the Application
pCBs->pfnLocationRsp( &rsp );
}
}
break;
case COMMAND_LOCATION_DATA_RSP:
case COMMAND_LOCATION_DATA_NOTIF:
case COMMAND_LOCATION_COMPACT_DATA_NOTIF:
zclGeneral_ProcessInLocationDataRsp( pInMsg, pCBs );
break;
case COMMAND_LOCATION_RSSI_PING:
if ( pCBs->pfnLocationRsp )
{
rsp.un.locationType = *pData;
rsp.srcAddr = &(pInMsg->msg->srcAddr);
rsp.cmdID = pInMsg->hdr.commandID;
// Notify the Application
pCBs->pfnLocationRsp( &rsp );
}
break;
default:
stat = ZFailure;
break;
}
return ( stat );
}
#endif // ZCL_LOCATION
#ifdef ZCL_SCENES
/*********************************************************************
* @fn zclGeneral_ScenesInitNV
*
* @brief Initialize the NV Scene Table Items
*
* @param none
*
* @return number of scenes
*/
static uint8 zclGeneral_ScenesInitNV( void )
{
uint8 status;
uint16 size;
size = (uint16)((sizeof ( nvGenScenesHdr_t ))
+ ( sizeof( zclGenSceneNVItem_t ) * ZCL_GEN_MAX_SCENES ));
status = osal_nv_item_init( ZCD_NV_SCENE_TABLE, size, NULL );
if ( status != ZSUCCESS )
{
zclGeneral_ScenesSetDefaultNV();
}
return status;
}
/*********************************************************************
* @fn zclGeneral_ScenesSetDefaultNV
*
* @brief Write the defaults to NV
*
* @param none
*
* @return none
*/
static void zclGeneral_ScenesSetDefaultNV( void )
{
nvGenScenesHdr_t hdr;
// Initialize the header
hdr.numRecs = 0;
// Save off the header
osal_nv_write( ZCD_NV_SCENE_TABLE, 0, sizeof( nvGenScenesHdr_t ), &hdr );
}
/*********************************************************************
* @fn zclGeneral_ScenesWriteNV
*
* @brief Save the Scene Table in NV
*
* @param none
*
* @return none
*/
static void zclGeneral_ScenesWriteNV( void )
{
nvGenScenesHdr_t hdr;
zclGenSceneItem_t *pLoop;
zclGenSceneNVItem_t item;
hdr.numRecs = 0;
// Look for end of list
pLoop = zclGenSceneTable;
while ( pLoop )
{
// Build the record
item.endpoint = pLoop->endpoint;
osal_memcpy( &(item.scene), &(pLoop->scene), sizeof ( zclGeneral_Scene_t ) );
// Save the record to NV
osal_nv_write( ZCD_NV_SCENE_TABLE,
(uint16)((sizeof( nvGenScenesHdr_t )) + (hdr.numRecs * sizeof ( zclGenSceneNVItem_t ))),
sizeof ( zclGenSceneNVItem_t ), &item );
hdr.numRecs++;
pLoop = pLoop->next;
}
// Save off the header
osal_nv_write( ZCD_NV_SCENE_TABLE, 0, sizeof( nvGenScenesHdr_t ), &hdr );
}
/*********************************************************************
* @fn zclGeneral_ScenesRestoreFromNV
*
* @brief Restore the Scene table from NV
*
* @param none
*
* @return Number of entries restored
*/
static uint16 zclGeneral_ScenesRestoreFromNV( void )
{
uint16 x;
nvGenScenesHdr_t hdr;
zclGenSceneNVItem_t item;
uint16 numAdded = 0;
if ( osal_nv_read( ZCD_NV_SCENE_TABLE, 0, sizeof(nvGenScenesHdr_t), &hdr ) == ZSuccess )
{
// Read in the device list
for ( x = 0; x < hdr.numRecs; x++ )
{
if ( osal_nv_read( ZCD_NV_SCENE_TABLE,
(uint16)(sizeof(nvGenScenesHdr_t) + (x * sizeof ( zclGenSceneNVItem_t ))),
sizeof ( zclGenSceneNVItem_t ), &item ) == ZSUCCESS )
{
// Add the scene
if ( zclGeneral_AddScene( item.endpoint, &(item.scene) ) == ZSuccess )
{
numAdded++;
}
}
}
}
return ( numAdded );
}
#endif // ZCL_SCENES
/***************************************************************************
****************************************************************************/