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

2464 lines
71 KiB
C

/******************************************************************************
Filename: zcl_ota.c
Revised: $Date: 2011-07-18 05:10:28 -0700 (Mon, 18 Jul 2011) $
Revision: $Revision: 26827 $
Description: Zigbee Cluster Library - Over-the-Air Upgrade Cluster ( OTA )
Copyright 2010-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 “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 "OSAL.h"
#include "zcl.h"
#include "zcl_general.h"
#include "zcl_ota.h"
#include "ota_common.h"
#include "hal_lcd.h"
#include "hal_led.h"
#include "hal_ota.h"
#include "MT_OTA.h"
#include "ZDProfile.h"
#include "ZDObject.h"
#if defined ( INTER_PAN )
#include "stub_aps.h"
#endif
#if defined OTA_MMO_SIGN
#include "ota_signature.h"
#endif
/******************************************************************************
* MACROS
*/
/******************************************************************************
* CONSTANTS
*/
#define OTA_MAX_TRANSACTIONS 4
#define OTA_TRANSACTION_EXPIRATION 1500
#define ZCL_OTA_HDR_LEN_OFFSET 6 // Header length location in OTA upgrade image
#define ZCL_OTA_STK_VER_OFFSET 18 // Stack version location in OTA upgrade image
/******************************************************************************
* GLOBAL VARIABLES
*/
// OTA attribute variables
uint8 zclOTA_UpgradeServerID[Z_EXTADDR_LEN];
uint32 zclOTA_FileOffset = 0xFFFFFFFF;
uint32 zclOTA_CurrentFileVersion = 0xFFFFFFFF;
uint16 zclOTA_CurrentZigBeeStackVersion;
uint32 zclOTA_DownloadedFileVersion = 0xFFFFFFFF;
uint16 zclOTA_DownloadedZigBeeStackVersion = 0xFFFF;
uint8 zclOTA_ImageUpgradeStatus;
// Other OTA variables
uint16 zclOTA_ManufacturerId; // Manufacturer ID
uint16 zclOTA_ImageType; // Image type
afAddrType_t zclOTA_serverAddr; // Server address
uint8 zclOTA_AppTask = 0xFF; // Callback Task ID
zclOTA_QueryImageRspParams_t queryResponse; // Global variable for sent query response
/******************************************************************************
* LOCAL VARIABLES
*/
// Other OTA variables
// Task ID
static uint8 zclOTA_TaskID;
// Sequence number
static uint8 zclOTA_SeqNo = 0;
static uint8 zclOTA_Permit = TRUE;
#if defined OTA_MMO_SIGN
static OTA_MmoCtrl_t zclOTA_MmoHash;
static uint8 zclOTA_DataToHash[OTA_MMO_HASH_SIZE];
static uint8 zclOTA_HashPos;
static uint8 zclOTA_SignerIEEE[Z_EXTADDR_LEN];
static uint8 zclOTA_SignatureData[OTA_SIGNATURE_LEN];
static uint8 zclOTA_Certificate[OTA_CERTIFICATE_LEN];
#endif // OTA_MMO_SIGN
#if (defined OTA_CLIENT) && (OTA_CLIENT == TRUE)
static uint32 zclOTA_DownloadedImageSize; // Downloaded image size
static uint16 zclOTA_HeaderLen; // Image header length
static uint16 zclOTA_UpdateDelay;
static zclOTA_FileID_t zclOTA_CurrentDlFileId;
static uint16 zclOTA_ElementTag;
static uint32 zclOTA_ElementLen;
static uint32 zclOTA_ElementPos;
// Retry counters
static uint8 zclOTA_BlockRetry;
static uint8 zclOTA_UpgradeEndRetry;
static uint8 zclOTA_ClientPdState;
// OTA Header Magic Number Bytes
static const uint8 zclOTA_HdrMagic[] = {0x1E, 0xF1, 0xEE, 0x0B};
#endif // OTA_CLIENT
/******************************************************************************
* LOCAL FUNCTIONS
*/
static ZStatus_t zclOTA_HdlIncoming( zclIncoming_t *pInMsg );
#if (defined OTA_CLIENT) && (OTA_CLIENT == TRUE)
static void zclOTA_StartTimer(uint16 eventId, uint32 minutes);
static ZStatus_t sendImageBlockReq(afAddrType_t *dstAddr);
static void zclOTA_ProcessZDOMsgs( zdoIncomingMsg_t *pMsg );
static void zclOTA_ImageBlockWaitExpired(void);
static void zclOTA_UpgradeComplete(uint8 status);
static uint8 zclOTA_CmpFileId(zclOTA_FileID_t *f1, zclOTA_FileID_t *f2);
static uint8 zclOTA_ProcessImageData(uint8 *pData, uint8 len);
static ZStatus_t zclOTA_SendQueryNextImageReq( afAddrType_t *dstAddr, zclOTA_QueryNextImageReqParams_t *pParams );
static ZStatus_t zclOTA_SendImageBlockReq( afAddrType_t *dstAddr, zclOTA_ImageBlockReqParams_t *pParams );
static ZStatus_t zclOTA_SendUpgradeEndReq( afAddrType_t *dstAddr, zclOTA_UpgradeEndReqParams_t *pParams );
static ZStatus_t zclOTA_ClientHdlIncoming( zclIncoming_t *pInMsg );
#endif // OTA_CLIENT
#if (defined OTA_SERVER) && (OTA_SERVER == TRUE)
static ZStatus_t zclOTA_SendQueryNextImageRsp( afAddrType_t *dstAddr, zclOTA_QueryImageRspParams_t *pParams );
static ZStatus_t zclOTA_SendImageBlockRsp( afAddrType_t *dstAddr, zclOTA_ImageBlockRspParams_t *pParams );
static ZStatus_t zclOTA_SendUpgradeEndRsp( afAddrType_t *dstAddr, zclOTA_UpgradeEndRspParams_t *pParams );
static ZStatus_t zclOTA_SendQuerySpecificFileRsp( afAddrType_t *dstAddr, zclOTA_QueryImageRspParams_t *pParams );
static ZStatus_t zclOTA_Srv_QueryNextImageReq(afAddrType_t *pSrcAddr, zclOTA_QueryNextImageReqParams_t *pParam);
static ZStatus_t zclOTA_Srv_ImageBlockReq(afAddrType_t *pSrcAddr, zclOTA_ImageBlockReqParams_t *pParam);
static ZStatus_t zclOTA_Srv_ImagePageReq(afAddrType_t *pSrcAddr, zclOTA_ImagePageReqParams_t *pParam);
static ZStatus_t zclOTA_Srv_UpgradeEndReq(afAddrType_t *pSrcAddr, zclOTA_UpgradeEndReqParams_t *pParam);
static ZStatus_t zclOTA_Srv_QuerySpecificFileReq(afAddrType_t *pSrcAddr, zclOTA_QuerySpecificFileReqParams_t *pParam);
static void zclOTA_ProcessNextImgRsp(uint8* pMSGpkt, zclOTA_FileID_t *pFileId, afAddrType_t *pAddr);
static void zclOTA_ProcessFileReadRsp(uint8* pMSGpkt, zclOTA_FileID_t *pFileId, afAddrType_t *pAddr);
static void zclOTA_ServerHandleFileSysCb(OTA_MtMsg_t* pMSGpkt);
static ZStatus_t zclOTA_ServerHdlIncoming( zclIncoming_t *pInMsg );
#endif // OTA_SERVER
/******************************************************************************
* OTA ATTRIBUTE DEFINITIONS - Uses REAL cluster IDs
*/
#define ZCL_OTA_MAX_ATTRIBUTES 7
CONST zclAttrRec_t zclOTA_Attrs[ZCL_OTA_MAX_ATTRIBUTES] =
{
{
ZCL_CLUSTER_ID_OTA, // Cluster IDs - defined in the foundation (ie. zcl.h)
{ // Attribute record
ATTRID_UPGRADE_SERVER_ID, // Attribute ID - Found in Cluster Library header (ie. zcl_general.h)
ZCL_DATATYPE_IEEE_ADDR, // Data Type - found in zcl.h
ACCESS_CONTROL_READ, // Variable access control - found in zcl.h
(void *)&zclOTA_UpgradeServerID // Pointer to attribute variable
}
},
{
ZCL_CLUSTER_ID_OTA,
{ // Attribute record
ATTRID_FILE_OFFSET,
ZCL_DATATYPE_UINT32,
ACCESS_CONTROL_READ,
(void *)&zclOTA_FileOffset
}
},
{
ZCL_CLUSTER_ID_OTA,
{ // Attribute record
ATTRID_CURRENT_FILE_VERSION,
ZCL_DATATYPE_UINT32,
ACCESS_CONTROL_READ,
(void *)&zclOTA_CurrentFileVersion
}
},
{
ZCL_CLUSTER_ID_OTA,
{ // Attribute record
ATTRID_CURRENT_ZIGBEE_STACK_VERSION,
ZCL_DATATYPE_UINT16,
ACCESS_CONTROL_READ,
(void *)&zclOTA_CurrentZigBeeStackVersion
}
},
{
ZCL_CLUSTER_ID_OTA,
{ // Attribute record
ATTRID_DOWNLOADED_FILE_VERSION,
ZCL_DATATYPE_UINT32,
ACCESS_CONTROL_READ,
(void *)&zclOTA_DownloadedFileVersion
}
},
{
ZCL_CLUSTER_ID_OTA,
{ // Attribute record
ATTRID_DOWNLOADED_ZIGBEE_STACK_VERSION,
ZCL_DATATYPE_UINT16,
ACCESS_CONTROL_READ,
(void *)&zclOTA_DownloadedZigBeeStackVersion
}
},
{
ZCL_CLUSTER_ID_OTA,
{ // Attribute record
ATTRID_IMAGE_UPGRADE_STATUS,
ZCL_DATATYPE_UINT8,
ACCESS_CONTROL_READ,
(void *)&zclOTA_ImageUpgradeStatus
}
}
};
/******************************************************************************
* OTA SIMPLE DESCRIPTOR
*/
#ifndef OTA_HA
#define ZCL_OTA_MAX_OPTIONS 1
zclOptionRec_t zclOta_Options[ZCL_OTA_MAX_OPTIONS] =
{
{
ZCL_CLUSTER_ID_OTA,
( AF_EN_SECURITY | AF_ACK_REQUEST ),
},
};
#endif // OTA_HA
#if defined OTA_SERVER && (OTA_SERVER == TRUE)
// Cluster ID list for match descriptor of the OTA Server.
#define ZCL_OTA_MAX_INCLUSTERS 1
const cId_t zclOTA_InClusterList[ZCL_OTA_MAX_INCLUSTERS] =
{
ZCL_CLUSTER_ID_OTA
};
#else
#define ZCL_OTA_MAX_INCLUSTERS 0
#define zclOTA_InClusterList NULL
#endif // OTA_SERVER
#if defined OTA_CLIENT && (OTA_CLIENT == TRUE)
// Cluster ID list for match descriptor of the OTA Client.
#define ZCL_OTA_MAX_OUTCLUSTERS 1
const cId_t zclOTA_OutClusterList[ZCL_OTA_MAX_OUTCLUSTERS] =
{
ZCL_CLUSTER_ID_OTA
};
#else
#define ZCL_OTA_MAX_OUTCLUSTERS 0
#define zclOTA_OutClusterList NULL
#endif // OTA_CLIENT
SimpleDescriptionFormat_t zclOTA_SimpleDesc =
{
ZCL_OTA_ENDPOINT, // int Endpoint;
ZCL_OTA_SAMPLE_PROFILE_ID, // uint16 AppProfId[2];
ZCL_OTA_SAMPLE_DEVICEID, // uint16 AppDeviceId[2];
ZCL_OTA_DEVICE_VERSION, // int AppDevVer:4;
ZCL_OTA_FLAGS, // int AppFlags:4;
ZCL_OTA_MAX_INCLUSTERS, // byte AppNumInClusters;
(cId_t *)zclOTA_InClusterList, // byte *pAppInClusterList;
ZCL_OTA_MAX_OUTCLUSTERS, // byte AppNumInClusters;
(cId_t *)zclOTA_OutClusterList // byte *pAppInClusterList;
};
// Endpoint for OTA Cluster
static endPointDesc_t zclOTA_Ep =
{
ZCL_OTA_ENDPOINT,
&zcl_TaskID,
(SimpleDescriptionFormat_t *)&zclOTA_SimpleDesc,
(afNetworkLatencyReq_t) 0
};
/******************************************************************************
* @fn zclOTA_PermitOta
*
* @brief Called to enable/disable OTA operation.
*
* @param permit - TRUE to enable OTA, FALSE to diable OTA
*
* @return none
*/
void zclOTA_PermitOta(uint8 permit)
{
zclOTA_Permit = permit;
}
/******************************************************************************
* @fn zclOTA_Register
*
* @brief Called by an application to register for callback messages
* from the OTA.
*
* @param applicationTaskId - Application Task ID
*
* @return none
*/
void zclOTA_Register(uint8 applicationTaskId)
{
zclOTA_AppTask = applicationTaskId;
}
/******************************************************************************
* @fn zclOTA_RequestNextUpdate
*
* @brief Called by an application after discovery of the OTA server
* to initiate the query next image of the OTA server.
*
* @param srvAddr - Short address of the server
* @param srvEndPoint - Endpoint on the server
*
* @return ZStatus_t
*/
void zclOTA_RequestNextUpdate(uint16 srvAddr, uint8 srvEndPoint)
{
// Record the server address
zclOTA_serverAddr.addrMode = afAddr16Bit;
zclOTA_serverAddr.endPoint = srvEndPoint;
zclOTA_serverAddr.addr.shortAddr = srvAddr;
// Set an event to query the server
osal_set_event(zclOTA_TaskID, ZCL_OTA_QUERY_SERVER_EVT);
}
/******************************************************************************
* @fn zclOTA_Init
*
* @brief Call to initialize the OTA Client Task
*
* @param task_id
*
* @return none
*/
void zclOTA_Init( uint8 task_id )
{
zclOTA_TaskID = task_id;
// Register for the cluster endpoint
afRegister( &zclOTA_Ep );
// Register as a ZCL Plugin
zcl_registerPlugin( ZCL_CLUSTER_ID_OTA,
ZCL_CLUSTER_ID_OTA,
zclOTA_HdlIncoming );
// Initialize attribute variables
zclOTA_CurrentZigBeeStackVersion = OTA_STACK_VER_PRO;
zclOTA_ImageUpgradeStatus = OTA_STATUS_NORMAL;
// Register attribute list
zcl_registerAttrList( ZCL_OTA_ENDPOINT,
ZCL_OTA_MAX_ATTRIBUTES,
zclOTA_Attrs );
#ifndef OTA_HA
// Register the application's cluster option list
zcl_registerClusterOptionList( ZCL_OTA_ENDPOINT, ZCL_OTA_MAX_OPTIONS, zclOta_Options );
#endif // OTA_HA
// Register with the ZDO to receive Network Address Responses
ZDO_RegisterForZDOMsg(task_id, IEEE_addr_rsp);
// The default upgradeServerID is FF:FF:FF:FF:FF:FF:FF:FF
osal_memset(zclOTA_UpgradeServerID, 0xFF, sizeof(zclOTA_UpgradeServerID));
#if defined (OTA_SERVER) && (OTA_SERVER == TRUE)
// Register with the files system
MT_OtaRegister(task_id);
#endif // OTA_SERVER
}
/******************************************************************************
* @fn zclOTA_event_loop
*
* @brief Event Loop Processor for OTA Client task.
*
* @param task_id - TaskId
* events - events
*
* @return Unprocessed event bits
*/
uint16 zclOTA_event_loop( uint8 task_id, uint16 events )
{
afIncomingMSGPacket_t *MSGpkt;
if ( events & SYS_EVENT_MSG )
{
while ( (MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( task_id )) )
{
switch ( MSGpkt->hdr.event )
{
#if (defined OTA_CLIENT) && (OTA_CLIENT == TRUE)
case ZDO_CB_MSG:
zclOTA_ProcessZDOMsgs( (zdoIncomingMsg_t *)MSGpkt );
break;
#endif // OTA_CLIENT
#if (defined OTA_SERVER) && (OTA_SERVER == TRUE)
case MT_SYS_OTA_MSG:
zclOTA_ServerHandleFileSysCb((OTA_MtMsg_t*)MSGpkt);
break;
#endif
default:
break;
}
// Release the memory
osal_msg_deallocate( (uint8 *)MSGpkt );
}
// return unprocessed events
return (events ^ SYS_EVENT_MSG);
}
#if (defined OTA_CLIENT) && (OTA_CLIENT == TRUE)
if ( events & ZCL_OTA_IMAGE_BLOCK_WAIT_EVT )
{
// If the time has expired, perform the required action
if (zclOTA_UpdateDelay == 0)
{
zclOTA_ImageBlockWaitExpired();
}
else
{
// Decrement the number of minutes to wait and reset the timer
zclOTA_UpdateDelay--;
osal_start_timerEx(zclOTA_TaskID, ZCL_OTA_IMAGE_BLOCK_WAIT_EVT, 60000);
}
return ( events ^ ZCL_OTA_IMAGE_BLOCK_WAIT_EVT );
}
if ( events & ZCL_OTA_UPGRADE_WAIT_EVT )
{
// If the time has expired, perform the required action
if (zclOTA_UpdateDelay == 0)
{
if (zclOTA_ImageUpgradeStatus == OTA_STATUS_COUNTDOWN)
{
zclOTA_UpgradeComplete(ZSuccess);
}
else if (zclOTA_ImageUpgradeStatus == OTA_STATUS_UPGRADE_WAIT)
{
if (++zclOTA_UpgradeEndRetry > OTA_MAX_END_REQ_RETRIES)
{
// If we have not heard from the server for N retries, perform the upgrade
zclOTA_UpgradeComplete(ZSuccess);
}
else
{
// Send another update end request
zclOTA_UpgradeEndReqParams_t req;
req.status = ZSuccess;
osal_memcpy(&req.fileId, &zclOTA_CurrentDlFileId, sizeof(zclOTA_FileID_t));
zclOTA_SendUpgradeEndReq(&zclOTA_serverAddr, &req);
// Restart the timer for another hour
zclOTA_StartTimer(ZCL_OTA_UPGRADE_WAIT_EVT, 3600);
}
}
}
else
{
// Decrement the number of minutes to wait and reset the timer
zclOTA_UpdateDelay--;
osal_start_timerEx(zclOTA_TaskID, ZCL_OTA_UPGRADE_WAIT_EVT, 60000);
}
return ( events ^ ZCL_OTA_UPGRADE_WAIT_EVT );
}
if (events & ZCL_OTA_IMAGE_QUERY_TO_EVT )
{
if (zclOTA_ImageUpgradeStatus == OTA_STATUS_NORMAL)
{
// Notify the application task of the timeout waiting for the download to start
zclOTA_CallbackMsg_t *pMsg;
pMsg = (zclOTA_CallbackMsg_t*) osal_msg_allocate(sizeof(zclOTA_CallbackMsg_t));
if (pMsg)
{
pMsg->hdr.event = ZCL_OTA_CALLBACK_IND;
pMsg->hdr.status = ZFailure;
pMsg->ota_event = ZCL_OTA_START_CALLBACK;
osal_msg_send(zclOTA_AppTask, (uint8*) pMsg);
}
}
return ( events ^ ZCL_OTA_IMAGE_QUERY_TO_EVT );
}
if (events & ZCL_OTA_BLOCK_RSP_TO_EVT )
{
// We timed out waiting for a Block Response
if (++zclOTA_BlockRetry > OTA_MAX_BLOCK_RETRIES)
{
// Send a failed update end request
zclOTA_UpgradeEndReqParams_t req;
req.status = ZOtaAbort;
osal_memcpy(&req.fileId, &zclOTA_CurrentDlFileId, sizeof(zclOTA_FileID_t));
zclOTA_SendUpgradeEndReq(&zclOTA_serverAddr, &req);
zclOTA_UpgradeComplete(ZOtaAbort);
}
else
{
// Send another block request
sendImageBlockReq(&zclOTA_serverAddr);
}
return ( events ^ ZCL_OTA_BLOCK_RSP_TO_EVT );
}
if (events & ZCL_OTA_QUERY_SERVER_EVT )
{
zclOTA_QueryNextImageReqParams_t queryParams;
queryParams.fieldControl = 0;
queryParams.fileId.manufacturer = OTA_MANUFACTURER_ID;
queryParams.fileId.type = OTA_TYPE_ID;
queryParams.fileId.version = zclOTA_CurrentFileVersion;
zclOTA_SendQueryNextImageReq(&zclOTA_serverAddr, &queryParams);
// Set a timer to wait for the response
osal_start_timerEx(zclOTA_TaskID, ZCL_OTA_IMAGE_QUERY_TO_EVT, 10000);
return ( events ^ ZCL_OTA_QUERY_SERVER_EVT );
}
#endif // OTA_CLIENT
// Discard unknown events
return 0;
}
/******************************************************************************
* @fn zclOTA_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 zclOTA_HdlIncoming( zclIncoming_t *pInMsg )
{
ZStatus_t stat = ZSuccess;
if ( zcl_ClusterCmd( pInMsg->hdr.fc.type ) )
{
// Is this a manufacturer specific command?
if ( pInMsg->hdr.fc.manuSpecific == 0 )
{
// Is command for server?
if ( zcl_ServerCmd( pInMsg->hdr.fc.direction ) )
{
#if (defined OTA_SERVER) && (OTA_SERVER == TRUE)
stat = zclOTA_ServerHdlIncoming( pInMsg );
#else
stat = ZCL_STATUS_UNSUP_CLUSTER_COMMAND;
#endif // OTA_SERVER
}
else // Else command is for client
{
#if (defined OTA_CLIENT) && (OTA_CLIENT == TRUE)
stat = zclOTA_ClientHdlIncoming( pInMsg );
#else
stat = ZCL_STATUS_UNSUP_CLUSTER_COMMAND;
#endif // OTA_CLIENT
}
}
else
{
// We don't support any manufacturer specific command.
stat = ZCL_STATUS_UNSUP_MANU_CLUSTER_COMMAND;
}
}
else
{
// Handle all the normal (Read, Write...) commands -- should never get here
stat = ZFailure;
}
return ( stat );
}
#if (defined OTA_SERVER) && (OTA_SERVER == TRUE)
/******************************************************************************
* @fn zclOTA_SendImageNotify
*
* @brief Send an OTA Image Notify message.
*
* @param dstAddr - where you want the message to go
* @param pParams - message parameters
*
* @return ZStatus_t
*/
ZStatus_t zclOTA_SendImageNotify( afAddrType_t *dstAddr,
zclOTA_ImageNotifyParams_t *pParams )
{
ZStatus_t status;
uint8 buf[PAYLOAD_MAX_LEN_IMAGE_NOTIFY];
uint8 *pBuf = buf;
*pBuf++ = pParams->payloadType;
*pBuf++ = pParams->queryJitter;
if (pParams->payloadType >= NOTIFY_PAYLOAD_JITTER_MFG)
{
*pBuf++ = LO_UINT16(pParams->fileId.manufacturer);
*pBuf++ = HI_UINT16(pParams->fileId.manufacturer);
}
if (pParams->payloadType >= NOTIFY_PAYLOAD_JITTER_MFG_TYPE)
{
*pBuf++ = LO_UINT16(pParams->fileId.type);
*pBuf++ = HI_UINT16(pParams->fileId.type);
}
if (pParams->payloadType == NOTIFY_PAYLOAD_JITTER_MFG_TYPE_VERS)
{
pBuf = osal_buffer_uint32(pBuf, pParams->fileId.version);
}
status = zcl_SendCommand( ZCL_OTA_ENDPOINT, dstAddr, ZCL_CLUSTER_ID_OTA,
COMMAND_IMAGE_NOTIFY, TRUE,
ZCL_FRAME_SERVER_CLIENT_DIR, TRUE, 0,
zclOTA_SeqNo++, (uint16) (pBuf - buf), buf );
return status;
}
/******************************************************************************
* @fn zclOTA_SendQueryNextImageRsp
*
* @brief Send an OTA Query Next Image Response message.
*
* @param dstAddr - where you want the message to go
* @param pParams - message parameters
*
* @return ZStatus_t
*/
ZStatus_t zclOTA_SendQueryNextImageRsp( afAddrType_t *dstAddr,
zclOTA_QueryImageRspParams_t *pParams )
{
ZStatus_t status;
uint8 buf[PAYLOAD_MAX_LEN_QUERY_NEXT_IMAGE_RSP];
uint8 *pBuf = buf;
*pBuf++ = pParams->status;
if (pParams->status == ZCL_STATUS_SUCCESS)
{
*pBuf++ = LO_UINT16(pParams->fileId.manufacturer);
*pBuf++ = HI_UINT16(pParams->fileId.manufacturer);
*pBuf++ = LO_UINT16(pParams->fileId.type);
*pBuf++ = HI_UINT16(pParams->fileId.type);
pBuf = osal_buffer_uint32(pBuf, pParams->fileId.version);
pBuf = osal_buffer_uint32(pBuf, pParams->imageSize);
}
status = zcl_SendCommand( ZCL_OTA_ENDPOINT, dstAddr, ZCL_CLUSTER_ID_OTA,
COMMAND_QUERY_NEXT_IMAGE_RSP, TRUE,
ZCL_FRAME_SERVER_CLIENT_DIR, TRUE, 0,
zclOTA_SeqNo++, (uint16) (pBuf - buf), buf );
return status;
}
/******************************************************************************
* @fn zclOTA_SendImageBlockRsp
*
* @brief Send an OTA Image Block Response mesage.
*
* @param dstAddr - where you want the message to go
* @param pParams - message parameters
*
* @return ZStatus_t
*/
ZStatus_t zclOTA_SendImageBlockRsp( afAddrType_t *dstAddr,
zclOTA_ImageBlockRspParams_t *pParams )
{
uint8 *buf;
uint8 *pBuf;
ZStatus_t status;
uint8 len;
if (pParams->status == ZCL_STATUS_SUCCESS)
{
len = PAYLOAD_MAX_LEN_IMAGE_BLOCK_RSP + pParams->rsp.success.dataSize;
}
else if (pParams->status == ZCL_STATUS_WAIT_FOR_DATA)
{
len = PAYLOAD_MIN_LEN_IMAGE_BLOCK_WAIT;
}
else
{
len = 1;
}
buf = osal_mem_alloc( len );
if ( buf == NULL )
{
return (ZMemError);
}
pBuf = buf;
*pBuf++ = pParams->status;
if (pParams->status == ZCL_STATUS_SUCCESS)
{
*pBuf++ = LO_UINT16(pParams->rsp.success.fileId.manufacturer);
*pBuf++ = HI_UINT16(pParams->rsp.success.fileId.manufacturer);
*pBuf++ = LO_UINT16(pParams->rsp.success.fileId.type);
*pBuf++ = HI_UINT16(pParams->rsp.success.fileId.type);
pBuf = osal_buffer_uint32(pBuf, pParams->rsp.success.fileId.version);
pBuf = osal_buffer_uint32(pBuf, pParams->rsp.success.fileOffset);
*pBuf++ = pParams->rsp.success.dataSize;
osal_memcpy(pBuf, pParams->rsp.success.pData, pParams->rsp.success.dataSize);
}
else if (pParams->status == ZCL_STATUS_WAIT_FOR_DATA)
{
pBuf = osal_buffer_uint32(pBuf, pParams->rsp.wait.currentTime);
pBuf = osal_buffer_uint32(pBuf, pParams->rsp.wait.requestTime);
}
status = zcl_SendCommand( ZCL_OTA_ENDPOINT, dstAddr, ZCL_CLUSTER_ID_OTA,
COMMAND_IMAGE_BLOCK_RSP, TRUE,
ZCL_FRAME_SERVER_CLIENT_DIR, TRUE, 0,
zclOTA_SeqNo++, len, buf );
osal_mem_free(buf);
return status;
}
/******************************************************************************
* @fn zclOTA_SendUpgradeEndRsp
*
* @brief Send an OTA Upgrade End Response mesage.
*
* @param dstAddr - where you want the message to go
* @param pParams - message parameters
*
* @return ZStatus_t
*/
ZStatus_t zclOTA_SendUpgradeEndRsp( afAddrType_t *dstAddr,
zclOTA_UpgradeEndRspParams_t *pParams )
{
ZStatus_t status;
uint8 buf[PAYLOAD_MAX_LEN_UPGRADE_END_RSP];
uint8 *pBuf = buf;
*pBuf++ = LO_UINT16(pParams->fileId.manufacturer);
*pBuf++ = HI_UINT16(pParams->fileId.manufacturer);
*pBuf++ = LO_UINT16(pParams->fileId.type);
*pBuf++ = HI_UINT16(pParams->fileId.type);
pBuf = osal_buffer_uint32(pBuf, pParams->fileId.version);
pBuf = osal_buffer_uint32(pBuf, pParams->currentTime);
pBuf = osal_buffer_uint32(pBuf, pParams->upgradeTime);
status = zcl_SendCommand( ZCL_OTA_ENDPOINT, dstAddr, ZCL_CLUSTER_ID_OTA,
COMMAND_UPGRADE_END_RSP, TRUE,
ZCL_FRAME_SERVER_CLIENT_DIR, TRUE, 0,
zclOTA_SeqNo++, PAYLOAD_MAX_LEN_UPGRADE_END_RSP, buf );
return status;
}
/******************************************************************************
* @fn zclOTA_SendQuerySpecificFileRsp
*
* @brief Send an OTA Query Specific File Response mesage.
*
* @param dstAddr - where you want the message to go
* @param pParams - message parameters
*
* @return ZStatus_t
*/
ZStatus_t zclOTA_SendQuerySpecificFileRsp( afAddrType_t *dstAddr,
zclOTA_QueryImageRspParams_t *pParams )
{
ZStatus_t status;
uint8 buf[PAYLOAD_MAX_LEN_QUERY_SPECIFIC_FILE_RSP];
uint8 *pBuf = buf;
*pBuf++ = pParams->status;
if (pParams->status == ZCL_STATUS_SUCCESS)
{
*pBuf++ = LO_UINT16(pParams->fileId.manufacturer);
*pBuf++ = HI_UINT16(pParams->fileId.manufacturer);
*pBuf++ = LO_UINT16(pParams->fileId.type);
*pBuf++ = HI_UINT16(pParams->fileId.type);
pBuf = osal_buffer_uint32(pBuf, pParams->fileId.version);
pBuf = osal_buffer_uint32(pBuf, pParams->imageSize);
}
status = zcl_SendCommand( ZCL_OTA_ENDPOINT, dstAddr, ZCL_CLUSTER_ID_OTA,
COMMAND_QUERY_SPECIFIC_FILE_RSP, TRUE,
ZCL_FRAME_SERVER_CLIENT_DIR, TRUE, 0,
zclOTA_SeqNo++, (uint16) (pBuf - buf), buf );
return status;
}
#endif // OTA_SERVER
#if (defined OTA_CLIENT) && (OTA_CLIENT == TRUE)
/******************************************************************************
* @fn zclOTA_SendQueryNextImageReq
*
* @brief Send an OTA Query Next Image Request mesage.
*
* @param dstAddr - where you want the message to go
* @param pParams - message parameters
*
* @return ZStatus_t
*/
ZStatus_t zclOTA_SendQueryNextImageReq( afAddrType_t *dstAddr,
zclOTA_QueryNextImageReqParams_t *pParams )
{
ZStatus_t status;
uint8 buf[PAYLOAD_MAX_LEN_QUERY_NEXT_IMAGE_REQ];
uint8 *pBuf = buf;
*pBuf++ = pParams->fieldControl;
*pBuf++ = LO_UINT16(pParams->fileId.manufacturer);
*pBuf++ = HI_UINT16(pParams->fileId.manufacturer);
*pBuf++ = LO_UINT16(pParams->fileId.type);
*pBuf++ = HI_UINT16(pParams->fileId.type);
pBuf = osal_buffer_uint32(pBuf, pParams->fileId.version);
if (pParams->fieldControl == 1)
{
*pBuf++ = LO_UINT16(pParams->hardwareVersion);
*pBuf++ = HI_UINT16(pParams->hardwareVersion);
}
status = zcl_SendCommand( ZCL_OTA_ENDPOINT, dstAddr, ZCL_CLUSTER_ID_OTA,
COMMAND_QUERY_NEXT_IMAGE_REQ, TRUE,
ZCL_FRAME_CLIENT_SERVER_DIR, FALSE, 0,
zclOTA_SeqNo++, (uint16) (pBuf - buf), buf );
return status;
}
/******************************************************************************
* @fn zclOTA_SendImageBlockReq
*
* @brief Send an OTA Image Block Request mesage.
*
* @param dstAddr - where you want the message to go
* @param pParams - message parameters
*
* @return ZStatus_t
*/
ZStatus_t zclOTA_SendImageBlockReq( afAddrType_t *dstAddr,
zclOTA_ImageBlockReqParams_t *pParams )
{
ZStatus_t status;
uint8 buf[PAYLOAD_MAX_LEN_IMAGE_BLOCK_REQ];
uint8 *pBuf = buf;
*pBuf++ = pParams->fieldControl;
*pBuf++ = LO_UINT16(pParams->fileId.manufacturer);
*pBuf++ = HI_UINT16(pParams->fileId.manufacturer);
*pBuf++ = LO_UINT16(pParams->fileId.type);
*pBuf++ = HI_UINT16(pParams->fileId.type);
pBuf = osal_buffer_uint32(pBuf, pParams->fileId.version);
pBuf = osal_buffer_uint32(pBuf, pParams->fileOffset);
*pBuf++ = pParams->maxDataSize;
if (pParams->fieldControl == 1)
{
osal_cpyExtAddr(pBuf, pParams->nodeAddr);
pBuf += Z_EXTADDR_LEN;
}
status = zcl_SendCommand( ZCL_OTA_ENDPOINT, dstAddr, ZCL_CLUSTER_ID_OTA,
COMMAND_IMAGE_BLOCK_REQ, TRUE,
ZCL_FRAME_CLIENT_SERVER_DIR, FALSE, 0,
zclOTA_SeqNo++, (uint16) (pBuf - buf), buf );
return status;
}
/******************************************************************************
* @fn zclOTA_SendUpgradeEndReq
*
* @brief Send an OTA Upgrade End Request mesage.
*
* @param dstAddr - where you want the message to go
* @param pParams - message parameters
*
* @return ZStatus_t
*/
ZStatus_t zclOTA_SendUpgradeEndReq( afAddrType_t *dstAddr,
zclOTA_UpgradeEndReqParams_t *pParams )
{
ZStatus_t status;
uint8 buf[PAYLOAD_MAX_LEN_UPGRADE_END_REQ];
uint8 *pBuf = buf;
*pBuf++ = pParams->status;
*pBuf++ = LO_UINT16(pParams->fileId.manufacturer);
*pBuf++ = HI_UINT16(pParams->fileId.manufacturer);
*pBuf++ = LO_UINT16(pParams->fileId.type);
*pBuf++ = HI_UINT16(pParams->fileId.type);
pBuf = osal_buffer_uint32(pBuf, pParams->fileId.version);
status = zcl_SendCommand( ZCL_OTA_ENDPOINT, dstAddr, ZCL_CLUSTER_ID_OTA,
COMMAND_UPGRADE_END_REQ, TRUE,
ZCL_FRAME_CLIENT_SERVER_DIR, FALSE, 0,
zclOTA_SeqNo++, (uint16) (pBuf - buf), buf );
return status;
}
/******************************************************************************
* @fn zclOTA_StartTimer
*
* @brief Start a ZCL OTA timer.
*
* @param eventId - OSAL event set on timer expiration
* @param seconds - timeout in seconds
*
* @return None
*/
static void zclOTA_StartTimer(uint16 eventId, uint32 seconds)
{
// Record the number of whole minutes to wait
zclOTA_UpdateDelay = (seconds / 60);
// Set a timer for the remaining seconds to wait.
osal_start_timerEx(zclOTA_TaskID, eventId, (seconds % 60) * 1000);
}
/******************************************************************************
* @fn sendImageBlockReq
*
* @brief Send an Image Block Request.
*
* @param dstAddr - where you want the message to go
*
* @return ZStatus_t
*/
static ZStatus_t sendImageBlockReq(afAddrType_t *dstAddr)
{
zclOTA_ImageBlockReqParams_t req;
req.fieldControl = 0;
req.fileId.manufacturer = zclOTA_ManufacturerId;
req.fileId.type = zclOTA_ImageType;
req.fileId.version = zclOTA_DownloadedFileVersion;
req.fileOffset = zclOTA_FileOffset;
if (zclOTA_DownloadedImageSize - zclOTA_FileOffset < OTA_MAX_MTU)
{
req.maxDataSize = zclOTA_DownloadedImageSize - zclOTA_FileOffset;
}
else
{
req.maxDataSize = OTA_MAX_MTU;
}
// Start a timer waiting for a response
osal_start_timerEx(zclOTA_TaskID, ZCL_OTA_BLOCK_RSP_TO_EVT, OTA_MAX_BLOCK_RSP_WAIT_TIME);
return zclOTA_SendImageBlockReq( dstAddr, &req);
}
/******************************************************************************
* @fn zclOTA_ProcessImageData
*
* @brief Process image data as it is received from the host.
*
* @param pData - pointer to the data
* @param len - length of the data
*
* @return status of the operation
*/
uint8 zclOTA_ProcessImageData(uint8 *pData, uint8 len)
{
int8 i;
#if defined OTA_MMO_SIGN
uint8 skipHash = FALSE;
#endif
if (zclOTA_ImageUpgradeStatus != OTA_STATUS_IN_PROGRESS)
{
return ZCL_STATUS_ABORT;
}
#if (defined HAL_LED) && (HAL_LED == TRUE)
// Toggle an LED to indicate we received a new block
HalLedSet(HAL_LED_2, HAL_LED_MODE_TOGGLE);
#endif
// write data to secondary storage
HalOTAWrite(zclOTA_FileOffset, pData, len, HAL_OTA_DL);
for (i=0; i<len; i++)
{
#if defined OTA_MMO_SIGN
// Skip the hash if we are receiving the signature element
if ((zclOTA_ClientPdState >= ZCL_OTA_PD_ELEM_LEN1_STATE) &&
(zclOTA_ClientPdState <= ZCL_OTA_PD_ELEMENT_STATE))
{
if (zclOTA_ElementTag == OTA_ECDSA_SIGNATURE_TAG_ID)
{
skipHash = TRUE;
}
}
#endif
switch (zclOTA_ClientPdState)
{
// verify header magic number
case ZCL_OTA_PD_MAGIC_0_STATE:
// Initialize control variables
#if defined OTA_MMO_SIGN
osal_memset(&zclOTA_MmoHash, 0, sizeof(zclOTA_MmoHash));
zclOTA_HashPos = 0;
#endif
// Missing break intended
case ZCL_OTA_PD_MAGIC_1_STATE:
case ZCL_OTA_PD_MAGIC_2_STATE:
case ZCL_OTA_PD_MAGIC_3_STATE:
if (pData[i] != zclOTA_HdrMagic[zclOTA_ClientPdState])
{
return ZCL_STATUS_INVALID_IMAGE;
}
zclOTA_ClientPdState++;
break;
case ZCL_OTA_PD_HDR_LEN1_STATE:
// get header length
if (zclOTA_FileOffset == ZCL_OTA_HDR_LEN_OFFSET)
{
zclOTA_HeaderLen = pData[i];
zclOTA_ClientPdState = ZCL_OTA_PD_HDR_LEN2_STATE;
}
break;
case ZCL_OTA_PD_HDR_LEN2_STATE:
zclOTA_HeaderLen |= (((uint16)pData[i]) << 8) & 0xFF00;
zclOTA_ClientPdState = ZCL_OTA_PD_STK_VER1_STATE;
break;
case ZCL_OTA_PD_STK_VER1_STATE:
// get stack version
if (zclOTA_FileOffset == ZCL_OTA_STK_VER_OFFSET)
{
zclOTA_DownloadedZigBeeStackVersion = pData[i];
zclOTA_ClientPdState = ZCL_OTA_PD_STK_VER2_STATE;
}
break;
case ZCL_OTA_PD_STK_VER2_STATE:
zclOTA_DownloadedZigBeeStackVersion |= (((uint16)pData[i]) << 8) & 0xFF00;
zclOTA_ClientPdState = ZCL_OTA_PD_CONT_HDR_STATE;
if (zclOTA_DownloadedZigBeeStackVersion != OTA_HDR_STACK_VERSION)
{
return ZCL_STATUS_INVALID_IMAGE;
}
break;
case ZCL_OTA_PD_CONT_HDR_STATE:
// Complete the header
if (zclOTA_FileOffset == zclOTA_HeaderLen-1)
{
zclOTA_ClientPdState = ZCL_OTA_PD_ELEM_TAG1_STATE;
}
break;
case ZCL_OTA_PD_ELEM_TAG1_STATE:
zclOTA_ElementTag = pData[i];
zclOTA_ClientPdState = ZCL_OTA_PD_ELEM_TAG2_STATE;
break;
case ZCL_OTA_PD_ELEM_TAG2_STATE:
zclOTA_ElementTag |= (((uint16)pData[i]) << 8) & 0xFF00;
zclOTA_ElementPos = 0;
zclOTA_ClientPdState = ZCL_OTA_PD_ELEM_LEN1_STATE;
break;
case ZCL_OTA_PD_ELEM_LEN1_STATE:
zclOTA_ElementLen = pData[i];
zclOTA_ClientPdState = ZCL_OTA_PD_ELEM_LEN2_STATE;
break;
case ZCL_OTA_PD_ELEM_LEN2_STATE:
zclOTA_ElementLen |= ((uint32)pData[i] << 8) & 0x0000FF00;
zclOTA_ClientPdState = ZCL_OTA_PD_ELEM_LEN3_STATE;
break;
case ZCL_OTA_PD_ELEM_LEN3_STATE:
zclOTA_ElementLen |= ((uint32)pData[i] << 16) & 0x00FF0000;
zclOTA_ClientPdState = ZCL_OTA_PD_ELEM_LEN4_STATE;
break;
case ZCL_OTA_PD_ELEM_LEN4_STATE:
zclOTA_ElementLen |= ((uint32)pData[i] << 24) & 0xFF000000;
zclOTA_ClientPdState = ZCL_OTA_PD_ELEMENT_STATE;
// Make sure the length of the element isn't bigger than the image
if (zclOTA_ElementLen > (zclOTA_DownloadedImageSize - zclOTA_FileOffset))
{
return ZCL_STATUS_INVALID_IMAGE;
}
#if defined OTA_MMO_SIGN
if (zclOTA_ElementTag == OTA_ECDSA_SIGNATURE_TAG_ID)
{
if (zclOTA_ElementLen != OTA_SIGNATURE_LEN + Z_EXTADDR_LEN)
{
return ZCL_STATUS_INVALID_IMAGE;
}
}
else if (zclOTA_ElementTag == OTA_ECDSA_CERT_TAG_ID)
{
if (zclOTA_ElementLen != OTA_CERTIFICATE_LEN)
{
return ZCL_STATUS_INVALID_IMAGE;
}
}
#endif
break;
case ZCL_OTA_PD_ELEMENT_STATE:
#if defined OTA_MMO_SIGN
if (zclOTA_ElementTag == OTA_ECDSA_SIGNATURE_TAG_ID)
{
if (zclOTA_ElementPos < Z_EXTADDR_LEN)
zclOTA_SignerIEEE[zclOTA_ElementPos] = pData[i];
else
zclOTA_SignatureData[zclOTA_ElementPos - Z_EXTADDR_LEN] = pData[i];
}
else if (zclOTA_ElementTag == OTA_ECDSA_CERT_TAG_ID)
{
zclOTA_Certificate[zclOTA_ElementPos] = pData[i];
}
#endif
if (++zclOTA_ElementPos == zclOTA_ElementLen)
{
// Element is complete
if (zclOTA_ElementTag == OTA_UPGRADE_IMAGE_TAG_ID)
{
// The serial flash can take up to 25 ms before it is ready for a read
uint32 k;
for (k=0; k<0xffff; k++)
{
asm("NOP");
}
// When the image is complete, verify CRC
if (HalOTAChkDL(HAL_OTA_CRC_OSET) != SUCCESS)
{
#if (defined HAL_LCD) && (HAL_LCD == TRUE)
HalLcdWriteString("OTA CRC Fail", HAL_LCD_LINE_3);
#endif
return ZCL_STATUS_INVALID_IMAGE;
}
}
zclOTA_ClientPdState = ZCL_OTA_PD_ELEM_TAG1_STATE;
}
break;
default:
break;
}
#if defined OTA_MMO_SIGN
// We need to skip the hash calculation on the signature element.
// When receiving a tag, we wait to receive the entire tag before
// adding the byte to the hash buffer because it could be the tag
// for the signature
if (zclOTA_ClientPdState == ZCL_OTA_PD_ELEM_TAG2_STATE)
{
skipHash = TRUE;
}
else if (zclOTA_ClientPdState == ZCL_OTA_PD_ELEM_LEN1_STATE)
{
if (zclOTA_ElementTag != OTA_ECDSA_SIGNATURE_TAG_ID)
{
// This tag is not for the signature.
// Put the Lower byte of the tag into the hash buffer now
// The high byte will be processed as usual below
zclOTA_DataToHash[zclOTA_HashPos++] = LO_UINT16(zclOTA_ElementTag);
// When the buffer reaches OTA_MMO_HASH_SIZE, update the Hash
if (zclOTA_HashPos == OTA_MMO_HASH_SIZE)
{
OTA_CalculateMmoR3(&zclOTA_MmoHash, zclOTA_DataToHash, OTA_MMO_HASH_SIZE, FALSE);
zclOTA_HashPos = 0;
}
skipHash = FALSE;
}
}
if (!skipHash)
{
// Maintain a buffer of data to hash
zclOTA_DataToHash[zclOTA_HashPos++] = pData[i];
// When the buffer reaches OTA_MMO_HASH_SIZE, update the Hash
if (zclOTA_HashPos == OTA_MMO_HASH_SIZE)
{
OTA_CalculateMmoR3(&zclOTA_MmoHash, zclOTA_DataToHash, OTA_MMO_HASH_SIZE, FALSE);
zclOTA_HashPos = 0;
}
}
#endif
// Check if the download is complete
if (++zclOTA_FileOffset >= zclOTA_DownloadedImageSize)
{
zclOTA_ImageUpgradeStatus = OTA_STATUS_COMPLETE;
#if defined OTA_MMO_SIGN
// Complete the hash calcualtion
OTA_CalculateMmoR3(&zclOTA_MmoHash, zclOTA_DataToHash, zclOTA_HashPos, TRUE);
// Validate the hash
if (OTA_ValidateSignature(zclOTA_MmoHash.hash, zclOTA_Certificate,
zclOTA_SignatureData, zclOTA_SignerIEEE) != ZSuccess)
return ZCL_STATUS_INVALID_IMAGE;
#endif
return ZSuccess;
}
}
return ZSuccess;
}
/******************************************************************************
* @fn zclOTA_ProcessImageNotify
*
* @brief Process received Image Notify command.
*
* @param pInMsg - pointer to the incoming message
*
* @return ZStatus_t
*/
static ZStatus_t zclOTA_ProcessImageNotify( zclIncoming_t *pInMsg )
{
zclOTA_ImageNotifyParams_t param;
zclOTA_QueryNextImageReqParams_t req;
uint8 *pData;
// verify message length
if ((pInMsg->pDataLen > PAYLOAD_MAX_LEN_IMAGE_NOTIFY) ||
(pInMsg->pDataLen < PAYLOAD_MIN_LEN_IMAGE_NOTIFY))
{
// no further processing if invalid
return ZCL_STATUS_MALFORMED_COMMAND;
}
// verify in 'normal' state
if ((zclOTA_Permit == FALSE) ||
(zclOTA_ImageUpgradeStatus != OTA_STATUS_NORMAL))
{
return ZFailure;
}
// parse message
pData = pInMsg->pData;
param.payloadType = *pData++;
param.queryJitter = *pData++;
param.fileId.manufacturer = BUILD_UINT16(pData[0], pData[1]);
pData += 2;
param.fileId.type = BUILD_UINT16(pData[0], pData[1]);
pData += 2;
param.fileId.version = osal_build_uint32( pData, 4 );
// if message is broadcast
if (pInMsg->msg->wasBroadcast)
{
// verify manufacturer
if ((param.payloadType >= NOTIFY_PAYLOAD_JITTER_MFG) &&
(param.fileId.manufacturer != zclOTA_ManufacturerId))
{
return ZSuccess;
}
// verify image type
if ((param.payloadType >= NOTIFY_PAYLOAD_JITTER_MFG_TYPE) &&
(param.fileId.type != zclOTA_ImageType))
{
return ZSuccess;
}
// verify version; if version matches ignore
if ((param.payloadType >= NOTIFY_PAYLOAD_JITTER_MFG_TYPE_VERS) &&
(param.fileId.version == zclOTA_CurrentFileVersion))
{
return ZSuccess;
}
// get random value and compare to query jitter
if (((uint8) osal_rand() % 100) > param.queryJitter)
{
// if greater than query jitter ignore;
return ZSuccess;
}
}
// if unicast message, or broadcast and still made it here, send query next image
req.fieldControl = 0;
req.fileId.manufacturer = zclOTA_ManufacturerId;
req.fileId.type = zclOTA_ImageType;
req.fileId.version = zclOTA_CurrentFileVersion;
zclOTA_SendQueryNextImageReq( &(pInMsg->msg->srcAddr), &req);
return ZSuccess;
}
/******************************************************************************
* @fn zclOTA_ProcessQueryNextImageRsp
*
* @brief Process received Query Next Image Response.
*
* @param pInMsg - pointer to the incoming message
*
* @return ZStatus_t
*/
static ZStatus_t zclOTA_ProcessQueryNextImageRsp( zclIncoming_t *pInMsg )
{
zclOTA_QueryImageRspParams_t param;
uint8 *pData;
uint8 status = ZFailure;
// verify message length
if ((pInMsg->pDataLen != PAYLOAD_MAX_LEN_QUERY_NEXT_IMAGE_RSP) &&
(pInMsg->pDataLen != PAYLOAD_MIN_LEN_QUERY_NEXT_IMAGE_RSP))
{
// no further processing if invalid
return ZCL_STATUS_MALFORMED_COMMAND;
}
// ignore message if in 'download in progress' state
if (zclOTA_ImageUpgradeStatus == OTA_STATUS_IN_PROGRESS)
{
return ZSuccess;
}
// get status
pData = pInMsg->pData;
param.status = *pData++;
// if status is success
if (param.status == ZCL_STATUS_SUCCESS)
{
// parse message
param.fileId.manufacturer = BUILD_UINT16(pData[0], pData[1]);
pData += 2;
param.fileId.type = BUILD_UINT16(pData[0], pData[1]);
pData += 2;
param.fileId.version = osal_build_uint32( pData, 4 );
pData += 4;
param.imageSize = osal_build_uint32( pData, 4 );
// verify manufacturer id and image type
if ((param.fileId.type == zclOTA_ImageType) &&
(param.fileId.manufacturer == zclOTA_ManufacturerId))
{
// store file version and image size
zclOTA_DownloadedFileVersion = param.fileId.version;
zclOTA_DownloadedImageSize = param.imageSize;
// initialize other variables
zclOTA_FileOffset = 0;
zclOTA_ClientPdState = ZCL_OTA_PD_MAGIC_0_STATE;
// set state to 'in progress'
zclOTA_ImageUpgradeStatus = OTA_STATUS_IN_PROGRESS;
// store server address
zclOTA_serverAddr = pInMsg->msg->srcAddr;
// Store the file ID
osal_memcpy(&zclOTA_CurrentDlFileId, &param.fileId, sizeof(zclOTA_FileID_t));
// send image block request
sendImageBlockReq(&(pInMsg->msg->srcAddr));
status = ZCL_STATUS_CMD_HAS_RSP;
// Request the IEEE address of the server to put into the
// ATTRID_UPGRADE_SERVER_ID attribute
ZDP_IEEEAddrReq(pInMsg->msg->srcAddr.addr.shortAddr, ZDP_ADDR_REQTYPE_SINGLE, 0, 0);
osal_stop_timerEx(zclOTA_TaskID, ZCL_OTA_IMAGE_QUERY_TO_EVT);
}
}
if (zclOTA_AppTask != 0xFF)
{
// Notify the application task of the failure
zclOTA_CallbackMsg_t *pMsg;
pMsg = (zclOTA_CallbackMsg_t*) osal_msg_allocate(sizeof(zclOTA_CallbackMsg_t));
if (pMsg)
{
pMsg->hdr.event = ZCL_OTA_CALLBACK_IND;
pMsg->hdr.status = param.status;
pMsg->ota_event = ZCL_OTA_START_CALLBACK;
osal_msg_send(zclOTA_AppTask, (uint8*) pMsg);
}
}
return status;
}
/******************************************************************************
* @fn zclOTA_ProcessImageBlockRsp
*
* @brief Process received Image Block Response.
*
* @param pInMsg - pointer to the incoming message
*
* @return ZStatus_t
*/
static ZStatus_t zclOTA_ProcessImageBlockRsp( zclIncoming_t *pInMsg )
{
zclOTA_ImageBlockRspParams_t param;
zclOTA_UpgradeEndReqParams_t req;
uint8 *pData;
uint8 status = ZSuccess;
// verify in 'in progress' state
if (zclOTA_ImageUpgradeStatus != OTA_STATUS_IN_PROGRESS)
{
return ZSuccess;
}
// get status
pData = pInMsg->pData;
param.status = *pData++;
// if status is success
if (param.status == ZCL_STATUS_SUCCESS)
{
// verify message length
if (pInMsg->pDataLen < PAYLOAD_MAX_LEN_IMAGE_BLOCK_RSP)
{
// no further processing if invalid
return ZCL_STATUS_MALFORMED_COMMAND;
}
// parse message
param.rsp.success.fileId.manufacturer = BUILD_UINT16(pData[0], pData[1]);
pData += 2;
param.rsp.success.fileId.type = BUILD_UINT16(pData[0], pData[1]);
pData += 2;
param.rsp.success.fileId.version = osal_build_uint32( pData, 4 );
pData += 4;
param.rsp.success.fileOffset = osal_build_uint32( pData, 4 );
pData += 4;
param.rsp.success.dataSize = *pData++;
param.rsp.success.pData = pData;
// verify manufacturer, image type, file version, file offset
if ((param.rsp.success.fileId.type != zclOTA_ImageType) ||
(param.rsp.success.fileId.manufacturer != zclOTA_ManufacturerId) ||
(param.rsp.success.fileId.version != zclOTA_DownloadedFileVersion))
{
status = ZCL_STATUS_INVALID_IMAGE;
}
else
{
// Drop duplicate packets (retries)
if (param.rsp.success.fileOffset != zclOTA_FileOffset)
{
return ZSuccess;
}
status = zclOTA_ProcessImageData(param.rsp.success.pData, param.rsp.success.dataSize);
// Stop the timer and clear the retry count
zclOTA_BlockRetry = 0;
osal_stop_timerEx(zclOTA_TaskID, ZCL_OTA_BLOCK_RSP_TO_EVT);
if (status == ZSuccess)
{
if (zclOTA_ImageUpgradeStatus == OTA_STATUS_COMPLETE)
{
// send upgrade end req with success status
osal_memcpy(&req.fileId, &param.rsp.success.fileId, sizeof(zclOTA_FileID_t));
req.status = ZSuccess;
zclOTA_SendUpgradeEndReq( &(pInMsg->msg->srcAddr), &req );
}
else
{
sendImageBlockReq(&(pInMsg->msg->srcAddr));
}
}
}
}
// else if status is 'wait for data'
else if (param.status == ZCL_STATUS_WAIT_FOR_DATA)
{
// verify message length
if (pInMsg->pDataLen != PAYLOAD_MIN_LEN_IMAGE_BLOCK_WAIT)
{
// no further processing if invalid
return ZCL_STATUS_MALFORMED_COMMAND;
}
// parse message
param.rsp.wait.currentTime = osal_build_uint32( pData, 4 );
pData += 4;
param.rsp.wait.requestTime = osal_build_uint32( pData, 4 );
// Stop the timer and clear the retry count
zclOTA_BlockRetry = 0;
osal_stop_timerEx(zclOTA_TaskID, ZCL_OTA_BLOCK_RSP_TO_EVT);
// set timer for next image block req
zclOTA_StartTimer(ZCL_OTA_IMAGE_BLOCK_WAIT_EVT,
(param.rsp.wait.requestTime - param.rsp.wait.currentTime));
}
else if (param.status == ZCL_STATUS_ABORT)
{
// download aborted; set state to 'normal' state
zclOTA_ImageUpgradeStatus = OTA_STATUS_NORMAL;
// Stop the timer and clear the retry count
zclOTA_BlockRetry = 0;
osal_stop_timerEx(zclOTA_TaskID, ZCL_OTA_BLOCK_RSP_TO_EVT);
zclOTA_UpgradeComplete(ZOtaAbort);
return ZSuccess;
}
else
{
return ZCL_STATUS_MALFORMED_COMMAND;
}
if (status != ZSuccess)
{
// download failed; set state to 'normal'
zclOTA_ImageUpgradeStatus = OTA_STATUS_NORMAL;
// send upgrade end req with failure status
osal_memcpy(&req.fileId, &param.rsp.success.fileId, sizeof(zclOTA_FileID_t));
req.status = status;
zclOTA_SendUpgradeEndReq( &(pInMsg->msg->srcAddr), &req );
}
return ZSuccess;
}
/******************************************************************************
* @fn zclOTA_ProcessUpgradeEndRsp
*
* @brief Process received Upgrade End Response.
*
* @param pInMsg - pointer to the incoming message
*
* @return ZStatus_t
*/
static ZStatus_t zclOTA_ProcessUpgradeEndRsp( zclIncoming_t *pInMsg )
{
zclOTA_UpgradeEndRspParams_t param;
zclOTA_FileID_t currentFileId = {zclOTA_ManufacturerId, zclOTA_ImageType, zclOTA_DownloadedFileVersion};
uint8 *pData;
// verify message length
if (pInMsg->pDataLen != PAYLOAD_MAX_LEN_UPGRADE_END_RSP)
{
// no further processing if invalid
return ZCL_STATUS_MALFORMED_COMMAND;
}
// parse message
pData = pInMsg->pData;
param.fileId.manufacturer = BUILD_UINT16(pData[0], pData[1]);
pData += 2;
param.fileId.type = BUILD_UINT16(pData[0], pData[1]);
pData += 2;
param.fileId.version = osal_build_uint32( pData, 4 );
pData += 4;
param.currentTime = osal_build_uint32( pData, 4 );
pData += 4;
param.upgradeTime = osal_build_uint32( pData, 4 );
// verify in 'download complete' or 'waiting for upgrade' state
if ((zclOTA_ImageUpgradeStatus == OTA_STATUS_COMPLETE) ||
((zclOTA_ImageUpgradeStatus == OTA_STATUS_UPGRADE_WAIT) && (param.upgradeTime!=OTA_UPGRADE_TIME_WAIT)))
{
// verify manufacturer, image type
if (zclOTA_CmpFileId(&param.fileId, &currentFileId) == FALSE)
{
return ZSuccess;
}
// check upgrade time
if (param.upgradeTime != OTA_UPGRADE_TIME_WAIT)
{
uint32 notifyDelay = 0;
if (param.upgradeTime > param.currentTime)
{
// time to wait before notification
notifyDelay = param.upgradeTime - param.currentTime;
}
// set state to 'countdown'
zclOTA_ImageUpgradeStatus = OTA_STATUS_COUNTDOWN;
// set timer for upgrade complete notification
zclOTA_StartTimer(ZCL_OTA_UPGRADE_WAIT_EVT, notifyDelay);
}
else
{
// Wait for another upgrade end response
zclOTA_ImageUpgradeStatus = OTA_STATUS_UPGRADE_WAIT;
// Set a timer for 60 minutes to send another Upgrade End Rsp
zclOTA_StartTimer(ZCL_OTA_UPGRADE_WAIT_EVT, 3600);
zclOTA_UpgradeEndRetry = 0;
}
}
return ZSuccess;
}
/******************************************************************************
* @fn zclOTA_ProcessQuerySpecificFileRsp
*
* @brief Process received Query Specific File Response.
*
* @param pInMsg - pointer to the incoming message
*
* @return ZStatus_t
*/
static ZStatus_t zclOTA_ProcessQuerySpecificFileRsp( zclIncoming_t *pInMsg )
{
zclOTA_QueryImageRspParams_t param;
uint8 *pData;
// verify message length
if ((pInMsg->pDataLen != PAYLOAD_MAX_LEN_QUERY_SPECIFIC_FILE_RSP) &&
(pInMsg->pDataLen != PAYLOAD_MIN_LEN_QUERY_SPECIFIC_FILE_RSP))
{
// no further processing if invalid
return ZCL_STATUS_MALFORMED_COMMAND;
}
// ignore message if in 'download in progress' state
if (zclOTA_ImageUpgradeStatus == OTA_STATUS_IN_PROGRESS)
{
return ZSuccess;
}
// get status
pData = pInMsg->pData;
param.status = *pData++;
// if status is success
if (param.status == ZCL_STATUS_SUCCESS)
{
// parse message
param.fileId.manufacturer = BUILD_UINT16(pData[0], pData[1]);
pData += 2;
param.fileId.type = BUILD_UINT16(pData[0], pData[1]);
pData += 2;
param.fileId.version = osal_build_uint32( pData, 4 );
pData += 4;
param.imageSize = osal_build_uint32( pData, 4 );
// verify manufacturer id and image type
if ((param.fileId.type == zclOTA_ImageType) &&
(param.fileId.manufacturer == zclOTA_ManufacturerId))
{
// store file version and image size
zclOTA_DownloadedFileVersion = param.fileId.version;
zclOTA_DownloadedImageSize = param.imageSize;
// initialize other variables
zclOTA_FileOffset = 0;
// set state to 'in progress'
zclOTA_ImageUpgradeStatus = OTA_STATUS_IN_PROGRESS;
// send image block request
sendImageBlockReq(&(pInMsg->msg->srcAddr));
}
}
return ZSuccess;
}
/******************************************************************************
* @fn zclOTA_ClientHdlIncoming
*
* @brief Handle incoming client commands.
*
* @param pInMsg - pointer to the incoming message
*
* @return ZStatus_t
*/
static ZStatus_t zclOTA_ClientHdlIncoming( zclIncoming_t *pInMsg )
{
switch (pInMsg->hdr.commandID)
{
case COMMAND_IMAGE_NOTIFY:
return zclOTA_ProcessImageNotify( pInMsg );
case COMMAND_QUERY_NEXT_IMAGE_RSP:
return zclOTA_ProcessQueryNextImageRsp( pInMsg );
case COMMAND_IMAGE_BLOCK_RSP:
return zclOTA_ProcessImageBlockRsp( pInMsg );
case COMMAND_UPGRADE_END_RSP:
return zclOTA_ProcessUpgradeEndRsp( pInMsg );
case COMMAND_QUERY_SPECIFIC_FILE_RSP:
return zclOTA_ProcessQuerySpecificFileRsp( pInMsg );
default:
return ZFailure;
}
}
/******************************************************************************
* @fn zclOTA_CmpFileId
*
* @brief Called to compare two file IDs
*
* @param f1, f2 - Pointers to the two file IDs to compare
*
* @return TRUE if the file IDs are the same, else FALSE
*/
static uint8 zclOTA_CmpFileId(zclOTA_FileID_t *f1, zclOTA_FileID_t *f2)
{
if ((f1->manufacturer == 0xFFFF) ||
(f2->manufacturer == 0xFFFF) ||
(f1->manufacturer == f2->manufacturer))
{
if ((f1->type == 0xFFFF) ||
(f2->type == 0xFFFF) ||
(f1->type == f2->type))
{
if ((f1->version == 0xFFFFFFFF) ||
(f2->version == 0xFFFFFFFF) ||
(f1->version == f2->version))
{
return TRUE;
}
}
}
return FALSE;
}
/******************************************************************************
* @fn zclOTA_ImageBlockWaitExpired
*
* @brief Perform action on image block wait timer expiration.
*
* @param none
*
* @return none
*/
static void zclOTA_ImageBlockWaitExpired(void)
{
// verify in 'in progress' state
if (zclOTA_ImageUpgradeStatus == OTA_STATUS_IN_PROGRESS)
{
// request next block
sendImageBlockReq(&zclOTA_serverAddr);
}
}
/******************************************************************************
* @fn zclOTA_UpgradeComplete
*
* @brief Notify the application task that an upgrade has completed.
*
* @param status - The status of the upgrade
*
* @return none
*/
static void zclOTA_UpgradeComplete(uint8 status)
{
// Go back to the normal state
zclOTA_ImageUpgradeStatus = OTA_STATUS_NORMAL;
if ((zclOTA_DownloadedImageSize == OTA_HEADER_LEN_MIN_ECDSA) ||
(zclOTA_DownloadedImageSize == OTA_HEADER_LEN_MIN))
{
status = ZFailure;
}
if (zclOTA_AppTask != 0xFF)
{
// Notify the application task the upgrade stopped
zclOTA_CallbackMsg_t *pMsg;
pMsg = (zclOTA_CallbackMsg_t*) osal_msg_allocate(sizeof(zclOTA_CallbackMsg_t));
if (pMsg)
{
pMsg->hdr.event = ZCL_OTA_CALLBACK_IND;
pMsg->hdr.status = status;
pMsg->ota_event = ZCL_OTA_DL_COMPLETE_CALLBACK;
osal_msg_send(zclOTA_AppTask, (uint8*) pMsg);
}
}
}
/******************************************************************************
* @fn zclOTA_ProcessZDOMsgs
*
* @brief Process callbacks from the ZDO.
*
* @param pMsg - a Pointer to the message from the ZDO
*
* @return none
*/
static void zclOTA_ProcessZDOMsgs( zdoIncomingMsg_t *pMsg )
{
if (pMsg->clusterID == IEEE_addr_rsp)
{
ZDO_NwkIEEEAddrResp_t *pNwkAddrRsp = ZDO_ParseAddrRsp( pMsg );
// If this is from the OTA server, record the server's IEEE address
if (pNwkAddrRsp != NULL)
{
if (pNwkAddrRsp->nwkAddr == zclOTA_serverAddr.addr.shortAddr)
{
osal_memcpy(&zclOTA_UpgradeServerID, pNwkAddrRsp->extAddr, Z_EXTADDR_LEN);
}
osal_mem_free( pNwkAddrRsp );
}
}
}
#endif // OTA_CLIENT
#if defined (OTA_SERVER) && (OTA_SERVER == TRUE)
/******************************************************************************
* @fn zclOTA_ProcessNextImgRsp
*
* @brief Handles a response to a MT_OTA_NEXT_IMG_RSP.
*
* @param pMsg - The data from the server.
* pFileId - The ID of the OTA File.
* pAddr - The source of the message.
*
* @return none
*/
void zclOTA_ProcessNextImgRsp(uint8* pMsg, zclOTA_FileID_t *pFileId,
afAddrType_t *pAddr)
{
zclOTA_QueryImageRspParams_t queryRsp;
uint8 options;
uint8 status;
// Get the status of the operation
status = *pMsg++;
// Get the options
options = *pMsg++;
// Copy the file ID
osal_memcpy(&queryRsp.fileId, pFileId, sizeof(zclOTA_FileID_t));
// Set the image size
if (status == ZSuccess)
{
queryRsp.status = ZSuccess;
queryRsp.imageSize = BUILD_UINT32(pMsg[0], pMsg[1], pMsg[2], pMsg[3]);
}
else
{
queryRsp.status = ZOtaNoImageAvailable;
queryRsp.imageSize = 0;
}
queryResponse = queryRsp; // save global variable for query image response. Used later in image block request check
// Send a response to the client
if (options & MT_OTA_QUERY_SPECIFIC_OPTION)
{
zclOTA_SendQuerySpecificFileRsp(pAddr, &queryRsp);
}
else
{
zclOTA_SendQueryNextImageRsp(pAddr, &queryRsp);
}
}
/******************************************************************************
* @fn zclOTA_ProcessFileReadRsp
*
* @brief Handles a response to a MT_OTA_FILE_READ_RSP.
*
* @param pMsg - The data from the server.
* pFileId - The ID of the OTA File.
* pAddr - The source of the message.
*
* @return none
*/
void zclOTA_ProcessFileReadRsp(uint8* pMsg, zclOTA_FileID_t *pFileId,
afAddrType_t *pAddr)
{
zclOTA_ImageBlockRspParams_t blockRsp;
// Set the status
blockRsp.status = *pMsg++;
// Check the status of the file read
if (blockRsp.status == ZSuccess)
{
// Fill in the response parameters
osal_memcpy(&blockRsp.rsp.success.fileId, pFileId, sizeof(zclOTA_FileID_t));
blockRsp.rsp.success.fileOffset = BUILD_UINT32(pMsg[0], pMsg[1], pMsg[2], pMsg[3]);
pMsg += 4;
blockRsp.rsp.success.dataSize = *pMsg++;
blockRsp.rsp.success.pData = pMsg;
}
else
{
blockRsp.status = ZOtaAbort;
}
// Send the block response to the peer
zclOTA_SendImageBlockRsp(pAddr, &blockRsp);
}
/******************************************************************************
* @fn OTA_HandleFileSysCb
*
* @brief Handles File Server Callbacks.
*
* @param pMSGpkt - The data from the server.
*
* @return none
*/
void zclOTA_ServerHandleFileSysCb(OTA_MtMsg_t* pMSGpkt)
{
zclOTA_FileID_t pFileId;
afAddrType_t pAddr;
uint8 *pMsg;
if (pMSGpkt != NULL)
{
// Get the File ID and AF Address
pMsg = pMSGpkt->data;
pMsg = OTA_StreamToFileId(&pFileId, pMsg);
pMsg = OTA_StreamToAfAddr(&pAddr, pMsg);
switch(pMSGpkt->cmd)
{
case MT_OTA_NEXT_IMG_RSP:
zclOTA_ProcessNextImgRsp(pMsg, &pFileId, &pAddr);
break;
case MT_OTA_FILE_READ_RSP:
zclOTA_ProcessFileReadRsp(pMsg, &pFileId, &pAddr);
break;
default:
break;
}
}
}
/******************************************************************************
* @fn zclOTA_Srv_QueryNextImageReq
*
* @brief Handle a Query Next Image Request.
*
* @param pSrcAddr - The source of the message
* pParam - message parameters
*
* @return ZStatus_t
*
* @note On a query next image, we must request a file listing
* from the File Server. Then open a file if
*/
ZStatus_t zclOTA_Srv_QueryNextImageReq(afAddrType_t *pSrcAddr, zclOTA_QueryNextImageReqParams_t *pParam)
{
uint8 options = 0;
uint8 status;
if (zclOTA_Permit)
{
if (pParam->fieldControl)
{
options |= MT_OTA_HW_VER_PRESENT_OPTION;
}
// Request the next image for this device from the console via the MT File System
status = MT_OtaGetImage(pSrcAddr, &pParam->fileId, pParam->hardwareVersion, NULL, options);
}
else
{
status = ZOtaNoImageAvailable;
}
if (status != ZSuccess)
{
zclOTA_QueryImageRspParams_t queryRsp;
// Fill in the response parameters
osal_memcpy(&queryRsp.fileId, &pParam->fileId, sizeof(zclOTA_FileID_t));
queryRsp.status = ZOtaNoImageAvailable;
queryRsp.imageSize = 0;
// Send a failure response to the client
zclOTA_SendQueryNextImageRsp(pSrcAddr, &queryRsp);
}
return ZCL_STATUS_CMD_HAS_RSP;
}
/******************************************************************************
* @fn zclOTA_Srv_ImageBlockReq
*
* @brief Handle an Image Block Request.
*
* @param pSrcAddr - The source of the message
* pParam - message parameters
*
* @return ZStatus_t
*/
ZStatus_t zclOTA_Srv_ImageBlockReq(afAddrType_t *pSrcAddr, zclOTA_ImageBlockReqParams_t *pParam)
{
uint8 status = ZFailure;
if (pParam->fileId.version != queryResponse.fileId.version)
{
status = ZCL_STATUS_NO_IMAGE_AVAILABLE;
}
else
{
if (zclOTA_Permit && (pParam != NULL))
{
uint8 len = pParam->maxDataSize;
if (len > OTA_MAX_MTU)
{
len = OTA_MAX_MTU;
}
// Read the data from the OTA Console
status = MT_OtaFileReadReq(pSrcAddr, &pParam->fileId, len, pParam->fileOffset);
// Send a wait response to the client
if (status != ZSuccess)
{
zclOTA_ImageBlockRspParams_t blockRsp;
// Fill in the response parameters
blockRsp.status = ZOtaWaitForData;
osal_memcpy(&blockRsp.rsp.success.fileId, &pParam->fileId, sizeof(zclOTA_FileID_t));
blockRsp.rsp.wait.currentTime = 0;
blockRsp.rsp.wait.requestTime = OTA_SEND_BLOCK_WAIT;
// Send the block to the peer
zclOTA_SendImageBlockRsp(pSrcAddr, &blockRsp);
}
status = ZCL_STATUS_CMD_HAS_RSP;
}
}
return status;
}
/******************************************************************************
* @fn zclOTA_Srv_ImagePageReq
*
* @brief Handle an Image Page Request. Note: Not currently supported.
*
* @param pSrcAddr - The source of the message
* pParam - message parameters
*
* @return ZStatus_t
*/
ZStatus_t zclOTA_Srv_ImagePageReq(afAddrType_t *pSrcAddr, zclOTA_ImagePageReqParams_t *pParam)
{
// Send not supported resposne
return ZUnsupClusterCmd;
}
/******************************************************************************
* @fn zclOTA_Srv_UpgradeEndReq
*
* @brief Handle an Upgrade End Request.
*
* @param pSrcAddr - The source of the message
* pParam - message parameters
*
* @return ZStatus_t
*/
ZStatus_t zclOTA_Srv_UpgradeEndReq(afAddrType_t *pSrcAddr, zclOTA_UpgradeEndReqParams_t *pParam)
{
uint8 status = ZFailure;
if (zclOTA_Permit && (pParam != NULL))
{
zclOTA_UpgradeEndRspParams_t rspParms;
if (pParam->status == ZSuccess)
{
osal_memcpy(&rspParms.fileId, &pParam->fileId, sizeof(zclOTA_FileID_t));
rspParms.currentTime = osal_GetSystemClock();
rspParms.upgradeTime = rspParms.currentTime + OTA_UPGRADE_DELAY;
// Send the response to the peer
zclOTA_SendUpgradeEndRsp(pSrcAddr, &rspParms);
}
// Notify the Console Tool
MT_OtaSendStatus(pSrcAddr->addr.shortAddr, MT_OTA_DL_COMPLETE, pParam->status, 0);
status = ZCL_STATUS_CMD_HAS_RSP;
}
return status;
}
/******************************************************************************
* @fn zclOTA_Srv_QuerySpecificFileReq
*
* @brief Handles a Query Specific File Request.
*
* @param pSrcAddr - The source of the message
* pParam - message parameters
*
* @return ZStatus_t
*/
ZStatus_t zclOTA_Srv_QuerySpecificFileReq(afAddrType_t *pSrcAddr, zclOTA_QuerySpecificFileReqParams_t *pParam)
{
uint8 status;
// Request the image from the console
if (zclOTA_Permit)
{
status = MT_OtaGetImage(pSrcAddr, &pParam->fileId, 0, pParam->nodeAddr, MT_OTA_QUERY_SPECIFIC_OPTION);
}
else
{
status = ZOtaNoImageAvailable;
}
if (status != ZSuccess)
{
zclOTA_QueryImageRspParams_t queryRsp;
// Fill in the response parameters
osal_memcpy(&queryRsp.fileId, &pParam->fileId, sizeof(zclOTA_FileID_t));
queryRsp.status = ZOtaNoImageAvailable;
queryRsp.imageSize = 0;
// Send a failure response to the client
zclOTA_SendQuerySpecificFileRsp(pSrcAddr, &queryRsp);
}
return ZCL_STATUS_CMD_HAS_RSP;
}
/******************************************************************************
* @fn zclOTA_ProcessQueryNextImageReq
*
* @brief Process received Query Next Image Request.
*
* @param pInMsg - pointer to the incoming message
*
* @return ZStatus_t
*/
static ZStatus_t zclOTA_ProcessQueryNextImageReq( zclIncoming_t *pInMsg )
{
zclOTA_QueryNextImageReqParams_t param;
uint8 *pData;
/* verify message length */
if ((pInMsg->pDataLen != PAYLOAD_MAX_LEN_QUERY_NEXT_IMAGE_REQ) &&
(pInMsg->pDataLen != PAYLOAD_MIN_LEN_QUERY_NEXT_IMAGE_REQ))
{
/* no further processing if invalid */
return ZCL_STATUS_MALFORMED_COMMAND;
}
/* parse message parameters */
pData = pInMsg->pData;
param.fieldControl = *pData++;
param.fileId.manufacturer = BUILD_UINT16(pData[0], pData[1]);
pData += 2;
param.fileId.type = BUILD_UINT16(pData[0], pData[1]);
pData += 2;
param.fileId.version = osal_build_uint32( pData, 4 );
pData += 4;
if ((param.fieldControl & 0x01) != 0)
{
param.hardwareVersion = BUILD_UINT16(pData[0], pData[1]);
}
/* call callback */
return zclOTA_Srv_QueryNextImageReq(&pInMsg->msg->srcAddr, &param);
}
/******************************************************************************
* @fn zclOTA_ProcessImageBlockReq
*
* @brief Process received Image Block Request.
*
* @param pInMsg - pointer to the incoming message
*
* @return ZStatus_t
*/
static ZStatus_t zclOTA_ProcessImageBlockReq( zclIncoming_t *pInMsg )
{
zclOTA_ImageBlockReqParams_t param;
uint8 *pData;
/* verify message length */
if ((pInMsg->pDataLen != PAYLOAD_MAX_LEN_IMAGE_BLOCK_REQ) &&
(pInMsg->pDataLen != PAYLOAD_MIN_LEN_IMAGE_BLOCK_REQ))
{
/* no further processing if invalid */
return ZCL_STATUS_MALFORMED_COMMAND;
}
/* parse message parameters */
pData = pInMsg->pData;
param.fieldControl = *pData++;
param.fileId.manufacturer = BUILD_UINT16(pData[0], pData[1]);
pData += 2;
param.fileId.type = BUILD_UINT16(pData[0], pData[1]);
pData += 2;
param.fileId.version = osal_build_uint32( pData, 4 );
pData += 4;
param.fileOffset = osal_build_uint32( pData, 4 );
pData += 4;
param.maxDataSize = *pData++;
if ((param.fieldControl & 0x01) != 0)
{
osal_cpyExtAddr(param.nodeAddr, pData);
}
/* call callback */
return zclOTA_Srv_ImageBlockReq(&pInMsg->msg->srcAddr, &param);
}
/******************************************************************************
* @fn zclOTA_ProcessImagePageReq
*
* @brief Process received Image Page Request.
*
* @param pInMsg - pointer to the incoming message
*
* @return ZStatus_t
*/
static ZStatus_t zclOTA_ProcessImagePageReq( zclIncoming_t *pInMsg )
{
zclOTA_ImagePageReqParams_t param;
uint8 *pData;
/* verify message length */
if ((pInMsg->pDataLen != PAYLOAD_MAX_LEN_IMAGE_PAGE_REQ) &&
(pInMsg->pDataLen != PAYLOAD_MIN_LEN_IMAGE_PAGE_REQ))
{
/* no further processing if invalid */
return ZCL_STATUS_MALFORMED_COMMAND;
}
/* parse message parameters */
pData = pInMsg->pData;
param.fieldControl = *pData++;
param.fileId.manufacturer = BUILD_UINT16(pData[0], pData[1]);
pData += 2;
param.fileId.type = BUILD_UINT16(pData[0], pData[1]);
pData += 2;
param.fileId.version = osal_build_uint32( pData, 4 );
pData += 4;
param.fileOffset = osal_build_uint32( pData, 4 );
pData += 4;
param.maxDataSize = *pData++;
param.pageSize = BUILD_UINT16(pData[0], pData[1]);
pData += 2;
param.responseSpacing = BUILD_UINT16(pData[0], pData[1]);
pData += 2;
if ((param.fieldControl & 0x01) != 0)
{
osal_cpyExtAddr(param.nodeAddr, pData);
}
/* call callback */
return zclOTA_Srv_ImagePageReq(&pInMsg->msg->srcAddr, &param);
}
/******************************************************************************
* @fn zclOTA_ProcessUpgradeEndReq
*
* @brief Process received Upgrade End Request.
*
* @param pInMsg - pointer to the incoming message
*
* @return ZStatus_t
*/
static ZStatus_t zclOTA_ProcessUpgradeEndReq( zclIncoming_t *pInMsg )
{
zclOTA_UpgradeEndReqParams_t param;
uint8 *pData;
/* verify message length */
if ((pInMsg->pDataLen != PAYLOAD_MAX_LEN_UPGRADE_END_REQ) &&
(pInMsg->pDataLen != PAYLOAD_MIN_LEN_UPGRADE_END_REQ))
{
/* no further processing if invalid */
return ZCL_STATUS_MALFORMED_COMMAND;
}
/* parse message parameters */
pData = pInMsg->pData;
param.status = *pData++;
if (param.status == ZCL_STATUS_SUCCESS)
{
param.fileId.manufacturer = BUILD_UINT16(pData[0], pData[1]);
pData += 2;
param.fileId.type = BUILD_UINT16(pData[0], pData[1]);
pData += 2;
param.fileId.version = osal_build_uint32( pData, 4 );
}
/* call callback */
return zclOTA_Srv_UpgradeEndReq(&pInMsg->msg->srcAddr, &param);
}
/******************************************************************************
* @fn zclOTA_ProcessQuerySpecificFileReq
*
* @brief Process received Image Page Request.
*
* @param pInMsg - pointer to the incoming message
*
* @return ZStatus_t
*/
static ZStatus_t zclOTA_ProcessQuerySpecificFileReq( zclIncoming_t *pInMsg )
{
zclOTA_QuerySpecificFileReqParams_t param;
uint8 *pData;
/* verify message length */
if (pInMsg->pDataLen != PAYLOAD_MAX_LEN_QUERY_SPECIFIC_FILE_REQ)
{
/* no further processing if invalid */
return ZCL_STATUS_MALFORMED_COMMAND;
}
/* parse message parameters */
pData = pInMsg->pData;
osal_cpyExtAddr(param.nodeAddr, pData);
pData += Z_EXTADDR_LEN;
param.fileId.manufacturer = BUILD_UINT16(pData[0], pData[1]);
pData += 2;
param.fileId.type = BUILD_UINT16(pData[0], pData[1]);
pData += 2;
param.fileId.version = osal_build_uint32( pData, 4 );
pData += 4;
param.stackVersion = BUILD_UINT16(pData[0], pData[1]);
/* call callback */
return zclOTA_Srv_QuerySpecificFileReq(&pInMsg->msg->srcAddr, &param);
}
/******************************************************************************
* @fn zclOTA_ServerHdlIncoming
*
* @brief Handle incoming server commands.
*
* @param pInMsg - pointer to the incoming message
*
* @return ZStatus_t
*/
static ZStatus_t zclOTA_ServerHdlIncoming( zclIncoming_t *pInMsg )
{
switch (pInMsg->hdr.commandID)
{
case COMMAND_QUERY_NEXT_IMAGE_REQ:
return zclOTA_ProcessQueryNextImageReq( pInMsg );
case COMMAND_IMAGE_BLOCK_REQ:
return zclOTA_ProcessImageBlockReq( pInMsg );
case COMMAND_IMAGE_PAGE_REQ:
return zclOTA_ProcessImagePageReq( pInMsg );
case COMMAND_UPGRADE_END_REQ:
return zclOTA_ProcessUpgradeEndReq( pInMsg );
case COMMAND_QUERY_SPECIFIC_FILE_REQ:
return zclOTA_ProcessQuerySpecificFileReq( pInMsg );
default:
return ZFailure;
}
}
#endif // OTA_SERVER