1045 lines
33 KiB
C
1045 lines
33 KiB
C
/**************************************************************************************************
|
||
Filename: sapi.c
|
||
Revised: $Date: 2010-05-03 17:46:57 -0700 (Mon, 03 May 2010) $
|
||
Revision: $Revision: 22364 $
|
||
|
||
Description: Z-Stack Simple Application Interface.
|
||
|
||
|
||
Copyright 2007-2010 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.
|
||
**************************************************************************************************/
|
||
|
||
/******************************************************************************
|
||
* INCLUDES
|
||
*/
|
||
|
||
#include "ZComDef.h"
|
||
#include "hal_drivers.h"
|
||
#include "OSAL.h"
|
||
#include "OSAL_Tasks.h"
|
||
//#include "OSAL_Custom.h"
|
||
|
||
#if defined ( MT_TASK )
|
||
#include "MT.h"
|
||
#include "MT_TASK.h"
|
||
#endif
|
||
|
||
#include "nwk.h"
|
||
#include "APS.h"
|
||
#include "ZDApp.h"
|
||
|
||
#include "osal_nv.h"
|
||
#include "NLMEDE.h"
|
||
#include "AF.h"
|
||
#include "OnBoard.h"
|
||
#include "nwk_util.h"
|
||
#include "ZDProfile.h"
|
||
#include "ZDObject.h"
|
||
#include "hal_led.h"
|
||
#include "hal_key.h"
|
||
#include "sapi.h"
|
||
#include "MT_SAPI.h"
|
||
|
||
extern uint8 zgStartDelay;
|
||
extern uint8 zgSapiEndpoint;
|
||
/*********************************************************************
|
||
* CONSTANTS
|
||
*/
|
||
|
||
#if !defined OSAL_SAPI
|
||
#define OSAL_SAPI TRUE
|
||
#endif
|
||
|
||
#if !defined SAPI_CB_FUNC
|
||
#define SAPI_CB_FUNC TRUE
|
||
#endif
|
||
|
||
// Message ID's for application user messages must be in 0xE0-0xEF range
|
||
#define ZB_USER_MSG 0xE0
|
||
#define SAPICB_DATA_CNF 0xE0
|
||
#define SAPICB_BIND_CNF 0xE1
|
||
#define SAPICB_START_CNF 0xE2
|
||
|
||
/*********************************************************************
|
||
* TYPEDEFS
|
||
*/
|
||
|
||
/*********************************************************************
|
||
* GLOBAL VARIABLES
|
||
*/
|
||
|
||
#if OSAL_SAPI
|
||
// The order in this table must be identical to the task initialization calls below in osalInitTask.
|
||
const pTaskEventHandlerFn tasksArr[] = {
|
||
macEventLoop,
|
||
nwk_event_loop,
|
||
Hal_ProcessEvent,
|
||
#if defined( MT_TASK )
|
||
MT_ProcessEvent,
|
||
#endif
|
||
APS_event_loop,
|
||
ZDApp_event_loop,
|
||
|
||
SAPI_ProcessEvent
|
||
};
|
||
|
||
const uint8 tasksCnt = sizeof( tasksArr ) / sizeof( tasksArr[0] );
|
||
uint16 *tasksEvents;
|
||
#endif
|
||
|
||
endPointDesc_t sapi_epDesc;
|
||
uint8 sapi_TaskID;
|
||
static uint16 sapi_bindInProgress;
|
||
|
||
/*********************************************************************
|
||
* LOCAL FUNCTIONS
|
||
*/
|
||
|
||
void SAPI_ProcessZDOMsgs( zdoIncomingMsg_t *inMsg );
|
||
static void SAPI_SendCback( uint8 event, uint8 status, uint16 data );
|
||
|
||
static void SAPI_StartConfirm( uint8 status );
|
||
static void SAPI_SendDataConfirm( uint8 handle, uint8 status );
|
||
static void SAPI_BindConfirm( uint16 commandId, uint8 status );
|
||
static void SAPI_FindDeviceConfirm( uint8 searchType,
|
||
uint8 *searchKey, uint8 *result );
|
||
static void SAPI_ReceiveDataIndication( uint16 source,
|
||
uint16 command, uint16 len, uint8 *pData );
|
||
static void SAPI_AllowBindConfirm( uint16 source );
|
||
|
||
/******************************************************************************
|
||
* @fn zb_SystemReset
|
||
*
|
||
* @brief The zb_SystemReset function reboots the ZigBee device. The
|
||
* zb_SystemReset function can be called after a call to
|
||
* zb_WriteConfiguration to restart Z-Stack with the updated
|
||
* configuration.
|
||
*
|
||
* @param none
|
||
*
|
||
* @return none
|
||
*/
|
||
void zb_SystemReset ( void )
|
||
{
|
||
SystemResetSoft(); // Especially useful for CC2531 to not break comm with USB Host.
|
||
}
|
||
|
||
/******************************************************************************
|
||
* @fn zb_StartRequest
|
||
*
|
||
* @brief The zb_StartRequest function starts the ZigBee stack. When the
|
||
* ZigBee stack starts, the device reads configuration parameters
|
||
* from Nonvolatile memory and the device joins its network. The
|
||
* ZigBee stack calls the zb_StartConrifm callback function when
|
||
* the startup process completes.
|
||
*
|
||
* @param none
|
||
*
|
||
* @return none
|
||
*/
|
||
void zb_StartRequest()
|
||
{
|
||
uint8 logicalType;
|
||
|
||
zb_ReadConfiguration( ZCD_NV_LOGICAL_TYPE, sizeof(uint8), &logicalType );
|
||
|
||
// Check for bad combinations of compile flag definitions and device type setting.
|
||
if ((logicalType > ZG_DEVICETYPE_ENDDEVICE) ||
|
||
#if !ZG_BUILD_ENDDEVICE_TYPE // Only RTR or Coord possible.
|
||
(logicalType == ZG_DEVICETYPE_ENDDEVICE) ||
|
||
#endif
|
||
#if !ZG_BUILD_RTR_TYPE // Only End Device possible.
|
||
(logicalType == ZG_DEVICETYPE_ROUTER) ||
|
||
(logicalType == ZG_DEVICETYPE_COORDINATOR) ||
|
||
#elif ZG_BUILD_RTRONLY_TYPE // Only RTR possible.
|
||
(logicalType == ZG_DEVICETYPE_COORDINATOR) ||
|
||
#elif !ZG_BUILD_JOINING_TYPE // Only Coord possible.
|
||
(logicalType == ZG_DEVICETYPE_ROUTER) ||
|
||
#endif
|
||
(0))
|
||
{
|
||
logicalType = ZB_INVALID_PARAMETER;
|
||
SAPI_SendCback(SAPICB_START_CNF, logicalType, 0);
|
||
}
|
||
else
|
||
{
|
||
logicalType = ZB_SUCCESS;
|
||
ZDOInitDevice(zgStartDelay);
|
||
}
|
||
|
||
|
||
return;
|
||
}
|
||
|
||
/******************************************************************************
|
||
* @fn zb_BindDevice
|
||
*
|
||
* @brief The zb_BindDevice function establishes or removes a ‘binding’
|
||
* between two devices. Once bound, an application can send
|
||
* messages to a device by referencing the commandId for the
|
||
* binding.
|
||
*
|
||
* @param create - TRUE to create a binding, FALSE to remove a binding
|
||
* commandId - The identifier of the binding
|
||
* pDestination - The 64-bit IEEE address of the device to bind to
|
||
*
|
||
* @return The status of the bind operation is returned in the
|
||
* zb_BindConfirm callback.
|
||
*/
|
||
void zb_BindDevice ( uint8 create, uint16 commandId, uint8 *pDestination )
|
||
{
|
||
zAddrType_t destination;
|
||
uint8 ret = ZB_ALREADY_IN_PROGRESS;
|
||
|
||
if ( create )
|
||
{
|
||
if (sapi_bindInProgress == 0xffff)
|
||
{
|
||
if ( pDestination )
|
||
{
|
||
destination.addrMode = Addr64Bit;
|
||
osal_cpyExtAddr( destination.addr.extAddr, pDestination );
|
||
|
||
ret = APSME_BindRequest( sapi_epDesc.endPoint, commandId,
|
||
&destination, sapi_epDesc.endPoint );
|
||
|
||
if ( ret == ZSuccess )
|
||
{
|
||
// Find nwk addr
|
||
ZDP_NwkAddrReq(pDestination, ZDP_ADDR_REQTYPE_SINGLE, 0, 0 );
|
||
osal_start_timerEx( ZDAppTaskID, ZDO_NWK_UPDATE_NV, 250 );
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ret = ZB_INVALID_PARAMETER;
|
||
destination.addrMode = Addr16Bit;
|
||
destination.addr.shortAddr = NWK_BROADCAST_SHORTADDR;
|
||
if ( ZDO_AnyClusterMatches( 1, &commandId, sapi_epDesc.simpleDesc->AppNumOutClusters,
|
||
sapi_epDesc.simpleDesc->pAppOutClusterList ) )
|
||
{
|
||
// Try to match with a device in the allow bind mode
|
||
ret = ZDP_MatchDescReq( &destination, NWK_BROADCAST_SHORTADDR,
|
||
sapi_epDesc.simpleDesc->AppProfId, 1, &commandId, 0, (cId_t *)NULL, 0 );
|
||
}
|
||
else if ( ZDO_AnyClusterMatches( 1, &commandId, sapi_epDesc.simpleDesc->AppNumInClusters,
|
||
sapi_epDesc.simpleDesc->pAppInClusterList ) )
|
||
{
|
||
ret = ZDP_MatchDescReq( &destination, NWK_BROADCAST_SHORTADDR,
|
||
sapi_epDesc.simpleDesc->AppProfId, 0, (cId_t *)NULL, 1, &commandId, 0 );
|
||
}
|
||
|
||
if ( ret == ZB_SUCCESS )
|
||
{
|
||
// Set a timer to make sure bind completes
|
||
#if ( ZG_BUILD_RTR_TYPE )
|
||
osal_start_timerEx(sapi_TaskID, ZB_BIND_TIMER, AIB_MaxBindingTime);
|
||
#else
|
||
// AIB_MaxBindingTime is not defined for an End Device
|
||
osal_start_timerEx(sapi_TaskID, ZB_BIND_TIMER, zgApsDefaultMaxBindingTime);
|
||
#endif
|
||
sapi_bindInProgress = commandId;
|
||
return; // dont send cback event
|
||
}
|
||
}
|
||
}
|
||
|
||
SAPI_SendCback( SAPICB_BIND_CNF, ret, commandId );
|
||
}
|
||
else
|
||
{
|
||
// Remove local bindings for the commandId
|
||
BindingEntry_t *pBind;
|
||
|
||
// Loop through bindings an remove any that match the cluster
|
||
while ( pBind = bindFind( sapi_epDesc.simpleDesc->EndPoint, commandId, 0 ) )
|
||
{
|
||
bindRemoveEntry(pBind);
|
||
}
|
||
osal_start_timerEx( ZDAppTaskID, ZDO_NWK_UPDATE_NV, 250 );
|
||
}
|
||
return;
|
||
}
|
||
/******************************************************************************
|
||
* @fn zb_PermitJoiningRequest
|
||
*
|
||
* @brief The zb_PermitJoiningRequest function is used to control the
|
||
* joining permissions and thus allow or disallow new devices from
|
||
* joining the network.
|
||
*
|
||
* @param destination - The destination parameter indicates the address
|
||
* of the device for which the joining permissions
|
||
* should be set. This is usually the local device
|
||
* address or the special broadcast address that denotes
|
||
* all routers and coordinator ( 0xFFFC ). This way
|
||
* the joining permissions of a single device or the
|
||
* whole network can be controlled.
|
||
* timeout - Indicates the amount of time in seconds for which
|
||
* the joining permissions should be turned on.
|
||
* If timeout is set to 0x00, the device will turn off the
|
||
* joining permissions indefinitely. If it is set to 0xFF,
|
||
* the joining permissions will be turned on indefinitely.
|
||
*
|
||
*
|
||
* @return ZB_SUCCESS or a failure code
|
||
*
|
||
*/
|
||
|
||
uint8 zb_PermitJoiningRequest ( uint16 destination, uint8 timeout )
|
||
{
|
||
#if defined( ZDO_MGMT_PERMIT_JOIN_REQUEST )
|
||
zAddrType_t dstAddr;
|
||
|
||
dstAddr.addrMode = Addr16Bit;
|
||
dstAddr.addr.shortAddr = destination;
|
||
|
||
return( (uint8) ZDP_MgmtPermitJoinReq( &dstAddr, timeout, 0, 0 ) );
|
||
#else
|
||
(void)destination;
|
||
(void)timeout;
|
||
return ZUnsupportedMode;
|
||
#endif
|
||
}
|
||
/******************************************************************************
|
||
* @fn zb_AllowBind
|
||
*
|
||
* @brief The zb_AllowBind function puts the device into the
|
||
* Allow Binding Mode for a given period of time. A peer device
|
||
* can establish a binding to a device in the Allow Binding Mode
|
||
* by calling zb_BindDevice with a destination address of NULL
|
||
*
|
||
* @param timeout - The number of seconds to remain in the allow binding
|
||
* mode. Valid values range from 1 through 65.
|
||
* If 0, the Allow Bind mode will be set false without TO
|
||
* If greater than 64, the Allow Bind mode will be true
|
||
*
|
||
* @return ZB_SUCCESS if the device entered the allow bind mode, else
|
||
* an error code.
|
||
*/
|
||
void zb_AllowBind ( uint8 timeout )
|
||
{
|
||
|
||
osal_stop_timerEx(sapi_TaskID, ZB_ALLOW_BIND_TIMER);
|
||
|
||
if ( timeout == 0 )
|
||
{
|
||
afSetMatch(sapi_epDesc.simpleDesc->EndPoint, FALSE);
|
||
}
|
||
else
|
||
{
|
||
afSetMatch(sapi_epDesc.simpleDesc->EndPoint, TRUE);
|
||
if ( timeout != 0xFF )
|
||
{
|
||
if ( timeout > 64 )
|
||
{
|
||
timeout = 64;
|
||
}
|
||
osal_start_timerEx(sapi_TaskID, ZB_ALLOW_BIND_TIMER, timeout*1000);
|
||
}
|
||
}
|
||
return;
|
||
}
|
||
/******************************************************************************
|
||
* @fn zb_SendDataRequest
|
||
*
|
||
* @brief The zb_SendDataRequest function initiates transmission of data
|
||
* to a peer device
|
||
*
|
||
* @param destination - The destination of the data. The destination can
|
||
* be one of the following:
|
||
* - 16-Bit short address of device [0-0xfffD]
|
||
* - ZB_BROADCAST_ADDR sends the data to all devices
|
||
* in the network.
|
||
* - ZB_BINDING_ADDR sends the data to a previously
|
||
* bound device.
|
||
*
|
||
* commandId - The command ID to send with the message. If the
|
||
* ZB_BINDING_ADDR destination is used, this parameter
|
||
* also indicates the binding to use.
|
||
*
|
||
* len - The size of the pData buffer in bytes
|
||
* handle - A handle used to identify the send data request.
|
||
* txOptions - TRUE if requesting acknowledgement from the destination.
|
||
* radius - The max number of hops the packet can travel through
|
||
* before it is dropped.
|
||
*
|
||
* @return none
|
||
*/
|
||
void zb_SendDataRequest ( uint16 destination, uint16 commandId, uint8 len,
|
||
uint8 *pData, uint8 handle, uint8 txOptions, uint8 radius )
|
||
{
|
||
afStatus_t status;
|
||
afAddrType_t dstAddr;
|
||
|
||
txOptions |= AF_DISCV_ROUTE;
|
||
|
||
// Set the destination address
|
||
if (destination == ZB_BINDING_ADDR)
|
||
{
|
||
// Binding
|
||
dstAddr.addrMode = afAddrNotPresent;
|
||
}
|
||
else
|
||
{
|
||
// Use short address
|
||
dstAddr.addr.shortAddr = destination;
|
||
dstAddr.addrMode = afAddr16Bit;
|
||
|
||
if ( ADDR_NOT_BCAST != NLME_IsAddressBroadcast( destination ) )
|
||
{
|
||
txOptions &= ~AF_ACK_REQUEST;
|
||
}
|
||
}
|
||
|
||
dstAddr.panId = 0; // Not an inter-pan message.
|
||
dstAddr.endPoint = sapi_epDesc.simpleDesc->EndPoint; // Set the endpoint.
|
||
|
||
// Send the message
|
||
status = AF_DataRequest(&dstAddr, &sapi_epDesc, commandId, len,
|
||
pData, &handle, txOptions, radius);
|
||
|
||
if (status != afStatus_SUCCESS)
|
||
{
|
||
SAPI_SendCback( SAPICB_DATA_CNF, status, handle );
|
||
}
|
||
}
|
||
|
||
/******************************************************************************
|
||
* @fn zb_ReadConfiguration
|
||
*
|
||
* @brief The zb_ReadConfiguration function is used to get a
|
||
* Configuration Protperty from Nonvolatile memory.
|
||
*
|
||
* @param configId - The identifier for the configuration property
|
||
* len - The size of the pValue buffer in bytes
|
||
* pValue - A buffer to hold the configuration property
|
||
*
|
||
* @return none
|
||
*/
|
||
uint8 zb_ReadConfiguration( uint8 configId, uint8 len, void *pValue )
|
||
{
|
||
uint8 size;
|
||
|
||
size = (uint8)osal_nv_item_len( configId );
|
||
if ( size > len )
|
||
{
|
||
return ZFailure;
|
||
}
|
||
else
|
||
{
|
||
return( osal_nv_read(configId, 0, size, pValue) );
|
||
}
|
||
}
|
||
/******************************************************************************
|
||
* @fn zb_WriteConfiguration
|
||
*
|
||
* @brief The zb_WriteConfiguration function is used to write a
|
||
* Configuration Property to nonvolatile memory.
|
||
*
|
||
* @param configId - The identifier for the configuration property
|
||
* len - The size of the pValue buffer in bytes
|
||
* pValue - A buffer containing the new value of the
|
||
* configuration property
|
||
*
|
||
* @return none
|
||
*/
|
||
uint8 zb_WriteConfiguration( uint8 configId, uint8 len, void *pValue )
|
||
{
|
||
return( osal_nv_write(configId, 0, len, pValue) );
|
||
}
|
||
/******************************************************************************
|
||
* @fn zb_GetDeviceInfo
|
||
*
|
||
* @brief The zb_GetDeviceInfo function retrieves a Device Information
|
||
* Property.
|
||
*
|
||
* @param param - The identifier for the device information
|
||
* pValue - A buffer to hold the device information
|
||
*
|
||
* @return none
|
||
*/
|
||
void zb_GetDeviceInfo ( uint8 param, void *pValue )
|
||
{
|
||
switch(param)
|
||
{
|
||
case ZB_INFO_DEV_STATE:
|
||
osal_memcpy(pValue, &devState, sizeof(uint8));
|
||
break;
|
||
case ZB_INFO_IEEE_ADDR:
|
||
osal_memcpy(pValue, &aExtendedAddress, Z_EXTADDR_LEN);
|
||
break;
|
||
case ZB_INFO_SHORT_ADDR:
|
||
osal_memcpy(pValue, &_NIB.nwkDevAddress, sizeof(uint16));
|
||
break;
|
||
case ZB_INFO_PARENT_SHORT_ADDR:
|
||
osal_memcpy(pValue, &_NIB.nwkCoordAddress, sizeof(uint16));
|
||
break;
|
||
case ZB_INFO_PARENT_IEEE_ADDR:
|
||
osal_memcpy(pValue, &_NIB.nwkCoordExtAddress, Z_EXTADDR_LEN);
|
||
break;
|
||
case ZB_INFO_CHANNEL:
|
||
osal_memcpy(pValue, &_NIB.nwkLogicalChannel, sizeof(uint8));
|
||
break;
|
||
case ZB_INFO_PAN_ID:
|
||
osal_memcpy(pValue, &_NIB.nwkPanId, sizeof(uint16));
|
||
break;
|
||
case ZB_INFO_EXT_PAN_ID:
|
||
osal_memcpy(pValue, &_NIB.extendedPANID, Z_EXTADDR_LEN);
|
||
break;
|
||
}
|
||
}
|
||
|
||
/******************************************************************************
|
||
* @fn zb_FindDeviceRequest
|
||
*
|
||
* @brief The zb_FindDeviceRequest function is used to determine the
|
||
* short address for a device in the network. The device initiating
|
||
* a call to zb_FindDeviceRequest and the device being discovered
|
||
* must both be a member of the same network. When the search is
|
||
* complete, the zv_FindDeviceConfirm callback function is called.
|
||
*
|
||
* @param searchType - The type of search to perform. Can be one of following:
|
||
* ZB_IEEE_SEARCH - Search for 16-bit addr given IEEE addr.
|
||
* searchKey - Value to search on.
|
||
*
|
||
* @return none
|
||
*/
|
||
void zb_FindDeviceRequest( uint8 searchType, void *searchKey )
|
||
{
|
||
if (searchType == ZB_IEEE_SEARCH)
|
||
{
|
||
ZDP_NwkAddrReq((uint8*) searchKey, ZDP_ADDR_REQTYPE_SINGLE, 0, 0 );
|
||
}
|
||
}
|
||
/******************************************************************************
|
||
* @fn SAPI_StartConfirm
|
||
*
|
||
* @brief The SAPI_StartConfirm callback is called by the ZigBee stack
|
||
* after a start request operation completes
|
||
*
|
||
* @param status - The status of the start operation. Status of
|
||
* ZB_SUCCESS indicates the start operation completed
|
||
* successfully. Else the status is an error code.
|
||
*
|
||
* @return none
|
||
*/
|
||
void SAPI_StartConfirm( uint8 status )
|
||
{
|
||
#if defined ( MT_SAPI_CB_FUNC )
|
||
/* First check if MT has subscribed for this callback. If so , pass it as
|
||
a event to MonitorTest and return control to calling function after that */
|
||
if ( SAPICB_CHECK( SPI_CB_SAPI_START_CNF ) )
|
||
{
|
||
zb_MTCallbackStartConfirm( status );
|
||
}
|
||
else
|
||
#endif //MT_SAPI_CB_FUNC
|
||
{
|
||
#if ( SAPI_CB_FUNC )
|
||
zb_StartConfirm( status );
|
||
#endif
|
||
}
|
||
}
|
||
|
||
/******************************************************************************
|
||
* @fn SAPI_SendDataConfirm
|
||
*
|
||
* @brief The SAPI_SendDataConfirm callback function is called by the
|
||
* ZigBee after a send data operation completes
|
||
*
|
||
* @param handle - The handle identifying the data transmission.
|
||
* status - The status of the operation.
|
||
*
|
||
* @return none
|
||
*/
|
||
void SAPI_SendDataConfirm( uint8 handle, uint8 status )
|
||
{
|
||
#if defined ( MT_SAPI_CB_FUNC )
|
||
/* First check if MT has subscribed for this callback. If so , pass it as
|
||
a event to MonitorTest and return control to calling function after that */
|
||
if ( SAPICB_CHECK( SPI_CB_SAPI_SEND_DATA_CNF ) )
|
||
{
|
||
zb_MTCallbackSendDataConfirm( handle, status );
|
||
}
|
||
else
|
||
#endif //MT_SAPI_CB_FUNC
|
||
{
|
||
#if ( SAPI_CB_FUNC )
|
||
zb_SendDataConfirm( handle, status );
|
||
#endif
|
||
}
|
||
}
|
||
|
||
/******************************************************************************
|
||
* @fn SAPI_BindConfirm
|
||
*
|
||
* @brief The SAPI_BindConfirm callback is called by the ZigBee stack
|
||
* after a bind operation completes.
|
||
*
|
||
* @param commandId - The command ID of the binding being confirmed.
|
||
* status - The status of the bind operation.
|
||
* allowBind - TRUE if the bind operation was initiated by a call
|
||
* to zb_AllowBindRespones. FALSE if the operation
|
||
* was initiated by a call to ZB_BindDevice
|
||
*
|
||
* @return none
|
||
*/
|
||
void SAPI_BindConfirm( uint16 commandId, uint8 status )
|
||
{
|
||
#if defined ( MT_SAPI_CB_FUNC )
|
||
/* First check if MT has subscribed for this callback. If so , pass it as
|
||
a event to MonitorTest and return control to calling function after that */
|
||
if ( SAPICB_CHECK( SPI_CB_SAPI_BIND_CNF ) )
|
||
{
|
||
zb_MTCallbackBindConfirm( commandId, status );
|
||
}
|
||
else
|
||
#endif //MT_SAPI_CB_FUNC
|
||
{
|
||
#if ( SAPI_CB_FUNC )
|
||
zb_BindConfirm( commandId, status );
|
||
#endif
|
||
}
|
||
}
|
||
/******************************************************************************
|
||
* @fn SAPI_AllowBindConfirm
|
||
*
|
||
* @brief Indicates when another device attempted to bind to this device
|
||
*
|
||
* @param
|
||
*
|
||
* @return none
|
||
*/
|
||
void SAPI_AllowBindConfirm( uint16 source )
|
||
{
|
||
#if defined ( MT_SAPI_CB_FUNC )
|
||
/* First check if MT has subscribed for this callback. If so , pass it as
|
||
a event to MonitorTest and return control to calling function after that */
|
||
if ( SAPICB_CHECK( SPI_CB_SAPI_ALLOW_BIND_CNF ) )
|
||
{
|
||
zb_MTCallbackAllowBindConfirm( source );
|
||
}
|
||
else
|
||
#endif //MT_SAPI_CB_FUNC
|
||
{
|
||
#if ( SAPI_CB_FUNC )
|
||
zb_AllowBindConfirm( source );
|
||
#endif
|
||
}
|
||
}
|
||
/******************************************************************************
|
||
* @fn SAPI_FindDeviceConfirm
|
||
*
|
||
* @brief The SAPI_FindDeviceConfirm callback function is called by the
|
||
* ZigBee stack when a find device operation completes.
|
||
*
|
||
* @param searchType - The type of search that was performed.
|
||
* searchKey - Value that the search was executed on.
|
||
* result - The result of the search.
|
||
*
|
||
* @return none
|
||
*/
|
||
void SAPI_FindDeviceConfirm( uint8 searchType, uint8 *searchKey, uint8 *result )
|
||
{
|
||
#if defined ( MT_SAPI_CB_FUNC )
|
||
/* First check if MT has subscribed for this callback. If so , pass it as
|
||
a event to MonitorTest and return control to calling function after that */
|
||
if ( SAPICB_CHECK( SPI_CB_SAPI_FIND_DEV_CNF ) )
|
||
{
|
||
zb_MTCallbackFindDeviceConfirm( searchType, searchKey, result );
|
||
}
|
||
else
|
||
#endif //MT_SAPI_CB_FUNC
|
||
{
|
||
#if ( SAPI_CB_FUNC )
|
||
zb_FindDeviceConfirm( searchType, searchKey, result );
|
||
#endif
|
||
}
|
||
}
|
||
/******************************************************************************
|
||
* @fn SAPI_ReceiveDataIndication
|
||
*
|
||
* @brief The SAPI_ReceiveDataIndication callback function is called
|
||
* asynchronously by the ZigBee stack to notify the application
|
||
* when data is received from a peer device.
|
||
*
|
||
* @param source - The short address of the peer device that sent the data
|
||
* command - The commandId associated with the data
|
||
* len - The number of bytes in the pData parameter
|
||
* pData - The data sent by the peer device
|
||
*
|
||
* @return none
|
||
*/
|
||
void SAPI_ReceiveDataIndication( uint16 source, uint16 command, uint16 len, uint8 *pData )
|
||
{
|
||
#if defined ( MT_SAPI_CB_FUNC )
|
||
/* First check if MT has subscribed for this callback. If so , pass it as
|
||
a event to MonitorTest and return control to calling function after that */
|
||
if ( SAPICB_CHECK( SPI_CB_SAPI_RCV_DATA_IND ) )
|
||
{
|
||
zb_MTCallbackReceiveDataIndication( source, command, len, pData );
|
||
}
|
||
else
|
||
#endif //MT_SAPI_CB_FUNC
|
||
{
|
||
#if ( SAPI_CB_FUNC )
|
||
zb_ReceiveDataIndication( source, command, len, pData );
|
||
#endif
|
||
}
|
||
}
|
||
/*********************************************************************
|
||
* @fn SAPI_ProcessEvent
|
||
*
|
||
* @brief Simple API Task event processor. This function
|
||
* is called to process all events for the task. Events
|
||
* include timers, messages and any other user defined events.
|
||
*
|
||
* @param task_id - The OSAL assigned task ID.
|
||
* @param events - events to process. This is a bit map and can
|
||
* contain more than one event.
|
||
*
|
||
* @return none
|
||
*/
|
||
UINT16 SAPI_ProcessEvent( byte task_id, UINT16 events )
|
||
{
|
||
osal_event_hdr_t *pMsg;
|
||
afIncomingMSGPacket_t *pMSGpkt;
|
||
afDataConfirm_t *pDataConfirm;
|
||
|
||
if ( events & SYS_EVENT_MSG )
|
||
{
|
||
pMsg = (osal_event_hdr_t *) osal_msg_receive( task_id );
|
||
while ( pMsg )
|
||
{
|
||
switch ( pMsg->event )
|
||
{
|
||
case ZDO_CB_MSG:
|
||
SAPI_ProcessZDOMsgs( (zdoIncomingMsg_t *)pMsg );
|
||
break;
|
||
|
||
case AF_DATA_CONFIRM_CMD:
|
||
// This message is received as a confirmation of a data packet sent.
|
||
// The status is of ZStatus_t type [defined in ZComDef.h]
|
||
// The message fields are defined in AF.h
|
||
pDataConfirm = (afDataConfirm_t *) pMsg;
|
||
SAPI_SendDataConfirm( pDataConfirm->transID, pDataConfirm->hdr.status );
|
||
break;
|
||
|
||
case AF_INCOMING_MSG_CMD:
|
||
pMSGpkt = (afIncomingMSGPacket_t *) pMsg;
|
||
SAPI_ReceiveDataIndication( pMSGpkt->srcAddr.addr.shortAddr, pMSGpkt->clusterId,
|
||
pMSGpkt->cmd.DataLength, pMSGpkt->cmd.Data);
|
||
break;
|
||
|
||
case ZDO_STATE_CHANGE:
|
||
// If the device has started up, notify the application
|
||
if (pMsg->status == DEV_END_DEVICE ||
|
||
pMsg->status == DEV_ROUTER ||
|
||
pMsg->status == DEV_ZB_COORD )
|
||
{
|
||
SAPI_StartConfirm( ZB_SUCCESS );
|
||
}
|
||
else if (pMsg->status == DEV_HOLD ||
|
||
pMsg->status == DEV_INIT)
|
||
{
|
||
SAPI_StartConfirm( ZB_INIT );
|
||
}
|
||
break;
|
||
|
||
case ZDO_MATCH_DESC_RSP_SENT:
|
||
SAPI_AllowBindConfirm( ((ZDO_MatchDescRspSent_t *)pMsg)->nwkAddr );
|
||
break;
|
||
|
||
case KEY_CHANGE:
|
||
#if ( SAPI_CB_FUNC )
|
||
zb_HandleKeys( ((keyChange_t *)pMsg)->state, ((keyChange_t *)pMsg)->keys );
|
||
#endif
|
||
break;
|
||
|
||
case SAPICB_DATA_CNF:
|
||
SAPI_SendDataConfirm( (uint8)((sapi_CbackEvent_t *)pMsg)->data,
|
||
((sapi_CbackEvent_t *)pMsg)->hdr.status );
|
||
break;
|
||
|
||
case SAPICB_BIND_CNF:
|
||
SAPI_BindConfirm( ((sapi_CbackEvent_t *)pMsg)->data,
|
||
((sapi_CbackEvent_t *)pMsg)->hdr.status );
|
||
break;
|
||
|
||
case SAPICB_START_CNF:
|
||
SAPI_StartConfirm( ((sapi_CbackEvent_t *)pMsg)->hdr.status );
|
||
break;
|
||
|
||
default:
|
||
// User messages should be handled by user or passed to the application
|
||
if ( pMsg->event >= ZB_USER_MSG )
|
||
{
|
||
|
||
}
|
||
break;
|
||
}
|
||
|
||
// Release the memory
|
||
osal_msg_deallocate( (uint8 *) pMsg );
|
||
|
||
// Next
|
||
pMsg = (osal_event_hdr_t *) osal_msg_receive( task_id );
|
||
}
|
||
|
||
// Return unprocessed events
|
||
return (events ^ SYS_EVENT_MSG);
|
||
}
|
||
|
||
if ( events & ZB_ALLOW_BIND_TIMER )
|
||
{
|
||
afSetMatch(sapi_epDesc.simpleDesc->EndPoint, FALSE);
|
||
return (events ^ ZB_ALLOW_BIND_TIMER);
|
||
}
|
||
|
||
if ( events & ZB_BIND_TIMER )
|
||
{
|
||
// Send bind confirm callback to application
|
||
SAPI_BindConfirm( sapi_bindInProgress, ZB_TIMEOUT );
|
||
sapi_bindInProgress = 0xffff;
|
||
|
||
return (events ^ ZB_BIND_TIMER);
|
||
}
|
||
|
||
if ( events & ZB_ENTRY_EVENT )
|
||
{
|
||
uint8 startOptions;
|
||
|
||
// Give indication to application of device startup
|
||
#if ( SAPI_CB_FUNC )
|
||
zb_HandleOsalEvent( ZB_ENTRY_EVENT );
|
||
#endif
|
||
|
||
// LED off cancels HOLD_AUTO_START blink set in the stack
|
||
HalLedSet (HAL_LED_4, HAL_LED_MODE_OFF);
|
||
|
||
zb_ReadConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8), &startOptions );
|
||
if ( startOptions & ZCD_STARTOPT_AUTO_START )
|
||
{
|
||
zb_StartRequest();
|
||
}
|
||
else
|
||
{
|
||
// blink leds and wait for external input to config and restart
|
||
HalLedBlink(HAL_LED_2, 0, 50, 500);
|
||
}
|
||
|
||
return (events ^ ZB_ENTRY_EVENT );
|
||
}
|
||
|
||
// This must be the last event to be processed
|
||
if ( events & ( ZB_USER_EVENTS ) )
|
||
{
|
||
// User events are passed to the application
|
||
#if ( SAPI_CB_FUNC )
|
||
zb_HandleOsalEvent( events );
|
||
#endif
|
||
|
||
// Do not return here, return 0 later
|
||
}
|
||
|
||
// Discard unknown events
|
||
return 0;
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @fn SAPI_ProcessZDOMsgs()
|
||
*
|
||
* @brief Process response messages
|
||
*
|
||
* @param none
|
||
*
|
||
* @return none
|
||
*/
|
||
void SAPI_ProcessZDOMsgs( zdoIncomingMsg_t *inMsg )
|
||
{
|
||
switch ( inMsg->clusterID )
|
||
{
|
||
case NWK_addr_rsp:
|
||
{
|
||
// Send find device callback to application
|
||
ZDO_NwkIEEEAddrResp_t *pNwkAddrRsp = ZDO_ParseAddrRsp( inMsg );
|
||
SAPI_FindDeviceConfirm( ZB_IEEE_SEARCH, (uint8*)&pNwkAddrRsp->nwkAddr, pNwkAddrRsp->extAddr );
|
||
}
|
||
break;
|
||
|
||
case Match_Desc_rsp:
|
||
{
|
||
zAddrType_t dstAddr;
|
||
ZDO_ActiveEndpointRsp_t *pRsp = ZDO_ParseEPListRsp( inMsg );
|
||
|
||
if ( sapi_bindInProgress != 0xffff )
|
||
{
|
||
// Create a binding table entry
|
||
dstAddr.addrMode = Addr16Bit;
|
||
dstAddr.addr.shortAddr = pRsp->nwkAddr;
|
||
|
||
if ( APSME_BindRequest( sapi_epDesc.simpleDesc->EndPoint,
|
||
sapi_bindInProgress, &dstAddr, pRsp->epList[0] ) == ZSuccess )
|
||
{
|
||
osal_stop_timerEx(sapi_TaskID, ZB_BIND_TIMER);
|
||
osal_start_timerEx( ZDAppTaskID, ZDO_NWK_UPDATE_NV, 250 );
|
||
|
||
// Find IEEE addr
|
||
ZDP_IEEEAddrReq( pRsp->nwkAddr, ZDP_ADDR_REQTYPE_SINGLE, 0, 0 );
|
||
#if defined ( MT_SAPI_CB_FUNC )
|
||
zb_MTCallbackBindConfirm( sapi_bindInProgress, ZB_SUCCESS );
|
||
#endif
|
||
// Send bind confirm callback to application
|
||
#if ( SAPI_CB_FUNC )
|
||
zb_BindConfirm( sapi_bindInProgress, ZB_SUCCESS );
|
||
#endif
|
||
sapi_bindInProgress = 0xffff;
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @fn SAPI_Init
|
||
*
|
||
* @brief Initialization function for the Simple API Task.
|
||
* This is called during initialization and should contain
|
||
* any application specific initialization (ie. hardware
|
||
* initialization/setup, table initialization, power up
|
||
* notification ... ).
|
||
*
|
||
* @param task_id - the ID assigned by OSAL. This ID should be
|
||
* used to send messages and set timers.
|
||
*
|
||
* @return none
|
||
*/
|
||
void SAPI_Init( byte task_id )
|
||
{
|
||
sapi_TaskID = task_id;
|
||
sapi_bindInProgress = 0xffff;
|
||
|
||
sapi_epDesc.task_id = &sapi_TaskID;
|
||
sapi_epDesc.endPoint = 0;
|
||
|
||
#if ( SAPI_CB_FUNC )
|
||
sapi_epDesc.endPoint = zb_SimpleDesc.EndPoint;
|
||
sapi_epDesc.task_id = &sapi_TaskID;
|
||
sapi_epDesc.simpleDesc = (SimpleDescriptionFormat_t *)&zb_SimpleDesc;
|
||
sapi_epDesc.latencyReq = noLatencyReqs;
|
||
|
||
// Register the endpoint/interface description with the AF
|
||
afRegister( &sapi_epDesc );
|
||
#endif
|
||
|
||
// Turn off match descriptor response by default
|
||
afSetMatch(sapi_epDesc.simpleDesc->EndPoint, FALSE);
|
||
|
||
// Register callback evetns from the ZDApp
|
||
ZDO_RegisterForZDOMsg( sapi_TaskID, NWK_addr_rsp );
|
||
ZDO_RegisterForZDOMsg( sapi_TaskID, Match_Desc_rsp );
|
||
|
||
#if ( SAPI_CB_FUNC )
|
||
#if (defined HAL_KEY) && (HAL_KEY == TRUE)
|
||
// Register for HAL events
|
||
RegisterForKeys( sapi_TaskID );
|
||
|
||
if ( HalKeyRead () == HAL_KEY_SW_5)
|
||
{
|
||
// If SW5 is pressed and held while powerup, force auto-start and nv-restore off and reset
|
||
uint8 startOptions = ZCD_STARTOPT_CLEAR_STATE | ZCD_STARTOPT_CLEAR_CONFIG;
|
||
zb_WriteConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8), &startOptions );
|
||
zb_SystemReset();
|
||
}
|
||
#endif // HAL_KEY
|
||
|
||
// Set an event to start the application
|
||
osal_set_event(task_id, ZB_ENTRY_EVENT);
|
||
#endif
|
||
}
|
||
/*********************************************************************
|
||
* @fn SAPI_SendCback
|
||
*
|
||
* @brief Sends a message to the sapi task ( itself ) so that a
|
||
* callback can be generated later.
|
||
*
|
||
* @return none
|
||
*/
|
||
void SAPI_SendCback( uint8 event, uint8 status, uint16 data )
|
||
{
|
||
sapi_CbackEvent_t *pMsg;
|
||
|
||
pMsg = (sapi_CbackEvent_t *)osal_msg_allocate( sizeof(sapi_CbackEvent_t) );
|
||
if( pMsg )
|
||
{
|
||
pMsg->hdr.event = event;
|
||
pMsg->hdr.status = status;
|
||
pMsg->data = data;
|
||
|
||
osal_msg_send( sapi_TaskID, (uint8 *)pMsg );
|
||
}
|
||
|
||
}
|
||
|
||
#if OSAL_SAPI
|
||
/*********************************************************************
|
||
* @fn osalInitTasks
|
||
*
|
||
* @brief This function invokes the initialization function for each task.
|
||
*
|
||
* @param void
|
||
*
|
||
* @return none
|
||
*/
|
||
void osalInitTasks( void )
|
||
{
|
||
uint8 taskID = 0;
|
||
|
||
tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);
|
||
osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));
|
||
|
||
macTaskInit( taskID++ );
|
||
nwk_init( taskID++ );
|
||
Hal_Init( taskID++ );
|
||
#if defined( MT_TASK )
|
||
MT_TaskInit( taskID++ );
|
||
#endif
|
||
APS_Init( taskID++ );
|
||
ZDApp_Init( taskID++ );
|
||
SAPI_Init( taskID );
|
||
}
|
||
#endif
|
||
|
||
/*********************************************************************
|
||
*********************************************************************/
|
||
|