CC2530,zigbee,协议栈,代码集(串口、监控调试层)

10 篇文章 1 订阅
8 篇文章 1 订阅

MT(串口,监控调试层)

DebugTrace.c

#if defined( MT_TASK ) || defined( APP_DEBUG )

#include "ZComDef.h"
#include "OSAL.h"
#include "MT.h"
#include "MT_TASK.h"
#include "MT_DEBUG.h"
#include "DebugTrace.h"

#if defined ( APP_DEBUG )
  #include "DebugApp.h"
#endif

void debug_msg( byte compID, byte severity, byte numParams, UINT16 param1,
																								UINT16 param2, UINT16 param3 )
{

  mtDebugMsg_t *mtDebugMsg;
  UINT16 timestamp;

  if ( debugThreshold == 0 || debugCompId != compID )
    return;

  // Fill in the timestamp
  timestamp = 0;

  // Get a message buffer to build the debug message
  mtDebugMsg = (mtDebugMsg_t *)osal_msg_allocate( sizeof( mtDebugMsg_t ) );
  if ( mtDebugMsg )
  {
      mtDebugMsg->hdr.event = CMD_DEBUG_MSG;
      mtDebugMsg->compID = compID;
      mtDebugMsg->severity = severity;
      mtDebugMsg->numParams = numParams;

      mtDebugMsg->param1 = param1;
      mtDebugMsg->param2 = param2;
      mtDebugMsg->param3 = param3;
      mtDebugMsg->timestamp = timestamp;

      osal_msg_send( MT_TaskID, (uint8 *)mtDebugMsg );
  }

} /* debug_msg() */

void debug_str( byte *str_ptr )
{
  mtDebugStr_t *msg;
  byte mln;
  byte strLen;

  // Text string length
  strLen = (byte)osal_strlen( (void*)str_ptr );

  // Debug string message length
  mln = sizeof ( mtDebugStr_t ) + strLen;

  // Get a message buffer to build the debug message
  msg = (mtDebugStr_t *)osal_msg_allocate( mln );
  if ( msg )
  {
    // Message type, length
    msg->hdr.event = CMD_DEBUG_STR;
    msg->strLen = strLen;

    // Append message, no terminator
    msg->pString = (uint8 *)(msg+1);
    osal_memcpy ( msg->pString, str_ptr, strLen );

    osal_msg_send( MT_TaskID, (uint8 *)msg );
  }
} // debug_str()

#endif 

DebugTrace.h


#ifndef DEBUGTRACE_H
#define DEBUGTRACE_H

#ifdef __cplusplus
extern "C"
{
#endif

// command id's		
#define CMDID_RTG_ADD					1
#define CMDID_RTG_EXP					0x81
#define CMDID_RREQ_SEND				2
#define CMDID_RREQ_DROP				0x82
#define CMDID_RREP_SEND				3
#define CMDID_RREP_DROP				0x83
#define CMDID_RREQ_EXP				4

#define CMDID_DATA_SEND					6
#define CMDID_DATA_FORWARD			7
#define CMDID_DATA_RECEIVE			8

#define CMDID_BCAST_RCV				0x10
#define CMDID_BCAST_ACK				0x11
#define CMDID_BCAST_RETX			0x12

#define CMDID_BCAST_EXP				0x13
#define CMDID_BCAST_ERR				0x15

#define WPRINTSTR( s )

#if defined ( MT_TASK )

  #define TRACE_MSG( compID, nParams, p1, p2, p3 )  debug_msg( compID, SEVERITY_TRACE, nParams, p1, p2, p3 )

  #define DEBUG_INFO( compID, subCompID, nParams, p1, p2, p3 )  debug_msg( compID, subCompID, nParams, p1, p2, p3 )


  /*** TEST MESSAGES ***/
  #define DBG_NWK_STARTUP           debug_msg( COMPID_TEST_NWK_STARTUP,         SEVERITY_INFORMATION, 0, 0, 0, 0 )
  #define DBG_SCAN_CONFIRM          debug_msg( COMPID_TEST_SCAN_CONFIRM,        SEVERITY_INFORMATION, 0, 0, 0, 0 )
  #define DBG_ASSOC_CONFIRM         debug_msg( COMPID_TEST_ASSOC_CONFIRM,       SEVERITY_INFORMATION, 0, 0, 0, 0 )
  #define DBG_REMOTE_DATA_CONFIRM   debug_msg( COMPID_TEST_REMOTE_DATA_CONFIRM, SEVERITY_INFORMATION, 0, 0, 0, 0 )

#else

  #define TRACE_MSG( compID, nParams, p1, p2, p3 )
  #define DEBUG_INFO( compID, subCompID, nParams, p1, p2, p3 )
  #define DBG_NWK_STARTUP
  #define DBG_SCAN_CONFIRM
  #define DBG_ASSOC_CONFIRM
  #define DBG_REMOTE_DATA_CONFIRM

#endif


#define SEVERITY_CRITICAL     0x01
#define SEVERITY_ERROR        0x02
#define SEVERITY_INFORMATION  0x03
#define SEVERITY_TRACE        0x04

#define NO_PARAM_DEBUG_LEN   5


extern void debug_msg( uint8 compID, uint8 severity, uint8 numParams,
                       uint16 param1, uint16 param2, uint16 param3 );

extern void debug_str( uint8 *str_ptr );

#ifdef __cplusplus
}
#endif

#endif /* DEBUGTRACE_H */

MT.c

#include "ZComDef.h"
#include "MT.h"
#include "MT_APP.h"
#include "MT_DEBUG.h"
#include "MT_UTIL.h"
#include "MT_SYS.h"

#include "OnBoard.h"
#include "OSAL.h"
#include "OSAL_Memory.h"
#include "OSAL_Nv.h"

#include "DebugTrace.h"
#include "ZMAC.h"

#if !defined ( NONWK )
  #include "NLMEDE.h"
  #include "nwk_bufs.h"
  #include "ZDObject.h"
  #include "ssp.h"
  #include "nwk_util.h"
  #include "AF.h"
  #include "MT_SAPI.h"
#endif

#if defined( MT_MAC_FUNC ) || defined( MT_MAC_CB_FUNC )
  #include "MT_MAC.h"
#endif
#if defined( MT_NWK_FUNC ) || defined( MT_NWK_CB_FUNC )
  #include "MT_NWK.h"
  #include "nwk.h"
  #include "nwk_bufs.h"
#endif
#if defined( MT_AF_FUNC ) || defined( MT_AF_CB_FUNC )
  #include "MT_AF.h"
#endif
#if defined( MT_USER_TEST_FUNC )
  #include "AF.h"
#endif
#if defined( MT_ZDO_FUNC )
  #include "MT_ZDO.h"
#endif
#if defined (MT_SAPI_FUNC)
	#include "MT_SAPI.h"
#endif
#if defined (MT_OTA_FUNC)
  #include "MT_OTA.h"
#endif

#if defined( APP_TP )
 #include "TestProfile.h"
#endif
#if defined( APP_TP2 )
 #include "TestProfile2.h"
#endif

#if defined(APP_TGEN)
  #include "TrafficGenApp.h"
#endif
#if defined(APP_DEBUG)
	#include "DebugApp.h"
#endif
#if defined (NWK_TEST)
	#include "HWTTApp.h"
#endif

/* HAL */
#include "hal_uart.h"
#include "hal_led.h"
#include "hal_key.h"
#include "MT_UART.h"

mtProcessMsg_t mtProcessIncoming[] =
{
  NULL,

#if defined (MT_SYS_FUNC)
  MT_SysCommandProcessing,
#else
  NULL,
#endif

#if defined (MT_MAC_FUNC)
  MT_MacCommandProcessing,
#else
  NULL,
#endif

#if defined (MT_NWK_FUNC)
  MT_NwkCommandProcessing,
#else
  NULL,
#endif

#if defined (MT_AF_FUNC)
  MT_AfCommandProcessing,
#else
  NULL,
#endif

#if defined (MT_ZDO_FUNC)
  MT_ZdoCommandProcessing,
#else
  NULL,
#endif

#if defined (MT_SAPI_FUNC)
  MT_SapiCommandProcessing,
#else
  NULL,
#endif

#if defined (MT_UTIL_FUNC)
  MT_UtilCommandProcessing,
#else
  NULL,
#endif

#if defined (MT_DEBUG_FUNC)
  MT_DebugCommandProcessing,
#else
  NULL,
#endif

#if defined (MT_APP_FUNC)
  MT_AppCommandProcessing,
#else
  NULL,
#endif

#if defined (MT_OTA_FUNC)
  MT_OtaCommandProcessing,
#else
  NULL,
#endif
};


byte debugThreshold;
byte debugCompId;


void MT_MsgQueueInit( void );
void MT_ResetMsgQueue( void );
byte MT_QueueMsg( byte *msg , byte len );
void MT_ProcessQueue( void );

#if defined ( MT_USER_TEST_FUNC )
void MT_ProcessAppUserCmd( byte *pData );
#endif

void MT_Init(void)
{
#if defined (MT_ZDO_FUNC)
  MT_ZdoInit();
#endif
  MT_SysResetInd();
}

void MT_BuildSPIMsg( uint8 cmdType, uint8 cmdId, byte *msg, byte dataLen, byte *pData )
{
  /* Fill in the CMD and Data Length */
  *msg++ = dataLen;
  *msg++ = cmdType;
  *msg++ = cmdId;

  /* Fill in the data */
  if ( pData )
  {
    osal_memcpy( msg, pData, dataLen );
  }
}

void MT_BuildAndSendZToolResponse(uint8 cmdType, uint8 cmdId, uint8 dataLen, uint8 *pData)
{
  uint8 *msg_ptr;

  /* Allocate memory including SOP and FCS */
  msg_ptr = MT_TransportAlloc((mtRpcCmdType_t)(cmdType & 0xE0), dataLen);

  if (msg_ptr)
  {
    /* Build the message */
    MT_BuildSPIMsg(cmdType, cmdId, msg_ptr, dataLen, pData);
    /* Send out the msg */
    MT_TransportSend(msg_ptr);
  }
}

void MT_ProcessIncoming(uint8 *pBuf)
{
  mtProcessMsg_t func;
  uint8 rsp[MT_RPC_FRAME_HDR_SZ];

  /* pre-build response message:  | status | cmd0 | cmd1 | */
  rsp[1] = pBuf[MT_RPC_POS_CMD0];
  rsp[2] = pBuf[MT_RPC_POS_CMD1];

  /* check length */
  if (pBuf[MT_RPC_POS_LEN] > MT_RPC_DATA_MAX)
  {
    rsp[0] = MT_RPC_ERR_LENGTH;
  }
  /* check subsystem range */
  else if ((rsp[1] & MT_RPC_SUBSYSTEM_MASK) < MT_RPC_SYS_MAX)
  {
    /* look up processing function */
    func = mtProcessIncoming[rsp[1] & MT_RPC_SUBSYSTEM_MASK];
    if (func)
    {
      /* execute processing function */
      rsp[0] = (*func)(pBuf);
    }
    else
    {
      rsp[0] = MT_RPC_ERR_SUBSYSTEM;
    }
  }
  else
  {
    rsp[0] = MT_RPC_ERR_SUBSYSTEM;
  }

  /* if error and this was an SREQ, send error message */
  if ((rsp[0] != MT_RPC_SUCCESS) && ((rsp[1] & MT_RPC_CMD_TYPE_MASK) == MT_RPC_CMD_SREQ))
  {
    MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_RES0), 0,
                                                                  MT_RPC_FRAME_HDR_SZ, rsp);
  }
}

void MTProcessAppRspMsg( byte *pData, byte len )
{
  /* Send out Reset Response message */
  MT_BuildAndSendZToolResponse( ((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_APP), MT_APP_RSP, len, pData );
}

void MT_ReverseBytes( byte *pData, byte len )
{
  byte i,j;
  byte temp;

  for ( i = 0, j = len-1; len > 1; len-=2 )
  {
    temp = pData[i];
    pData[i++] = pData[j];
    pData[j--] = temp;
  }
}


uint8 *MT_Word2Buf( uint8 *pBuf, uint16 *pWord, uint8 len )
{
  while ( len-- > 0 )
  {
    *pBuf++ = LO_UINT16( *pWord );
    *pBuf++ = HI_UINT16( *pWord );
    pWord++;
  }

  return pBuf;
}
#if !defined(NONWK)

uint8 MT_BuildEndpointDesc( uint8 *pBuf, void *param )
{
  uint8 i;
  uint8 ret = ZSuccess;
  endPointDesc_t *epDesc;

  epDesc = (endPointDesc_t *)param;
  /* check if this endpoint is already registered */
  if ( afFindEndPointDesc( *pBuf ) != NULL )
  {
    ret = ZApsDuplicateEntry;
  }
  else if ( epDesc )
  {
    epDesc->endPoint = *pBuf;

    /* Ignore the latency reqs */
    epDesc->latencyReq = noLatencyReqs;

    /* allocate memory for the simple descriptor */
    epDesc->simpleDesc = (SimpleDescriptionFormat_t *) osal_mem_alloc(sizeof(SimpleDescriptionFormat_t));
    if (epDesc->simpleDesc)
    {
      /* Endpoint */
      epDesc->simpleDesc->EndPoint = *pBuf++;

      /* AppProfId */
      epDesc->simpleDesc->AppProfId = BUILD_UINT16(pBuf[0], pBuf[1]);
      pBuf += sizeof(uint16);

      /* AppDeviceId */
      epDesc->simpleDesc->AppDeviceId = BUILD_UINT16(pBuf[0],pBuf[1]);
      pBuf += sizeof(uint16);

      /* AppDevVer */
      epDesc->simpleDesc->AppDevVer = (*pBuf++) & AF_APP_DEV_VER_MASK ;

      /* LatencyReq */
      pBuf++;

      /* AppNumInClusters */
      epDesc->simpleDesc->AppNumInClusters = *pBuf++;
      if (epDesc->simpleDesc->AppNumInClusters)
      {
        epDesc->simpleDesc->pAppInClusterList = (uint16 *)
                  osal_mem_alloc((epDesc->simpleDesc->AppNumInClusters)*sizeof(uint16));
        if ( epDesc->simpleDesc->pAppInClusterList )
        {
          for (i=0; i<(epDesc->simpleDesc->AppNumInClusters); i++)
          {
            epDesc->simpleDesc->pAppInClusterList[i] = BUILD_UINT16(*pBuf, *(pBuf+1));
            pBuf += 2;
          }
        }
        else
        {
          ret = ZMemError;
        }
      }

      /* AppNumOutClusters */
      epDesc->simpleDesc->AppNumOutClusters = *pBuf++;
      if (epDesc->simpleDesc->AppNumOutClusters)
      {
        epDesc->simpleDesc->pAppOutClusterList = (uint16 *)
                          osal_mem_alloc((epDesc->simpleDesc->AppNumOutClusters)*sizeof(uint16));
        if (epDesc->simpleDesc->pAppOutClusterList)
        {
          for (i=0; i<(epDesc->simpleDesc->AppNumOutClusters); i++)
          {
            epDesc->simpleDesc->pAppOutClusterList[i] = BUILD_UINT16(*pBuf, *(pBuf+1));
            pBuf += 2;
          }
        }
        else
        {
          ret = ZMemError;
        }
      }

      /* if any list cannot be allocated...free all */
      if ( ret == ZMemError )
      {
        if (epDesc->simpleDesc->pAppInClusterList)
        {
          osal_mem_free(epDesc->simpleDesc->pAppInClusterList);
        }

        if (epDesc->simpleDesc->AppNumOutClusters)
        {
          osal_mem_free(epDesc->simpleDesc->pAppOutClusterList);
        }

        osal_mem_free(epDesc->simpleDesc);
      }
    }
    else
    {
      ret = ZMemError;
    }
  }

  return ret;
}
#endif

MT.h

#ifndef MT_H
#define MT_H

#ifdef __cplusplus
extern "C"
{
#endif


#include "MT_RPC.h"
#include "ZComDef.h"


//Special definitions for ZTOOL (Zigbee 0.7 release)
#define ZTEST_DEFAULT_PARAM_LEN              0x10  //( 16 Bytes)
#define ZTEST_DEFAULT_ADDR_LEN               0x08  //(  8 Bytes)
#define ZTEST_DEFAULT_DATA_LEN               0x66  //(102 Bytes)
#define ZTEST_DEFAULT_AF_DATA_LEN            0x20  //( 32 Bytes) - AF
#define ZTEST_DEFAULT_SEC_LEN                0x0B
#define ZTEST_DEFAULT_SEC_PARAM_LEN          0x1C  //( 28 Bytes)

/* AREQ from host */
#define MT_SYS_RESET_REQ                     0x00

/* SREQ/SRSP */
#define MT_SYS_PING                          0x01
#define MT_SYS_VERSION                       0x02
#define MT_SYS_SET_EXTADDR                   0x03
#define MT_SYS_GET_EXTADDR                   0x04
#define MT_SYS_RAM_READ                      0x05
#define MT_SYS_RAM_WRITE                     0x06
#define MT_SYS_OSAL_NV_ITEM_INIT             0x07
#define MT_SYS_OSAL_NV_READ                  0x08
#define MT_SYS_OSAL_NV_WRITE                 0x09
#define MT_SYS_OSAL_START_TIMER              0x0A
#define MT_SYS_OSAL_STOP_TIMER               0x0B
#define MT_SYS_RANDOM                        0x0C
#define MT_SYS_ADC_READ                      0x0D
#define MT_SYS_GPIO                          0x0E
#define MT_SYS_STACK_TUNE                    0x0F
#define MT_SYS_SET_TIME                      0x10
#define MT_SYS_GET_TIME                      0x11
#define MT_SYS_OSAL_NV_DELETE                0x12
#define MT_SYS_OSAL_NV_LENGTH                0x13
#define MT_SYS_SET_TX_POWER                  0x14

/* AREQ to host */
#define MT_SYS_RESET_IND                     0x80
#define MT_SYS_OSAL_TIMER_EXPIRED            0x81

/* SREQ/SRSP */
#define MT_MAC_RESET_REQ                     0x01
#define MT_MAC_INIT                          0x02
#define MT_MAC_START_REQ                     0x03
#define MT_MAC_SYNC_REQ                      0x04
#define MT_MAC_DATA_REQ                      0x05
#define MT_MAC_ASSOCIATE_REQ                 0x06
#define MT_MAC_DISASSOCIATE_REQ              0x07
#define MT_MAC_GET_REQ                       0x08
#define MT_MAC_SET_REQ                       0x09
#define MT_MAC_GTS_REQ                       0x0a
#define MT_MAC_RX_ENABLE_REQ                 0x0b
#define MT_MAC_SCAN_REQ                      0x0c
#define MT_MAC_POLL_REQ                      0x0d
#define MT_MAC_PURGE_REQ                     0x0e
#define MT_MAC_SET_RX_GAIN_REQ               0x0f

/* Security PIB SREQ */
#define MT_MAC_SECURITY_GET_REQ              0x10
#define MT_MAC_SECURITY_SET_REQ              0x11

/* AREQ from Host */
#define MT_MAC_ASSOCIATE_RSP                 0x50
#define MT_MAC_ORPHAN_RSP                    0x51

/* AREQ to host */
#define MT_MAC_SYNC_LOSS_IND                 0x80
#define MT_MAC_ASSOCIATE_IND                 0x81
#define MT_MAC_ASSOCIATE_CNF                 0x82
#define MT_MAC_BEACON_NOTIFY_IND             0x83
#define MT_MAC_DATA_CNF                      0x84
#define MT_MAC_DATA_IND                      0x85
#define MT_MAC_DISASSOCIATE_IND              0x86
#define MT_MAC_DISASSOCIATE_CNF              0x87
#define MT_MAC_GTS_CNF                       0x88
#define MT_MAC_GTS_IND                       0x89
#define MT_MAC_ORPHAN_IND                    0x8a
#define MT_MAC_POLL_CNF                      0x8b
#define MT_MAC_SCAN_CNF                      0x8c
#define MT_MAC_COMM_STATUS_IND               0x8d
#define MT_MAC_START_CNF                     0x8e
#define MT_MAC_RX_ENABLE_CNF                 0x8f
#define MT_MAC_PURGE_CNF                     0x90


/* AREQ from host */
#define MT_NWK_INIT                          0x00

/* SREQ/SRSP */
#define MT_NLDE_DATA_REQ                     0x01
#define MT_NLME_NETWORK_FORMATION_REQ        0x02
#define MT_NLME_PERMIT_JOINING_REQ           0x03
#define MT_NLME_JOIN_REQ                     0x04
#define MT_NLME_LEAVE_REQ                    0x05
#define MT_NLME_RESET_REQ                    0x06
#define MT_NLME_GET_REQ                      0x07
#define MT_NLME_SET_REQ                      0x08
#define MT_NLME_NETWORK_DISCOVERY_REQ        0x09
#define MT_NLME_ROUTE_DISCOVERY_REQ          0x0A
#define MT_NLME_DIRECT_JOIN_REQ              0x0B
#define MT_NLME_ORPHAN_JOIN_REQ              0x0C
#define MT_NLME_START_ROUTER_REQ             0x0D

/* AREQ to host */
#define MT_NLDE_DATA_CONF                    0x80
#define MT_NLDE_DATA_IND                     0x81
#define MT_NLME_NETWORK_FORMATION_CONF       0x82
#define MT_NLME_JOIN_CONF                    0x83
#define MT_NLME_JOIN_IND                     0x84
#define MT_NLME_LEAVE_CONF                   0x85
#define MT_NLME_LEAVE_IND                    0x86
#define MT_NLME_POLL_CONF                    0x87
#define MT_NLME_SYNC_IND                     0x88
#define MT_NLME_NETWORK_DISCOVERY_CONF       0x89
#define MT_NLME_START_ROUTER_CONF            0x8A


/* SREQ/SRSP */
#define MT_AF_REGISTER                       0x00
#define MT_AF_DATA_REQUEST                   0x01  /* AREQ optional, but no AREQ response. */
#define MT_AF_DATA_REQUEST_EXT               0x02  /* AREQ optional, but no AREQ response. */
#define MT_AF_DATA_REQUEST_SRCRTG            0x03

#define MT_AF_INTER_PAN_CTL                  0x10
#define MT_AF_DATA_STORE                     0x11
#define MT_AF_DATA_RETRIEVE                  0x12
#define MT_AF_APSF_CONFIG_SET                0x13

/* AREQ to host */
#define MT_AF_DATA_CONFIRM                   0x80
#define MT_AF_INCOMING_MSG                   0x81
#define MT_AF_INCOMING_MSG_EXT               0x82

/* SREQ/SRSP */
#define MT_ZDO_NWK_ADDR_REQ                  0x00
#define MT_ZDO_IEEE_ADDR_REQ                 0x01
#define MT_ZDO_NODE_DESC_REQ                 0x02
#define MT_ZDO_POWER_DESC_REQ                0x03
#define MT_ZDO_SIMPLE_DESC_REQ               0x04
#define MT_ZDO_ACTIVE_EP_REQ                 0x05
#define MT_ZDO_MATCH_DESC_REQ                0x06
#define MT_ZDO_COMPLEX_DESC_REQ              0x07
#define MT_ZDO_USER_DESC_REQ                 0x08
#define MT_ZDO_END_DEV_ANNCE                 0x0A
#define MT_ZDO_USER_DESC_SET                 0x0B
#define MT_ZDO_SERVICE_DISC_REQ              0x0C
#define MT_ZDO_END_DEV_BIND_REQ              0x20
#define MT_ZDO_BIND_REQ                      0x21
#define MT_ZDO_UNBIND_REQ                    0x22

#define MT_ZDO_SET_LINK_KEY                  0x23
#define MT_ZDO_REMOVE_LINK_KEY               0x24
#define MT_ZDO_GET_LINK_KEY                  0x25
#define MT_ZDO_NWK_DISCOVERY_REQ             0x26
#define MT_ZDO_JOIN_REQ                      0x27

#define MT_ZDO_MGMT_NWKDISC_REQ              0x30
#define MT_ZDO_MGMT_LQI_REQ                  0x31
#define MT_ZDO_MGMT_RTG_REQ                  0x32
#define MT_ZDO_MGMT_BIND_REQ                 0x33
#define MT_ZDO_MGMT_LEAVE_REQ                0x34
#define MT_ZDO_MGMT_DIRECT_JOIN_REQ          0x35
#define MT_ZDO_MGMT_PERMIT_JOIN_REQ          0x36
#define MT_ZDO_MGMT_NWK_UPDATE_REQ           0x37

/* AREQ optional, but no AREQ response. */
#define MT_ZDO_MSG_CB_REGISTER               0x3E
#define MT_ZDO_MSG_CB_REMOVE                 0x3F
#define MT_ZDO_STARTUP_FROM_APP              0x40

/* AREQ from host */
#define MT_ZDO_AUTO_FIND_DESTINATION_REQ     0x41

/* AREQ to host */
#define MT_ZDO_AREQ_TO_HOST                  0x80 /* Mark the start of the ZDO CId AREQs to host. */
#define MT_ZDO_NWK_ADDR_RSP               /* 0x80 */ ((uint8)NWK_addr_req | 0x80)
#define MT_ZDO_IEEE_ADDR_RSP              /* 0x81 */ ((uint8)IEEE_addr_req | 0x80)
#define MT_ZDO_NODE_DESC_RSP              /* 0x82 */ ((uint8)Node_Desc_req | 0x80)
#define MT_ZDO_POWER_DESC_RSP             /* 0x83 */ ((uint8)Power_Desc_req | 0x80)
#define MT_ZDO_SIMPLE_DESC_RSP            /* 0x84 */ ((uint8)Simple_Desc_req | 0x80)
#define MT_ZDO_ACTIVE_EP_RSP              /* 0x85 */ ((uint8)Active_EP_req | 0x80)
#define MT_ZDO_MATCH_DESC_RSP             /* 0x86 */ ((uint8)Match_Desc_req | 0x80)

#define MT_ZDO_COMPLEX_DESC_RSP              0x87
#define MT_ZDO_USER_DESC_RSP                 0x88
//                                        /* 0x92 */ ((uint8)Discovery_Cache_req | 0x80)
#define MT_ZDO_USER_DESC_CONF                0x89
#define MT_ZDO_SERVER_DISC_RSP               0x8A

#define MT_ZDO_END_DEVICE_BIND_RSP        /* 0xA0 */ ((uint8)End_Device_Bind_req | 0x80)
#define MT_ZDO_BIND_RSP                   /* 0xA1 */ ((uint8)Bind_req | 0x80)
#define MT_ZDO_UNBIND_RSP                 /* 0xA2 */ ((uint8)Unbind_req | 0x80)

#define MT_ZDO_MGMT_NWK_DISC_RSP          /* 0xB0 */ ((uint8)Mgmt_NWK_Disc_req | 0x80)
#define MT_ZDO_MGMT_LQI_RSP               /* 0xB1 */ ((uint8)Mgmt_Lqi_req | 0x80)
#define MT_ZDO_MGMT_RTG_RSP               /* 0xB2 */ ((uint8)Mgmt_Rtg_req | 0x80)
#define MT_ZDO_MGMT_BIND_RSP              /* 0xB3 */ ((uint8)Mgmt_Bind_req | 0x80)
#define MT_ZDO_MGMT_LEAVE_RSP             /* 0xB4 */ ((uint8)Mgmt_Leave_req | 0x80)
#define MT_ZDO_MGMT_DIRECT_JOIN_RSP       /* 0xB5 */ ((uint8)Mgmt_Direct_Join_req | 0x80)
#define MT_ZDO_MGMT_PERMIT_JOIN_RSP       /* 0xB6 */ ((uint8)Mgmt_Permit_Join_req | 0x80)

//                                        /* 0xB8 */ ((uint8)Mgmt_NWK_Update_req | 0x80)

#define MT_ZDO_STATE_CHANGE_IND              0xC0
#define MT_ZDO_END_DEVICE_ANNCE_IND          0xC1
#define MT_ZDO_MATCH_DESC_RSP_SENT           0xC2
#define MT_ZDO_STATUS_ERROR_RSP              0xC3
#define MT_ZDO_SRC_RTG_IND                   0xC4
#define MT_ZDO_BEACON_NOTIFY_IND             0xC5
#define MT_ZDO_JOIN_CNF                      0xC6
#define MT_ZDO_NWK_DISCOVERY_CNF             0xC7
#define MT_ZDO_CONCENTRATOR_IND_CB           0xC8
#define MT_ZDO_LEAVE_IND                     0xC9

#define MT_ZDO_MSG_CB_INCOMING               0xFF

// Some arbitrarily chosen value for a default error status msg.
#define MtZdoDef_rsp                         0x0040


// SAPI MT Command Identifiers
/* AREQ from Host */
#define MT_SAPI_SYS_RESET                   0x09

/* SREQ/SRSP */
#define MT_SAPI_START_REQ                   0x00
#define MT_SAPI_BIND_DEVICE_REQ             0x01
#define MT_SAPI_ALLOW_BIND_REQ              0x02
#define MT_SAPI_SEND_DATA_REQ               0x03
#define MT_SAPI_READ_CFG_REQ                0x04
#define MT_SAPI_WRITE_CFG_REQ               0x05
#define MT_SAPI_GET_DEV_INFO_REQ            0x06
#define MT_SAPI_FIND_DEV_REQ                0x07
#define MT_SAPI_PMT_JOIN_REQ                0x08
#define MT_SAPI_APP_REGISTER_REQ            0x0a

/* AREQ to host */
#define MT_SAPI_START_CNF                   0x80
#define MT_SAPI_BIND_CNF                    0x81
#define MT_SAPI_ALLOW_BIND_CNF              0x82
#define MT_SAPI_SEND_DATA_CNF               0x83
#define MT_SAPI_READ_CFG_RSP                0x84
#define MT_SAPI_FIND_DEV_CNF                0x85
#define MT_SAPI_DEV_INFO_RSP                0x86
#define MT_SAPI_RCV_DATA_IND                0x87


/* SREQ/SRSP: */
#define MT_UTIL_GET_DEVICE_INFO              0x00
#define MT_UTIL_GET_NV_INFO                  0x01
#define MT_UTIL_SET_PANID                    0x02
#define MT_UTIL_SET_CHANNELS                 0x03
#define MT_UTIL_SET_SECLEVEL                 0x04
#define MT_UTIL_SET_PRECFGKEY                0x05
#define MT_UTIL_CALLBACK_SUB_CMD             0x06
#define MT_UTIL_KEY_EVENT                    0x07
#define MT_UTIL_TIME_ALIVE                   0x09
#define MT_UTIL_LED_CONTROL                  0x0A

#define MT_UTIL_TEST_LOOPBACK                0x10
#define MT_UTIL_DATA_REQ                     0x11

#define MT_UTIL_SRC_MATCH_ENABLE             0x20
#define MT_UTIL_SRC_MATCH_ADD_ENTRY          0x21
#define MT_UTIL_SRC_MATCH_DEL_ENTRY          0x22
#define MT_UTIL_SRC_MATCH_CHECK_SRC_ADDR     0x23
#define MT_UTIL_SRC_MATCH_ACK_ALL_PENDING    0x24
#define MT_UTIL_SRC_MATCH_CHECK_ALL_PENDING  0x25

#define MT_UTIL_ADDRMGR_EXT_ADDR_LOOKUP      0x40
#define MT_UTIL_ADDRMGR_NWK_ADDR_LOOKUP      0x41
#define MT_UTIL_APSME_LINK_KEY_DATA_GET      0x44
#define MT_UTIL_APSME_LINK_KEY_NV_ID_GET     0x45
#define MT_UTIL_ASSOC_COUNT                  0x48
#define MT_UTIL_ASSOC_FIND_DEVICE            0x49
#define MT_UTIL_ASSOC_GET_WITH_ADDRESS       0x4A
#define MT_UTIL_APSME_REQUEST_KEY_CMD        0x4B

#define MT_UTIL_ZCL_KEY_EST_INIT_EST         0x80
#define MT_UTIL_ZCL_KEY_EST_SIGN             0x81

/* AREQ from/to host */
#define MT_UTIL_SYNC_REQ                     0xE0
#define MT_UTIL_ZCL_KEY_ESTABLISH_IND        0xE1


/* SREQ/SRSP: */
#define MT_DEBUG_SET_THRESHOLD               0x00

#define MT_DEBUG_MAC_DATA_DUMP               0x10

/* AREQ */
#define MT_DEBUG_MSG                         0x80


/* SREQ/SRSP: */
#define MT_APP_MSG                           0x00
#define MT_APP_USER_TEST                     0x01

/* SRSP */
#define MT_APP_RSP                           0x80

#define MT_OTA_FILE_READ_REQ                  0x00
#define MT_OTA_NEXT_IMG_REQ                   0x01

#define MT_OTA_FILE_READ_RSP                  0x80
#define MT_OTA_NEXT_IMG_RSP                   0x81
#define MT_OTA_STATUS_IND                     0x82


/* Task Event IDs - bit masks */
#define MT_ZTOOL_SERIAL_RCV_CHAR        0x0001
#define MT_ZTOOL_SERIAL_RCV_BUFFER_FULL 0x0002
#define MT_SERIAL_ZTOOL_XMT_READY       0x0004
#define MT_ZAPP_SERIAL_RCV_CHAR         MT_ZTOOL_SERIAL_RCV_CHAR
#define MT_ZAPP_SERIAL_RCV_BUFFER_FULL  MT_ZTOOL_SERIAL_RCV_BUFFER_FULL
#define MT_SERIAL_ZAPP_XMT_READY        MT_SERIAL_ZTOOL_XMT_READY
#define MT_AF_EXEC_EVT                  0x0008
#define MT_SECONDARY_INIT_EVENT         0x0010

#define MT_MSG_SEQUENCE_EVT             0x0040
#define MT_KEYPRESS_POLL_EVT            0x0080

/* SYS_OSAL_EVENT ID's */
#define MT_SYS_OSAL_EVENT_0             0x0800
#define MT_SYS_OSAL_EVENT_1             0x0400
#define MT_SYS_OSAL_EVENT_2             0x0200
#define MT_SYS_OSAL_EVENT_3             0x0100
#define MT_SYS_OSAL_EVENT_MASK (MT_SYS_OSAL_EVENT_0 | MT_SYS_OSAL_EVENT_1 | \
                                MT_SYS_OSAL_EVENT_2 | MT_SYS_OSAL_EVENT_3)

/* Message Command IDs */
#define CMD_SERIAL_MSG                  0x01
#define CMD_DEBUG_MSG                   0x02
#define CMD_TX_MSG                      0x03
#define CB_FUNC                         0x04
#define CMD_SEQUENCE_MSG                0x05
#define CMD_DEBUG_STR                   0x06
#define AF_INCOMING_MSG_FOR_MT          0x0F

/* Error Response IDs */
#define UNRECOGNIZED_COMMAND            0x00
#define UNSUPPORTED_COMMAND             0x01
#define RECEIVE_BUFFER_FULL             0x02

/* Serial Message Command IDs */
#define SPI_CMD_DEBUG_MSG               0x4003
#define SPI_CMD_TRACE_SUB               0x0004
#define SPI_CMD_TRACE_MSG               0x4004

/* User CMD IDs */
#define SPI_CMD_USER0                   0x000A
#define SPI_CMD_USER1                   0x000B
#define SPI_CMD_USER2                   0x000C
#define SPI_CMD_USER3                   0x000D
#define SPI_CMD_USER4                   0x000E
#define SPI_CMD_USER5                   0x000F


#define SPI_SYS_STRING_MSG              0x0015
#define SPI_CMD_SYS_NETWORK_START       0x0020
#define SPI_CMD_ZIGNET_DATA             0x0022

/* system command response */
#define SPI_CB_SYS_CALLBACK_SUB_RSP     0x1006
#define SPI_CB_SYS_PING_RSP             0x1007
#define SPI_CB_SYS_GET_DEVICE_INFO_RSP  0x1014
#define SPI_CB_SYS_KEY_EVENT_RSP        0x1016
#define SPI_CB_SYS_HEARTBEAT_RSP        0x1017
#define SPI_CB_SYS_LED_CONTROL_RSP      0x1019

/* Message Sequence definitions */
#define SPI_CMD_SEQ_START               0x0600
#define SPI_CMD_SEQ_WAIT                0x0601
#define SPI_CMD_SEQ_END                 0x0602
#define SPI_CMD_SEQ_RESET               0x0603
#define DEFAULT_WAIT_INTERVAL           5000      //5 seconds

/* Serial Message Command Routing Bits */
#define SPI_RESPONSE_BIT                0x1000
#define SPI_SUBSCRIPTION_BIT            0x2000
#define SPI_DEBUGTRACE_BIT              0x4000

#define SPI_0DATA_MSG_LEN                5
#define SPI_RESP_MSG_LEN_DEFAULT         6

#define LEN_MAC_BEACON_MSDU             15
#define LEN_MAC_COORDEXTND_ADDR          8
#define LEN_MAC_ATTR_BYTE                1
#define LEN_MAC_ATTR_INT                 2

#define SOP_FIELD                        0
#define CMD_FIELD_HI                     1
#define CMD_FIELD_LO                     2
#define DATALEN_FIELD                    3
#define DATA_BEGIN                       4

/* MT PACKET (For Test Tool): FIELD IDENTIFIERS */
#define MT_MAC_CB_ID                0
#define MT_OFFSET                   1
#define MT_SOP_FIELD                MT_OFFSET + SOP_FIELD
#define MT_CMD_FIELD_HI             MT_OFFSET + CMD_FIELD_HI
#define MT_CMD_FIELD_LO             MT_OFFSET + CMD_FIELD_LO
#define MT_DATALEN_FIELD            MT_OFFSET + DATALEN_FIELD
#define MT_DATA_BEGIN               MT_OFFSET + DATA_BEGIN

#define MT_INFO_HEADER_LEN         1
#define MT_RAM_READ_RESP_LEN       0x02
#define MT_RAM_WRITE_RESP_LEN      0x01

/* Defines for the fields in the AF structures */
#define AF_INTERFACE_BITS          0x07
#define AF_INTERFACE_OFFSET        0x05
#define AF_APP_DEV_VER_MASK        0x0F
#define AF_APP_FLAGS_MASK          0x0F
#define AF_TRANSTYPE_MASK          0x0F
#define AF_TRANSDATATYPE_MASK      0x0F

#define TGEN_START									0x000a
#define TGEN_STOP										0x000b
#define TGEN_COUNT									0x000c
#define DEBUG_GET					          0x000d
#define HW_TEST                     0x000e
#define HW_DISPLAY_RESULT						0x000f
#define HW_SEND_STATUS							0x0010

#if defined( APP_TP ) || defined ( APP_TP2 )
#if defined( APP_TP )
#define TP_SEND_NODATA              0x0011
#else
#define TP_SEND_BCAST_RSP           0x0011
#endif
#define TP_SEND_BUFFERTEST          0x0012
#if defined (APP_TP)
#define TP_SEND_UINT8               0x0013
#define TP_SEND_INT8                0x0014
#define TP_SEND_UINT16              0x0015
#define TP_SEND_INT16               0x0016
#define TP_SEND_SEMIPREC            0x0017
#endif
#define TP_SEND_FREEFORM            0x0018
#if defined( APP_TP )
#define TP_SEND_ABS_TIME            0x0019
#define TP_SEND_REL_TIME            0x001A
#define TP_SEND_CHAR_STRING         0x001B
#define TP_SEND_OCTET_STRING        0x001C
#endif
#define TP_SET_DSTADDRESS           0x001D
#if defined( APP_TP2 )
#define TP_SEND_BUFFER_GROUP        0x001E
#endif
#define TP_SEND_BUFFER              0x001F
#if defined( APP_TP )
#define TP_SEND_CON_INT8						0x0020
#define TP_SEND_CON_INT16						0x0021
#define TP_SEND_CON_TIME						0x0022

#define TP_SEND_MULT_KVP_8BIT       0x0023
#define TP_SEND_MULT_KVP_16BIT      0x0024
#define TP_SEND_MULT_KVP_TIME       0x0025
#define TP_SEND_MULT_KVP_STRING     0x0026
#endif

#define TP_SEND_COUNTED_PKTS        0x0027
#define TP_SEND_RESET_COUNTER       0x0028
#define TP_SEND_GET_COUNTER         0x0029

#if defined( APP_TP )
#define TP_SEND_MULTI_KVP_STR_TIME  0x0030
#endif

#define TP_SET_PERMIT_JOIN          0x0040

#define TP_ADD_GROUP                0x0041
#define TP_REMOVE_GROUP             0x0042

#define TP_SEND_UPDATE_KEY          0x0043
#define TP_SEND_SWITCH_KEY          0x0044

#if defined( APP_TP2 )
#define TP_SEND_BUFFERTEST_GROUP    0x0045
#define TP_SEND_ROUTE_DISC_REQ      0x0046
#define TP_SEND_ROUTE_DISCOVERY     0x0047
#define TP_SEND_NEW_ADDR            0x0048
#define TP_SEND_NWK_UPDATE          0x0049
#define TP_AK_SETUP_PARTNER         0x0050
#define TP_AK_REQ_KEY               0x0051
#define TP_AK_PARTNER_NWKADDR       0x0052
#define TP_AK_PARTNER_EXTADDR7654   0x0053
#define TP_AK_PARTNER_EXTADDR3210   0x0054
#define TP_AK_PARTNER_SET           0x0055
#define TP_AK_TYPE_SET              0x0056
#define TP_FRAG_SKIP_BLOCK          0x0057
#define TP_APS_REMOVE               0x0058
#define TP_NWK_ADDR_CONFLICT        0x0059
#endif

#endif

#if defined ( OSAL_TOTAL_MEM )
  #define OSAL_MEM_STACK_HIGH_WATER   0x0100
  #define OSAL_MEM_HEAP_HIGH_WATER    0x0101
#endif

/* Capabilities - PING Response */

#if defined (MT_SYS_FUNC)
  #define MT_CAP_SYS    0x0001
#else
  #define MT_CAP_SYS    0x0000
#endif

#if defined ( MT_MAC_FUNC )
  #define MT_CAP_MAC    0x0002
#else
  #define MT_CAP_MAC    0x0000
#endif

#if defined ( MT_NWK_FUNC )
  #define MT_CAP_NWK    0x0004
#else
  #define MT_CAP_NWK    0x0000
#endif

#if defined ( MT_AF_FUNC )
  #define MT_CAP_AF     0x0008
#else
  #define MT_CAP_AF     0x0000
#endif

#if defined ( MT_ZDO_FUNC )
  #define MT_CAP_ZDO    0x0010
#else
  #define MT_CAP_ZDO    0x0000
#endif

#if defined ( MT_SAPI_FUNC )
  #define MT_CAP_SAPI   0x0020
#else
  #define MT_CAP_SAPI   0x0000
#endif

#if defined ( MT_UTIL_FUNC )
  #define MT_CAP_UTIL   0x0040
#else
  #define MT_CAP_UTIL   0x0000
#endif

#if defined ( MT_DEBUG_FUNC )
  #define MT_CAP_DEBUG  0x0080
#else
  #define MT_CAP_DEBUG  0x0000
#endif

#if defined ( MT_APP_FUNC )
  #define MT_CAP_APP    0x0100
#else
  #define MT_CAP_APP    0x0000
#endif

#if defined ( ZPORT )
  #define MT_CAP_ZOAD 0x1000
#else
  #define MT_CAP_ZOAD 0x0000
#endif

/* ZNP NV items, 1-4 2-bytes each, 5-6 16-bytes each */
#define ZNP_NV_APP_ITEM_1       0x0F01
#define ZNP_NV_APP_ITEM_2       0x0F02
#define ZNP_NV_APP_ITEM_3       0x0F03
#define ZNP_NV_APP_ITEM_4       0x0F04
#define ZNP_NV_APP_ITEM_5       0x0F05
#define ZNP_NV_APP_ITEM_6       0x0F06

#define ZNP_NV_RF_TEST_PARMS    0x0F07

typedef struct {
  uint16 waitInterval;
  byte *msg;
  void *next;
} MT_msg_queue_t;

extern byte MT_TaskID;
extern byte debugThreshold;
extern byte debugCompId;

extern byte queueMsgs;
extern MT_msg_queue_t *_pMtMsgQueue;
extern MT_msg_queue_t *_pLastInQueue;
extern MT_msg_queue_t *_pCurQueueElem;

extern void MT_BuildAndSendZToolResponse(uint8 cmdType, uint8 cmdId, uint8 dataLen, uint8 *dataPtr);

extern void MT_BuildSPIMsg( uint8 cmdType, uint8 cmdId, byte *msg, byte dataLen, byte *dataPtr );

extern void MT_ProcessUserCmd( byte cmd );

extern void MT_RadioCommandProcessing( uint16 cmd_id , byte len , byte *pData );

extern void MT_PhyCommandProcessing( uint16 cmd_id , byte len , byte *pData );

extern uint8 *MT_Word2Buf( uint8 *pBuf, uint16 *pWord, uint8 len );

extern void MT_ReverseBytes( byte *pData, byte len );

extern void MTProcessAppRspMsg(byte *pData, byte len);

extern void MT_Init(void);

extern void MT_ProcessIncoming(uint8 *pBuf);


extern uint8 *MT_TransportAlloc(uint8 cmd0, uint8 len);

extern void MT_TransportSend(uint8 *pBuf);

extern uint8 MT_BuildEndpointDesc( uint8 *pBuf, void *param );


#ifdef __cplusplus
}
#endif

#endif

MT_AF.c

#include "ZComDef.h"
#include "OSAL.h"
#include "MT.h"
#include "MT_AF.h"
#include "MT_ZDO.h"
#include "nwk.h"
#include "OnBoard.h"
#include "MT_UART.h"

#if defined INTER_PAN
#include "stub_aps.h"
#endif


#if !defined MT_AF_EXEC_CNT
#define MT_AF_EXEC_CNT  15
#endif

#if !defined MT_AF_EXEC_DLY
#define MT_AF_EXEC_DLY  1000
#endif


typedef struct
{
  uint8 *data;
  afAddrType_t dstAddr;
  endPointDesc_t *epDesc;
  uint16 cId;
  uint16 dataLen;
  uint8 transId;
  uint8 txOpts;
  uint8 radius;
  uint8 tick;
} mtAfDataReq_t;

typedef struct _mtAfInMsgList_t
{
  struct _mtAfInMsgList_t *next;
  uint8 *data;
  uint32 timestamp;         // Receipt timestamp from MAC.
  uint8 tick;
} mtAfInMsgList_t;


mtAfInMsgList_t *pMtAfInMsgList = NULL;
mtAfDataReq_t *pMtAfDataReq = NULL;


#if defined ( MT_AF_CB_FUNC )
uint16 _afCallbackSub;
#endif


void MT_AfRegister(uint8 *pBuf);
void MT_AfDataRequest(uint8 *pBuf);

#if defined ( ZIGBEE_SOURCE_ROUTING )
void MT_AfDataRequestSrcRtg(uint8 *pBuf);
#endif

#if defined INTER_PAN
static void MT_AfInterPanCtl(uint8 *pBuf);
#endif

static void MT_AfDataRetrieve(uint8 *pBuf);
static void MT_AfDataStore(uint8 *pBuf);
static void MT_AfAPSF_ConfigSet(uint8 *pBuf);

void MT_AfExec(void)
{
  mtAfInMsgList_t *pPrev, *pItem = pMtAfInMsgList;

  while (pItem != NULL)
  {
    if (--(pItem->tick) == 0)
    {
      if (pMtAfInMsgList == pItem)
      {
        pMtAfInMsgList = pItem->next;
        (void)osal_mem_free(pItem);
        pItem = pMtAfInMsgList;
      }
      else
      {
        pPrev->next = pItem->next;
        (void)osal_mem_free(pItem);
        pItem = pPrev->next;
      }
    }
    else
    {
      pPrev = pItem;
      pItem = pItem->next;
    }
  }

  if (pMtAfDataReq != NULL)
  {
    if (--(pMtAfDataReq->tick) == 0)
    {
      (void)osal_mem_free(pMtAfDataReq);
      pMtAfDataReq = NULL;
    }
  }

  if ((pMtAfInMsgList != NULL) || (pMtAfDataReq != NULL))
  {
    if (ZSuccess != osal_start_timerEx(MT_TaskID, MT_AF_EXEC_EVT, MT_AF_EXEC_DLY))
    {
      osal_set_event(MT_TaskID, MT_AF_EXEC_EVT);
    }
  }
}

uint8 MT_AfCommandProcessing(uint8 *pBuf)
{
  uint8 status = MT_RPC_SUCCESS;

  switch (pBuf[MT_RPC_POS_CMD1])
  {
    case MT_AF_REGISTER:
      MT_AfRegister(pBuf);
      break;

    case MT_AF_DATA_REQUEST:
    case MT_AF_DATA_REQUEST_EXT:
      MT_AfDataRequest(pBuf);
      break;

#if defined ( ZIGBEE_SOURCE_ROUTING )
    case MT_AF_DATA_REQUEST_SRCRTG:
      MT_AfDataRequestSrcRtg(pBuf);
      break;
#endif

#if defined INTER_PAN
    case MT_AF_INTER_PAN_CTL:
      MT_AfInterPanCtl(pBuf);
      break;
#endif

    case MT_AF_DATA_RETRIEVE:
      MT_AfDataRetrieve(pBuf);
      break;

    case MT_AF_DATA_STORE:
      MT_AfDataStore(pBuf);
      break;

    case MT_AF_APSF_CONFIG_SET:
      MT_AfAPSF_ConfigSet(pBuf);
      break;

    default:
      status = MT_RPC_ERR_COMMAND_ID;
      break;
  }

  return status;
}

void MT_AfRegister(uint8 *pBuf)
{
  uint8 cmdId;
  uint8 retValue = ZMemError;
  endPointDesc_t *epDesc;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  epDesc = (endPointDesc_t *)osal_mem_alloc(sizeof(endPointDesc_t));
  if ( epDesc )
  {
    epDesc->task_id = &MT_TaskID;
    retValue = MT_BuildEndpointDesc( pBuf, epDesc );
    if ( retValue == ZSuccess )
    {
      retValue = afRegister( epDesc );
    }

    if ( retValue != ZSuccess )
    {
      osal_mem_free( epDesc );
    }
  }

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_AF), cmdId, 1, &retValue);
}

void MT_AfDataRequest(uint8 *pBuf)
{
  #define MT_AF_REQ_MSG_LEN  10
  #define MT_AF_REQ_MSG_EXT  10

  endPointDesc_t *epDesc;
  afAddrType_t dstAddr;
  cId_t cId;
  uint8 transId, txOpts, radius;
  uint8 cmd0, cmd1;
  uint8 retValue = ZFailure;
  uint16 dataLen, tempLen;

  /* Parse header */
  cmd0 = pBuf[MT_RPC_POS_CMD0];
  cmd1 = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  if (cmd1 == MT_AF_DATA_REQUEST_EXT)
  {
    dstAddr.addrMode = (afAddrMode_t)*pBuf++;

    if (dstAddr.addrMode == afAddr64Bit)
    {
      (void)osal_memcpy(dstAddr.addr.extAddr, pBuf, Z_EXTADDR_LEN);
    }
    else
    {
      dstAddr.addr.shortAddr = BUILD_UINT16(pBuf[0], pBuf[1]);
    }
    pBuf += Z_EXTADDR_LEN;

    dstAddr.endPoint = *pBuf++;
    dstAddr.panId = BUILD_UINT16(pBuf[0], pBuf[1]);
    pBuf += 2;
  }
  else
  {
    /* Destination address */
    dstAddr.addrMode = afAddr16Bit;
    dstAddr.addr.shortAddr = BUILD_UINT16(pBuf[0], pBuf[1]);
    pBuf += 2;

    /* Destination endpoint */
    dstAddr.endPoint = *pBuf++;
    dstAddr.panId = 0;
  }

  /* Source endpoint */
  epDesc = afFindEndPointDesc(*pBuf++);

  /* ClusterId */
  cId = BUILD_UINT16(pBuf[0], pBuf[1]);
  pBuf +=2;

  /* TransId */
  transId = *pBuf++;

  /* TxOption */
  txOpts = *pBuf++;

  /* Radius */
  radius = *pBuf++;

  /* Length */
  if (cmd1 == MT_AF_DATA_REQUEST_EXT)
  {
    dataLen = BUILD_UINT16(pBuf[0], pBuf[1]);
    tempLen = dataLen + MT_AF_REQ_MSG_LEN + MT_AF_REQ_MSG_EXT;
    pBuf += 2;
  }
  else
  {
    dataLen = *pBuf++;
    tempLen = dataLen + MT_AF_REQ_MSG_LEN;
  }

  if ( epDesc == NULL )
  {
    retValue = afStatus_INVALID_PARAMETER;
  }
  else if (tempLen > (uint16)MT_RPC_DATA_MAX)
  {
    if (pMtAfDataReq != NULL)
    {
      retValue = afStatus_INVALID_PARAMETER;
    }
    else if ((pMtAfDataReq = osal_mem_alloc(sizeof(mtAfDataReq_t) + dataLen)) == NULL)
    {
      retValue = afStatus_MEM_FAIL;
    }
    else
    {
      retValue = afStatus_SUCCESS;

      pMtAfDataReq->data = (uint8 *)(pMtAfDataReq+1);
      (void)osal_memcpy(&(pMtAfDataReq->dstAddr), &dstAddr, sizeof(afAddrType_t));
      pMtAfDataReq->epDesc = epDesc;
      pMtAfDataReq->cId = cId;
      pMtAfDataReq->dataLen = dataLen;
      pMtAfDataReq->transId = transId;
      pMtAfDataReq->txOpts = txOpts;
      pMtAfDataReq->radius = radius;

      // Setup to time-out the huge outgoing item if host does not MT_AF_DATA_STORE it.
      pMtAfDataReq->tick = MT_AF_EXEC_CNT;
      if (ZSuccess != osal_start_timerEx(MT_TaskID, MT_AF_EXEC_EVT, MT_AF_EXEC_DLY))
      {
        (void)osal_set_event(MT_TaskID, MT_AF_EXEC_EVT);
      }
    }
  }
  else
  {
    retValue = AF_DataRequest(&dstAddr, epDesc, cId, dataLen, pBuf, &transId, txOpts, radius);
  }

  if (MT_RPC_CMD_SREQ == (cmd0 & MT_RPC_CMD_TYPE_MASK))
  {
    MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP|(uint8)MT_RPC_SYS_AF), cmd1, 1, &retValue);
  }
}

#if defined ( ZIGBEE_SOURCE_ROUTING )

void MT_AfDataRequestSrcRtg(uint8 *pBuf)
{
  uint8 cmdId, dataLen = 0;
  uint8 retValue = ZFailure;
  endPointDesc_t *epDesc;
  byte transId;
  afAddrType_t dstAddr;
  cId_t cId;
  byte txOpts, radius, srcEP, relayCnt;
  uint16 *pRelayList;
  uint8 i;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Destination address */
  /* Initialize the panID field to zero to avoid inter-pan */
  osal_memset( &dstAddr, 0, sizeof(afAddrType_t) );
  dstAddr.addrMode = afAddr16Bit;
  dstAddr.addr.shortAddr = BUILD_UINT16(pBuf[0], pBuf[1]);
  pBuf += 2;

  /* Destination endpoint */
  dstAddr.endPoint = *pBuf++;

  /* Source endpoint */
  srcEP = *pBuf++;
  epDesc = afFindEndPointDesc( srcEP );

  /* ClusterId */
  cId = BUILD_UINT16(pBuf[0], pBuf[1]);
  pBuf +=2;

  /* TransId */
  transId = *pBuf++;

  /* TxOption */
  txOpts = *pBuf++;

  /* Radius */
  radius = *pBuf++;

  /* Source route relay count */
  relayCnt = *pBuf++;

  /* Convert the source route relay list */
  if( (pRelayList = osal_mem_alloc( relayCnt * sizeof( uint16 ))) != NULL )
  {
    for( i = 0; i < relayCnt; i++ )
    {
      pRelayList[i]  = BUILD_UINT16( pBuf[0], pBuf[1] );
      pBuf += 2;
    }

    /* Data payload Length */
    dataLen = *pBuf++;

    if ( epDesc == NULL )
    {
      retValue = afStatus_INVALID_PARAMETER;
    }
    else
    {
      retValue = AF_DataRequestSrcRtg( &dstAddr, epDesc, cId, dataLen, pBuf,
                                     &transId, txOpts, radius, relayCnt, pRelayList );
    }

    /* Free the memory allocated */
    osal_mem_free( pRelayList );
  }
  else
  {
    retValue = afStatus_MEM_FAIL;
  }


  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_AF), cmdId, 1, &retValue);
}
#endif

#if defined INTER_PAN

static void MT_AfInterPanCtl(uint8 *pBuf)
{
  uint8 cmd, rtrn;
  uint16 panId;
  endPointDesc_t *pEP;

  cmd = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  switch (*pBuf++)  // Inter-pan request parameter.
  {
  case InterPanClr:
    rtrn = StubAPS_SetIntraPanChannel();           // Switch channel back to the NIB channel.
    break;

  case InterPanSet:
    rtrn = StubAPS_SetInterPanChannel(*pBuf);      // Set channel for inter-pan communication.
    break;

  case InterPanReg:
    if ((pEP = afFindEndPointDesc(*pBuf)))
    {
      StubAPS_RegisterApp(pEP);
      rtrn = SUCCESS;
    }
    else
    {
      rtrn = FAILURE;
    }
    break;

  case InterPanChk:
    panId = BUILD_UINT16(pBuf[0], pBuf[1]);
    rtrn = (StubAPS_InterPan(panId, pBuf[2])) ? ZSuccess : ZFailure;
    break;

  default:
    rtrn = afStatus_INVALID_PARAMETER;
    break;
  }

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_AF), cmd, 1, &rtrn);
}
#endif

void MT_AfDataConfirm(afDataConfirm_t *pMsg)
{
  uint8 retArray[3];

  retArray[0] = pMsg->hdr.status;
  retArray[1] = pMsg->endpoint;
  retArray[2] = pMsg->transID;

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_AF), MT_AF_DATA_CONFIRM, 3, retArray);
}

void MT_AfIncomingMsg(afIncomingMSGPacket_t *pMsg)
{
  #define MT_AF_INC_MSG_LEN  17
  #define MT_AF_INC_MSG_EXT  10

  uint16 dataLen = pMsg->cmd.DataLength;  // Length of the data section in the response packet.
  uint16 respLen = MT_AF_INC_MSG_LEN + dataLen;
  uint8 cmd = MT_AF_INCOMING_MSG;
  uint8 *pRsp, *pTmp;
  mtAfInMsgList_t *pItem = NULL;

#if defined INTER_PAN
  if (StubAPS_InterPan(pMsg->srcAddr.panId, pMsg->srcAddr.endPoint))
  {
    cmd = MT_AF_INCOMING_MSG_EXT;
  }
  else
#endif
  if ((pMsg->srcAddr.addrMode == afAddr64Bit) ||
      (respLen > (uint16)(MT_RPC_DATA_MAX - MT_AF_INC_MSG_EXT)))
  {
    cmd = MT_AF_INCOMING_MSG_EXT;
  }

  if (cmd == MT_AF_INCOMING_MSG_EXT)
  {
    respLen += MT_AF_INC_MSG_EXT;
  }

  if (respLen > (uint16)MT_RPC_DATA_MAX)
  {
    if ((pItem = (mtAfInMsgList_t *)osal_mem_alloc(sizeof(mtAfInMsgList_t) + dataLen)) == NULL)
    {
      return;  // If cannot hold a huge message, cannot give indication at all.
    }

    pItem->data = (uint8 *)(pItem+1);
    respLen -= dataLen;  // Zero data bytes are sent with an over-sized incoming indication.
  }

  // Attempt to allocate memory for the response packet.
  if ((pRsp = osal_mem_alloc(respLen)) == NULL)
  {
    if (pItem != NULL)
    {
      (void)osal_mem_free(pItem);
    }
    return;
  }
  pTmp = pRsp;

  /* Group ID */
  *pTmp++ = LO_UINT16(pMsg->groupId);
  *pTmp++ = HI_UINT16(pMsg->groupId);

  /* Cluster ID */
  *pTmp++ = LO_UINT16(pMsg->clusterId);
  *pTmp++ = HI_UINT16(pMsg->clusterId);

  if (cmd == MT_AF_INCOMING_MSG_EXT)
  {
    *pTmp++ = pMsg->srcAddr.addrMode;

    if (pMsg->srcAddr.addrMode == afAddr64Bit)
    {
      (void)osal_memcpy(pTmp, pMsg->srcAddr.addr.extAddr, Z_EXTADDR_LEN);
    }
    else
    {
      pTmp[0] = LO_UINT16(pMsg->srcAddr.addr.shortAddr);
      pTmp[1] = HI_UINT16(pMsg->srcAddr.addr.shortAddr);
    }
    pTmp += Z_EXTADDR_LEN;

    *pTmp++ = pMsg->srcAddr.endPoint;
#if defined INTER_PAN
    *pTmp++ = LO_UINT16(pMsg->srcAddr.panId);
    *pTmp++ = HI_UINT16(pMsg->srcAddr.panId);
#else
    *pTmp++ = 0;
    *pTmp++ = 0;
#endif
  }
  else
  {
    /* Source Address */
    *pTmp++ = LO_UINT16(pMsg->srcAddr.addr.shortAddr);
    *pTmp++ = HI_UINT16(pMsg->srcAddr.addr.shortAddr);

    /* Source EP */
    *pTmp++ = pMsg->srcAddr.endPoint;
  }

  /* Destination EP */
  *pTmp++ = pMsg->endPoint;

  /* WasBroadCast */
  *pTmp++ = pMsg->wasBroadcast;

  /* LinkQuality */
  *pTmp++ = pMsg->LinkQuality;

  /* SecurityUse */
  *pTmp++ = pMsg->SecurityUse;

  /* Timestamp */
  *pTmp++ = BREAK_UINT32(pMsg->timestamp, 0);
  *pTmp++ = BREAK_UINT32(pMsg->timestamp, 1);
  *pTmp++ = BREAK_UINT32(pMsg->timestamp, 2);
  *pTmp++ = BREAK_UINT32(pMsg->timestamp, 3);


  /* Data Length */
  if (cmd == MT_AF_INCOMING_MSG_EXT)
  {
    /* Z-Tool apparently takes the last Byte before the data buffer as the dynamic length and
     * ignores the bigger UInt16 length of an EXT incoming message. But no data bytes will be sent
     * with a huge message, so it's necessary to work-around and fake-out Z-Tool with a zero here.
     */
    *pTmp++ = 0;  // TODO - workaround Z-Tool shortcoming; should be: = pMsg->cmd.TransSeqNumber;
    *pTmp++ = LO_UINT16(dataLen);
    *pTmp++ = HI_UINT16(dataLen);
  }
  else
  {
    *pTmp++ = pMsg->cmd.TransSeqNumber;
    *pTmp++ = dataLen;
  }

  /* Data */
  if (pItem != NULL)
  {
    // Enqueue the new huge incoming item.
    pItem->next = pMtAfInMsgList;
    pMtAfInMsgList = pItem;

    // Setup to time-out the huge incoming item if host does not MT_AF_DATA_RETRIEVE it.
    pItem->tick = MT_AF_EXEC_CNT;
    if (ZSuccess != osal_start_timerEx(MT_TaskID, MT_AF_EXEC_EVT, MT_AF_EXEC_DLY))
    {
      (void)osal_set_event(MT_TaskID, MT_AF_EXEC_EVT);
    }

    pItem->timestamp = pMsg->timestamp;
    (void)osal_memcpy(pItem->data, pMsg->cmd.Data, dataLen);
  }
  else
  {
    (void)osal_memcpy(pTmp, pMsg->cmd.Data, dataLen);
  }

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ|(uint8)MT_RPC_SYS_AF), cmd, respLen, pRsp);

  (void)osal_mem_free(pRsp);
}

void MT_AfDataRetrieve(uint8 *pBuf)
{
  #define MT_AF_RTV_HDR_SZ  2

  uint32 timestamp;
  mtAfInMsgList_t *pPrev, *pItem = pMtAfInMsgList;
  uint8 rtrn = afStatus_FAILED;
  uint8 len = 0;

  pBuf += MT_RPC_FRAME_HDR_SZ;
  timestamp = BUILD_UINT32(pBuf[0], pBuf[1], pBuf[2], pBuf[3]);

  while (pItem != NULL)
  {
    pPrev = pItem;
    if (pItem->timestamp == timestamp)
    {
      break;
    }
    pItem = pItem->next;
  }

  if (pItem != NULL)
  {
    uint16 idx;
    uint8 *pRsp;

    pBuf += 4;
    idx = BUILD_UINT16(pBuf[0], pBuf[1]);
    len = pBuf[2];

    if (len == 0)  // Indication to delete the afIncomingMSGPacket.
    {
      if (pMtAfInMsgList == pItem)
      {
        pMtAfInMsgList = pItem->next;
      }
      else
      {
        pPrev->next = pItem->next;
      }
      (void)osal_mem_free(pItem);
      rtrn = afStatus_SUCCESS;
    }
    else if ((pRsp = osal_mem_alloc(len + MT_AF_RTV_HDR_SZ)) == NULL)
    {
      rtrn = afStatus_MEM_FAIL;
      len = 0;
    }
    else
    {
      pRsp[0] = ZSuccess;
      pRsp[1] = len;
      (void)osal_memcpy(pRsp + MT_AF_RTV_HDR_SZ, pItem->data+idx, len);
      MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_AF),
                                           MT_AF_DATA_RETRIEVE, len + MT_AF_RTV_HDR_SZ, pRsp);
      (void)osal_mem_free(pRsp);
      return;
    }
  }

  pBuf[0] = rtrn;
  pBuf[1] = len;
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_AF),
                                       MT_AF_DATA_RETRIEVE, MT_AF_RTV_HDR_SZ, pBuf);
}

void MT_AfDataStore(uint8 *pBuf)
{
  uint16 idx;
  uint8 len, rtrn = afStatus_FAILED;

  pBuf += MT_RPC_FRAME_HDR_SZ;
  idx = BUILD_UINT16(pBuf[0], pBuf[1]);
  len = pBuf[2];
  pBuf += 3;

  if (pMtAfDataReq == NULL)
  {
    rtrn = afStatus_MEM_FAIL;
  }
  else if (len == 0)  // Indication to send the message.
  {
    rtrn = AF_DataRequest(&(pMtAfDataReq->dstAddr), pMtAfDataReq->epDesc, pMtAfDataReq->cId,
                            pMtAfDataReq->dataLen,  pMtAfDataReq->data,
                          &(pMtAfDataReq->transId), pMtAfDataReq->txOpts, pMtAfDataReq->radius);
    (void)osal_mem_free(pMtAfDataReq);
    pMtAfDataReq = NULL;
  }
  else
  {
    (void)osal_memcpy(pMtAfDataReq->data+idx, pBuf, len);
    rtrn = afStatus_SUCCESS;
  }

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_AF),
                                                                MT_AF_DATA_STORE, 1, &rtrn);
}

static void MT_AfAPSF_ConfigSet(uint8 *pBuf)
{
  afAPSF_Config_t cfg = { pBuf[MT_RPC_POS_DAT0+1], pBuf[MT_RPC_POS_DAT0+2] };
  afStatus_t rtrn = afAPSF_ConfigSet(pBuf[MT_RPC_POS_DAT0], &cfg);

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_AF),
                                       MT_AF_APSF_CONFIG_SET, 1, (uint8 *)&rtrn);
}

MT_AF.h

#if defined ( MT_AF_CB_FUNC )
#define CB_ID_AF_DATA_IND               0x0001
#define CB_ID_AF_DATA_CNF               0x0002
#define SPI_AF_CB_TYPE                  0x0900
#endif

#if defined (INTER_PAN)
typedef enum {
  InterPanClr,
  InterPanSet,
  InterPanReg,
  InterPanChk
} InterPanCtl_t;
#endif
extern uint16 _afCallbackSub;


extern void MT_AfExec(void);


extern uint8 MT_AfCommandProcessing(uint8 *pBuf);

extern void MT_AfIncomingMsg(afIncomingMSGPacket_t *pMsg);

extern void MT_AfDataConfirm(afDataConfirm_t *pMsg);

#endif

MT_APP.c

#include "ZComDef.h"
#include "MT.h"        /* This is here because all the SPI_CMD_XXX are defined in this header */
#include "MT_APP.h"
#include "MT_AF.h"     /* This is here because this MT_APP makes some routine call to AF */
#include "MT_RPC.h"

#if defined( APP_TP )
 #include "TestProfile.h"
#endif
#if defined( APP_TP2 )
 #include "TestProfile2.h"
 #include "nwk_util.h"
#endif

#if defined (MT_APP_FUNC)
void MT_AppMsg(uint8 *pBuf);
void MT_AppUserCmd(byte *pData);
#endif

#if defined (MT_APP_FUNC)

uint8 MT_AppCommandProcessing(uint8 *pBuf)
{
  uint8 status = MT_RPC_SUCCESS;

  switch (pBuf[MT_RPC_POS_CMD1])
  {
    case MT_APP_MSG:
      MT_AppMsg(pBuf);
      break;

    case MT_APP_USER_TEST:
      MT_AppUserCmd(pBuf);
      break;

    default:
      status = MT_RPC_ERR_COMMAND_ID;
      break;
  }

  return status;
}

void MT_AppMsg(uint8 *pBuf)
{
  uint8 retValue = ZFailure;
  uint8 endpoint;
  endPointDesc_t *epDesc;
  mtSysAppMsg_t *msg;
  uint8 cmdId, dataLen;

  /* parse header */
  dataLen = pBuf[MT_RPC_POS_LEN];
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Get the endpoint and skip past it.*/
  endpoint = *pBuf++;
  dataLen--;

  /* Look up the endpoint */
  epDesc = afFindEndPointDesc( endpoint );

  if (epDesc)
  {
    /* Build and send the message to the APP */
    msg = (mtSysAppMsg_t *)osal_msg_allocate(sizeof(mtSysAppMsg_t) + (dataLen));
    if ( msg )
    {
      /* Build and send message up the app */
      msg->hdr.event = MT_SYS_APP_MSG;
      msg->endpoint = endpoint;
      msg->appDataLen = dataLen;
      msg->appData = (uint8*)(msg+1);
      osal_memcpy( msg->appData, pBuf, dataLen);
      osal_msg_send( *(epDesc->task_id), (uint8 *)msg );

      /* Info for response */
      retValue = ZSuccess;
    }
  }

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_APP), cmdId, 1, &retValue);
}


void MT_AppUserCmd(uint8 *pBuf)
{

  uint8 retValue, cmdId;

#if defined (APP_TGEN) || defined (NWK_TEST) || defined (APP_TP) || defined (APP_TP2) || defined (OSAL_TOTAL_MEM) || defined (APP_DEBUG)
  uint16 app_cmd;
  uint8 srcEp;
  uint16 param1;
  uint16 param2;
#endif
#if defined (OSAL_TOTAL_MEM)
  uint8 pData[2];
#endif

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  retValue = INVALID_TASK;     //should be changed later

#if defined (APP_TGEN) || defined (NWK_TEST) || defined (APP_TP) || defined (APP_TP2) || defined (OSAL_TOTAL_MEM) || defined (APP_DEBUG)

  srcEp = *pBuf++;

  app_cmd = BUILD_UINT16( pBuf[0] , pBuf[1] );
  pBuf = pBuf + sizeof( uint16 );

  param1 = BUILD_UINT16( pBuf[0] , pBuf[1] );
  pBuf = pBuf + sizeof( uint16 );

  param2 = BUILD_UINT16( pBuf[0] , pBuf[1] );

  switch ( app_cmd )
  {

#if defined (APP_TGEN)
    case TGEN_START:
      TrafficGenApp_SendCmdMSG( param1, param2, TRAFFICGENAPP_CMD_START );
      retValue = ZSUCCESS;
      break;

    case TGEN_STOP:
      TrafficGenApp_SendCmdMSG( param1, param2, TRAFFICGENAPP_CMD_STOP );
      retValue = ZSUCCESS;
      break;

    case TGEN_COUNT:
      retValue = TrafficGenApp_CountPkt( param1, param2 );
      return;
      break;
#endif

#if defined (NWK_TEST)
    case HW_TEST:
      HwApp_Start( HI_UINT16(param1), LO_UINT16(param1), HI_UINT16(param2),
                    1000, LO_UINT16(param2), 3, 0 );
      break;

    case HW_DISPLAY_RESULT:
      HwApp_TestInfo();
      break;

    case HW_SEND_STATUS:
      HwApp_SendStats();
      break;
#endif

#if defined( APP_TP ) || defined ( APP_TP2 )
  #if defined( APP_TP )
    case TP_SEND_NODATA:
      retValue = TestProfileApp_SendNoData( srcEp, (byte)param1 );
      break;
  #endif // APP_TP

    case TP_SEND_BUFFERTEST:
      retValue = TestProfileApp_SendBufferReq( srcEp, (byte)param1 );
      break;

  #if defined( APP_TP )
    case TP_SEND_UINT8:
      retValue = TestProfileApp_SendUint8( srcEp, (byte)param1 );
      break;

    case TP_SEND_INT8:
      retValue = TestProfileApp_SendInt8( srcEp, (byte)param1 );
      break;

    case TP_SEND_UINT16:
      retValue = TestProfileApp_SendUint16( srcEp, (byte)param1 );
      break;

    case TP_SEND_INT16:
      retValue = TestProfileApp_SendInt16( srcEp, (byte)param1 );
      break;

    case TP_SEND_SEMIPREC:
      retValue = TestProfileApp_SendSemiPrec( srcEp, (byte)param1 );
      break;

    case TP_SEND_FREEFORM:
      retValue = TestProfileApp_SendFreeFormReq( srcEp, (byte)param1 );
      break;

  #else // APP_TP
    case TP_SEND_FREEFORM:
      retValue = TestProfileApp_SendFreeFormReq(srcEp, (byte)param1, (byte)param2);
      break;
  #endif

  #if defined( APP_TP )
    case TP_SEND_ABS_TIME:
      retValue = TestProfileApp_SendAbsTime( srcEp, (byte)param1 );
      break;

    case TP_SEND_REL_TIME:
      retValue = TestProfileApp_SendRelativeTime( srcEp, (byte)param1 );
      break;

    case TP_SEND_CHAR_STRING:
      retValue = TestProfileApp_SendCharString( srcEp, (byte)param1 );
      break;

    case TP_SEND_OCTET_STRING:
      retValue = TestProfileApp_SendOctetString( srcEp, (byte)param1 );
      break;
  #endif // APP_TP

    case TP_SET_DSTADDRESS:
      retValue = TestProfileApp_SetDestAddress(HI_UINT16(param1), LO_UINT16(param1), param2);
      break;

  #if defined( APP_TP2 )
    case TP_SEND_BUFFER_GROUP:
      retValue = TestProfileApp_SendBufferGroup( srcEp, (byte)param1 );
      break;
  #endif // APP_TP

    case TP_SEND_BUFFER:
      retValue = TestProfileApp_SendBuffer( srcEp, (byte)param1 );
      break;

  #if defined( APP_TP )
    case TP_SEND_MULT_KVP_8BIT:
      TestProfileApp_SendMultiKVP_8bit( srcEp, (byte)param1 );
      retValue = ZSuccess;
      break;

    case TP_SEND_MULT_KVP_16BIT:
      TestProfileApp_SendMultiKVP_16bit( srcEp, (byte)param1 );
      retValue = ZSuccess;
      break;

    case TP_SEND_MULT_KVP_TIME:
      TestProfileApp_SendMultiKVP_Time( srcEp, (byte)param1 );
      retValue = ZSuccess;
      break;

    case TP_SEND_MULT_KVP_STRING:
      TestProfileApp_SendMultiKVP_String( srcEp, (byte)param1 );
      retValue = ZSuccess;
      break;

    case TP_SEND_MULTI_KVP_STR_TIME:
      retValue = ZSuccess;
      TestProfileApp_SendMultiKVP_String_Time( srcEp, (byte)param1 );
      break;
  #endif // APP_TP

    case TP_SEND_COUNTED_PKTS:
      TestProfileApp_SendCountedPktsReq(HI_UINT16(param1), LO_UINT16(param1), param2);
      retValue = ZSuccess;
      break;

    case TP_SEND_RESET_COUNTER:
      TestProfileApp_CountedPakts_ResetCounterReq( (byte)param1 );
      retValue = ZSuccess;
      break;

    case TP_SEND_GET_COUNTER:
      TestProfileApp_CountedPakts_GetCounterReq( srcEp, (byte)param1 );
      retValue = ZSuccess;
      break;

    case TP_SET_PERMIT_JOIN:
      if ( ZG_BUILD_RTR_TYPE && ZG_DEVICE_RTR_TYPE )
      {
        NLME_PermitJoiningRequest( (byte)param1 );
        retValue = ZSuccess;
      }
      else
      {
        retValue = ZFailure;
      }
      break;

  #if defined ( APP_TP2 )
    case TP_ADD_GROUP:
      retValue = TestProfileApp_SetGroup( srcEp, param1 );
      break;

    case TP_REMOVE_GROUP:
      retValue = TestProfileApp_RemoveGroup( srcEp, param1 );
      break;

    case TP_SEND_UPDATE_KEY:
      retValue = TestProfileApp_UpdateKey( srcEp, (uint8)param1, param2 );
      break;

    case TP_SEND_SWITCH_KEY:
      retValue = TestProfileApp_SwitchKey(  srcEp, (uint8)param1, param2 );
      break;

    case TP_SEND_BUFFERTEST_GROUP:
      retValue = TestProfileApp_SendBufferGroupReq( srcEp, (byte)param1, (byte)param2 );
      break;

    case TP_SEND_ROUTE_DISC_REQ:
      retValue = TestProfileApp_SendRouteDiscReq( srcEp, param1,
                                  HI_UINT16( param2 ), LO_UINT16( param2 ) );
      break;

    case TP_SEND_ROUTE_DISCOVERY:
      if ( ZG_BUILD_RTR_TYPE && ZG_DEVICE_RTR_TYPE )
      {
        retValue = TestProfileApp_SendRouteDiscovery( param1,
                                    HI_UINT16( param2 ), LO_UINT16( param2 ) );
      }
      break;

    case TP_SEND_NEW_ADDR:
      retValue = TestProfileApp_ChangeShortAddr( param1, LO_UINT16(param2) );
      break;

    case TP_SEND_NWK_UPDATE:
      /* Send out a Network Update command. */
      retValue = NLME_SendNetworkUpdate( NWK_BROADCAST_SHORTADDR, NWKUPDATE_PANID_UPDATE,
                                        _NIB.extendedPANID, _NIB.nwkUpdateId+1, param1 );
      break;

    case TP_NWK_ADDR_CONFLICT:
      retValue = NLME_SendNetworkStatus( NWK_BROADCAST_SHORTADDR_DEVZCZR, param1,
                                         NWKSTAT_ADDRESS_CONFLICT, FALSE );
      break;

 #if (ZG_BUILD_JOINING_TYPE)
    case TP_AK_SETUP_PARTNER:
      retValue = TestProfileApp_AppKeySetupPartner( srcEp, param1, param2 );
      break;

    case TP_AK_REQ_KEY:
      retValue = TestProfileApp_AppKeyRequest( srcEp, param1, param2 );
      break;

    case TP_AK_PARTNER_NWKADDR:
      retValue = TestProfileApp_SetPartnerNwkAddr( srcEp, param1, param2 );
      break;

    case TP_AK_PARTNER_EXTADDR7654:
       retValue = TestProfileApp_SetPartnerExtAddr7654( srcEp, param1, param2 );
      break;

    case TP_AK_PARTNER_EXTADDR3210:
      retValue = TestProfileApp_SetPartnerExtAddr3210( srcEp, param1, param2 );
      break;

    case TP_AK_PARTNER_SET:
      retValue = TestProfileApp_SetPartner( srcEp, param1, param2 );
      break;
#endif /* ZG_BUILD_JOINING_TYPE */

#if (ZG_BUILD_COORDINATOR_TYPE)
    case TP_AK_TYPE_SET:
      retValue = TestProfileApp_AppKeyTypeSet( srcEp, param1, param2 );
      break;
#endif /* ZG_BUILD_COORDINATOR_TYPE */

#if defined ( ZIGBEE_FRAGMENTATION )
    case TP_FRAG_SKIP_BLOCK:
      retValue = TestProfileApp_FragSkipBlock( (uint8)param1 );
      break;
#endif

    case TP_APS_REMOVE:
      retValue = TestProfileApp_APSRemove( param1, param2 );
      break;
#endif // APP_TP2

#endif  // APP_TP || APP_TP2

#if defined ( OSAL_TOTAL_MEM )
    case OSAL_MEM_STACK_HIGH_WATER:
    case OSAL_MEM_HEAP_HIGH_WATER:
      if ( app_cmd == OSAL_MEM_STACK_HIGH_WATER)
      {
        param1 = osal_stack_used();
      }
      else
      {
        param1 = osal_heap_high_water();
      }

      pData[0] = LO_UINT16( param1 );
      pData[1] = HI_UINT16( param1 );

      MT_BuildAndSendZToolResponse((MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_APP), cmdId, 2, pData);
      return;
#endif

#if defined ( APP_DEBUG )
    case DEBUG_GET:
      DebugApp_SendQuery( param1 );
      retValue = ZSUCCESS;
      break;
#endif

#if defined ( APP_TP2 )
    case TP_SEND_BCAST_RSP:
      retValue = TestProfileApp_SendBcastRsp( srcEp, (byte)param1 );
      break;
#endif

    default:
      break;
  }
#endif // (APP_TGEN) || (NWK_TEST) || (APP_TP) || (APP_TP2) || (OSAL_TOTAL_MEM) || (APP_DEBUG)

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_APP), cmdId, 1, &retValue);
}

#endif 

MT_APP.h

#ifndef MT_APP_H
#define MT_APP_H

#ifdef __cplusplus
extern "C"
{
#endif

#include "OSAL.h"


typedef struct
{
  osal_event_hdr_t  hdr;
  uint8             endpoint;
  uint8             appDataLen;
  uint8             *appData;
} mtSysAppMsg_t;

#if defined (MT_APP_FUNC)

extern uint8 MT_AppCommandProcessing(uint8 *pBuf);
#endif

#ifdef __cplusplus
}
#endif

#endif

MT_DEBUG.c

#include "ZComDef.h"
#include "MT.h"
#include "MT_DEBUG.h"
#include "MT_UART.h"
#include "mac_main.h"
#include "mac_data.h"
#include "mac_rx.h"
#include "mac_tx.h"
#include "nwk_globals.h"


#if defined (MT_DEBUG_FUNC)
static void MT_DebugSetThreshold(uint8 *pBuf);
static void MT_DebugMacDataDump(void);
#endif

#if defined (MT_DEBUG_FUNC)

uint8 MT_DebugCommandProcessing(uint8 *pBuf)
{
  uint8 status = MT_RPC_SUCCESS;

  switch (pBuf[MT_RPC_POS_CMD1])
  {
    case MT_DEBUG_SET_THRESHOLD:
      MT_DebugSetThreshold(pBuf);
      break;

  case MT_DEBUG_MAC_DATA_DUMP:
      MT_DebugMacDataDump();
      break;

    default:
      status = MT_RPC_ERR_COMMAND_ID;
      break;
  }

  return status;
}

static void MT_DebugSetThreshold(uint8 *pBuf)
{
  uint8 retValue = ZSuccess;
  uint8 cmdId;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Populate info */
  debugCompId = *pBuf++;
  debugThreshold = *pBuf++;

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_DBG), cmdId, 1, &retValue);
}

static void MT_DebugMacDataDump(void)
{
  uint8 buf[sizeof(mtDebugMacDataDump_t)];
  uint8 *pBuf = buf;

#ifdef PACKET_FILTER_STATS
  *pBuf++ = BREAK_UINT32(nwkInvalidPackets, 0);
  *pBuf++ = BREAK_UINT32(nwkInvalidPackets, 1);
  *pBuf++ = BREAK_UINT32(nwkInvalidPackets, 2);
  *pBuf++ = BREAK_UINT32(nwkInvalidPackets, 3);
  *pBuf++ = BREAK_UINT32(rxCrcFailure, 0);
  *pBuf++ = BREAK_UINT32(rxCrcFailure, 1);
  *pBuf++ = BREAK_UINT32(rxCrcFailure, 2);
  *pBuf++ = BREAK_UINT32(rxCrcFailure, 3);
  *pBuf++ = BREAK_UINT32(rxCrcSuccess, 0);
  *pBuf++ = BREAK_UINT32(rxCrcSuccess, 1);
  *pBuf++ = BREAK_UINT32(rxCrcSuccess, 2);
  *pBuf++ = BREAK_UINT32(rxCrcSuccess, 3);
#endif
#if defined HAL_MCU_CC2530
  *pBuf++ = FSMSTAT0;
  *pBuf++ = FSMSTAT1;
#else
  *pBuf++ = macSpiReadReg(FSMSTAT0);
  *pBuf++ = macSpiReadReg(FSMSTAT1);
#endif
  *pBuf++ = macData.rxCount;
  *pBuf++ = macData.directCount;
  *pBuf++ = macMain.state;
  *pBuf++ = macRxActive;
  *pBuf   = macTxActive;

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_DBG),
                                       MT_DEBUG_MAC_DATA_DUMP, sizeof(buf), buf);
}
#endif

void MT_ProcessDebugMsg( mtDebugMsg_t *msg )
{
  byte *msg_ptr;
  byte dataLen;
  uint8 buf[11];
  uint8 *pBuf;

  /* Calculate the data length based */
  dataLen = 5 + (msg->numParams * sizeof ( uint16 ));

  /* Get a message buffer to build the debug message */
  msg_ptr = osal_msg_allocate( (byte)(SPI_0DATA_MSG_LEN + dataLen + 1) );
  if ( msg_ptr )
  {
    /* Build the message */
    pBuf = buf;
    *pBuf++ = msg->compID;
    *pBuf++ = msg->severity;
    *pBuf++ = msg->numParams;

    if ( msg->numParams >= 1 )
    {
      *pBuf++ = LO_UINT16( msg->param1 );
      *pBuf++ = HI_UINT16( msg->param1 );
    }

    if ( msg->numParams >= 2 )
    {
      *pBuf++ = LO_UINT16( msg->param2 );
      *pBuf++ = HI_UINT16( msg->param2 );
    }

    if ( msg->numParams == 3 )
    {
      *pBuf++ = LO_UINT16( msg->param3 );
      *pBuf++ = HI_UINT16( msg->param3 );
    }

    *pBuf++ = LO_UINT16( msg->timestamp );
    *pBuf++ = HI_UINT16( msg->timestamp );

#ifdef MT_UART_DEFAULT_PORT
    /* Debug message is set to AREQ CMD 0x80 for now */
    /* Build and send back the response */
    MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_DBG), 0x80, dataLen, buf);
#endif
    osal_msg_deallocate( msg_ptr );
  }
}

void MT_ProcessDebugStr(mtDebugStr_t *dstr)
{
  byte *msg_ptr;

  /* Get a message buffer to build the debug message */
  msg_ptr = osal_mem_alloc( (byte)(SPI_0DATA_MSG_LEN + dstr->strLen) );
  if ( msg_ptr )
  {
#ifdef MT_UART_DEFAULT_PORT
    /* Debug message is set to AREQ CMD 0x80 for now */
    /* Build and send back the response */
    MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_DBG), MT_DEBUG_MSG, dstr->strLen, dstr->pString);
#endif
    osal_mem_free( msg_ptr );
  }
}

MT_DEBUG.h

#ifndef MT_DEBUG_H
#define MT_DEBUG_H

#ifdef __cplusplus
extern "C"
{
#endif

#include "OSAL.h"


typedef struct
{
  osal_event_hdr_t  hdr;
  uint8             compID;
  uint8             severity;
  uint8             numParams;
  uint16            param1;
  uint16            param2;
  uint16            param3;
  uint16            timestamp;
} mtDebugMsg_t;

typedef struct
{
  osal_event_hdr_t  hdr;
  uint8             strLen;
  uint8             *pString;
} mtDebugStr_t;

typedef struct {
#ifdef PACKET_FILTER_STATS
  uint32 nwkInvalidPackets;
  uint32 rxCrcFailure;
  uint32 rxCrcSuccess;
#endif
  uint8  fsmstat0;
  uint8  fsmstat1;
  uint8  macData_rxCount;
  uint8  macData_directCount;
  uint8  macMain_state;
  uint8  macRxActive;
  uint8  macTxActive;
} mtDebugMacDataDump_t;


#if defined (MT_DEBUG_FUNC)

extern uint8 MT_DebugCommandProcessing(uint8 *pBuf);
#endif /* MT_DEBUG_FUNC */

extern void MT_ProcessDebugMsg(mtDebugMsg_t *pData);

extern void MT_ProcessDebugStr(mtDebugStr_t *pData);



#ifdef __cplusplus
}
#endif

#endif 

MT_NWK.c

#include "ZComDef.h"
#include "MT.h"
#include "MT_NWK.h"
#include "NLMEDE.h"
#include "nwk.h"
#include "nwk_globals.h"
#include "nwk_util.h"
#include "OSAL.h"
#include "ZDApp.h"

#if !defined( WIN32 )
  #include "OnBoard.h"
#endif

uint16 _nwkCallbackSub;

#if defined (MT_NWK_FUNC)
void MT_NldeDataRequest(uint8 *pBuf);
void MT_NlmeNetworkFormationRequest(uint8 *pBuf);
void MT_NlmePermitJoiningRequest(uint8 *pBuf);
void MT_NlmeStartRouterRequest(uint8 *pBuf);
void MT_NlmeJoinRequest(uint8 *pBuf);
void MT_NlmeLeaveRequest(uint8 *pBuf);
void MT_NlmeResetRequest(uint8 *pBuf);
void MT_NlmeGetRequest(uint8 *pBuf);
void MT_NlmeSetRequest(uint8 *pBuf);
void MT_NlmeNetworkDiscoveryRequest(uint8 *pBuf);
void MT_NlmeRouteDiscoveryRequest(uint8 *pBuf);
void MT_NlmeDirectJoinRequest(uint8 *pBuf);
void MT_NlmeOrphanJoinRequest(uint8 *pBuf);

uint8 MT_Nwk_DataRequest( uint16 dstAddr, uint8 nsduLen, uint8* nsdu,
                         uint8 nsduHandle, uint16 nsduHandleOptions,
                         uint8 secure, uint8 discoverRoute,
                         uint8 radius);
#endif /* MT_NWK_FUNC */

#if defined (MT_NWK_FUNC)

uint8 MT_NwkCommandProcessing(uint8 *pBuf)
{
  uint8 status = MT_RPC_SUCCESS;

  switch (pBuf[MT_RPC_POS_CMD1])
  {
    case MT_NWK_INIT:
      nwk_init(NWK_TaskID);
      break;

    case MT_NLDE_DATA_REQ:
      MT_NldeDataRequest(pBuf);
      break;

    case MT_NLME_NETWORK_FORMATION_REQ:
      MT_NlmeNetworkFormationRequest(pBuf);
      break;

    case MT_NLME_PERMIT_JOINING_REQ:
       MT_NlmePermitJoiningRequest(pBuf);
      break;

     case MT_NLME_JOIN_REQ:
       MT_NlmeJoinRequest(pBuf);
       break;

     case MT_NLME_LEAVE_REQ:
       MT_NlmeLeaveRequest(pBuf);
       break;

     case MT_NLME_RESET_REQ:
       MT_NlmeResetRequest(pBuf);
       break;

     case MT_NLME_GET_REQ:
       MT_NlmeGetRequest(pBuf);
       break;

     case MT_NLME_SET_REQ:
       MT_NlmeSetRequest(pBuf);
       break;

     case MT_NLME_NETWORK_DISCOVERY_REQ:
       MT_NlmeNetworkDiscoveryRequest(pBuf);
       break;

     case MT_NLME_ROUTE_DISCOVERY_REQ:
       MT_NlmeRouteDiscoveryRequest(pBuf);
       break;

     case MT_NLME_DIRECT_JOIN_REQ:
       MT_NlmeDirectJoinRequest(pBuf);
       break;

     case MT_NLME_ORPHAN_JOIN_REQ:
       MT_NlmeOrphanJoinRequest(pBuf);
       break;

    case MT_NLME_START_ROUTER_REQ:
      MT_NlmeStartRouterRequest(pBuf);
      break;

    default:
      status = MT_RPC_ERR_COMMAND_ID;
      break;
  }

  return status;
}

void MT_NldeDataRequest(uint8 *pBuf)
{
  uint8 retValue = ZFailure;
  uint16 dstAddr;
  uint8 dataLen = 0;
  uint8 *dataPtr;
  uint8 cmdId;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* First read the DstAddr */
  dstAddr = BUILD_UINT16( pBuf[0], pBuf[1] );
  pBuf += sizeof( dstAddr );

  /* Get the NSDU details */
  dataLen = *pBuf++;
  dataPtr = pBuf;

  /* Skip a length of ZTEST_DEFAULT_DATA_LEN */
  pBuf += ZTEST_DEFAULT_DATA_LEN;

  /* Send out Data Request */
  retValue = MT_Nwk_DataRequest(dstAddr, dataLen, dataPtr, pBuf[0], BUILD_UINT16(pBuf[1], pBuf[2]),
                                pBuf[3], pBuf[4], pBuf[5]);

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_NWK), cmdId, 1, &retValue);
}

void MT_NlmeNetworkFormationRequest(uint8 *pBuf)
{
  uint8 retValue = ZFailure;
	uint16 panId;
  uint32 channelList;
  uint8 cmdId;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Build panId */
  panId = BUILD_UINT16( pBuf[0], pBuf[1]);
  pBuf += sizeof(uint16);
			
  /* Build the channel list */
  channelList = osal_build_uint32(pBuf, 4);
  pBuf += sizeof(uint32);

  if ( ZG_BUILD_COORDINATOR_TYPE && ZG_DEVICE_COORDINATOR_TYPE )
  {
    retValue = NLME_NetworkFormationRequest( panId, NULL, channelList, pBuf[0], pBuf[1], pBuf[2], pBuf[3] );
  }
  else
  {
    retValue = ZUnsupportedMode;
  }

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_NWK), cmdId, 1, &retValue);
}

void MT_NlmePermitJoiningRequest(uint8 *pBuf)
{
  uint8 retValue = ZFailure;
  uint8 cmdId;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  if (ZSTACK_ROUTER_BUILD)
  {
    retValue = NLME_PermitJoiningRequest(*pBuf);
  }
  else
  {
    retValue = ZUnsupportedMode;
  }

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_NWK), cmdId, 1, &retValue);
}

void MT_NlmeStartRouterRequest(uint8 *pBuf)
{
  uint8 retValue = ZFailure;
  uint8 cmdId;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  if ( ZSTACK_ROUTER_BUILD )
  {
    retValue = (uint8)NLME_StartRouterRequest(pBuf[0], pBuf[1], pBuf[2]);
  }
  else
  {
    retValue = ZUnsupportedMode;
  }

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_NWK), cmdId, 1, &retValue);
}

void MT_NlmeJoinRequest(uint8 *pBuf)
{
  uint8 retValue = ZFailure;
  uint8 dummyExPANID[Z_EXTADDR_LEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
  uint16 panID;
  uint8 cmdId;
  networkDesc_t *pNwkDesc;   
  
  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;     
  panID = BUILD_UINT16(pBuf[0], pBuf[1]);
  
  if((pNwkDesc = nwk_getNetworkDesc(dummyExPANID,panID, pBuf[2])) != NULL )
  {  
    if (pNwkDesc->chosenRouter == INVALID_NODE_ADDR )
    {
      retValue = ZNwkNotPermitted;
    }
    else
    {      
      retValue = NLME_JoinRequest( dummyExPANID, panID, pBuf[2], pBuf[3],
                                   pNwkDesc->chosenRouter, pNwkDesc->chosenRouterDepth );
    }
  }
  else
  {
    retValue = ZNwkNotPermitted;    
  }

  if ( pBuf[3] & CAPINFO_RCVR_ON_IDLE )
  {
    /* The receiver is on, turn network layer polling off. */
    NLME_SetPollRate( 0 );
    NLME_SetQueuedPollRate( 0 );
    NLME_SetResponseRate( 0 );
  }

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_NWK), cmdId, 1, &retValue);
}

void MT_NlmeLeaveRequest(uint8 *pBuf)
{
  NLME_LeaveReq_t req;
  uint8 retValue = ZFailure;
  uint8 index, cmdId;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* If extAddr is all zeros, it means null pointer */
  for(index=0;((index < Z_EXTADDR_LEN) && (pBuf[index] == 0));index++);

  if (index == Z_EXTADDR_LEN)
  {
    req.extAddr = NULL;
  }
  else
  {
    req.extAddr = pBuf;
  }

  /* Increment the pointer */
  pBuf += Z_EXTADDR_LEN;

  req.removeChildren = FALSE;
  req.rejoin         = FALSE;
  req.silent         = FALSE;

  retValue = NLME_LeaveReq(&req);

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_NWK), cmdId, 1, &retValue);
}

void MT_NlmeResetRequest(uint8 *pBuf)
{
  uint8 retValue = NLME_ResetRequest();

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_NWK), MT_NLME_RESET_REQ, 1, &retValue);
}

void MT_NlmeGetRequest(uint8 *pBuf)
{
  uint8 dataBuf[11];
  uint8 attr, index, cmdId;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  attr = *pBuf++;
  index = *pBuf;

  dataBuf[0] = NLME_GetRequest((ZNwkAttributes_t )attr, index, &dataBuf[1]);

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_NWK), cmdId,
                               11, dataBuf );
}

void MT_NlmeSetRequest(uint8 *pBuf)
{
  uint8 retValue = ZFailure;
  uint8 cmdId;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  retValue = NLME_SetRequest((ZNwkAttributes_t)pBuf[0], pBuf[1], &pBuf[2]);

  /* Update NV */
  ZDApp_NVUpdate();

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_NWK), cmdId, 1, &retValue );
}

void MT_NlmeNetworkDiscoveryRequest(uint8 *pBuf)
{
  uint8 retValue = ZFailure;
  uint8 cmdId;
  uint32 scanChannels;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Scan channels */
  scanChannels = osal_build_uint32(pBuf, 4);
  pBuf += sizeof(uint32);

  retValue = NLME_NetworkDiscoveryRequest(scanChannels, *pBuf);

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_NWK), cmdId, 1, &retValue );
}


void MT_NlmeRouteDiscoveryRequest(uint8 *pBuf)
{
  uint8 retValue = ZFailure;
  uint8 cmdId;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  if ( ZSTACK_ROUTER_BUILD )
  {
    retValue = NLME_RouteDiscoveryRequest(BUILD_UINT16(pBuf[0], pBuf[1]), pBuf[2], pBuf[3]);
  }
  else
  {
    retValue = ZUnsupportedMode;
  }

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_NWK), cmdId, 1, &retValue);
}

void MT_NlmeDirectJoinRequest(uint8 *pBuf)
{
  uint8 retValue = ZFailure;
  uint8 cmdId;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  if ( ZSTACK_ROUTER_BUILD )
  {
    retValue = NLME_DirectJoinRequest( pBuf, pBuf[8] );
  }
  else
  {
    retValue = ZUnsupportedMode;
  }

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_NWK), cmdId, 1, &retValue);
}

void MT_NlmeOrphanJoinRequest(uint8 *pBuf)
{
  uint8 i, j, attr;
  uint8 retValue = ZFailure;
  uint32 channelList;
  uint8 cmdId;

  if ( ZSTACK_END_DEVICE_BUILD )
  {
    /* parse header */
    cmdId = pBuf[MT_RPC_POS_CMD1];
    pBuf += MT_RPC_FRAME_HDR_SZ;

    /* Channel list bit mask */
    channelList = osal_build_uint32(pBuf, 4);
    pBuf += sizeof(uint32);

    /* Count number of channels */
    j = attr = 0;

    for (i = 0; i < ED_SCAN_MAXCHANNELS; i++)
    {
      if (channelList & (1 << i))
      {
        j++;
        attr = i;
      }
    }

    /* If only one channel specified */
    if (j == 1)
    {
      _NIB.scanDuration = *pBuf;
      _NIB.nwkLogicalChannel = attr;
      _NIB.channelList = channelList;
      if ( !_NIB.CapabilityFlags )
      {
        _NIB.CapabilityFlags = ZDO_Config_Node_Descriptor.CapabilityFlags;
      }

      devState = DEV_NWK_ORPHAN;
      retValue = (uint8)NLME_OrphanJoinRequest(channelList, *pBuf);
    }
    else
    {
      retValue = ZNwkInvalidParam;
    }
   }
   else
   {
     retValue = ZUnsupportedMode;
   }

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_NWK), cmdId, 1, &retValue);
}

uint8 MT_Nwk_DataRequest(uint16 dstAddr, uint8 nsduLen, uint8* nsdu,
                         uint8 nsduHandle, uint16 nsduHandleOptions,
                         uint8 secure, uint8 discoverRoute,
                         uint8 radius)
{
    uint8               status;
    NLDE_DataReqAlloc_t dra;
    NLDE_DataReq_t*     req;


    dra.overhead = sizeof(NLDE_DataReq_t);
    dra.nsduLen  = nsduLen;
    dra.secure   = secure;

    req = NLDE_DataReqAlloc(&dra);

    if ( req != NULL )
    {
      osal_memcpy(req->nfd.nsdu, nsdu, nsduLen);

      req->nfd.dstAddr           = dstAddr;
      req->nfd.nsduHandleOptions = nsduHandleOptions;
      req->nfd.discoverRoute     = discoverRoute;
      req->nfd.radius            = radius;

      status = NLDE_DataReq( req );
    }
    else
    {
      status = ZMemError;
    }

    return status;
}
#endif /* MT_NWK_FUNC */

#if defined ( MT_NWK_CB_FUNC )             //NWK callback commands

void nwk_MTCallbackSubDataConfirm(uint8 nsduHandle, ZStatus_t status)
{
  uint8 buf[2];

  buf[0] = nsduHandle;
  buf[1] = (uint8)status;

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_NWK), MT_NLDE_DATA_CONF, 2, buf );
}

void nwk_MTCallbackSubDataIndication(uint16 SrcAddress, int16 nsduLength, uint8 *nsdu, uint8 LinkQuality)
{
  uint8 *msgPtr;
  uint8 *msg;
  uint8 msgLen;

  msgLen = sizeof( uint16 ) + sizeof( uint8 ) + ZTEST_DEFAULT_DATA_LEN
            + sizeof( uint8);

  msgPtr = osal_mem_alloc( msgLen );
  if ( msgPtr )
  {
    //Fill up the data bytes
    msg = msgPtr;

    //First fill in details
    *msg++ = LO_UINT16( SrcAddress );
    *msg++ = HI_UINT16( SrcAddress );

    //Since the max packet size is less than 255 bytes, a byte is enough
    //to represent nsdu length
    *msg++ = ( uint8 ) nsduLength;

    osal_memset( msg, NULL, ZTEST_DEFAULT_DATA_LEN ); // Clear the mem
    osal_memcpy( msg, nsdu, nsduLength );
    msg += ZTEST_DEFAULT_DATA_LEN;

    *msg++ = LinkQuality;

    MT_BuildAndSendZToolResponse( ((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_NWK), MT_NLDE_DATA_IND, msgLen, msgPtr );

    osal_mem_free( msgPtr );
  }
}


void nwk_MTCallbackSubInitCoordConfirm( ZStatus_t Status )
{
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_NWK), MT_NLME_NETWORK_FORMATION_CONF,
                          sizeof(uint8), (uint8*)&Status);
}

void nwk_MTCallbackSubStartRouterConfirm( ZStatus_t Status )
{
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_NWK), MT_NLME_START_ROUTER_CONF,
                          sizeof(uint8), (uint8*)&Status);
}

void nwk_MTCallbackSubJoinConfirm(uint16 PanId, ZStatus_t Status)
{
  uint8 msg[Z_EXTADDR_LEN + 3];

  /* This device's 64-bit address */
  ZMacGetReq( ZMacExtAddr, msg );

  msg[Z_EXTADDR_LEN + 0] = LO_UINT16(PanId);
  msg[Z_EXTADDR_LEN + 1] = HI_UINT16(PanId);
  msg[Z_EXTADDR_LEN + 2] = (uint8)Status;

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_NWK), MT_NLME_JOIN_CONF, Z_EXTADDR_LEN + 3, msg );
}

void nwk_MTCallbackSubNetworkDiscoveryConfirm( uint8 ResultCount, networkDesc_t *NetworkList )
{
	uint8 len;
	uint8 *msgPtr;
	uint8 *msg;
	uint8 i;

  // The message cannot be bigger then SPI_TX_BUFF_MAX.  Reduce resultCount if necessary
  if (ResultCount * sizeof(networkDesc_t) > MT_UART_TX_BUFF_MAX - (1 + SPI_0DATA_MSG_LEN))
  {
    ResultCount = (MT_UART_TX_BUFF_MAX - (1 + SPI_0DATA_MSG_LEN)) / sizeof(networkDesc_t);
  }

	len = 1 + ResultCount * sizeof(networkDesc_t);
  msgPtr = osal_mem_alloc( len );
	if ( msgPtr )
	{
	  /* Fill up the data bytes */
    msg = msgPtr;

		*msg++ = ResultCount;

		for ( i = 0; i < ResultCount; i++ )
		{
		  *msg++ = LO_UINT16( NetworkList->panId );
		  *msg++ = HI_UINT16( NetworkList->panId );
		  *msg++ = NetworkList->logicalChannel;
		  *msg++ = BEACON_ORDER_NO_BEACONS;
		  *msg++ = BEACON_ORDER_NO_BEACONS;
		  *msg++ = NetworkList->routerCapacity;
		  *msg++ = NetworkList->deviceCapacity;
		  *msg++ = NetworkList->version;
		  *msg++ = NetworkList->stackProfile;
		  //*msg++ = NetworkList->securityLevel;
		
			NetworkList = (networkDesc_t*)NetworkList->nextDesc;
		}

    MT_BuildAndSendZToolResponse (((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_NWK), MT_NLME_NETWORK_DISCOVERY_CONF, len, msgPtr);

    osal_mem_free( msgPtr );
	}
}

void nwk_MTCallbackSubJoinIndication( uint16 ShortAddress, uint8 *ExtendedAddress,
                                      uint8 CapabilityFlags )
{
  uint8 *msgPtr;
  uint8 *msg;
  uint8 len;

  len = sizeof( uint16 ) + Z_EXTADDR_LEN + sizeof( uint8 );
  msgPtr = osal_mem_alloc( len );

  if ( msgPtr )
  {
    /* Fill up the data bytes */
    msg = msgPtr;

    /* First fill in details */
    *msg++ = LO_UINT16( ShortAddress );
    *msg++ = HI_UINT16( ShortAddress );

    osal_cpyExtAddr( msg, ExtendedAddress );
    msg += Z_EXTADDR_LEN;

    *msg = CapabilityFlags;

    MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_NWK), MT_NLME_JOIN_IND, len, msgPtr );

    osal_mem_free( msgPtr );
  }
}

void nwk_MTCallbackSubLeaveConfirm( uint8 *DeviceAddress, ZStatus_t Status )
{
  uint8 *msgPtr;
  uint8 *msg;

  msgPtr = osal_mem_alloc( Z_EXTADDR_LEN + sizeof( uint8 ) );
  if ( msgPtr )
  {
    /* Fill up the data bytes */
    msg = msgPtr;

    /* First fill in details */
    osal_cpyExtAddr( msg, DeviceAddress );
    msg += Z_EXTADDR_LEN;

    *msg = (uint8)Status;

    MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_NWK), MT_NLME_LEAVE_CONF,
                            Z_EXTADDR_LEN + sizeof( uint8 ), msgPtr );

    osal_mem_free( msgPtr );
  }
}

void nwk_MTCallbackSubLeaveIndication( uint8 *DeviceAddress )
{
  uint8 msg[Z_EXTADDR_LEN+1];

  /* First fill in details */
  if ( DeviceAddress )
  {
    osal_cpyExtAddr( msg, DeviceAddress );
  }
  else
  {
    osal_memset( msg, 0, Z_EXTADDR_LEN );
  }

  /* Status, assume good if we get this far */
  msg[Z_EXTADDR_LEN] = 0;

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_NWK), MT_NLME_LEAVE_IND, Z_EXTADDR_LEN+1, msg );
}

void nwk_MTCallbackSubSyncIndication( void )
{
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_NWK), MT_NLME_SYNC_IND, 0, NULL );
}

void nwk_MTCallbackSubPollConfirm( uint8 status )
{
  uint8 msg = status;

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_NWK), MT_NLME_POLL_CONF, 1, &msg );
}

#endif

MT_NWK.h

#include "hal_types.h"
#include "NLMEDE.h"

#define NWKCB_CHECK(cbi) (_nwkCallbackSub & (cbi))

/* NWK Callback subscription IDs */
#define CB_ID_NLDE_DATA_CNF          0x0001
#define CB_ID_NLDE_DATA_IND          0x0002
#define CB_ID_NLME_INIT_COORD_CNF    0x0004
#define CB_ID_NLME_JOIN_CNF          0x0008
#define CB_ID_NLME_JOIN_IND          0x0010
#define CB_ID_NLME_LEAVE_CNF         0x0020
#define CB_ID_NLME_LEAVE_IND         0x0040
#define CB_ID_NLME_POLL_CNF          0x0080
#define CB_ID_NLME_SYNC_IND          0x0200
#define CB_ID_NLME_NWK_DISC_CNF      0x2000
#define CB_ID_NLME_START_ROUTER_CNF	 0x8000

extern uint16 _nwkCallbackSub;


#ifdef MT_NWK_FUNC

extern uint8 MT_NwkCommandProcessing (byte *pBuf);

#endif   /* NWK Command Processing in MT */

#ifdef MT_NWK_CB_FUNC

extern void nwk_MTCallbackSubDataConfirm(byte nsduHandle, ZStatus_t status);

extern void nwk_MTCallbackSubDataIndication(uint16 SrcAddress, int16 nsduLength,
                                            byte *nsdu, byte LinkQuality);

extern void nwk_MTCallbackSubInitCoordConfirm(ZStatus_t Status);

extern void nwk_MTCallbackSubStartRouterConfirm(ZStatus_t Status);

extern void nwk_MTCallbackSubNetworkDiscoveryConfirm(byte ResultCount,	networkDesc_t *NetworkList);

extern void nwk_MTCallbackSubJoinConfirm(uint16 PanId, ZStatus_t Status);


extern void nwk_MTCallbackSubJoinIndication(uint16 ShortAddress, byte *ExtendedAddress,
                                            byte CapabilityFlags);


extern void nwk_MTCallbackSubLeaveConfirm(byte *DeviceAddress, ZStatus_t Status);

extern void nwk_MTCallbackSubLeaveIndication(byte *DeviceAddress);

extern void nwk_MTCallbackSubSyncIndication(void);

extern void nwk_MTCallbackSubPollConfirm(byte status);

#endif   /*NWK Callback Processing in MT*/

extern void nwk_MTCallbackPingConfirm(uint16 DstAddress, byte pingSeqNo,
                                      uint16 delay, byte routeCnt, byte *routeAddr);

MT_RPC.h

#ifndef MT_RPC_H
#define MT_RPC_H

#ifdef __cplusplus
extern "C" {
#endif


#include "hal_types.h"


/* 1st byte is the length of the data field, 2nd/3rd bytes are command field. */
#define MT_RPC_FRAME_HDR_SZ   3

#define MT_RPC_DATA_MAX       250

/* The 3 MSB's of the 1st command field byte are for command type. */
#define MT_RPC_CMD_TYPE_MASK  0xE0

/* The 5 LSB's of the 1st command field byte are for the subsystem. */
#define MT_RPC_SUBSYSTEM_MASK 0x1F

/* position of fields in the general format frame */
#define MT_RPC_POS_LEN        0
#define MT_RPC_POS_CMD0       1
#define MT_RPC_POS_CMD1       2
#define MT_RPC_POS_DAT0       3

/* Error codes */
#define MT_RPC_SUCCESS        0     /* success */
#define MT_RPC_ERR_SUBSYSTEM  1     /* invalid subsystem */
#define MT_RPC_ERR_COMMAND_ID 2     /* invalid command ID */
#define MT_RPC_ERR_PARAMETER  3     /* invalid parameter */
#define MT_RPC_ERR_LENGTH     4     /* invalid length */


typedef enum {
  MT_RPC_CMD_POLL = 0x00,
  MT_RPC_CMD_SREQ = 0x20,
  MT_RPC_CMD_AREQ = 0x40,
  MT_RPC_CMD_SRSP = 0x60,
  MT_RPC_CMD_RES4 = 0x80,
  MT_RPC_CMD_RES5 = 0xA0,
  MT_RPC_CMD_RES6 = 0xC0,
  MT_RPC_CMD_RES7 = 0xE0
} mtRpcCmdType_t;

typedef enum {
  MT_RPC_SYS_RES0,   /* Reserved. */
  MT_RPC_SYS_SYS,
  MT_RPC_SYS_MAC,
  MT_RPC_SYS_NWK,
  MT_RPC_SYS_AF,
  MT_RPC_SYS_ZDO,
  MT_RPC_SYS_SAPI,   /* Simple API. */
  MT_RPC_SYS_UTIL,
  MT_RPC_SYS_DBG,
  MT_RPC_SYS_APP,
  MT_RPC_SYS_OTA,
  MT_RPC_SYS_MAX     /* Maximum value, must be last */
  /* 10-32 available, not yet assigned. */
} mtRpcSysType_t;

typedef struct
{
  uint8 *(*alloc)(mtRpcCmdType_t type, uint8 len);
  void (*send)(uint8 *pBuf);
} mtTransport_t;

typedef uint8 (*mtProcessMsg_t)(uint8 *pBuf);


#ifdef __cplusplus
};
#endif

#endif /* MT_RPC_H */

MT__SAPI.c

#include "ZComDef.h"
#include "AddrMgr.h"
#include "OSAL.h"
#include "OSAL_Nv.h"
#include "OnBoard.h"
#include "MT.h"
#include "MT_SAPI.h"
#include "MT_UART.h"

#if defined ( MT_SAPI_CB_FUNC )
uint16 _sapiCallbackSub;
#endif

void MT_SapiSystemReset(uint8 *pBuf);
void MT_SapiStart(uint8* pBuf);
void MT_SapiBindDevice(uint8 *pBuf);
void MT_SapiAllowBind(uint8 *pBuf);
void MT_SapiSendData(uint8 *pBuf);
void MT_SapiReadCfg(uint8 *pBuf);
void MT_SapiWriteCfg(uint8 *pBuf);
void MT_SapiGetDevInfo(uint8 *pBuf);
void MT_SapiFindDev(uint8 *pBuf);
void MT_SapiPermitJoin(uint8 *pBuf);
void MT_SapiAppRegister(uint8 *pBuf);

#if defined ( MT_SAPI_FUNC )

uint8 MT_SapiCommandProcessing(uint8 *pBuf)
{
  uint8 status = MT_RPC_SUCCESS;

  switch (pBuf[MT_RPC_POS_CMD1])
  {
    case MT_SAPI_START_REQ:
      MT_SapiStart(pBuf);
      break;

    case MT_SAPI_BIND_DEVICE_REQ:
      MT_SapiBindDevice(pBuf);
      break;

    case MT_SAPI_ALLOW_BIND_REQ:
      MT_SapiAllowBind(pBuf);
      break;

    case MT_SAPI_SEND_DATA_REQ:
      MT_SapiSendData(pBuf);
      break;

    case MT_SAPI_READ_CFG_REQ:
      MT_SapiReadCfg(pBuf);
      break;

    case MT_SAPI_WRITE_CFG_REQ:
      MT_SapiWriteCfg(pBuf);
      break;

    case MT_SAPI_GET_DEV_INFO_REQ:
      MT_SapiGetDevInfo(pBuf);
      break;

    case MT_SAPI_FIND_DEV_REQ:
      MT_SapiFindDev(pBuf);
      break;

    case MT_SAPI_PMT_JOIN_REQ:
      MT_SapiPermitJoin(pBuf);
      break;

    case MT_SAPI_SYS_RESET:
      MT_SapiSystemReset(pBuf);
      break;

    case MT_SAPI_APP_REGISTER_REQ:
      MT_SapiAppRegister(pBuf);
      break;

    default:
      status = MT_RPC_ERR_COMMAND_ID;
      break;
  }

  return status;
}

void MT_SapiSystemReset(uint8 *pBuf)
{
  zb_SystemReset();
}

void MT_SapiStart(uint8 *pBuf)
{
  zb_StartRequest();

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_SAPI), MT_SAPI_START_REQ, 0, NULL);
}

void MT_SapiAppRegister(uint8 *pBuf)
{
  uint8 ret = ZApsIllegalRequest;

  /* check if sapi is alredy registered with an endpoint */
  if ( (sapi_epDesc.endPoint == 0) && (*pBuf != 0) )
  {
    ret = MT_BuildEndpointDesc( pBuf+MT_RPC_FRAME_HDR_SZ, &sapi_epDesc );
    if ( ret == ZSuccess )
    {
      ret = afRegister( &sapi_epDesc );
      // Turn off match descriptor response by default
      afSetMatch(sapi_epDesc.simpleDesc->EndPoint, FALSE);
    }

    if ( ret != ZSuccess )
    {
      sapi_epDesc.endPoint = 0;
    }
  }

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_SAPI),
                                       MT_SAPI_APP_REGISTER_REQ, 1, &ret);
}

void MT_SapiBindDevice(uint8 *pBuf)
{
  uint8 cmdId;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  if (AddrMgrExtAddrValid(pBuf+3))
  {
    zb_BindDevice(pBuf[0], BUILD_UINT16(pBuf[1], pBuf[2]), &pBuf[3]);
  }
  else
  {
    zb_BindDevice(pBuf[0], BUILD_UINT16(pBuf[1], pBuf[2]), (uint8 *)NULL);
  }

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_SAPI), cmdId, 0, NULL);
}

void MT_SapiAllowBind(uint8 *pBuf)
{
  uint8 cmdId;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  zb_AllowBind(pBuf[0]);

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_SAPI), cmdId, 0, NULL);
}


void MT_SapiSendData(uint8 *pBuf)
{
  uint8 cmdId;
  uint16 destination, command;
  uint8 len, handle, txOption, radius;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Destination */
  destination = BUILD_UINT16(pBuf[0], pBuf[1]);
  /* Command */
  command = BUILD_UINT16(pBuf[2], pBuf[3]);
  /* Handle */
  handle = pBuf[4];
  /* txOption */
  txOption = pBuf[5];
  /* Radius */
  radius = pBuf[6];
  /* Length */
  len = pBuf[7];

  zb_SendDataRequest(destination, command, len, &pBuf[8], handle, txOption, radius);

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_SAPI), cmdId, 0, NULL);
}

void MT_SapiReadCfg(uint8 *pBuf)
{
  uint8 len, retStatus;
  uint8 cfgId, cmdId;
  uint8 *pRetBuf;

  /* Parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  cfgId = pBuf[MT_RPC_POS_DAT0];

  /* Length of item in NV memory */
  len = (uint8)osal_nv_item_len(cfgId);

  pRetBuf = osal_mem_alloc(len+3);
  if (pRetBuf != NULL)
  {
    if (len && ((cfgId != ZCD_NV_NIB) && (cfgId != ZCD_NV_DEVICE_LIST) &&
                (cfgId != ZCD_NV_ADDRMGR) && (cfgId != ZCD_NV_NWKKEY)))
    {
      if ((zb_ReadConfiguration(cfgId, len, pRetBuf+3)) == ZSUCCESS)
      {
        retStatus = ZSuccess;
      }
      else
      {
        retStatus = ZFailure;
      }
    }
    else
    {
      retStatus = ZInvalidParameter;
    }

    if (retStatus != ZSuccess)
    {
       /* Don't return garbage with error */
       len = 0;
    }

    /* Status */
    pRetBuf[0] = retStatus;
    /* Config ID */
    pRetBuf[1] = cfgId;
    /* NV item length */
    pRetBuf[2] = len;

    /* Build and send back the response */
    MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_SAPI), cmdId, len+3, pRetBuf );

    osal_mem_free(pRetBuf);
  }
}

void MT_SapiWriteCfg(uint8 *pBuf)
{
  uint8 retValue, cmdId;

  /* Parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  if ((pBuf[0] != ZCD_NV_NIB) && (pBuf[0] != ZCD_NV_DEVICE_LIST) &&
      (pBuf[0] != ZCD_NV_ADDRMGR) && (pBuf[0] != ZCD_NV_NWKKEY))
  {
    if ((zb_WriteConfiguration(pBuf[0], pBuf[1], &pBuf[2])) == ZSUCCESS)
    {
      retValue = ZSuccess;
    }
    else
    {
      retValue = ZFailure;
    }
  }
  else
  {
    retValue = ZInvalidParameter;
  }

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_SAPI), cmdId, 1, &retValue );
}

void MT_SapiGetDevInfo(uint8 *pBuf)
{
  uint8 *pRetBuf;
  uint8 cmdId;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  pRetBuf = osal_mem_alloc(Z_EXTADDR_LEN+1);
  if (pRetBuf)
  {
    zb_GetDeviceInfo(pBuf[0], pRetBuf+1);
    pRetBuf[0] = pBuf[0];

    /* Build and send back the response */
    MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_SAPI), cmdId, Z_EXTADDR_LEN+1, pRetBuf );

    osal_mem_free(pRetBuf);
  }
}

void MT_SapiFindDev(uint8 *pBuf)
{
  uint8 cmdId;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Currently only supports IEEE search */
  zb_FindDeviceRequest(ZB_IEEE_SEARCH, pBuf);

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_SAPI), cmdId, 0, NULL );
}

void MT_SapiPermitJoin(uint8 *pBuf)
{
  uint8 retValue, cmdId;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  retValue = (zb_PermitJoiningRequest(BUILD_UINT16(pBuf[0], pBuf[1]), pBuf[2]));

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_SAPI), cmdId, 1, &retValue );

}
#endif  /* MT_SAPI_FUNC */

#if defined ( MT_SAPI_CB_FUNC )

void zb_MTCallbackStartConfirm( uint8 status )
{
  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_SAPI), MT_SAPI_START_CNF, 1, &status);
}

void zb_MTCallbackSendDataConfirm(uint8 handle, uint8 status)
{
  uint8 retArray[2];

  retArray[0] = handle;
  retArray[1] = status;

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_SAPI), MT_SAPI_SEND_DATA_CNF, 2, retArray);

}

void zb_MTCallbackBindConfirm( uint16 commandId, uint8 status )
{
  uint8 retArray[3];

  retArray[0] = LO_UINT16(commandId);
  retArray[1] = HI_UINT16(commandId);
  retArray[2] = status;

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_SAPI), MT_SAPI_BIND_CNF, 3, retArray);

}

void zb_MTCallbackAllowBindConfirm( uint16 source )
{
  uint8 retArray[2];

  retArray[0] = LO_UINT16(source);
  retArray[1] = HI_UINT16(source);

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_SAPI), MT_SAPI_ALLOW_BIND_CNF, 3, retArray);

}

void zb_MTCallbackFindDeviceConfirm( uint8 searchType, uint8 *searchKey, uint8 *result )
{
  uint8 retArray[SPI_CB_SAPI_FIND_DEV_CNF_LEN];
  uint16 addr = *((uint16*)searchKey);

  // Currently only supports IEEE Addr Search
  retArray[0] = ZB_IEEE_SEARCH;
  retArray[1] = LO_UINT16(addr);
  retArray[2] = HI_UINT16(addr);
  osal_memcpy(&retArray[3], result, Z_EXTADDR_LEN);

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_SAPI), MT_SAPI_FIND_DEV_CNF, 11, retArray);

}


void zb_MTCallbackReceiveDataIndication( uint16 source, uint16 command, uint16 len, uint8 *pData  )
{
  uint8 *memPtr;
  int8 i;
  uint8 msgLen = 6 + len;

  memPtr = osal_mem_alloc(msgLen);

  if (memPtr)
  {
    memPtr[0] = LO_UINT16(source);
    memPtr[1] = HI_UINT16(source);
    memPtr[2] = LO_UINT16(command);
    memPtr[3] = HI_UINT16(command);
    memPtr[4] = LO_UINT16(len);
    memPtr[5] = HI_UINT16(len);

    for (i=0; i<len; i++)
    {
      memPtr[6+i] = pData[i];
    }

    /* Build and send back the response */
    MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_SAPI), MT_SAPI_RCV_DATA_IND, msgLen, memPtr);

    osal_mem_free( memPtr );
  }
}
#endif  /* MT_SAPI_CB_FUNC */

MT__SAPI.h


#ifndef MT_SAPI_H
#define MT_SAPI_H

#include "ZComDef.h"
#include "MT.h"
#include "sapi.h"

#include "OnBoard.h"

#if !defined (SAPI_OSAL_ADD_TASK_ENABLED)
#define SAPICB_CHECK(cbi) 1
#else
#define SAPICB_CHECK(cbi) (_sapiCallbackSub & (cbi))
#endif

// SAPI MT Message Lengths
#define SPI_CB_SAPI_START_CNF_LEN           1
#define SPI_CB_SAPI_SEND_DATA_CNF_LEN       2
#define SPI_CB_SAPI_BIND_CNF_LEN            3
#define SPI_CB_SAPI_DISC_NET_CNF_LEN        1
#define SPI_CB_SAPI_FIND_DEV_CNF_LEN        11
#define SPI_CB_SAPI_RCV_DATA_IND_LEN        6
#define SPI_CB_SAPI_ALLOW_BIND_CNF_LEN      2

#if defined ( MT_SAPI_CB_FUNC )
extern uint16 _sapiCallbackSub;
#endif

#if defined ( MT_SAPI_FUNC )

extern uint8 MT_SapiCommandProcessing(uint8 *pBuf);

#endif  // MT_SAPI_FUNC

#if defined ( MT_SAPI_CB_FUNC )

extern void zb_MTCallbackStartConfirm( uint8 status );

extern void zb_MTCallbackSendDataConfirm( uint8 handle, uint8 status );

extern void zb_MTCallbackBindConfirm( uint16 commandId, uint8 status );

extern void zb_MTCallbackFindDeviceConfirm( uint8 searchType,
                                        uint8 *searchKey, uint8 *result );

extern void zb_MTCallbackReceiveDataIndication( uint16 source,
                              uint16 command, uint16 len, uint8 *pData  );

extern void zb_MTCallbackAllowBindConfirm( uint16 source );

#endif // MT_SAPI_CB_FUNC

#endif

MT__SYS.c

#include "ZComDef.h"
#include "MT.h"
#include "MT_SYS.h"
#include "MT_VERSION.h"
#include "nwk_util.h"
#include "OSAL.h"
#include "OSAL_NV.h"
#include "Onboard.h"  /* This is here because RAM read/write macros need it */
#include "hal_adc.h"
#include "ZGlobals.h"
#include "OSAL_Clock.h"
#include "mac_low_level.h"


#define MT_SYS_DEVICE_INFO_RESPONSE_LEN 14
#define MT_NV_ITEM_MAX_LENGTH           250

#if !defined HAL_GPIO || !HAL_GPIO
#define GPIO_DIR_IN(IDX)
#define GPIO_DIR_OUT(IDX)
#define GPIO_TRI(IDX)
#define GPIO_PULL_UP(IDX)
#define GPIO_PULL_DN(IDX)
#define GPIO_SET(IDX)
#define GPIO_CLR(IDX)
#define GPIO_TOG(IDX)
#define GPIO_GET(IDX) 0
#define GPIO_HiD_SET() (val = 0)
#define GPIO_HiD_CLR() (val = 0)
#endif

#if !defined MT_SYS_OSAL_NV_READ_CERTIFICATE_DATA
#define MT_SYS_OSAL_NV_READ_CERTIFICATE_DATA  FALSE
#endif

const uint16 MT_SysOsalEventId [] = {
                                      MT_SYS_OSAL_EVENT_0,
                                      MT_SYS_OSAL_EVENT_1,
                                      MT_SYS_OSAL_EVENT_2,
                                      MT_SYS_OSAL_EVENT_3
                                    };

typedef enum {
  GPIO_DIR,
  GPIO_TRI,
  GPIO_SET,
  GPIO_CLR,
  GPIO_TOG,
  GPIO_GET,
  GPIO_HiD = 0x12
} GPIO_Op_t;

#if defined (MT_SYS_FUNC)
void MT_SysReset(uint8 *pBuf);
void MT_SysPing(void);
void MT_SysVersion(void);
void MT_SysSetExtAddr(uint8 *pBuf);
void MT_SysGetExtAddr(void);
void MT_SysOsalNVItemInit(uint8 *pBuf);
void MT_SysOsalNVDelete(uint8 *pBuf);
void MT_SysOsalNVLength(uint8 *pBuf);
void MT_SysOsalNVRead(uint8 *pBuf);
void MT_SysOsalNVWrite(uint8 *pBuf);
void MT_SysOsalStartTimer(uint8 *pBuf);
void MT_SysOsalStopTimer(uint8 *pBuf);
void MT_SysRandom(void);
void MT_SysAdcRead(uint8 *pBuf);
void MT_SysGpio(uint8 *pBuf);
void MT_SysStackTune(uint8 *pBuf);
void MT_SysGetDeviceInfo(uint8 *pBuf);
void MT_SysSetUtcTime(uint8 *pBuf);
void MT_SysGetUtcTime(void);
void MT_SysSetTxPower(uint8 *pBuf);
#endif /* MT_SYS_FUNC */

#if defined (MT_SYS_FUNC)

uint8 MT_SysCommandProcessing(uint8 *pBuf)
{
  uint8 status = MT_RPC_SUCCESS;

  switch (pBuf[MT_RPC_POS_CMD1])
  {
    case MT_SYS_RESET_REQ:
      MT_SysReset(pBuf);
      break;

    case MT_SYS_PING:
      MT_SysPing();
      break;

    case MT_SYS_VERSION:
      MT_SysVersion();
      break;

    case MT_SYS_SET_EXTADDR:
      MT_SysSetExtAddr(pBuf);
      break;

    case MT_SYS_GET_EXTADDR:
      MT_SysGetExtAddr();
      break;

// CC253X MAC Network Processor does not have NV support
#if !defined(CC253X_MACNP)
    case MT_SYS_OSAL_NV_DELETE:
      MT_SysOsalNVDelete(pBuf);
      break;

    case MT_SYS_OSAL_NV_ITEM_INIT:
      MT_SysOsalNVItemInit(pBuf);
      break;

    case MT_SYS_OSAL_NV_LENGTH:
      MT_SysOsalNVLength(pBuf);
      break;

    case MT_SYS_OSAL_NV_READ:
      MT_SysOsalNVRead(pBuf);
      break;

    case MT_SYS_OSAL_NV_WRITE:
      MT_SysOsalNVWrite(pBuf);
      break;
#endif

    case MT_SYS_OSAL_START_TIMER:
      MT_SysOsalStartTimer(pBuf);
      break;

    case MT_SYS_OSAL_STOP_TIMER:
      MT_SysOsalStopTimer(pBuf);
      break;

    case MT_SYS_RANDOM:
      MT_SysRandom();
      break;

    case MT_SYS_ADC_READ:
      MT_SysAdcRead(pBuf);
      break;

    case MT_SYS_GPIO:
      MT_SysGpio(pBuf);
      break;

    case MT_SYS_STACK_TUNE:
      MT_SysStackTune(pBuf);
      break;

    case MT_SYS_SET_TIME:
      MT_SysSetUtcTime(pBuf);
      break;

    case MT_SYS_GET_TIME:
      MT_SysGetUtcTime();
      break;

    case MT_SYS_SET_TX_POWER:
      MT_SysSetTxPower(pBuf);
      break;

    default:
      status = MT_RPC_ERR_COMMAND_ID;
      break;
  }

  return status;
}

void MT_SysReset(uint8 *pBuf)
{
  if (pBuf[MT_RPC_POS_DAT0] == 0)
  {
    SystemReset();
  }
#if !(defined(HAL_BOARD_F2618) || defined(HAL_BOARD_F5438) || defined(HAL_BOARD_LM3S))
  else
  {
    SystemResetSoft();  // Especially useful for CC2531 to not break comm with USB Host.
  }
#endif

}

void MT_SysPing(void)
{
  uint16 tmp16;
  uint8 retArray[2];

  /* Build Capabilities */
  tmp16 = MT_CAP_SYS | MT_CAP_MAC | MT_CAP_NWK | MT_CAP_AF | MT_CAP_ZDO |
          MT_CAP_SAPI | MT_CAP_UTIL | MT_CAP_DEBUG | MT_CAP_APP | MT_CAP_ZOAD;

  /* Convert to high byte first into temp buffer */
  retArray[0] = LO_UINT16( tmp16 );
  retArray[1] = HI_UINT16( tmp16 );

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_SYS), MT_SYS_PING,
                                sizeof (tmp16), retArray );
}

void MT_SysVersion(void)
{
  byte *verStr = (byte *)MTVersionString;
  uint8 respLen = sizeof(MTVersionString);

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_SYS), MT_SYS_VERSION,
                               respLen, verStr);
}

void MT_SysSetExtAddr(uint8 *pBuf)
{
  uint8 retValue = ZFailure;
  uint8 cmdId;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  if ( ZMacSetReq(ZMacExtAddr, pBuf) == ZMacSuccess )
  {
// CC253X MAC Network Processor does not have NV support
#if !defined(CC253X_MACNP)
    retValue = osal_nv_write(ZCD_NV_EXTADDR, 0, Z_EXTADDR_LEN, pBuf);
#endif
  }

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_SYS), cmdId, 1, &retValue);

}

void MT_SysGetExtAddr(void)
{
  uint8 extAddr[Z_EXTADDR_LEN];

  ZMacGetReq( ZMacExtAddr, extAddr );

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_SYS), MT_SYS_GET_EXTADDR,
                               Z_EXTADDR_LEN, extAddr);
}

void MT_SysOsalNVRead(uint8 *pBuf)
{
  uint16 nvId;
  uint8 nvItemLen=0, nvItemOffset=0;
  uint8 *pRetBuf=NULL;
  uint8 respLen;

  /* Skip over RPC header */
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Get the ID */
  nvId = BUILD_UINT16(pBuf[0], pBuf[1]);
  /* Get the offset */
  nvItemOffset = pBuf[2];

#if !MT_SYS_OSAL_NV_READ_CERTIFICATE_DATA
  if ((ZCD_NV_IMPLICIT_CERTIFICATE == nvId) ||
      (ZCD_NV_CA_PUBLIC_KEY == nvId)        ||
      (ZCD_NV_DEVICE_PRIVATE_KEY == nvId))
  {
    uint8 tmp[2] = { INVALIDPARAMETER, 0 };
    MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_SYS),
                                   MT_SYS_OSAL_NV_READ, 2, tmp);
    return;
  }
#endif

#if !MT_SYS_KEY_MANAGEMENT
  if ( (nvId == ZCD_NV_NWK_ACTIVE_KEY_INFO) ||
       (nvId == ZCD_NV_NWK_ALTERN_KEY_INFO) ||
      ((nvId >= ZCD_NV_TCLK_TABLE_START) && (nvId <= ZCD_NV_TCLK_TABLE_END)) ||
      ((nvId >= ZCD_NV_APS_LINK_KEY_DATA_START) && (nvId <= ZCD_NV_APS_LINK_KEY_DATA_END)) ||
      ((nvId >= ZCD_NV_MASTER_KEY_DATA_START) && (nvId <= ZCD_NV_MASTER_KEY_DATA_END)) ||
       (nvId == ZCD_NV_PRECFGKEY) )
  {
    uint8 tmp1[2] = { INVALIDPARAMETER, 0 };
    MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_SYS),
                                   MT_SYS_OSAL_NV_READ, 2, tmp1);
    return;
  }
#endif //!MT_SYS_KEY_MANAGEMENT

  nvItemLen = osal_nv_item_len(nvId);

  /* Return only 250 bytes max */
  if (nvItemLen > MT_NV_ITEM_MAX_LENGTH)
  {
    nvItemLen = MT_NV_ITEM_MAX_LENGTH;
  }

  if ((nvItemLen > 0) && ((nvItemLen - nvItemOffset) > 0))
  {
    respLen = nvItemLen - nvItemOffset + 2;
  }
  else
  {
    respLen = 2;
  }

  pRetBuf = osal_mem_alloc(respLen);

  if (pRetBuf != NULL)
  {
    osal_memset(pRetBuf, 0, respLen);

    /* Default to ZFailure */
    pRetBuf[0] = ZFailure;

    if (respLen > 2)
    {
      if (((osal_nv_read( nvId, (uint16)nvItemOffset, (uint16)nvItemLen, &pRetBuf[2])) == ZSUCCESS) && (respLen > 2))
      {
        pRetBuf[0] = ZSuccess;
      }
      pRetBuf[1] = nvItemLen - nvItemOffset;
    }
    else
    {
      pRetBuf[1] = 0;
    }

    /* Build and send back the response */
    MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_SYS),
                                   MT_SYS_OSAL_NV_READ, respLen, pRetBuf );

    osal_mem_free(pRetBuf);
  }
}

void MT_SysOsalNVWrite(uint8 *pBuf)
{
  uint16 nvId;
  uint8 nvItemLen=0, nvItemOffset=0;
  uint8 rtrn;

  /* Skip over RPC header */
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Get the ID */
  nvId = BUILD_UINT16(pBuf[0], pBuf[1]);
  /* Get the offset */
  nvItemOffset = pBuf[2];
  /* Get the length */
  nvItemLen = pBuf[3];
  pBuf += 4;

  /* Default to ZFailure */
  rtrn = ZFailure;

  /* Set the Z-Globals value of this NV item. */
  zgSetItem( nvId, (uint16)nvItemLen, pBuf );

  if ((osal_nv_write(nvId, (uint16)nvItemOffset, (uint16)nvItemLen, pBuf)) == ZSUCCESS)
  {
    if (nvId == ZCD_NV_EXTADDR)
    {
      rtrn = ZMacSetReq(ZMacExtAddr, pBuf);
    }
    else
    {
      rtrn = ZSuccess;
    }
  }

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_SYS),
                                 MT_SYS_OSAL_NV_WRITE, 1, &rtrn);
}

void MT_SysOsalNVItemInit(uint8 *pBuf)
{
  uint8 ret;
  uint8 idLen;
  uint16 nvId;
  uint16 nvLen;

  /* Skip over RPC header */
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* NV item ID */
  nvId = BUILD_UINT16(pBuf[0], pBuf[1]);
  /* NV item length */
  nvLen = BUILD_UINT16(pBuf[2], pBuf[3]);
  /* Initialization data length */
  idLen = pBuf[4];
  pBuf += 5;

  if ( idLen < nvLen )
  {
    /* Attempt to create a new NV item */
    ret = osal_nv_item_init( nvId, nvLen, NULL );
    if ( (ret == NV_ITEM_UNINIT) && (idLen > 0) )
    {
      /* Write initialization data to first part of new item */
      (void) osal_nv_write( nvId, 0, (uint16)idLen, pBuf );
    }
  }
  else
  {
    /* Attempt to create/initialize a new NV item */
    ret = osal_nv_item_init( nvId, nvLen, pBuf );
  }

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_SYS),
                                 MT_SYS_OSAL_NV_ITEM_INIT, 1, &ret);
}

void MT_SysOsalNVDelete(uint8 *pBuf)
{
  uint16 nvId;
  uint16 nvLen;
  uint8 ret;

  /* Skip over RPC header */
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Get the ID */
  nvId = BUILD_UINT16(pBuf[0], pBuf[1]);
  /* Get the length */
  nvLen = BUILD_UINT16(pBuf[2], pBuf[3]);

  /* Attempt to delete the NV item */
  ret = osal_nv_delete( nvId, nvLen );

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_SYS),
                                 MT_SYS_OSAL_NV_DELETE, 1, &ret);
}

void MT_SysOsalNVLength(uint8 *pBuf)
{
  uint16 nvId;
  uint16 nvLen;
  uint8 rsp[2];

  /* Skip over RPC header */
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Get the ID */
  nvId = BUILD_UINT16(pBuf[0], pBuf[1]);

  /* Attempt to get NV item length */
  nvLen = osal_nv_item_len( nvId );
  rsp[0] = LO_UINT16( nvLen );
  rsp[1] = HI_UINT16( nvLen );

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_SYS),
                                 MT_SYS_OSAL_NV_LENGTH, 2, rsp);
}

void MT_SysOsalStartTimer(uint8 *pBuf)
{
  uint16 eventId;
  uint8 retValue = ZFailure;
  uint8 cmdId;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  if (*pBuf <= 3)
  {
    eventId = (uint16) MT_SysOsalEventId[*pBuf];
    retValue = osal_start_timerEx(MT_TaskID, eventId, BUILD_UINT16(pBuf[1], pBuf[2]));
  }
  else
  {
    retValue = ZInvalidParameter;
  }

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_SYS), cmdId, 1, &retValue);
}

void MT_SysOsalStopTimer(uint8 *pBuf)
{
  uint16 eventId;
  uint8 retValue = ZFailure;
  uint8 cmdId;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  if (*pBuf <= 3)
  {
    eventId = (uint16) MT_SysOsalEventId[*pBuf];
    retValue = osal_stop_timerEx(MT_TaskID, eventId);
  }
  else
  {
    retValue = ZInvalidParameter;
  }

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_SYS), cmdId, 1, &retValue );
}

void MT_SysRandom()
{
  uint16 randValue = Onboard_rand();
  uint8 retArray[2];

  retArray[0] = LO_UINT16(randValue);
  retArray[1] = HI_UINT16(randValue);

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_SYS), MT_SYS_RANDOM, 2, retArray );
}

void MT_SysAdcRead(uint8 *pBuf)
{
#ifndef HAL_BOARD_LM3S
  uint8 channel, resolution;
  uint16 tempValue;
  uint8 retArray[2];
  uint8 cmdId;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Channel */
  channel = *pBuf++;

  /* Resolution */
  resolution = *pBuf++;

  /* Voltage reading */
  switch (channel)
  {
    /* Analog input channel */
    case HAL_ADC_CHANNEL_0:
    case HAL_ADC_CHANNEL_1:
    case HAL_ADC_CHANNEL_2:
    case HAL_ADC_CHANNEL_3:
    case HAL_ADC_CHANNEL_4:
    case HAL_ADC_CHANNEL_5:
    case HAL_ADC_CHANNEL_6:
    case HAL_ADC_CHANNEL_7:
      tempValue = HalAdcRead(channel, resolution);
      break;

    /* Temperature sensor */
    case(HAL_ADC_CHANNEL_TEMP):
      tempValue = HalAdcRead(HAL_ADC_CHANNEL_TEMP, HAL_ADC_RESOLUTION_14);
      break;

    /* Voltage reading */
    case(HAL_ADC_CHANNEL_VDD):
      tempValue = HalAdcRead(HAL_ADC_CHANNEL_VDD, HAL_ADC_RESOLUTION_14);
      break;

    /* Undefined channels */
    default:
      tempValue = 0x00;
      break;
  }

  retArray[0] = LO_UINT16(tempValue);
  retArray[1] = HI_UINT16(tempValue);

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_SYS), cmdId, 2, retArray);
#endif /* #ifndef HAL_BOARD_LM3S */
}

void MT_SysGpio(uint8 *pBuf)
{
  uint8 cmd, val;
  GPIO_Op_t op;

  cmd = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  op = (GPIO_Op_t)(*pBuf++);
  val = *pBuf;

  switch (op)
  {
    case GPIO_DIR:
      if (val & BV(0)) {GPIO_DIR_OUT(0);} else {GPIO_DIR_IN(0);}
      if (val & BV(1)) {GPIO_DIR_OUT(1);} else {GPIO_DIR_IN(1);}
      if (val & BV(2)) {GPIO_DIR_OUT(2);} else {GPIO_DIR_IN(2);}
      if (val & BV(3)) {GPIO_DIR_OUT(3);} else {GPIO_DIR_IN(3);}
      break;

    case GPIO_TRI:
      if(val & BV(0)) {GPIO_TRI(0);} else if(val & BV(4)) {GPIO_PULL_DN(0);} else {GPIO_PULL_UP(0);}
      if(val & BV(1)) {GPIO_TRI(1);} else if(val & BV(5)) {GPIO_PULL_DN(1);} else {GPIO_PULL_UP(1);}
      if(val & BV(2)) {GPIO_TRI(2);} else if(val & BV(6)) {GPIO_PULL_DN(2);} else {GPIO_PULL_UP(2);}
      if(val & BV(3)) {GPIO_TRI(3);} else if(val & BV(7)) {GPIO_PULL_DN(3);} else {GPIO_PULL_UP(3);}
      break;

    case GPIO_SET:
      if (val & BV(0)) {GPIO_SET(0);}
      if (val & BV(1)) {GPIO_SET(1);}
      if (val & BV(2)) {GPIO_SET(2);}
      if (val & BV(3)) {GPIO_SET(3);}
      break;

    case GPIO_CLR:
      if (val & BV(0)) {GPIO_CLR(0);}
      if (val & BV(1)) {GPIO_CLR(1);}
      if (val & BV(2)) {GPIO_CLR(2);}
      if (val & BV(3)) {GPIO_CLR(3);}
      break;

    case GPIO_TOG:
      if (val & BV(0)) {GPIO_TOG(0);}
      if (val & BV(1)) {GPIO_TOG(1);}
      if (val & BV(2)) {GPIO_TOG(2);}
      if (val & BV(3)) {GPIO_TOG(3);}
      break;

    case GPIO_GET:
      break;

    case GPIO_HiD:
      (val) ? GPIO_HiD_SET() :  GPIO_HiD_CLR();
      break;

    default:
      break;
  }

  val  = (GPIO_GET(0)) ? BV(0) : 0;
  val |= (GPIO_GET(1)) ? BV(1) : 0;
  val |= (GPIO_GET(2)) ? BV(2) : 0;
  val |= (GPIO_GET(3)) ? BV(3) : 0;

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_SYS), cmd, 1, &val);
}

void MT_SysStackTune(uint8 *pBuf)
{
  uint8 cmd, rtrn;

  cmd = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  switch (*pBuf++)
  {
  case STK_TX_PWR:
    rtrn = ZMacSetReq(ZMacPhyTransmitPowerSigned, pBuf);
    break;

  case STK_RX_ON_IDLE:
    if ((*pBuf != TRUE) && (*pBuf != FALSE))
    {
      (void)ZMacGetReq(ZMacRxOnIdle, &rtrn);
    }
    else
    {
      rtrn = ZMacSetReq(ZMacRxOnIdle, pBuf);
    }
    break;

  default:
    rtrn = ZInvalidParameter;
    break;
  }

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_SYS), cmd, 1, &rtrn);
}

void MT_SysSetUtcTime(uint8 *pBuf)
{
  uint8 cmdId;
  uint8 retStat;
  UTCTime utcSecs;

  /* Parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  utcSecs = osal_build_uint32( pBuf, 4 );
  if ( utcSecs == 0 )
  {
    UTCTimeStruct utc;

    /* Skip past UTC time */
    pBuf += 4;

    /* Get time and date parameters */
    utc.hour = *pBuf++;
    utc.minutes = *pBuf++;
    utc.seconds = *pBuf++;
    utc.month = (*pBuf++) - 1;
    utc.day = (*pBuf++) - 1;
    utc.year = osal_build_uint16 ( pBuf );

    if ((utc.hour < 24) && (utc.minutes < 60) && (utc.seconds < 60) &&
        (utc.month < 12) && (utc.day < 31) && (utc.year > 1999) && (utc.year < 2136))
    {
      /* Got past the course filter, now check for leap year */
      if ((utc.month != 1) || (utc.day < (IsLeapYear( utc.year ) ? 29 : 28)))
      {
        /* Numbers look reasonable, convert to UTC */
        utcSecs = osal_ConvertUTCSecs( &utc );
      }
    }
  }

  if ( utcSecs == 0 )
  {
    /* Bad parameter(s) */
    retStat = ZInvalidParameter;
  }
  else
  {
    /* Parameters accepted, set the time */
    osal_setClock( utcSecs );
    retStat = ZSuccess;
  }

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_SYS),
                                 cmdId, 1, &retStat);
}

void MT_SysGetUtcTime(void)
{
  uint8 len;
  uint8 *buf;

  len = sizeof( UTCTime ) + sizeof( UTCTimeStruct );

  buf = osal_mem_alloc( len );
  if ( buf )
  {
    uint8 *pBuf;
    UTCTime utcSecs;
    UTCTimeStruct utcTime;

    // Get current 32-bit UTC time and parse it
    utcSecs = osal_getClock();
    osal_ConvertUTCTime( &utcTime, utcSecs );

    // Start with 32-bit UTC time
    pBuf = osal_buffer_uint32( buf, utcSecs );

    // Concatenate parsed UTC time fields
    *pBuf++ = utcTime.hour;
    *pBuf++ = utcTime.minutes;
    *pBuf++ = utcTime.seconds;
    *pBuf++ = utcTime.month + 1;  // Convert to human numbers
    *pBuf++ = utcTime.day + 1;
    *pBuf++ = LO_UINT16( utcTime.year );
    *pBuf++ = HI_UINT16( utcTime.year );

    /* Build and send back the response */
    MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_SYS),
                                   MT_SYS_GET_TIME, (uint8)(pBuf-buf), buf);

    osal_mem_free( buf );
  }
}

void MT_SysSetTxPower(uint8 *pBuf)
{
  /* A local variable to hold the signed dBm value of TxPower that is being requested. */
  uint8 signed_dBm_of_TxPower_requeseted;
  uint8 signed_dBm_of_TxPower_range_corrected;

  /* Parse the requested dBm from the RPC message. */
  signed_dBm_of_TxPower_requeseted = pBuf[MT_RPC_POS_DAT0];


  signed_dBm_of_TxPower_range_corrected = macRadioSetTxPower(signed_dBm_of_TxPower_requeseted);

  /*
   * Call the function to store the requested dBm in the MAC PIB and to set the TxPower as closely
   * as possible within the TxPower range that is valid for the compile-time and run-time
   * configuration.
   */
  (void)MAC_MlmeSetReq(MAC_PHY_TRANSMIT_POWER_SIGNED, &signed_dBm_of_TxPower_requeseted);

  /* Build and send back the response that includes the actual dBm TxPower that can be set. */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_SYS),
                                       MT_SYS_SET_TX_POWER, 1,
                                       &signed_dBm_of_TxPower_range_corrected);
}
#endif /* MT_SYS_FUNC */

void MT_SysResetInd(void)
{
  uint8 retArray[6];

  retArray[0] = ResetReason();   /* Reason */
  osal_memcpy( &retArray[1], MTVersionString, 5 );   /* Revision info */

  /* Send out Reset Response message */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_SYS), MT_SYS_RESET_IND,
                                sizeof(retArray), retArray);
}

void MT_SysOsalTimerExpired(uint8 Id)
{
  uint8 retValue;
  retValue = Id;
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_SYS), MT_SYS_OSAL_TIMER_EXPIRED, 1, &retValue);
}

MT__SYS.h

#ifndef MT_SYS_H
#define MT_SYS_H

#ifdef __cplusplus
extern "C"
{
#endif


typedef enum {
  STK_TX_PWR,
  STK_RX_ON_IDLE  // If 2nd parameter value is not TRUE or FALSE, then makes a ZMacGet request vice set.
} STK_Tune_t;


#if defined (MT_SYS_FUNC)

extern uint8 MT_SysCommandProcessing(uint8 *pBuf);
#endif

extern void MT_SysResetInd( void );

extern void MT_SysOsalTimerExpired(uint8 Id);

#ifdef __cplusplus
}
#endif

#endif 

MT__TASK.c

#include "ZComDef.h"
#include "MT_TASK.h"
#include "MT.h"
#include "MT_DEBUG.h"
#include "MT_UART.h"
#include "MT_UTIL.h"
#include "MT_SYS.h"

#if !defined( NONWK )
#include "MT_ZDO.h"
#include "MT_AF.h"
#endif  /* NONWK */

#include "hal_uart.h"
#include "OSAL_Memory.h"


static void MT_ProcessIncomingCommand( mtOSALSerialData_t *msg );


uint8 MT_TaskID;

void MT_TaskInit(uint8 task_id)
{
  MT_TaskID = task_id;

  /* Initialize the Serial port */
  MT_UartInit();

  /* Register taskID - Do this after UartInit() because it will reset the taskID */
  MT_UartRegisterTaskID(task_id);

  osal_set_event(task_id, MT_SECONDARY_INIT_EVENT);
}

UINT16 MT_ProcessEvent(uint8 task_id, uint16 events)
{
  /* Could be multiple events, so switch won't work */
  if ( events & SYS_EVENT_MSG )
  {
    uint8 *msg_ptr = osal_msg_receive(task_id);

    if (msg_ptr != NULL)
    {
      MT_ProcessIncomingCommand((mtOSALSerialData_t *)msg_ptr);

      osal_msg_deallocate(msg_ptr);
    }

    /* Return unproccessed events */
    return (events ^ SYS_EVENT_MSG);
  }

  if ( events & MT_SECONDARY_INIT_EVENT )
  {
    MT_Init();
    /* Return unproccessed events */
    return (events ^ MT_SECONDARY_INIT_EVENT);
  }

  if ( events & MT_ZTOOL_SERIAL_RCV_BUFFER_FULL )
  {
    /* Return unproccessed events */
    return (events ^ MT_ZTOOL_SERIAL_RCV_BUFFER_FULL);
  }

#if !defined( NONWK )
  if ( events & MT_AF_EXEC_EVT )
  {
    MT_AfExec();
    return (events ^ MT_AF_EXEC_EVT);
  }
#endif  /* NONWK */

  /* Handle MT_SYS_OSAL_START_TIMER callbacks */
#if defined MT_SYS_FUNC
  if ( events & (MT_SYS_OSAL_EVENT_MASK))
  {
    if (events & MT_SYS_OSAL_EVENT_0)
    {
      MT_SysOsalTimerExpired(0x00);
      events ^= MT_SYS_OSAL_EVENT_0;
    }

    if (events & MT_SYS_OSAL_EVENT_1)
    {
      MT_SysOsalTimerExpired(0x01);
      events ^= MT_SYS_OSAL_EVENT_1;
    }

    if (events & MT_SYS_OSAL_EVENT_2)
    {
      MT_SysOsalTimerExpired(0x02);
      events ^= MT_SYS_OSAL_EVENT_2;
    }

    if (events & MT_SYS_OSAL_EVENT_3)
    {
      MT_SysOsalTimerExpired(0x03);
      events ^= MT_SYS_OSAL_EVENT_3;
    }

    return events;
  }
#endif

  /* Discard or make more handlers */
  return 0;

} /* MT_ProcessEvent() */

static void MT_ProcessIncomingCommand( mtOSALSerialData_t *msg )
{
  uint8 len, *msg_ptr = msg->msg;

  /* Use the first byte of the message as the command ID */
  switch ( msg->hdr.event )
  {
    case CMD_SERIAL_MSG:
      MT_ProcessIncoming(msg_ptr);
      break;

    case CMD_DEBUG_MSG:
      MT_ProcessDebugMsg( (mtDebugMsg_t *)msg );
      break;

    case CB_FUNC:
      /*
        Build SPI message here instead of redundantly calling MT_BuildSPIMsg
        because we have copied data already in the allocated message
      */

      /* msg_ptr is the beginning of the intended SPI message */
      len = SPI_0DATA_MSG_LEN + msg_ptr[DATALEN_FIELD];

      /*
        FCS goes to the last byte in the message and is calculated over all
        the bytes except FCS and SOP
      */
      msg_ptr[len-1] = MT_UartCalcFCS(msg_ptr + 1, (uint8)(len-2));

#ifdef MT_UART_DEFAULT_PORT
      HalUARTWrite ( MT_UART_DEFAULT_PORT, msg_ptr, len );
#endif
      break;

    case CMD_DEBUG_STR:
      MT_ProcessDebugStr( (mtDebugStr_t *)msg );
      break;

#if !defined ( NONWK )
    case MT_SYS_APP_RSP_MSG:
      len = SPI_0DATA_MSG_LEN + msg_ptr[DATALEN_FIELD];
      MTProcessAppRspMsg( msg_ptr, len );
      break;
#endif  // NONWK

#if defined (MT_UTIL_FUNC)
#if defined ZCL_KEY_ESTABLISH
    case ZCL_KEY_ESTABLISH_IND:
      MT_UtilKeyEstablishInd((keyEstablishmentInd_t *)msg);
      break;
#endif
#endif
#ifdef MT_ZDO_CB_FUNC
    case ZDO_STATE_CHANGE:
      MT_ZdoStateChangeCB((osal_event_hdr_t *)msg);
      break;
#endif

    default:
      break;
  }
}

#ifdef MT_TASK

uint8 *MT_TransportAlloc(uint8 cmd0, uint8 len)
{
  uint8 *p;

  (void)cmd0;  // Intentionally unreferenced parameter

  /* Allocate a buffer of data length + SOP+CMD+FCS (5 bytes) */
  p = osal_msg_allocate(len + SPI_0DATA_MSG_LEN);

  if (p)
  {
    p++; /* Save space for SOP_VALUE, msg structure */
    return p;
  }
  else
  {
    return NULL;
  }
}

void MT_TransportSend(uint8 *pBuf)
{
  uint8 *msgPtr;
  uint8 dataLen = pBuf[0]; /* Data length is on byte #1 from the pointer */

  /* Move back to the SOP */
  msgPtr = pBuf-1;

  /* Insert SOP */
  msgPtr[0] = MT_UART_SOF;

  /* Insert FCS */
  msgPtr[SPI_0DATA_MSG_LEN - 1 + dataLen] = MT_UartCalcFCS (pBuf, (3 + dataLen));

  /* Send to UART */
#ifdef MT_UART_DEFAULT_PORT
  HalUARTWrite(MT_UART_DEFAULT_PORT, msgPtr, dataLen + SPI_0DATA_MSG_LEN);
#endif

  /* Deallocate */
  osal_msg_deallocate(msgPtr);
}
#endif

MT__TASK.h

#ifndef MT_TASK_H
#define MT_TASK_H

#ifdef __cplusplus
extern "C"
{
#endif

extern void MT_TaskInit(uint8 task_id);

extern UINT16 MT_ProcessEvent(uint8 task_id, uint16 event);


#ifdef __cplusplus
}
#endif

#endif 

MT__UART.c

#include "ZComDef.h"
#include "OSAL.h"
#include "hal_uart.h"
#include "MT.h"
#include "MT_UART.h"
#include "OSAL_Memory.h"

/* State values for ZTool protocal */
#define SOP_STATE      0x00
#define CMD_STATE1     0x01
#define CMD_STATE2     0x02
#define LEN_STATE      0x03
#define DATA_STATE     0x04
#define FCS_STATE      0x05

/* Used to indentify the application ID for osal task */
byte App_TaskID;

/* ZTool protocal parameters */
uint8 state;
uint8  CMD_Token[2];
uint8  LEN_Token;
uint8  FSC_Token;
mtOSALSerialData_t  *pMsg;
uint8  tempDataLen;

#if defined (ZAPP_P1) || defined (ZAPP_P2)
uint16  MT_UartMaxZAppBufLen;
bool    MT_UartZAppRxStatus;
#endif

void MT_UartInit ()
{
  halUARTCfg_t uartConfig;

  /* Initialize APP ID */
  App_TaskID = 0;

  /* UART Configuration */
  uartConfig.configured           = TRUE;
  uartConfig.baudRate             = MT_UART_DEFAULT_BAUDRATE;
  uartConfig.flowControl          = MT_UART_DEFAULT_OVERFLOW;
  uartConfig.flowControlThreshold = MT_UART_DEFAULT_THRESHOLD;
  uartConfig.rx.maxBufSize        = MT_UART_DEFAULT_MAX_RX_BUFF;
  uartConfig.tx.maxBufSize        = MT_UART_DEFAULT_MAX_TX_BUFF;
  uartConfig.idleTimeout          = MT_UART_DEFAULT_IDLE_TIMEOUT;
  uartConfig.intEnable            = TRUE;
#if defined (ZTOOL_P1) || defined (ZTOOL_P2)
  uartConfig.callBackFunc         = MT_UartProcessZToolData;
#elif defined (ZAPP_P1) || defined (ZAPP_P2)
  uartConfig.callBackFunc         = MT_UartProcessZAppData;
#else
  uartConfig.callBackFunc         = NULL;
#endif

  /* Start UART */
#if defined (MT_UART_DEFAULT_PORT)
  HalUARTOpen (MT_UART_DEFAULT_PORT, &uartConfig);
#else
  /* Silence IAR compiler warning */
  (void)uartConfig;
#endif

  /* Initialize for ZApp */
#if defined (ZAPP_P1) || defined (ZAPP_P2)
  /* Default max bytes that ZAPP can take */
  MT_UartMaxZAppBufLen  = 1;
  MT_UartZAppRxStatus   = MT_UART_ZAPP_RX_READY;
#endif

}

void MT_UartRegisterTaskID( byte taskID )
{
  App_TaskID = taskID;
}

byte MT_UartCalcFCS( uint8 *msg_ptr, uint8 len )
{
  byte x;
  byte xorResult;

  xorResult = 0;

  for ( x = 0; x < len; x++, msg_ptr++ )
    xorResult = xorResult ^ *msg_ptr;

  return ( xorResult );
}


void MT_UartProcessZToolData ( uint8 port, uint8 event )
{
  uint8  ch;
  uint8  bytesInRxBuffer;
  
  (void)event;  // Intentionally unreferenced parameter

  while (Hal_UART_RxBufLen(port))
  {
    HalUARTRead (port, &ch, 1);

    switch (state)
    {
      case SOP_STATE:
        if (ch == MT_UART_SOF)
          state = LEN_STATE;
        break;

      case LEN_STATE:
        LEN_Token = ch;

        tempDataLen = 0;

        /* Allocate memory for the data */
        pMsg = (mtOSALSerialData_t *)osal_msg_allocate( sizeof ( mtOSALSerialData_t ) +
                                                        MT_RPC_FRAME_HDR_SZ + LEN_Token );

        if (pMsg)
        {
          /* Fill up what we can */
          pMsg->hdr.event = CMD_SERIAL_MSG;
          pMsg->msg = (uint8*)(pMsg+1);
          pMsg->msg[MT_RPC_POS_LEN] = LEN_Token;
          state = CMD_STATE1;
        }
        else
        {
          state = SOP_STATE;
          return;
        }
        break;

      case CMD_STATE1:
        pMsg->msg[MT_RPC_POS_CMD0] = ch;
        state = CMD_STATE2;
        break;

      case CMD_STATE2:
        pMsg->msg[MT_RPC_POS_CMD1] = ch;
        /* If there is no data, skip to FCS state */
        if (LEN_Token)
        {
          state = DATA_STATE;
        }
        else
        {
          state = FCS_STATE;
        }
        break;

      case DATA_STATE:

        /* Fill in the buffer the first byte of the data */
        pMsg->msg[MT_RPC_FRAME_HDR_SZ + tempDataLen++] = ch;

        /* Check number of bytes left in the Rx buffer */
        bytesInRxBuffer = Hal_UART_RxBufLen(port);

        /* If the remain of the data is there, read them all, otherwise, just read enough */
        if (bytesInRxBuffer <= LEN_Token - tempDataLen)
        {
          HalUARTRead (port, &pMsg->msg[MT_RPC_FRAME_HDR_SZ + tempDataLen], bytesInRxBuffer);
          tempDataLen += bytesInRxBuffer;
        }
        else
        {
          HalUARTRead (port, &pMsg->msg[MT_RPC_FRAME_HDR_SZ + tempDataLen], LEN_Token - tempDataLen);
          tempDataLen += (LEN_Token - tempDataLen);
        }

        /* If number of bytes read is equal to data length, time to move on to FCS */
        if ( tempDataLen == LEN_Token )
            state = FCS_STATE;

        break;

      case FCS_STATE:

        FSC_Token = ch;

        /* Make sure it's correct */
        if ((MT_UartCalcFCS ((uint8*)&pMsg->msg[0], MT_RPC_FRAME_HDR_SZ + LEN_Token) == FSC_Token))
        {
          osal_msg_send( App_TaskID, (byte *)pMsg );
        }
        else
        {
          /* deallocate the msg */
          osal_msg_deallocate ( (uint8 *)pMsg );
        }

        /* Reset the state, send or discard the buffers at this point */
        state = SOP_STATE;

        break;

      default:
       break;
    }
  }
}

#if defined (ZAPP_P1) || defined (ZAPP_P2)

void MT_UartProcessZAppData ( uint8 port, uint8 event )
{

  osal_event_hdr_t  *msg_ptr;
  uint16 length = 0;
  uint16 rxBufLen  = Hal_UART_RxBufLen(MT_UART_DEFAULT_PORT);

  /*
     If maxZAppBufferLength is 0 or larger than current length
     the entire length of the current buffer is returned.
  */
  if ((MT_UartMaxZAppBufLen != 0) && (MT_UartMaxZAppBufLen <= rxBufLen))
  {
    length = MT_UartMaxZAppBufLen;
  }
  else
  {
    length = rxBufLen;
  }

  /* Verify events */
  if (event == HAL_UART_TX_FULL)
  {
    // Do something when TX if full
    return;
  }

  if (event & ( HAL_UART_RX_FULL | HAL_UART_RX_ABOUT_FULL | HAL_UART_RX_TIMEOUT))
  {
    if ( App_TaskID )
    {
      /*
         If Application is ready to receive and there is something
         in the Rx buffer then send it up
      */
      if ((MT_UartZAppRxStatus == MT_UART_ZAPP_RX_READY ) && (length != 0))
      {
        /* Disable App flow control until it processes the current data */
         MT_UartAppFlowControl (MT_UART_ZAPP_RX_NOT_READY);

        /* 2 more bytes are added, 1 for CMD type, other for length */
        msg_ptr = (osal_event_hdr_t *)osal_msg_allocate( length + sizeof(osal_event_hdr_t) );
        if ( msg_ptr )
        {
          msg_ptr->event = SPI_INCOMING_ZAPP_DATA;
          msg_ptr->status = length;

          /* Read the data of Rx buffer */
          HalUARTRead( MT_UART_DEFAULT_PORT, (uint8 *)(msg_ptr + 1), length );

          /* Send the raw data to application...or where ever */
          osal_msg_send( App_TaskID, (uint8 *)msg_ptr );
        }
      }
    }
  }
}

void MT_UartZAppBufferLengthRegister ( uint16 maxLen )
{
  /* If the maxLen is larger than the RX buff, something is not right */
  if (maxLen <= MT_UART_DEFAULT_MAX_RX_BUFF)
    MT_UartMaxZAppBufLen = maxLen;
  else
    MT_UartMaxZAppBufLen = 1; /* default is 1 byte */
}

void MT_UartAppFlowControl ( bool status )
{

  /* Make sure only update if needed */
  if (status != MT_UartZAppRxStatus )
  {
    MT_UartZAppRxStatus = status;
  }

  /* App is ready to read again, ProcessZAppData have to be triggered too */
  if (status == MT_UART_ZAPP_RX_READY)
  {
    MT_UartProcessZAppData (MT_UART_DEFAULT_PORT, HAL_UART_RX_TIMEOUT );
  }

}

#endif 

MT__UART.h

#ifndef MT_UART_H
#define MT_UART_H

#ifdef __cplusplus
extern "C"
{
#endif

#include "Onboard.h"
#include "OSAL.h"


/* Start-of-frame delimiter for UART transport */
#define MT_UART_SOF                     0xFE

/* UART frame overhead for SOF and FCS bytes */
#define MT_UART_FRAME_OVHD              2

/* Default values */
#if defined (ZTOOL_P1) || defined (ZTOOL_P2)
  #define MT_UART_DEFAULT_PORT           ZTOOL_PORT
#elif defined (ZAPP_P1) || defined (ZAPP_P2)
  #define MT_UART_DEFAULT_PORT           ZAPP_PORT
#endif

#if !defined( MT_UART_DEFAULT_OVERFLOW )
  #define MT_UART_DEFAULT_OVERFLOW       TRUE
#endif

#if !defined MT_UART_DEFAULT_BAUDRATE
#define MT_UART_DEFAULT_BAUDRATE         HAL_UART_BR_38400
#endif
#define MT_UART_DEFAULT_THRESHOLD        MT_UART_THRESHOLD
#define MT_UART_DEFAULT_MAX_RX_BUFF      MT_UART_RX_BUFF_MAX
#if !defined( MT_UART_DEFAULT_MAX_TX_BUFF )
  #define MT_UART_DEFAULT_MAX_TX_BUFF    MT_UART_TX_BUFF_MAX
#endif
#define MT_UART_DEFAULT_IDLE_TIMEOUT     MT_UART_IDLE_TIMEOUT

/* Application Flow Control */
#define MT_UART_ZAPP_RX_NOT_READY         0x00
#define MT_UART_ZAPP_RX_READY             0x01

typedef struct
{
  osal_event_hdr_t  hdr;
  uint8             *msg;
} mtOSALSerialData_t;

extern void MT_UartInit (void);

void MT_UartProcessZToolData ( uint8 port, uint8 taskId );

void MT_UartProcessZAppData ( uint8 port, uint8 event );

extern uint8 MT_UartCalcFCS( uint8 *msg_ptr, uint8 length );

extern void MT_UartRegisterTaskID( uint8 taskID );

extern void MT_UartZAppBufferLengthRegister ( uint16 maxLen );

extern void MT_UartAppFlowControl ( uint8 status );

#endif 

MT__UTIL.c

#include "ZComDef.h"

#include "AddrMgr.h"

#include "OnBoard.h"   /* This is here because of the key reading */
#include "hal_key.h"
#include "hal_led.h"
#include "OSAL_Nv.h"
#include "osal.h"
#include "NLMEDE.h"
#include "MT.h"
#include "MT_UTIL.h"
#include "MT_MAC.h"
#include "ssp.h"
#if defined ZCL_KEY_ESTABLISH
#include "zcl_key_establish.h"
#endif
#if defined TC_LINKKEY_JOIN
#include "zcl_se.h"
#endif

#if !defined NONWK
#include "MT_ZDO.h"
#include "MT_SAPI.h"
#include "MT_NWK.h"
#include "MT_AF.h"
#include "AssocList.h"
#include "ZDApp.h"
#include "ZDSecMgr.h"
#endif
#define MT_UTIL_DEVICE_INFO_RESPONSE_LEN 14
#define MT_UTIL_STATUS_LEN    1
#define MT_UTIL_FRM_CTR_LEN   4
// Status + LinkKeyDataLen + Tx+Rx Frame counter.
#define MT_APSME_LINKKEY_GET_RSP_LEN (MT_UTIL_STATUS_LEN + SEC_KEY_LEN + (MT_UTIL_FRM_CTR_LEN * 2))
// Status + NV id
#define MT_APSME_LINKKEY_NV_ID_GET_RSP_LEN (MT_UTIL_STATUS_LEN + 2)

#if defined ZCL_KEY_ESTABLISH
uint8 zcl_key_establish_task_id;
#endif

#ifdef AUTO_PEND
static void MT_UtilRevExtCpy( uint8 *pDst, uint8 *pSrc );
static void MT_UtilSpi2Addr( zAddrType_t *pDst, uint8 *pSrc );
#endif

#if defined (MT_UTIL_FUNC)
void MT_UtilGetDeviceInfo(void);
void MT_UtilGetNvInfo(void);
void MT_UtilSetPanID(uint8 *pBuf);
void MT_UtilSetChannels(uint8 *pBuf);
void MT_UtilSetSecLevel(uint8 *pBuf);
void MT_UtilSetPreCfgKey(uint8 *pBuf);
void MT_UtilCallbackSub(uint8 *pData);
void MT_UtilKeyEvent(uint8 *pBuf);
void MT_UtilTimeAlive(void);
void MT_UtilLedControl(uint8 *pBuf);
void MT_UtilSrcMatchEnable (uint8 *pBuf);
void MT_UtilSrcMatchAddEntry (uint8 *pBuf);
void MT_UtilSrcMatchDeleteEntry (uint8 *pBuf);
void MT_UtilSrcMatchCheckSrcAddr (uint8 *pBuf);
void MT_UtilSrcMatchAckAllPending (uint8 *pBuf);
void MT_UtilSrcMatchCheckAllPending (uint8 *pBuf);

#if !defined NONWK
void MT_UtilDataReq(uint8 *pBuf);
static void MT_UtilAddrMgrEntryLookupExt(uint8 *pBuf);
static void MT_UtilAddrMgrEntryLookupNwk(uint8 *pBuf);
#if defined MT_SYS_KEY_MANAGEMENT
static void MT_UtilAPSME_LinkKeyDataGet(uint8 *pBuf);
static void MT_UtilAPSME_LinkKeyNvIdGet(uint8 *pBuf);
#endif //MT_SYS_KEY_MANAGEMENT
static void MT_UtilAPSME_RequestKeyCmd(uint8 *pBuf);
static void MT_UtilAssocCount(uint8 *pBuf);
static void MT_UtilAssocFindDevice(uint8 *pBuf);
static void MT_UtilAssocGetWithAddress(uint8 *pBuf);
static void packDev_t(uint8 *pBuf, associated_devices_t *pDev);
#if defined ZCL_KEY_ESTABLISH
static void MT_UtilzclGeneral_KeyEstablish_InitiateKeyEstablishment(uint8 *pBuf);
static void MT_UtilzclGeneral_KeyEstablishment_ECDSASign(uint8 *pBuf);
#endif // ZCL_KEY_ESTABLISH
static void MT_UtilSync(void);
#endif // !defined NONWK
#endif // MT_UTIL_FUNC

#if defined (MT_UTIL_FUNC)

uint8 MT_UtilCommandProcessing(uint8 *pBuf)
{
  uint8 status = MT_RPC_SUCCESS;

  switch (pBuf[MT_RPC_POS_CMD1])
  {
// CC253X MAC Network Processor does not have NV support
#if !defined(CC253X_MACNP)
    case MT_UTIL_GET_DEVICE_INFO:
      MT_UtilGetDeviceInfo();
      break;

    case MT_UTIL_GET_NV_INFO:
      MT_UtilGetNvInfo();
      break;

    case MT_UTIL_SET_PANID:
      MT_UtilSetPanID(pBuf);
      break;

    case MT_UTIL_SET_CHANNELS:
      MT_UtilSetChannels(pBuf);
      break;

    case MT_UTIL_SET_SECLEVEL:
      MT_UtilSetSecLevel(pBuf);
      break;

    case MT_UTIL_SET_PRECFGKEY:
      MT_UtilSetPreCfgKey(pBuf);
      break;
#endif
    case MT_UTIL_CALLBACK_SUB_CMD:
      MT_UtilCallbackSub(pBuf);
      break;

    case MT_UTIL_KEY_EVENT:
#if (defined HAL_KEY) && (HAL_KEY == TRUE)
      MT_UtilKeyEvent(pBuf);
#endif
      break;

    case MT_UTIL_TIME_ALIVE:
      MT_UtilTimeAlive();
      break;

    case MT_UTIL_LED_CONTROL:
#if (defined HAL_LED) && (HAL_LED == TRUE)
      MT_UtilLedControl(pBuf);
#endif
      break;

    case MT_UTIL_SRC_MATCH_ENABLE:
      MT_UtilSrcMatchEnable(pBuf);
      break;

    case MT_UTIL_SRC_MATCH_ADD_ENTRY:
      MT_UtilSrcMatchAddEntry(pBuf);
      break;

    case MT_UTIL_SRC_MATCH_DEL_ENTRY:
      MT_UtilSrcMatchDeleteEntry(pBuf);
      break;

    case MT_UTIL_SRC_MATCH_CHECK_SRC_ADDR:
      MT_UtilSrcMatchCheckSrcAddr(pBuf);
      break;

    case MT_UTIL_SRC_MATCH_ACK_ALL_PENDING:
      MT_UtilSrcMatchAckAllPending(pBuf);
      break;

    case MT_UTIL_SRC_MATCH_CHECK_ALL_PENDING:
      MT_UtilSrcMatchCheckAllPending(pBuf);
      break;

    case MT_UTIL_TEST_LOOPBACK:
      MT_BuildAndSendZToolResponse((MT_RPC_CMD_SRSP|(uint8)MT_RPC_SYS_UTIL), MT_UTIL_TEST_LOOPBACK,
                                    pBuf[MT_RPC_POS_LEN], (pBuf+MT_RPC_FRAME_HDR_SZ));
      break;

#if !defined NONWK
    case MT_UTIL_DATA_REQ:
      MT_UtilDataReq(pBuf);
      break;

    case MT_UTIL_ADDRMGR_EXT_ADDR_LOOKUP:
      MT_UtilAddrMgrEntryLookupExt(pBuf);
      break;

    case MT_UTIL_ADDRMGR_NWK_ADDR_LOOKUP:
      MT_UtilAddrMgrEntryLookupNwk(pBuf);
      break;

#if defined MT_SYS_KEY_MANAGEMENT
    case MT_UTIL_APSME_LINK_KEY_DATA_GET:
      MT_UtilAPSME_LinkKeyDataGet(pBuf);
      break;

    case MT_UTIL_APSME_LINK_KEY_NV_ID_GET:
      MT_UtilAPSME_LinkKeyNvIdGet(pBuf);
      break;
#endif // MT_SYS_KEY_MANAGEMENT

    case MT_UTIL_APSME_REQUEST_KEY_CMD:
      MT_UtilAPSME_RequestKeyCmd(pBuf);
      break;

    case MT_UTIL_ASSOC_COUNT:
      MT_UtilAssocCount(pBuf);
      break;

    case MT_UTIL_ASSOC_FIND_DEVICE:
      MT_UtilAssocFindDevice(pBuf);
      break;

    case MT_UTIL_ASSOC_GET_WITH_ADDRESS:
      MT_UtilAssocGetWithAddress(pBuf);
      break;

#if defined ZCL_KEY_ESTABLISH
    case MT_UTIL_ZCL_KEY_EST_INIT_EST:
      MT_UtilzclGeneral_KeyEstablish_InitiateKeyEstablishment(pBuf);
      break;

    case MT_UTIL_ZCL_KEY_EST_SIGN:
      MT_UtilzclGeneral_KeyEstablishment_ECDSASign(pBuf);
      break;
#endif

    case MT_UTIL_SYNC_REQ:
      MT_UtilSync();
      break;
#endif /* !defined NONWK */

    default:
      status = MT_RPC_ERR_COMMAND_ID;
      break;
  }

  return status;
}

void MT_UtilGetDeviceInfo(void)
{
  uint8  *buf;
  uint8  *pBuf;
  uint8  bufLen = MT_UTIL_DEVICE_INFO_RESPONSE_LEN;
  uint16 *assocList = NULL;

#if !defined NONWK
  uint8  assocCnt = 0;

  if (ZG_DEVICE_RTR_TYPE)
  {
    assocList = AssocMakeList( &assocCnt );
    bufLen += (assocCnt * sizeof(uint16));
  }
#endif

  buf = osal_mem_alloc( bufLen );
  if ( buf )
  {
    pBuf = buf;

    *pBuf++ = ZSUCCESS; // Status

    osal_nv_read( ZCD_NV_EXTADDR, 0, Z_EXTADDR_LEN, pBuf );
    pBuf += Z_EXTADDR_LEN;

#if defined NONWK
    // Skip past ZStack only parameters for NONWK
    *pBuf++ = 0;
    *pBuf++ = 0;
    *pBuf++ = 0;
    *pBuf++ = 0;
    *pBuf = 0;
#else
    {
      uint16 shortAddr = NLME_GetShortAddr();
      *pBuf++ = LO_UINT16( shortAddr );
      *pBuf++ = HI_UINT16( shortAddr );
    }

    /* Return device type */
    *pBuf++ = ZSTACK_DEVICE_BUILD;

    /*Return device state */
    *pBuf++ = (uint8)devState;

    if (ZG_DEVICE_RTR_TYPE)
    {
      *pBuf++ = assocCnt;

      if ( assocCnt )
      {
        uint8 x;
        uint16 *puint16 = assocList;

        for ( x = 0; x < assocCnt; x++, puint16++ )
        {
          *pBuf++ = LO_UINT16( *puint16 );
          *pBuf++ = HI_UINT16( *puint16 );
        }
      }
    }
    else
    {
      *pBuf++ = 0;
    }
#endif

    MT_BuildAndSendZToolResponse( ((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_UTIL),
                                 MT_UTIL_GET_DEVICE_INFO,
                                 bufLen, buf );

    osal_mem_free( buf );
  }

  if ( assocList )
  {
    osal_mem_free( assocList );
  }
}

void MT_UtilGetNvInfo(void)
{
  uint8 len;
  uint8 stat;
  uint8 *buf;
  uint8 *pBuf;
  uint16 tmp16;
  uint32 tmp32;

  /*
    Get required length of buffer
    Status + ExtAddr + ChanList + PanID  + SecLevel + PreCfgKey
  */
  len = 1 + Z_EXTADDR_LEN + 4 + 2 + 1 + SEC_KEY_LEN;

  buf = osal_mem_alloc( len );
  if ( buf )
  {
    /* Assume NV not available */
    osal_memset( buf, 0xFF, len );

    /* Skip over status */
    pBuf = buf + 1;

    /* Start with 64-bit extended address */
    stat = osal_nv_read( ZCD_NV_EXTADDR, 0, Z_EXTADDR_LEN, pBuf );
    if ( stat ) stat = 0x01;
    pBuf += Z_EXTADDR_LEN;

    /* Scan channel list (bit mask) */
    if (  osal_nv_read( ZCD_NV_CHANLIST, 0, sizeof( tmp32 ), &tmp32 ) )
      stat |= 0x02;
    else
    {
      pBuf[0] = BREAK_UINT32( tmp32, 3 );
      pBuf[1] = BREAK_UINT32( tmp32, 2 );
      pBuf[2] = BREAK_UINT32( tmp32, 1 );
      pBuf[3] = BREAK_UINT32( tmp32, 0 );
    }
    pBuf += sizeof( tmp32 );

    /* ZigBee PanID */
    if ( osal_nv_read( ZCD_NV_PANID, 0, sizeof( tmp16 ), &tmp16 ) )
      stat |= 0x04;
    else
    {
      pBuf[0] = LO_UINT16( tmp16 );
      pBuf[1] = HI_UINT16( tmp16 );
    }
    pBuf += sizeof( tmp16 );

    /* Security level */
    if ( osal_nv_read( ZCD_NV_SECURITY_LEVEL, 0, sizeof( uint8 ), pBuf++ ) )
      stat |= 0x08;

    /* Pre-configured security key */
    if ( osal_nv_read( ZCD_NV_PRECFGKEY, 0, SEC_KEY_LEN, pBuf ) )
      stat |= 0x10;

    /* Status bit mask - bit=1 indicates failure */
    *buf = stat;

    MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_UTIL), MT_UTIL_GET_NV_INFO,
                                  len, buf );

    osal_mem_free( buf );
  }
}

void MT_UtilSetPanID(uint8 *pBuf)
{
  uint16 temp16;
  uint8 retValue = ZFailure;
  uint8 cmdId;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  temp16 = BUILD_UINT16(pBuf[0], pBuf[1]);
  pBuf += sizeof(uint16);

  retValue = osal_nv_write(ZCD_NV_PANID, 0, osal_nv_item_len( ZCD_NV_PANID ), &temp16);

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_UTIL), cmdId, 1, &retValue);
}

void MT_UtilSetChannels(uint8 *pBuf)
{
  uint32 tmp32;
  uint8 retValue = ZFailure;
  uint8 cmdId;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  tmp32 = BUILD_UINT32(pBuf[0], pBuf[1], pBuf[2], pBuf[3]);

  retValue = osal_nv_write(ZCD_NV_CHANLIST, 0, osal_nv_item_len( ZCD_NV_CHANLIST ), &tmp32);

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_UTIL), cmdId, 1, &retValue);
}

void MT_UtilSetSecLevel(uint8 *pBuf)
{
  uint8 retValue = ZFailure;
  uint8 cmdId;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  retValue = osal_nv_write( ZCD_NV_SECURITY_LEVEL, 0, osal_nv_item_len( ZCD_NV_SECURITY_LEVEL ), pBuf);

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_UTIL), cmdId, 1, &retValue );

}

void MT_UtilSetPreCfgKey(uint8 *pBuf)
{
  uint8 retValue = ZFailure;
  uint8 cmdId;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  retValue = osal_nv_write( ZCD_NV_PRECFGKEY, 0, osal_nv_item_len( ZCD_NV_PRECFGKEY ), pBuf);

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_UTIL), cmdId, 1, &retValue );

}

void MT_UtilCallbackSub(uint8 *pBuf)
{
  uint8 cmdId = pBuf[MT_RPC_POS_CMD1];
  uint8 retValue = ZFailure;

#if defined(MT_MAC_CB_FUNC) || defined(MT_NWK_CB_FUNC) || defined(MT_ZDO_CB_FUNC) || defined(MT_AF_CB_FUNC) || defined(MT_SAPI_CB_FUNC)
  uint8 subSystem;
  uint16 subscribed_command;

  // Move past header
  retValue = ZSuccess;
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Command */
  subscribed_command = BUILD_UINT16(pBuf[0], pBuf[1]);
  pBuf += 2;

  /* Subsystem - 5 bits on the MSB of the command */
  subSystem = HI_UINT16(subscribed_command) & 0x1F ;

  /* What is the action - SUBSCRIBE or !SUBSCRIBE */
  if (*pBuf)
  {
    /* Turn ON */
  #if defined( MT_MAC_CB_FUNC )
    if ((subSystem == MT_RPC_SYS_MAC) || (subscribed_command == 0xFFFF))
      _macCallbackSub = 0xFFFF;
  #endif

  #if defined( MT_NWK_CB_FUNC )
    if ((subSystem == MT_RPC_SYS_NWK) || (subscribed_command == 0xFFFF))
      _nwkCallbackSub = 0xFFFF;
  #endif

  #if defined( MT_ZDO_CB_FUNC )
    if ((subSystem == MT_RPC_SYS_ZDO) || (subscribed_command == 0xFFFF))
      _zdoCallbackSub = 0xFFFFFFFF;
  #endif

  #if defined( MT_AF_CB_FUNC )
    if ((subSystem == MT_RPC_SYS_AF) || (subscribed_command == 0xFFFF))
      _afCallbackSub = 0xFFFF;
  #endif

  #if defined( MT_SAPI_CB_FUNC )
    if ((subSystem == MT_RPC_SYS_SAPI) || (subscribed_command == 0xFFFF))
      _sapiCallbackSub = 0xFFFF;
  #endif
  }
  else
  {
    /* Turn OFF */
  #if defined( MT_MAC_CB_FUNC )
    if ((subSystem == MT_RPC_SYS_MAC) || (subscribed_command == 0xFFFF))
      _macCallbackSub = 0x0000;
  #endif

  #if defined( MT_NWK_CB_FUNC )
    if ((subSystem == MT_RPC_SYS_NWK) || (subscribed_command == 0xFFFF))
      _nwkCallbackSub = 0x0000;
  #endif

  #if defined( MT_ZDO_CB_FUNC )
    if ((subSystem == MT_RPC_SYS_ZDO) || (subscribed_command == 0xFFFF))
      _zdoCallbackSub = 0x00000000;
  #endif

  #if defined( MT_AF_CB_FUNC )
    if ((subSystem == MT_RPC_SYS_AF) || (subscribed_command == 0xFFFF))
      _afCallbackSub = 0x0000;
  #endif

  #if defined( MT_SAPI_CB_FUNC )
    if ((subSystem == MT_RPC_SYS_SAPI) || (subscribed_command == 0xFFFF))
        _sapiCallbackSub = 0x0000;
  #endif
  }
#endif  // MT_MAC_CB_FUNC || MT_NWK_CB_FUNC || MT_ZDO_CB_FUNC || MT_AF_CB_FUNC || MT_SAPI_CB_FUNC || MT_SAPI_CB_FUNC

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_UTIL), cmdId, 1, &retValue );
}

#if (defined HAL_KEY) && (HAL_KEY == TRUE)

void MT_UtilKeyEvent(uint8 *pBuf)
{
  uint8 x = 0;
  uint8 retValue = ZFailure;
  uint8 cmdId;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Translate between SPI values to device values */
  if ( *pBuf & 0x01 )
    x |= HAL_KEY_SW_1;
  if ( *pBuf & 0x02 )
    x |= HAL_KEY_SW_2;
  if ( *pBuf & 0x04 )
    x |= HAL_KEY_SW_3;
  if ( *pBuf & 0x08 )
  x |= HAL_KEY_SW_4;
#if defined ( HAL_KEY_SW_5 )
  if ( *pBuf & 0x10 )
    x |= HAL_KEY_SW_5;
#endif
#if defined ( HAL_KEY_SW_6 )
  if ( *pBuf & 0x20 )
    x |= HAL_KEY_SW_6;
#endif
#if defined ( HAL_KEY_SW_7 )
  if ( *pBuf & 0x40 )
    x |= HAL_KEY_SW_7;
#endif
#if defined ( HAL_KEY_SW_8 )
  if ( *pBuf & 0x80 )
    x |= HAL_KEY_SW_8;
#endif
  pBuf++;

  retValue = OnBoard_SendKeys(x, *pBuf);

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_UTIL), cmdId, 1, &retValue );
}
#endif

void MT_UtilTimeAlive(void)
{
  uint8 timeAlive[4];
  uint32 tmp32;

  /* Time since last reset (seconds) */
  tmp32 = osal_GetSystemClock() / 1000;

  /* Convert to high byte first into temp buffer */
  timeAlive[0] = BREAK_UINT32(tmp32, 0);
  timeAlive[1] = BREAK_UINT32(tmp32, 1);
  timeAlive[2] = BREAK_UINT32(tmp32, 2);
  timeAlive[3] = BREAK_UINT32(tmp32, 3);

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_UTIL),
                                       MT_UTIL_TIME_ALIVE, sizeof(timeAlive), timeAlive);
}

#if (defined HAL_LED) && (HAL_LED == TRUE)

{
  uint8 iLed, Led, iMode, Mode, cmdId;
  uint8 retValue = ZFailure;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* LED and Mode */
  iLed = *pBuf++;
  iMode = *pBuf;

  if ( iLed == 1 )
    Led = HAL_LED_1;
  else if ( iLed == 2 )
    Led = HAL_LED_2;
  else if ( iLed == 3 )
    Led = HAL_LED_3;
  else if ( iLed == 4 )
    Led = HAL_LED_4;
  else if ( iLed == 0xFF )
    Led = HAL_LED_ALL;
  else
    Led = 0;

  if ( iMode == 0 )
    Mode = HAL_LED_MODE_OFF;
  else if ( iMode == 1 )
    Mode = HAL_LED_MODE_ON;
  else if ( iMode == 2 )
    Mode = HAL_LED_MODE_BLINK;
  else if ( iMode == 3 )
    Mode = HAL_LED_MODE_FLASH;
  else if ( iMode == 4 )
    Mode = HAL_LED_MODE_TOGGLE;
  else
    Led = 0;

  if ( Led != 0 )
  {
    HalLedSet (Led, Mode);
    retValue = ZSuccess;
  }

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_UTIL), cmdId, 1, &retValue );
}
#endif /* HAL_LED */


void MT_UtilSrcMatchEnable (uint8 *pBuf)
{
  uint8 retValue, cmdId;

  /* Parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

#ifdef AUTO_PEND
  /* Call the routine */
  retValue = ZMacSrcMatchEnable (pBuf[0], pBuf[1]);
#else
  retValue = ZMacUnsupported;
#endif

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_UTIL), cmdId, 1, &retValue );

}

void MT_UtilSrcMatchAddEntry (uint8 *pBuf)
{
  uint8 retValue, cmdId;

  /* Parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

#ifdef AUTO_PEND
  uint16 panID;
  zAddrType_t devAddr;

  /* Address mode */
  devAddr.addrMode = *pBuf++;

  /* Address based on the address mode */
  MT_UtilSpi2Addr( &devAddr, pBuf);
  pBuf += Z_EXTADDR_LEN;

  /* PanID */
  panID = BUILD_UINT16( pBuf[0] , pBuf[1] );

  /* Call the routine */
  retValue =  ZMacSrcMatchAddEntry (&devAddr, panID);
#else
  retValue = ZMacUnsupported;
#endif

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_UTIL), cmdId, 1, &retValue );
}

void MT_UtilSrcMatchDeleteEntry (uint8 *pBuf)
{
  uint8 retValue, cmdId;

  /* Parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

#ifdef AUTO_PEND
  uint16 panID;
  zAddrType_t devAddr;

  /* Address mode */
  devAddr.addrMode = *pBuf++;

  /* Address based on the address mode */
  MT_UtilSpi2Addr( &devAddr, pBuf);
  pBuf += Z_EXTADDR_LEN;

  /* PanID */
  panID = BUILD_UINT16( pBuf[0] , pBuf[1] );

  /* Call the routine */
  retValue =  ZMacSrcMatchDeleteEntry (&devAddr, panID);
#else
  retValue = ZMacUnsupported;
#endif

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_UTIL), cmdId, 1, &retValue );
}

void MT_UtilSrcMatchCheckSrcAddr (uint8 *pBuf)
{
  uint8 cmdId;
  uint8 retArray[2];

  /* Parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

#if 0  /* Unsupported  */
  uint16 panID;
  zAddrType_t devAddr;

  /* Address mode */
  devAddr.addrMode = *pBuf++;

  /* Address based on the address mode */
  MT_UtilSpi2Addr( &devAddr, pBuf);
  pBuf += Z_EXTADDR_LEN;

  /* PanID */
  panID = BUILD_UINT16( pBuf[0] , pBuf[1] );

  /* Call the routine */
  retArray[1] =  ZMacSrcMatchCheckSrcAddr (&devAddr, panID);

    /* Return failure if the index is invalid */
  if (retArray[1] == ZMacSrcMatchInvalidIndex )
  {
    retArray[0] = ZFailure;
  }
  else
  {
    retArray[0] = ZSuccess;
  }
#else
  retArray[0] = ZMacUnsupported;
  retArray[1] = ZMacSrcMatchInvalidIndex;
#endif

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_UTIL), cmdId, 2, retArray );
}

void MT_UtilSrcMatchAckAllPending (uint8 *pBuf)
{
  uint8 retValue, cmdId;

  /* Parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

#ifdef AUTO_PEND
  /* Call the routine */
  retValue = ZMacSrcMatchAckAllPending(*pBuf);
#else
  retValue = ZMacUnsupported;
#endif

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_UTIL), cmdId, 1, &retValue );
}

void MT_UtilSrcMatchCheckAllPending (uint8 *pBuf)
{
  uint8 retArray[2], cmdId;

  /* Parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

#ifdef AUTO_PEND
  /* Call the routine */
  retArray[0] = ZMacSuccess;
  retArray[1] = ZMacSrcMatchCheckAllPending();
#else
  retArray[0] = ZMacUnsupported;
  retArray[1] = FALSE;
#endif

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_UTIL), cmdId, 2, retArray );
}


#ifdef AUTO_PEND
static void MT_UtilRevExtCpy( uint8 *pDst, uint8 *pSrc )
{
  int8 i;

  for ( i = Z_EXTADDR_LEN - 1; i >= 0; i-- )
  {
    *pDst++ = pSrc[i];
  }
}

static void MT_UtilSpi2Addr( zAddrType_t *pDst, uint8 *pSrc )
{
  if ( pDst->addrMode == Addr16Bit )
  {
    pDst->addr.shortAddr = BUILD_UINT16( pSrc[0] , pSrc[1] );
  }
  else if ( pDst->addrMode == Addr64Bit )
  {
    MT_UtilRevExtCpy( pDst->addr.extAddr, pSrc );
  }
}
#endif // AUTO_PEND

#if !defined NONWK

{
  uint8 rtrn = NwkPollReq(pBuf[MT_RPC_POS_DAT0]);
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_UTIL), MT_UTIL_DATA_REQ,
                                                                               1, &rtrn);
}

static void MT_UtilAddrMgrEntryLookupExt(uint8 *pBuf)
{
  uint8 nwkAddr[2];
  AddrMgrEntry_t entry;
  uint8 cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  osal_memcpy(entry.extAddr, pBuf, Z_EXTADDR_LEN);
  (void)AddrMgrEntryLookupExt(&entry);
  
  nwkAddr[0] = LO_UINT16(entry.nwkAddr);
  nwkAddr[1] = HI_UINT16(entry.nwkAddr);
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_UTIL),
                                       cmdId, sizeof(uint16), nwkAddr);
}


static void MT_UtilAddrMgrEntryLookupNwk(uint8 *pBuf)
{
  AddrMgrEntry_t entry;
  uint8 cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  entry.nwkAddr = BUILD_UINT16(pBuf[0], pBuf[1]);
  (void)AddrMgrEntryLookupNwk(&entry);

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_UTIL),
                                       cmdId, Z_EXTADDR_LEN, entry.extAddr);
}

#if defined MT_SYS_KEY_MANAGEMENT

static void MT_UtilAPSME_LinkKeyDataGet(uint8 *pBuf)
{
  uint8 rsp[MT_APSME_LINKKEY_GET_RSP_LEN];
  APSME_LinkKeyData_t *pData = NULL;
  uint8 cmdId = pBuf[MT_RPC_POS_CMD1];
  uint16 apsLinkKeyNvId;
  uint32 *apsRxFrmCntr;
  uint32 *apsTxFrmCntr;

  pBuf += MT_RPC_FRAME_HDR_SZ;

  *rsp = APSME_LinkKeyNVIdGet(pBuf, &apsLinkKeyNvId);

  if (SUCCESS == *rsp)
  {
    pData = (APSME_LinkKeyData_t *)osal_mem_alloc(sizeof(APSME_LinkKeyData_t));

    if (pData != NULL)
    {
      // retrieve key from NV
      if ( osal_nv_read( apsLinkKeyNvId, 0,
                        sizeof(APSME_LinkKeyData_t), pData) == SUCCESS)

      {
        apsRxFrmCntr = &ApsLinkKeyFrmCntr[apsLinkKeyNvId - ZCD_NV_APS_LINK_KEY_DATA_START].rxFrmCntr;
        apsTxFrmCntr = &ApsLinkKeyFrmCntr[apsLinkKeyNvId - ZCD_NV_APS_LINK_KEY_DATA_START].txFrmCntr;

        uint8 *ptr = rsp+1;
        (void)osal_memcpy(ptr, pData->key, SEC_KEY_LEN);
        ptr += SEC_KEY_LEN;
        *ptr++ = BREAK_UINT32(*apsTxFrmCntr, 0);
        *ptr++ = BREAK_UINT32(*apsTxFrmCntr, 1);
        *ptr++ = BREAK_UINT32(*apsTxFrmCntr, 2);
        *ptr++ = BREAK_UINT32(*apsTxFrmCntr, 3);
        *ptr++ = BREAK_UINT32(*apsRxFrmCntr, 0);
        *ptr++ = BREAK_UINT32(*apsRxFrmCntr, 1);
        *ptr++ = BREAK_UINT32(*apsRxFrmCntr, 2);
        *ptr++ = BREAK_UINT32(*apsRxFrmCntr, 3);
      }

      // clear copy of key in RAM
      osal_memset( pData, 0x00, sizeof(APSME_LinkKeyData_t) );

      osal_mem_free(pData);
    }
  }
  else
  {
    // set data key and counters 0xFF
    osal_memset(&rsp[1], 0xFF, SEC_KEY_LEN + (MT_UTIL_FRM_CTR_LEN * 2));
  }

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_UTIL), cmdId,
                                       MT_APSME_LINKKEY_GET_RSP_LEN, rsp);

  // clear key data
  osal_memset(rsp, 0x00, MT_APSME_LINKKEY_GET_RSP_LEN);

}

static void MT_UtilAPSME_LinkKeyNvIdGet(uint8 *pBuf)
{
  uint8 rsp[MT_APSME_LINKKEY_NV_ID_GET_RSP_LEN];
  uint8 cmdId = pBuf[MT_RPC_POS_CMD1];
  uint16 apsLinkKeyNvId;

  pBuf += MT_RPC_FRAME_HDR_SZ;

  *rsp = APSME_LinkKeyNVIdGet(pBuf, &apsLinkKeyNvId);

  if (SUCCESS == *rsp)
  {
    rsp[1] = LO_UINT16(apsLinkKeyNvId);
    rsp[2] = HI_UINT16(apsLinkKeyNvId);
  }
  else
  {
    // send failure response with invalid NV ID
    osal_memset(&rsp[1], 0xFF, 2);
  }

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_UTIL), cmdId,
                                       MT_APSME_LINKKEY_NV_ID_GET_RSP_LEN, rsp);
}
#endif // MT_SYS_KEY_MANAGEMENT

void MT_UtilAPSME_RequestKeyCmd(uint8 *pBuf)
{
  uint8 cmdId;
  uint8 partnerAddr[Z_EXTADDR_LEN];
  uint8 retValue;

  // parse header
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* PartnerAddress */
  osal_memcpy(partnerAddr, pBuf, Z_EXTADDR_LEN);

  retValue = (uint8)ZDSecMgrRequestAppKey(partnerAddr);

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_UTIL), cmdId, 1, &retValue);
}


static void MT_UtilAssocCount(uint8 *pBuf)
{
  uint16 cnt;
  uint8 cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  cnt = AssocCount(pBuf[0], pBuf[1]);
  pBuf[0] = LO_UINT16(cnt);
  pBuf[1] = HI_UINT16(cnt);

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_UTIL), cmdId, 2, pBuf);
}

static void MT_UtilAssocFindDevice(uint8 *pBuf)
{
  uint8 cmdId = pBuf[MT_RPC_POS_CMD1];
  uint8 buf[sizeof(associated_devices_t)];

  packDev_t(buf, AssocFindDevice(pBuf[MT_RPC_FRAME_HDR_SZ]));
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_UTIL), cmdId,
                                       sizeof(associated_devices_t), buf);
}

static void MT_UtilAssocGetWithAddress(uint8 *pBuf)
{
  extern associated_devices_t *AssocGetWithAddress(uint8 *extAddr, uint16 shortAddr);
  uint8 cmdId = pBuf[MT_RPC_POS_CMD1];
  uint8 buf[sizeof(associated_devices_t)];

  pBuf += MT_RPC_FRAME_HDR_SZ;
  packDev_t(buf, AssocGetWithAddress(((AddrMgrExtAddrValid(pBuf)) ? pBuf : NULL),
                                  BUILD_UINT16(pBuf[Z_EXTADDR_LEN], pBuf[Z_EXTADDR_LEN+1])));

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_UTIL), cmdId,
                                       sizeof(associated_devices_t), buf);
}

static void packDev_t(uint8 *pBuf, associated_devices_t *pDev)
{
  if (NULL == pDev)
  {
    uint16 rtrn = INVALID_NODE_ADDR;
    *pBuf++ = LO_UINT16(rtrn);
    *pBuf++ = HI_UINT16(rtrn);
  }
  else
  {
    *pBuf++ = LO_UINT16(pDev->shortAddr);
    *pBuf++ = HI_UINT16(pDev->shortAddr);
    *pBuf++ = LO_UINT16(pDev->addrIdx);
    *pBuf++ = HI_UINT16(pDev->addrIdx);
    *pBuf++ = pDev->nodeRelation;
    *pBuf++ = pDev->devStatus;
    *pBuf++ = pDev->assocCnt;
    *pBuf++ = pDev->age;
    *pBuf++ = pDev->linkInfo.txCounter;
    *pBuf++ = pDev->linkInfo.txCost;
    *pBuf++ = pDev->linkInfo.rxLqi;
    *pBuf++ = pDev->linkInfo.inKeySeqNum;
    *pBuf++ = BREAK_UINT32(pDev->linkInfo.inFrmCntr, 0);
    *pBuf++ = BREAK_UINT32(pDev->linkInfo.inFrmCntr, 1);
    *pBuf++ = BREAK_UINT32(pDev->linkInfo.inFrmCntr, 2);
    *pBuf++ = BREAK_UINT32(pDev->linkInfo.inFrmCntr, 3);
    *pBuf++ = LO_UINT16(pDev->linkInfo.txFailure);
    *pBuf++ = HI_UINT16(pDev->linkInfo.txFailure);
  }
}

#if defined ZCL_KEY_ESTABLISH

static void MT_UtilzclGeneral_KeyEstablish_InitiateKeyEstablishment(uint8 *pBuf)
{
  afAddrType_t partnerAddr;
  uint8 cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  partnerAddr.panId = 0;  // Not an inter-pan message.
  partnerAddr.endPoint = pBuf[2];
  partnerAddr.addrMode = (afAddrMode_t)pBuf[3];
  if (afAddr64Bit == partnerAddr.addrMode)
  {
    (void)osal_memcpy(partnerAddr.addr.extAddr, pBuf+4, Z_EXTADDR_LEN);
  }
  else
  {
    partnerAddr.addr.shortAddr = BUILD_UINT16(pBuf[4], pBuf[5]);
  }

  zcl_key_establish_task_id = pBuf[0];
  *pBuf = zclGeneral_KeyEstablish_InitiateKeyEstablishment(MT_TaskID, &partnerAddr, pBuf[1]);
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_UTIL), cmdId, 1, pBuf);
}

static void MT_UtilzclGeneral_KeyEstablishment_ECDSASign(uint8 *pBuf)
{
#if defined TC_LINKKEY_JOIN
  uint8 *output = osal_mem_alloc(SE_PROFILE_SIGNATURE_LENGTH+1);
  uint8 cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  if (NULL == output)
  {
    *pBuf = FAILURE;
    MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_UTIL), cmdId, 1, pBuf);
  }
  else
  {
    *output = zclGeneral_KeyEstablishment_ECDSASign(pBuf+1, *pBuf, output+1);
    MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_UTIL), cmdId,
                                         SE_PROFILE_SIGNATURE_LENGTH+1, output);
    osal_mem_free(output);
  }
#endif
}


void MT_UtilKeyEstablishInd(keyEstablishmentInd_t *pInd)
{
  uint8 msg[6];

  msg[0] = zcl_key_establish_task_id;
  msg[1] = pInd->hdr.event;
  msg[2] = pInd->hdr.status;
  msg[3] = pInd->waitTime;
  msg[4] = LO_UINT16(pInd->keyEstablishmentSuite);
  msg[5] = HI_UINT16(pInd->keyEstablishmentSuite);

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_UTIL),
                                       MT_UTIL_ZCL_KEY_ESTABLISH_IND, 6, msg);
}
#endif

static void MT_UtilSync(void)
{
 MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ|(uint8)MT_RPC_SYS_UTIL),MT_UTIL_SYNC_REQ,0,0);
}
#endif /* !defined NONWK */
#endif /* MT_UTIL_FUNC */

MT__UTIL.h

#ifndef MT_UTIL_H
#define MT_UTIL_H

#if defined ZCL_KEY_ESTABLISH
#include "zcl_key_establish.h"
#endif

#ifdef __cplusplus
extern "C"
{
#endif


#if defined (MT_UTIL_FUNC)

extern uint8 MT_UtilCommandProcessing(uint8 *pBuf);

#if defined ZCL_KEY_ESTABLISH

void MT_UtilKeyEstablishInd(keyEstablishmentInd_t *pInd);
#endif
#endif /* MT_UTIL_FUNC */

#ifdef __cplusplus
}
#endif

#endif /* MTEL_H */

MT__VERSION.c

#include "ZComDef.h"
#include "MT_VERSION.h"

const uint8 MTVersionString[5] = {
                                   2,  /* Transport protocol revision */
                                   0,  /* Product ID */
                                   2,  /* Software major release number */
                                   5,  /* Software minor release number */
                                   1   /* Software maintenance release number */
                                 };

MT__VERSION.h

#ifndef MT_VERSION_H
#define MT_VERSION_H

#ifdef __cplusplus
extern "C"
{
#endif

extern const uint8 MTVersionString[5];

#ifdef __cplusplus
}
#endif

#endif /* MT_VERSION_H */

MT__ZDO.c

#ifdef MT_ZDO_FUNC


#include "ZComDef.h"
#include "OSAL.h"
#include "OSAL_Nv.h"
#include "MT.h"
#include "MT_ZDO.h"
#include "APSMEDE.h"
#include "ZDConfig.h"
#include "ZDProfile.h"
#include "ZDObject.h"
#include "ZDApp.h"

#if !defined( WIN32 )
  #include "OnBoard.h"
#endif

#if defined ( MT_SYS_KEY_MANAGEMENT )
  #include "ZDSecMgr.h"
#endif

#include "nwk_util.h"

#define MT_ZDO_END_DEVICE_ANNCE_IND_LEN   0x0D
#define MT_ZDO_ADDR_RSP_LEN               0x0D
#define MT_ZDO_BIND_UNBIND_RSP_LEN        0x03
#define MT_ZDO_BEACON_IND_LEN             21
#define MT_ZDO_BEACON_IND_PACK_LEN        (MT_UART_TX_BUFF_MAX - SPI_0DATA_MSG_LEN)
#define MT_ZDO_JOIN_CNF_LEN               5

// Message must pack nwk addr, entire (not just pointer to) ieee addr, and packet cost, so the
// sizeof(zdoConcentratorInd_t) is not usable.
#define MT_ZDO_CONCENTRATOR_IND_LEN      (2 + Z_EXTADDR_LEN + 1)

#define MTZDO_RESPONSE_BUFFER_LEN   100

#define MTZDO_MAX_MATCH_CLUSTERS    16
#define MTZDO_MAX_ED_BIND_CLUSTERS  15

// Conversion from ZDO Cluster Id to the RPC AREQ Id is direct as follows:
#define MT_ZDO_CID_TO_AREQ_ID(CId)  ((uint8)(CId) | 0x80)

#define MT_ZDO_STATUS_LEN   1

uint32 _zdoCallbackSub;
uint8 *pBeaconIndBuf = NULL;

/**************************************************************************************************
 * LOCAL VARIABLES
 **************************************************************************************************/

/**************************************************************************************************
 * LOCAL FUNCTIONS
 **************************************************************************************************/
#if defined (MT_ZDO_FUNC)
void MT_ZdoNWKAddressRequest(uint8 *pBuf);
void MT_ZdoIEEEAddrRequest(uint8 *pBuf);
void MT_ZdoNodeDescRequest(uint8 *pBuf);
void MT_ZdoPowerDescRequest(uint8 *pBuf);
void MT_ZdoSimpleDescRequest(uint8 *pBuf);
void MT_ZdoActiveEpRequest(uint8 *pBuf);
void MT_ZdoMatchDescRequest(uint8 *pBuf);
void MT_ZdoComplexDescRequest(uint8 *pBuf);
void MT_ZdoUserDescRequest(uint8 *pBuf);
void MT_ZdoEndDevAnnce(uint8 *pBuf);
void MT_ZdoUserDescSet(uint8 *pBuf);
void MT_ZdoServiceDiscRequest(uint8 *pBuf);
void MT_ZdoEndDevBindRequest(uint8 *pBuf);
void MT_ZdoBindRequest(uint8 *pBuf);
void MT_ZdoUnbindRequest(uint8 *pBuf);
void MT_ZdoMgmtNwkDiscRequest(uint8 *pBuf);
#if defined ( MT_SYS_KEY_MANAGEMENT )
void MT_ZdoSetLinkKey(uint8 *pBuf);
void MT_ZdoRemoveLinkKey(uint8 *pBuf);
void MT_ZdoGetLinkKey(uint8 *pBuf);
#endif /* MT_SYS_KEY_MANAGEMENT */
void MT_ZdoNetworkDiscoveryReq(uint8 *pBuf);
void MT_ZdoJoinReq(uint8 *pBuf);
/* Call back function */
void *MT_ZdoNwkDiscoveryCnfCB ( void *pStr );
void *MT_ZdoBeaconIndCB ( void *pStr );
void *MT_ZdoJoinCnfCB ( void *pStr );
#if defined (MT_ZDO_MGMT)
void MT_ZdoMgmtLqiRequest(uint8 *pBuf);
void MT_ZdoMgmtRtgRequest(uint8 *pBuf);
void MT_ZdoMgmtBindRequest(uint8 *pBuf);
void MT_ZdoMgmtLeaveRequest(uint8 *pBuf);
void MT_ZdoMgmtDirectJoinRequest(uint8 *pBuf);
void MT_ZdoMgmtPermitJoinRequest(uint8 *pBuf);
void MT_ZdoMgmtNwkUpdateRequest(uint8 *pBuf);
#endif /* MT_ZDO_MGMT */
void MT_ZdoStartupFromApp(uint8 *pBuf);
void MT_ZdoRegisterForZDOMsg(uint8 *pBuf);
void MT_ZdoRemoveRegisteredCB(uint8 *pBuf);
#endif /* MT_ZDO_FUNC */

#if defined (MT_ZDO_CB_FUNC)
uint8 MT_ZdoHandleExceptions( afIncomingMSGPacket_t *pData, zdoIncomingMsg_t *inMsg );
void MT_ZdoAddrRspCB( ZDO_NwkIEEEAddrResp_t *pMsg, uint16 clusterID );
void MT_ZdoEndDevAnnceCB( ZDO_DeviceAnnce_t *pMsg, uint16 srcAddr );
void MT_ZdoBindUnbindRspCB( uint16 clusterID, uint16 srcAddr, uint8 status );
void* MT_ZdoSrcRtgCB( void *pStr );
static void *MT_ZdoConcentratorIndCB(void *pStr);
static void *MT_ZdoLeaveInd(void *vPtr);
#endif /* MT_ZDO_CB_FUNC */

#if defined (MT_ZDO_FUNC)

void MT_ZdoInit(void)
{
#ifdef MT_ZDO_CB_FUNC
  /* Register with ZDO for indication callbacks */
  ZDO_RegisterForZdoCB(ZDO_SRC_RTG_IND_CBID, &MT_ZdoSrcRtgCB);
  ZDO_RegisterForZdoCB(ZDO_CONCENTRATOR_IND_CBID, &MT_ZdoConcentratorIndCB);
  ZDO_RegisterForZdoCB(ZDO_LEAVE_IND_CBID, &MT_ZdoLeaveInd);
#endif
}

uint8 MT_ZdoCommandProcessing(uint8* pBuf)
{
  uint8 status = MT_RPC_SUCCESS;

  switch (pBuf[MT_RPC_POS_CMD1])
  {
#if defined ( ZDO_NWKADDR_REQUEST )
    case MT_ZDO_NWK_ADDR_REQ:
      MT_ZdoNWKAddressRequest(pBuf);
      break;
#endif

#if defined ( ZDO_IEEEADDR_REQUEST )
    case MT_ZDO_IEEE_ADDR_REQ:
      MT_ZdoIEEEAddrRequest(pBuf);
      break;
#endif

#if defined ( ZDO_NODEDESC_REQUEST )
    case MT_ZDO_NODE_DESC_REQ:
      MT_ZdoNodeDescRequest(pBuf);
      break;
#endif

#if defined ( ZDO_POWERDESC_REQUEST )
    case MT_ZDO_POWER_DESC_REQ:
      MT_ZdoPowerDescRequest(pBuf);
      break;
#endif

#if defined ( ZDO_SIMPLEDESC_REQUEST )
    case MT_ZDO_SIMPLE_DESC_REQ:
      MT_ZdoSimpleDescRequest(pBuf);
      break;
#endif

#if defined ( ZDO_ACTIVEEP_REQUEST )
    case MT_ZDO_ACTIVE_EP_REQ:
      MT_ZdoActiveEpRequest(pBuf);
      break;
#endif

#if defined ( ZDO_MATCH_REQUEST )
    case MT_ZDO_MATCH_DESC_REQ:
      MT_ZdoMatchDescRequest(pBuf);
      break;
#endif

#if defined ( ZDO_COMPLEXDESC_REQUEST )
    case MT_ZDO_COMPLEX_DESC_REQ:
      MT_ZdoComplexDescRequest(pBuf);
      break;
#endif

#if defined ( ZDO_USERDESC_REQUEST )
    case MT_ZDO_USER_DESC_REQ:
      MT_ZdoUserDescRequest(pBuf);
      break;
#endif

#if defined ( ZDO_ENDDEVICE_ANNCE )
    case MT_ZDO_END_DEV_ANNCE:
      MT_ZdoEndDevAnnce(pBuf);
      break;
#endif

#if defined ( ZDO_USERDESCSET_REQUEST )
    case MT_ZDO_USER_DESC_SET:
      MT_ZdoUserDescSet(pBuf);
      break;
#endif

#if defined ( ZDO_SERVERDISC_REQUEST )
    case MT_ZDO_SERVICE_DISC_REQ:
      MT_ZdoServiceDiscRequest(pBuf);
      break;
#endif

#if defined ( ZDO_ENDDEVICEBIND_REQUEST )
    case MT_ZDO_END_DEV_BIND_REQ:
      MT_ZdoEndDevBindRequest(pBuf);
      break;
#endif

#if defined ( ZDO_BIND_UNBIND_REQUEST )
    case MT_ZDO_BIND_REQ:
      MT_ZdoBindRequest(pBuf);
      break;
#endif

#if defined ( ZDO_BIND_UNBIND_REQUEST )
    case MT_ZDO_UNBIND_REQ:
      MT_ZdoUnbindRequest(pBuf);
      break;
#endif

#if defined ( MT_SYS_KEY_MANAGEMENT )
    case MT_ZDO_SET_LINK_KEY:
      MT_ZdoSetLinkKey(pBuf);
      break;

    case MT_ZDO_REMOVE_LINK_KEY:
      MT_ZdoRemoveLinkKey(pBuf);
      break;

    case MT_ZDO_GET_LINK_KEY:
      MT_ZdoGetLinkKey(pBuf);
      break;
#endif // MT_SYS_KEY_MANAGEMENT

#if defined ( ZDO_MANUAL_JOIN )
    case MT_ZDO_NWK_DISCOVERY_REQ:
      MT_ZdoNetworkDiscoveryReq(pBuf);
      break;

    case MT_ZDO_JOIN_REQ:
      MT_ZdoJoinReq(pBuf);
      break;
#endif

#if defined ( ZDO_MGMT_NWKDISC_REQUEST )
    case MT_ZDO_MGMT_NWKDISC_REQ:
      MT_ZdoMgmtNwkDiscRequest(pBuf);
      break;
#endif

#if defined ( ZDO_MGMT_LQI_REQUEST )
    case MT_ZDO_MGMT_LQI_REQ:
      MT_ZdoMgmtLqiRequest(pBuf);
      break;
#endif

#if defined ( ZDO_MGMT_RTG_REQUEST )
    case MT_ZDO_MGMT_RTG_REQ:
      MT_ZdoMgmtRtgRequest(pBuf);
      break;
#endif

#if defined ( ZDO_MGMT_BIND_REQUEST )
    case MT_ZDO_MGMT_BIND_REQ:
      MT_ZdoMgmtBindRequest(pBuf);
      break;
#endif

#if defined ( ZDO_MGMT_LEAVE_REQUEST )
    case MT_ZDO_MGMT_LEAVE_REQ:
      MT_ZdoMgmtLeaveRequest(pBuf);
      break;
#endif

#if defined ( ZDO_MGMT_JOINDIRECT_REQUEST )
    case MT_ZDO_MGMT_DIRECT_JOIN_REQ:
      MT_ZdoMgmtDirectJoinRequest(pBuf);
      break;
#endif

#if defined ( ZDO_MGMT_PERMIT_JOIN_REQUEST )
    case MT_ZDO_MGMT_PERMIT_JOIN_REQ:
      MT_ZdoMgmtPermitJoinRequest(pBuf);
      break;
#endif

#if defined ( ZDO_MGMT_NWKUPDATE_REQUEST )
    case MT_ZDO_MGMT_NWK_UPDATE_REQ:
      MT_ZdoMgmtNwkUpdateRequest(pBuf);
      break;
#endif

#if defined ( ZDO_NETWORKSTART_REQUEST )
    case MT_ZDO_STARTUP_FROM_APP:
      MT_ZdoStartupFromApp(pBuf);
      break;
#endif

    case MT_ZDO_MSG_CB_REGISTER:
      MT_ZdoRegisterForZDOMsg(pBuf);
      break;

    case MT_ZDO_MSG_CB_REMOVE:
      MT_ZdoRemoveRegisteredCB(pBuf);
      break;

    default:
      status = MT_RPC_ERR_COMMAND_ID;
      break;
  }

  return status;
}

void MT_ZdoNWKAddressRequest(uint8 *pBuf)
{
  uint8 cmdId;
  uint8 retValue;
  uint8 reqType;
  uint8 startIndex;
  uint8 *pExtAddr;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* parse parameters */
  pExtAddr = pBuf;
  pBuf += Z_EXTADDR_LEN;

  /* Request type */
  reqType = *pBuf++;

  /* Start index */
  startIndex = *pBuf;

  retValue = (uint8)ZDP_NwkAddrReq(pExtAddr, reqType, startIndex, 0);

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_ZDO), cmdId, 1, &retValue);
}

void MT_ZdoIEEEAddrRequest (uint8 *pBuf)
{
  uint8 cmdId;
  uint8 retValue;
  uint16 shortAddr;
  uint8 reqType;
  uint8 startIndex;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Dev address */
  shortAddr = BUILD_UINT16(pBuf[0], pBuf[1]);
  pBuf += 2;

  /* request type */
  reqType = *pBuf++;

  /* start index */
  startIndex = *pBuf;

  retValue = (uint8)ZDP_IEEEAddrReq(shortAddr, reqType, startIndex, 0);

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_ZDO), cmdId, 1, &retValue);
}

void MT_ZdoNodeDescRequest (uint8 *pBuf)
{
  uint8 cmdId;
  uint8 retValue;
  zAddrType_t destAddr;
  uint16 shortAddr;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Destination address */
  destAddr.addrMode = Addr16Bit;
  destAddr.addr.shortAddr = BUILD_UINT16( pBuf[0], pBuf[1] );
  pBuf += 2;

  /* Network address of interest */
  shortAddr = BUILD_UINT16( pBuf[0], pBuf[1] );
  pBuf += 2;

  retValue = (uint8)ZDP_NodeDescReq( &destAddr, shortAddr, 0);

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_ZDO), cmdId, 1, &retValue);
}

void MT_ZdoPowerDescRequest(uint8 *pBuf)
{
  uint8 cmdId;
  uint8 retValue;
  zAddrType_t destAddr;
  uint16 shortAddr;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Dev address */
  destAddr.addrMode = Addr16Bit;
  destAddr.addr.shortAddr = BUILD_UINT16( pBuf[0], pBuf[1] );
  pBuf += 2;

  /* Network address of interest */
  shortAddr = BUILD_UINT16( pBuf[0], pBuf[1] );
  pBuf += 2;

  retValue = (uint8)ZDP_PowerDescReq( &destAddr, shortAddr, 0);

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_ZDO), cmdId, 1, &retValue);
}

void MT_ZdoSimpleDescRequest(uint8 *pBuf)
{
  uint8 cmdId;
  uint8 retValue;
  uint8 epInt;
  zAddrType_t destAddr;
  uint16 shortAddr;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Dev address */
  destAddr.addrMode = Addr16Bit;
  destAddr.addr.shortAddr = BUILD_UINT16( pBuf[0], pBuf[1] );
  pBuf += 2;

  /* Network address of interest */
  shortAddr = BUILD_UINT16( pBuf[0], pBuf[1] );
  pBuf += 2;

  /* endpoint/interface */
  epInt = *pBuf++;

  retValue = (uint8)ZDP_SimpleDescReq( &destAddr, shortAddr, epInt, 0);

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_ZDO), cmdId, 1, &retValue);
}

void MT_ZdoActiveEpRequest(uint8 *pBuf)
{
  uint8 cmdId;
  uint8 retValue;
  zAddrType_t destAddr;
  uint16 shortAddr;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Dev address */
  destAddr.addrMode = Addr16Bit;
  destAddr.addr.shortAddr = BUILD_UINT16( pBuf[0], pBuf[1] );
  pBuf += 2;

  /* Network address of interest */
  shortAddr = BUILD_UINT16( pBuf[0], pBuf[1] );
  pBuf += 2;

  retValue = (uint8)ZDP_ActiveEPReq( &destAddr, shortAddr, 0);

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_ZDO), cmdId, 1, &retValue);
}

void MT_ZdoMatchDescRequest(uint8 *pBuf)
{
  uint8 cmdId;
  uint8 retValue = 0;
  uint8 i, numInClusters, numOutClusters;
  uint16 profileId;
  zAddrType_t destAddr;
  uint16 shortAddr;
  uint16 inClusters[MTZDO_MAX_MATCH_CLUSTERS], outClusters[MTZDO_MAX_MATCH_CLUSTERS];

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Dev address */
  destAddr.addrMode = Addr16Bit;
  destAddr.addr.shortAddr = BUILD_UINT16( pBuf[0], pBuf[1] );
  pBuf += 2;

  /* Network address of interest */
  shortAddr = BUILD_UINT16( pBuf[0], pBuf[1] );
  pBuf += 2;

  /* Profile ID */
  profileId = BUILD_UINT16( pBuf[0], pBuf[1] );
  pBuf += 2;

  /* NumInClusters */
  numInClusters = *pBuf++;
  if ( numInClusters <= MTZDO_MAX_MATCH_CLUSTERS )
  {
    /* IN clusters */
    for ( i = 0; i < numInClusters; i++ )
    {
      inClusters[i] = BUILD_UINT16( pBuf[0], pBuf[1]);
      pBuf += 2;
    }
  }
  else
  {
    retValue = ZDP_INVALID_REQTYPE;
  }

  /* NumOutClusters */
  numOutClusters = *pBuf++;
  if ( numOutClusters <= MTZDO_MAX_MATCH_CLUSTERS )
  {
    /* OUT Clusters */
    for ( i = 0; i < numOutClusters; i++ )
    {
      outClusters[i] = BUILD_UINT16( pBuf[0], pBuf[1]);
      pBuf += 2;
    }
  }
  else
  {
    retValue = ZDP_INVALID_REQTYPE;
  }

  if ( retValue == 0 )
  {
    retValue = (uint8)ZDP_MatchDescReq( &destAddr, shortAddr, profileId, numInClusters,
                                       inClusters, numOutClusters, outClusters, 0);
  }

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_ZDO), cmdId, 1, &retValue);
}

void MT_ZdoComplexDescRequest(uint8 *pBuf)
{
  uint8 cmdId;
  uint8 retValue;
  zAddrType_t destAddr;
  uint16 shortAddr;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Dev address */
  destAddr.addrMode = Addr16Bit;
  destAddr.addr.shortAddr = BUILD_UINT16( pBuf[0], pBuf[1] );
  pBuf += 2;

  /* Network address of interest */
  shortAddr = BUILD_UINT16( pBuf[0], pBuf[1] );
  pBuf += 2;

  retValue = (uint8)ZDP_ComplexDescReq( &destAddr, shortAddr, 0);

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_ZDO), cmdId, 1, &retValue);
}

void MT_ZdoUserDescRequest(uint8 *pBuf)
{
  uint8 cmdId;
  uint8 retValue;
  zAddrType_t destAddr;
  uint16 shortAddr;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Dev address */
  destAddr.addrMode = Addr16Bit;
  destAddr.addr.shortAddr = BUILD_UINT16( pBuf[0], pBuf[1]);
  pBuf += 2;

  /* Network address of interest */
  shortAddr = BUILD_UINT16( pBuf[0], pBuf[1]);
  pBuf += 2;

  retValue = (uint8)ZDP_UserDescReq( &destAddr, shortAddr, 0);

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_ZDO), cmdId, 1, &retValue);
}

void MT_ZdoEndDevAnnce(uint8 *pBuf)
{
  uint8 cmdId;
  uint8 retValue;
  uint16 shortAddr;
  uint8 *pIEEEAddr;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* network address */
  shortAddr = BUILD_UINT16( pBuf[0], pBuf[1] );
  pBuf += 2;

  /* extended address */
  pIEEEAddr = pBuf;
  pBuf += Z_EXTADDR_LEN;

  retValue = (uint8)ZDP_DeviceAnnce( shortAddr, pIEEEAddr, *pBuf, 0);

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_ZDO), cmdId, 1, &retValue);
}

void MT_ZdoUserDescSet(uint8 *pBuf)
{
  uint8 cmdId;
  uint8 retValue;
  zAddrType_t destAddr;
  uint16 shortAddr;
  UserDescriptorFormat_t userDesc;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Dev address */
  destAddr.addrMode = Addr16Bit;
  destAddr.addr.shortAddr = BUILD_UINT16( pBuf[0], pBuf[1] );
  pBuf += 2;

  /* Network address of interest */
  shortAddr = BUILD_UINT16( pBuf[0], pBuf[1] );
  pBuf += 2;

  /* User descriptor */
  userDesc.len = *pBuf++;
  osal_memcpy( userDesc.desc, pBuf, userDesc.len );
  pBuf += 16;

  retValue = (uint8)ZDP_UserDescSet( &destAddr, shortAddr, &userDesc, 0);

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_ZDO), cmdId, 1, &retValue);
}

void MT_ZdoServiceDiscRequest(uint8 *pBuf)
{
  uint8 cmdId;
  uint8 retValue;
  uint16 serviceMask;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Service Mask */
  serviceMask = BUILD_UINT16( pBuf[0], pBuf[1]);
  pBuf += 2;

  retValue = (uint8)ZDP_ServerDiscReq( serviceMask, 0);

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_ZDO), cmdId, 1, &retValue);
}

void MT_ZdoEndDevBindRequest(uint8 *pBuf)
{
  uint8 cmdId;
  uint8 retValue = 0;
  uint8 i, epInt, numInClusters, numOutClusters;
  zAddrType_t destAddr;
  uint16 shortAddr;
  uint16 profileID, inClusters[MTZDO_MAX_ED_BIND_CLUSTERS], outClusters[MTZDO_MAX_ED_BIND_CLUSTERS];

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Dev address */
  destAddr.addrMode = Addr16Bit;
  destAddr.addr.shortAddr = BUILD_UINT16( pBuf[0], pBuf[1] );
  pBuf += 2;

  /* Local coordinator of the binding */
  shortAddr = BUILD_UINT16( pBuf[0], pBuf[1] );
  pBuf += 2;

  /* For now, skip past the extended address */
  pBuf += Z_EXTADDR_LEN;

  /* Endpoint */
  epInt = *pBuf++;

  /* Profile ID */
  profileID = BUILD_UINT16( pBuf[0], pBuf[1] );
  pBuf += 2;

  /* NumInClusters */
  numInClusters = *pBuf++;
  if ( numInClusters <= MTZDO_MAX_ED_BIND_CLUSTERS )
  {
    for ( i = 0; i < numInClusters; i++ )
    {
      inClusters[i] = BUILD_UINT16(pBuf[0], pBuf[1]);
      pBuf += 2;
    }
  }
  else
  {
    retValue = ZDP_INVALID_REQTYPE;
  }

  /* NumOutClusters */
  numOutClusters = *pBuf++;
  if ( numOutClusters <= MTZDO_MAX_ED_BIND_CLUSTERS )
  {
    for ( i = 0; i < numOutClusters; i++ )
    {
      outClusters[i] = BUILD_UINT16(pBuf[0], pBuf[1]);
      pBuf += 2;
    }
  }
  else
  {
    retValue = ZDP_INVALID_REQTYPE;
  }

  if ( retValue == 0 )
  {
    retValue = (uint8)ZDP_EndDeviceBindReq( &destAddr, shortAddr, epInt, profileID,
                                          numInClusters, inClusters, numOutClusters, outClusters, 0);
  }

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_ZDO), cmdId, 1, &retValue);
}

void MT_ZdoBindRequest(uint8 *pBuf)
{
  uint8 cmdId;
  uint8 retValue;
  zAddrType_t destAddr, devAddr;
  uint8 *pSrcAddr, *ptr;
  uint8 srcEPInt, dstEPInt;
  uint16 clusterID;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Dev address */
  destAddr.addrMode = Addr16Bit;
  destAddr.addr.shortAddr = BUILD_UINT16( pBuf[0], pBuf[1] );
  pBuf += 2;

  /* SrcAddress */
  pSrcAddr = pBuf;
  pBuf += Z_EXTADDR_LEN;

  /* SrcEPInt */
  srcEPInt = *pBuf++;

  /* ClusterID */
  clusterID = BUILD_UINT16( pBuf[0], pBuf[1]);
  pBuf += 2;

  /* Destination Address mode */
  devAddr.addrMode = *pBuf++;

  /* Destination Address */
  if ( devAddr.addrMode == Addr64Bit )
  {
    ptr = pBuf;
    osal_cpyExtAddr( devAddr.addr.extAddr, ptr );
  }
  else
  {
    devAddr.addr.shortAddr = BUILD_UINT16( pBuf[0], pBuf[1] );
  }
  /* The short address occupies LSB two bytes */
  pBuf += Z_EXTADDR_LEN;

  /* DstEPInt */
  dstEPInt = *pBuf;

  retValue = (uint8)ZDP_BindReq( &destAddr, pSrcAddr, srcEPInt, clusterID, &devAddr, dstEPInt, 0);

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_ZDO), cmdId, 1, &retValue);
}

void MT_ZdoUnbindRequest(uint8 *pBuf)
{
  uint8 cmdId;
  uint8 retValue;
  zAddrType_t destAddr, devAddr;
  uint8 *pSrcAddr, *ptr;
  uint8 srcEPInt, dstEPInt;
  uint16 clusterID;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* dev address */
  destAddr.addrMode = Addr16Bit;
  destAddr.addr.shortAddr = BUILD_UINT16( pBuf[0], pBuf[1] );
  pBuf += 2;

  /* SrcAddress */
  pSrcAddr = pBuf;
  pBuf += Z_EXTADDR_LEN;

  /* SrcEPInt */
  srcEPInt = *pBuf++;

  /* ClusterID */
  clusterID = BUILD_UINT16( pBuf[0], pBuf[1]);
  pBuf += 2;

  /* Destination Address mode */
  devAddr.addrMode = *pBuf++;

  /* Destination Address */
  if ( devAddr.addrMode == Addr64Bit )
  {
    ptr = pBuf;
    osal_cpyExtAddr( devAddr.addr.extAddr, ptr );
  }
  else
  {
    devAddr.addr.shortAddr = BUILD_UINT16( pBuf[0], pBuf[1] );
  }
  /* The short address occupies LSB two bytes */
  pBuf += Z_EXTADDR_LEN;

  /* dstEPInt */
  dstEPInt = *pBuf;

  retValue = (uint8)ZDP_UnbindReq( &destAddr, pSrcAddr, srcEPInt, clusterID, &devAddr, dstEPInt, 0);

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_ZDO), cmdId, 1, &retValue);
}

#if defined (MT_SYS_KEY_MANAGEMENT)

void MT_ZdoSetLinkKey(uint8 *pBuf)
{
  uint8 cmdId;
  uint8 retValue;
  uint8 *pExtAddr;
  uint8 *pKey;
  uint16 shortAddr;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* ShortAddr */
  shortAddr = BUILD_UINT16( pBuf[0], pBuf[1] );
  pBuf += 2;

  /* Extended Addr */
  pExtAddr = pBuf;
  pBuf += Z_EXTADDR_LEN;

  /* Key data */
  pKey = pBuf;

  retValue = (uint8)ZDSecMgrAddLinkKey( shortAddr, pExtAddr, pKey);

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_ZDO), cmdId, 1, &retValue);
}

void MT_ZdoRemoveLinkKey(uint8 *pBuf)
{
  uint8 cmdId;
  uint8 retValue;
  uint8 *pExtAddr;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* ShortAddr */
  pExtAddr = pBuf;

  retValue = ZDSecMgrDeviceRemoveByExtAddr( pExtAddr );

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_ZDO), cmdId, 1, &retValue);
}

void MT_ZdoGetLinkKey(uint8 *pBuf)
{
  uint8 cmdId;
  uint8 retValue;
  uint8 *pExtAddr;
  uint8 *retBuf = NULL;
  uint8 len;
  APSME_LinkKeyData_t *pApsLinkKey = NULL;
  uint16 apsLinkKeyNvId;

  // parse header
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  // Extended Address
  pExtAddr = pBuf;

  // Fetch the key NV ID
  retValue = APSME_LinkKeyNVIdGet( pExtAddr, &apsLinkKeyNvId );

  if (retValue == ZSuccess)
  {
    if ((pApsLinkKey = (APSME_LinkKeyData_t *)osal_mem_alloc(sizeof(APSME_LinkKeyData_t))) != NULL)
    {
      // retrieve key from NV
      if (osal_nv_read( apsLinkKeyNvId, 0,
                       sizeof(APSME_LinkKeyData_t), pApsLinkKey) != SUCCESS)
      {
        retValue = ZNwkUnknownDevice;
      }
    }
    else
    {
      retValue = ZNwkUnknownDevice;
    }
  }

  // Construct the response message
  len = MT_ZDO_STATUS_LEN + Z_EXTADDR_LEN + SEC_KEY_LEN; // status + extAddr + key
  if ((retBuf = (uint8 *)osal_mem_alloc(len)) != NULL)
  {
    if (retValue == ZSuccess)
    {
      // Extended Address
      osal_memcpy( &(retBuf[1]), pExtAddr, Z_EXTADDR_LEN );

      // Key data
      osal_memcpy( &(retBuf[1 + Z_EXTADDR_LEN]), pApsLinkKey->key, SEC_KEY_LEN );
    }
    else
    {
      // Failed case - set the rest fields to all FF
      osal_memset( &(retBuf[1]), 0xFF, Z_EXTADDR_LEN + SEC_KEY_LEN );
    }

    retBuf[0] = retValue;  // Status

    MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_ZDO), cmdId, len, retBuf);

    // clear retBuf because it contains key data and free allocated memory
    osal_memset(retBuf, 0x00, len);

    osal_mem_free(retBuf);
  }

  // clear copy of key in RAM
  if (pApsLinkKey != NULL)
  {
    osal_memset(pApsLinkKey, 0x00, sizeof(APSME_LinkKeyData_t));

    osal_mem_free(pApsLinkKey);
  }

  return;
}
#endif // MT_SYS_KEY_MANAGEMENT

#if defined (MT_ZDO_MGMT)

void MT_ZdoMgmtNwkDiscRequest(uint8 *pBuf)
{
  uint8 cmdId;
  uint8 retValue;
  zAddrType_t destAddr;
  uint32 scanChannels;
  uint8 scanDuration, startIndex;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Dev address */
  destAddr.addrMode = Addr16Bit;
  destAddr.addr.shortAddr = BUILD_UINT16( pBuf[0], pBuf[1] );
  pBuf += 2;

  /* Scan Channels */
  scanChannels = BUILD_UINT32( pBuf[0], pBuf[1], pBuf[2], pBuf[3] );
  pBuf += 4;

  /* Scan Duration */
  scanDuration = *pBuf++;

  /* Start Index */
  startIndex = *pBuf;

  retValue = (uint8)ZDP_MgmtNwkDiscReq( &destAddr, scanChannels, scanDuration, startIndex, 0);

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_ZDO), cmdId, 1, &retValue);
}

void MT_ZdoMgmtLqiRequest(uint8 *pBuf)
{
  uint8 cmdId;
  uint8 retValue;
  zAddrType_t destAddr;
  uint8 startIndex;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Dev address */
  destAddr.addrMode = Addr16Bit;
  destAddr.addr.shortAddr = BUILD_UINT16( pBuf[0], pBuf[1] );
  pBuf += 2;

  /* Start Index */
  startIndex = *pBuf;

  retValue = (uint8)ZDP_MgmtLqiReq( &destAddr, startIndex, 0);

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_ZDO), cmdId, 1, &retValue);
}

void MT_ZdoMgmtRtgRequest(uint8 *pBuf)
{
  uint8 cmdId;
  uint8 retValue;
  zAddrType_t destAddr;
  uint8 startIndex;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Dev Address */
  destAddr.addrMode = Addr16Bit;
  destAddr.addr.shortAddr = BUILD_UINT16( pBuf[0], pBuf[1]);
  pBuf += 2;

  /* Start Index */
  startIndex = *pBuf;

  retValue = (byte)ZDP_MgmtRtgReq( &destAddr, startIndex, 0);

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_ZDO), cmdId, 1, &retValue);
}

void MT_ZdoMgmtBindRequest(uint8 *pBuf)
{
  uint8 cmdId;
  uint8 retValue;
  zAddrType_t destAddr;
  uint8 startIndex;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Dev Address */
  destAddr.addrMode = Addr16Bit;
  destAddr.addr.shortAddr = BUILD_UINT16( pBuf[0], pBuf[1] );
  pBuf += 2;

  /* Start Index */
  startIndex = *pBuf;

  retValue = (uint8)ZDP_MgmtBindReq( &destAddr, startIndex, 0);

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_ZDO), cmdId, 1, &retValue);
}

void MT_ZdoMgmtLeaveRequest(uint8 *pBuf)
{
  uint8 cmdId;
  uint8 retValue;
  zAddrType_t destAddr;
  uint8 *pIEEEAddr;
  uint8 removeChildren, rejoin;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Destination Address */
  destAddr.addrMode = Addr16Bit;
  destAddr.addr.shortAddr = BUILD_UINT16( pBuf[0], pBuf[1] );
  pBuf += 2;

  /* IEEE address */
  pIEEEAddr = pBuf;
  pBuf += Z_EXTADDR_LEN;

  /* Remove Children */
  removeChildren = *pBuf++;

  /* Rejoin */
  rejoin = *pBuf;

  retValue = (byte)ZDP_MgmtLeaveReq( &destAddr, pIEEEAddr, removeChildren, rejoin, 0);

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_ZDO), cmdId, 1, &retValue);
}


void MT_ZdoMgmtDirectJoinRequest(uint8 *pBuf)
{
  uint8 cmdId;
  uint8 retValue;
  zAddrType_t destAddr;
  uint8 *deviceAddr;
  uint8 capInfo;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Destination Address */
  destAddr.addrMode = Addr16Bit;
  destAddr.addr.shortAddr = BUILD_UINT16( pBuf[0], pBuf[1] );
  pBuf += 2;

  /* Device Address */
  deviceAddr = pBuf;
  pBuf += Z_EXTADDR_LEN;

  /* Capability information */
  capInfo = *pBuf;

  retValue = (uint8)ZDP_MgmtDirectJoinReq( &destAddr, deviceAddr, capInfo, 0);

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_ZDO), cmdId, 1, &retValue);
}

void MT_ZdoMgmtPermitJoinRequest(uint8 *pBuf)
{
  uint8 cmdId;
  uint8 retValue;
  zAddrType_t destAddr;
  uint8 duration, tcSignificance;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Destination Address */
  destAddr.addrMode = Addr16Bit;
  destAddr.addr.shortAddr = BUILD_UINT16( pBuf[0], pBuf[1] );
  pBuf += 2;

  /* Duration */
  duration = *pBuf++;

  /* Trust center significance */
  tcSignificance = *pBuf;

  retValue = (byte)ZDP_MgmtPermitJoinReq( &destAddr, duration, tcSignificance, 0);

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_ZDO), cmdId, 1, &retValue);
}

void MT_ZdoMgmtNwkUpdateRequest(uint8 *pBuf)
{
  uint8 cmdId;
  uint8 retValue;
  zAddrType_t destAddr;
  uint32 channelMask;
  uint8 scanDuration, scanCount;
  uint16 nwkManagerAddr;

    /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Destination address */
  destAddr.addr.shortAddr = BUILD_UINT16( pBuf[0], pBuf[1] );
  pBuf += 2;

  /* Destination address mode */
  destAddr.addrMode = *pBuf++;

  channelMask = BUILD_UINT32( pBuf[0], pBuf[1], pBuf[2], pBuf[3]);
  pBuf += 4;

  /* Scan duration */
  scanDuration = *pBuf++;

  /* Scan count */
  scanCount = *pBuf++;

  /* NWK manager address */
  nwkManagerAddr = BUILD_UINT16( pBuf[0], pBuf[1] );

  /* Send the Management Network Update request */
  retValue = (uint8)ZDP_MgmtNwkUpdateReq( &destAddr, channelMask, scanDuration,
                                          scanCount, _NIB.nwkUpdateId+1, nwkManagerAddr );

  /*
    Since we don't recevied our own broadcast messages, we should
    send a unicast copy of the message to ourself.
  */
  if ( destAddr.addrMode == AddrBroadcast )
  {
    destAddr.addrMode = Addr16Bit;
    destAddr.addr.shortAddr = _NIB.nwkDevAddress;
    retValue = (uint8) ZDP_MgmtNwkUpdateReq( &destAddr, channelMask, scanDuration,
                                             scanCount, _NIB.nwkUpdateId+1, nwkManagerAddr );
  }

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_ZDO), cmdId, 1, &retValue);
}
#endif /* MT_ZDO_MGMT */

void MT_ZdoStartupFromApp(uint8 *pBuf)
{
  uint8 cmd0, cmd1, retValue;

  /* parse header */
  cmd0 = pBuf[MT_RPC_POS_CMD0];
  cmd1 = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  retValue = ZDOInitDevice(100);

  if (MT_RPC_CMD_SREQ == (cmd0 & MT_RPC_CMD_TYPE_MASK))
  {
    MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP|(uint8)MT_RPC_SYS_ZDO), cmd1,1, &retValue);
  }
}

void MT_ZdoNetworkDiscoveryReq(uint8 *pBuf)
{
  uint8  retValue = ZFailure;
  uint8  cmdId;
  uint32 scanChannels;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Packet format */
  /* scan channels (4) | scan duration (1) */

  /* Scan channels */
  scanChannels = osal_build_uint32(pBuf, 4);
  pBuf += 4;

  retValue = ZDApp_NetworkDiscoveryReq(scanChannels, *pBuf);

  // Register ZDO callback for MT to handle the network discovery confirm
  // and beacon notification confirm
  ZDO_RegisterForZdoCB( ZDO_NWK_DISCOVERY_CNF_CBID, &MT_ZdoNwkDiscoveryCnfCB );
  ZDO_RegisterForZdoCB( ZDO_BEACON_NOTIFY_IND_CBID, &MT_ZdoBeaconIndCB );

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_ZDO), cmdId, 1, &retValue );
}

void MT_ZdoJoinReq(uint8 *pBuf)
{
  uint8  retValue = ZFailure;
  uint8  cmdId;
  uint16 panId;
  uint16 chosenParent;

  /* parse header */
  cmdId = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  /* Packet format */
  /* channel     (1) | panID (2) | extendedPanID (8) | chosenParent (2) |
   * parentDepth (1) | stackProfile  (1)
   */

  panId        = BUILD_UINT16(pBuf[1], pBuf[2]);
  chosenParent = BUILD_UINT16(pBuf[11], pBuf[12]);

  retValue = ZDApp_JoinReq(pBuf[0], panId, &(pBuf[3]), chosenParent, pBuf[13], pBuf[14]);

  /* Register for MT to receive Join Confirm */
  ZDO_RegisterForZdoCB( ZDO_JOIN_CNF_CBID, &MT_ZdoJoinCnfCB );

  /* Build and send back the response */
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP | (uint8)MT_RPC_SYS_ZDO), cmdId, 1, &retValue );

}

void *MT_ZdoNwkDiscoveryCnfCB ( void *pStr )
{
  /* pStr: status (uint8) */
  /* Packet Format */
  /* Status (1) */

  // Scan completed. De-register the callback with ZDO
  ZDO_DeregisterForZdoCB( ZDO_NWK_DISCOVERY_CNF_CBID );
  ZDO_DeregisterForZdoCB( ZDO_BEACON_NOTIFY_IND_CBID );

  // Send the buffered beacon indication
  MT_ZdoBeaconIndCB ( NULL );

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_ZDO),
                                         MT_ZDO_NWK_DISCOVERY_CNF, 1, pStr);
  return NULL;
}

void *MT_ZdoBeaconIndCB ( void *pStr )
{
  zdoBeaconInd_t *pBeacon = pStr;
  uint8 *pTmp;

  /* Packet Format */
  /* devCnt (1) | device #1 (21) | device #2 (21) |... | device #n (21) */

  if( pStr != NULL)
  {
    if( pBeaconIndBuf == NULL )
    {
      // If pBeaconIndBuf has not been allocated yet
      // allocate memory now with MAX_UART_TX_BUFF
      if( NULL == (pBeaconIndBuf = (uint8 *)osal_mem_alloc(MT_ZDO_BEACON_IND_PACK_LEN)))
      {
        // Memory failure
        return NULL;
      }
      pBeaconIndBuf[0] = 0; // First byte is devCnt. Initialize to 0.
    }

    // Fill in the buffer with the beacon indication
    pTmp = pBeaconIndBuf + (1 + pBeaconIndBuf[0] * MT_ZDO_BEACON_IND_LEN);
    *pTmp++ = LO_UINT16(pBeacon->sourceAddr);
    *pTmp++ = HI_UINT16(pBeacon->sourceAddr);
    *pTmp++ = LO_UINT16(pBeacon->panID);
    *pTmp++ = HI_UINT16(pBeacon->panID);
    *pTmp++ = pBeacon->logicalChannel;
    *pTmp++ = pBeacon->permitJoining;
    *pTmp++ = pBeacon->routerCapacity;
    *pTmp++ = pBeacon->deviceCapacity;
    *pTmp++ = pBeacon->protocolVersion;
    *pTmp++ = pBeacon->stackProfile;
    *pTmp++ = pBeacon->LQI;
    *pTmp++ = pBeacon->depth;
    *pTmp++ = pBeacon->updateID;
    osal_memcpy( pTmp, pBeacon->extendedPanID, Z_EXTADDR_LEN);

    pBeaconIndBuf[0] += 1; // Increment the devCnt

    // Check if the buffer can fit in another beacon
    if( ((pBeaconIndBuf[0] + 1) * MT_ZDO_BEACON_IND_LEN + 1) > MT_ZDO_BEACON_IND_PACK_LEN )
    {
      // Packet full, send the packet over MT
      MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_ZDO),
                                   MT_ZDO_BEACON_NOTIFY_IND,
                                   (pBeaconIndBuf[0] * MT_ZDO_BEACON_IND_LEN + 1), pBeaconIndBuf);
      pBeaconIndBuf[0] = 0; // Reset the devCnt back to zero
    }
  }
  else
  {
    if( (pBeaconIndBuf != NULL) && (pBeaconIndBuf[0] != 0) )
    {
      // End of beacon indication, send the packet over MT
      MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_ZDO),
                                   MT_ZDO_BEACON_NOTIFY_IND,
                                   (pBeaconIndBuf[0] * MT_ZDO_BEACON_IND_LEN + 1), pBeaconIndBuf);
    }
    // Free the allocated memory
    if(pBeaconIndBuf != NULL)
    {
      osal_mem_free(pBeaconIndBuf);
      pBeaconIndBuf = NULL;
    }
  }

  return NULL;
}


void *MT_ZdoJoinCnfCB ( void *pStr )
{
  /* pStr: zdoJoinCnf_t* */
  /* Packet Format */
  /* Status (1) | device addr (2) | parent addr (2) */

  uint8 buf[MT_ZDO_JOIN_CNF_LEN];
  zdoJoinCnf_t *joinCnf = pStr;

  /* Join Complete. De-register the callback with ZDO */
  ZDO_DeregisterForZdoCB( ZDO_JOIN_CNF_CBID );

  buf[0] = joinCnf->status;
  buf[1] = LO_UINT16( joinCnf->deviceAddr );
  buf[2] = HI_UINT16( joinCnf->deviceAddr );
  buf[3] = LO_UINT16( joinCnf->parentAddr );
  buf[4] = HI_UINT16( joinCnf->parentAddr );

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_ZDO),
                               MT_ZDO_JOIN_CNF, MT_ZDO_JOIN_CNF_LEN, buf);

  return NULL;
}

void MT_ZdoRegisterForZDOMsg(uint8 *pBuf)
{
  uint8 cmd0, cmd1, tmp;
  uint16 cId;

  /* parse header */
  cmd0 = pBuf[MT_RPC_POS_CMD0];
  cmd1 = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  cId = BUILD_UINT16(pBuf[0], pBuf[1]);
  tmp = ZDO_RegisterForZDOMsg(MT_TaskID, cId);

  if (MT_RPC_CMD_SREQ == (cmd0 & MT_RPC_CMD_TYPE_MASK))
  {
    MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP|(uint8)MT_RPC_SYS_ZDO), cmd1, 1, &tmp);
  }
}

void MT_ZdoRemoveRegisteredCB(uint8 *pBuf)
{
  uint8 cmd0, cmd1, tmp;
  uint16 cId;

  /* parse header */
  cmd0 = pBuf[MT_RPC_POS_CMD0];
  cmd1 = pBuf[MT_RPC_POS_CMD1];
  pBuf += MT_RPC_FRAME_HDR_SZ;

  cId = BUILD_UINT16(pBuf[0], pBuf[1]);
  tmp = ZDO_RemoveRegisteredCB(MT_TaskID, cId);

  if (MT_RPC_CMD_SREQ == (cmd0 & MT_RPC_CMD_TYPE_MASK))
  {
    MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_SRSP|(uint8)MT_RPC_SYS_ZDO), cmd1, 1, &tmp);
  }
}

#endif /* MT_ZDO_FUNC */

#if defined (MT_ZDO_CB_FUNC)

void MT_ZdoStateChangeCB(osal_event_hdr_t *pMsg)
{
  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_ZDO),
                                       MT_ZDO_STATE_CHANGE_IND, 1, &pMsg->status);
}

void MT_ZdoDirectCB( afIncomingMSGPacket_t *pData, zdoIncomingMsg_t *inMsg )
{
  uint8 len, *pBuf;
  uint16 origClusterId;

  // save original value because MT_ZdoHandleExceptions() function could modify pData->clusterId
  origClusterId = pData->clusterId;

  // Is the message an exception or not a response?
  if ( MT_ZdoHandleExceptions( pData, inMsg ) || ( (origClusterId & ZDO_RESPONSE_BIT) == 0 ) )
  {
    return;  // Handled somewhere else or not needed.
  }

  /* ZDO data starts after one-byte sequence number and the msg buffer length includes
   * two bytes for srcAddr.
   */
  len = pData->cmd.DataLength - 1 + sizeof(uint16);

  if (NULL != (pBuf = (uint8 *)osal_mem_alloc(len)))
  {
    uint8 id = MT_ZDO_CID_TO_AREQ_ID(pData->clusterId);

    pBuf[0] = LO_UINT16(pData->srcAddr.addr.shortAddr);
    pBuf[1] = HI_UINT16(pData->srcAddr.addr.shortAddr);

    /* copy ZDO data, skipping one-byte sequence number */
    osal_memcpy(pBuf+2, (pData->cmd.Data + 1), pData->cmd.DataLength-1);

    MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_ZDO), id, len, pBuf);
    osal_mem_free(pBuf);
  }
}

uint8 MT_ZdoHandleExceptions( afIncomingMSGPacket_t *pData, zdoIncomingMsg_t *inMsg )
{
  uint8 ret = TRUE;
  ZDO_NwkIEEEAddrResp_t *nwkRsp;
  ZDO_DeviceAnnce_t devAnnce;
  uint8 doDefault = FALSE;

  switch ( inMsg->clusterID )
  {
    case NWK_addr_rsp:
    case IEEE_addr_rsp:
      if ( NULL != (nwkRsp = ZDO_ParseAddrRsp(inMsg)) )
      {
        if ( nwkRsp->status == ZDO_SUCCESS )
        {
          MT_ZdoAddrRspCB( nwkRsp, inMsg->clusterID );
        }
        osal_mem_free( nwkRsp );
      }
      break;

    case Device_annce:
      ZDO_ParseDeviceAnnce( inMsg, &devAnnce );
      MT_ZdoEndDevAnnceCB( &devAnnce, inMsg->srcAddr.addr.shortAddr );
      break;

    case Simple_Desc_rsp:
      if ( pData->cmd.DataLength > 5 )
      {
        ret = FALSE;
      }
      else
      {
        doDefault = TRUE;
      }
      break;

    default:
      ret = FALSE;
      break;
  }

  if ( doDefault )
  {
    ret = FALSE;
    pData->clusterId = MtZdoDef_rsp;
    pData->cmd.DataLength = 2;
  }

  return ( ret );
}

void MT_ZdoAddrRspCB( ZDO_NwkIEEEAddrResp_t *pMsg, uint16 clusterID )
{
  uint8   listLen, len, *pBuf;

  /* both ZDO_NwkAddrResp_t and ZDO_IEEEAddrResp_t must be the same */

  /* get length, sanity check length */
  listLen = pMsg->numAssocDevs;

  /* calculate msg length */
  len = MT_ZDO_ADDR_RSP_LEN + (listLen * sizeof(uint16));

  /* get buffer */
  if (NULL != (pBuf = (uint8 *)osal_mem_alloc(len)))
  {
    uint8 id = MT_ZDO_CID_TO_AREQ_ID(clusterID);
    uint8 *pTmp = pBuf;

    *pTmp++ = pMsg->status;

    osal_cpyExtAddr(pTmp, pMsg->extAddr);
    pTmp += Z_EXTADDR_LEN;

    *pTmp++ = LO_UINT16(pMsg->nwkAddr);
    *pTmp++ = HI_UINT16(pMsg->nwkAddr);

    *pTmp++ = pMsg->startIndex;
    *pTmp++ = listLen;

    MT_Word2Buf(pTmp, pMsg->devList, listLen);

    MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_ZDO), id, len, pBuf);
    osal_mem_free(pBuf);
  }
}

void MT_ZdoEndDevAnnceCB( ZDO_DeviceAnnce_t *pMsg, uint16 srcAddr )
{
  uint8 *pBuf;

  if (NULL != (pBuf = (uint8 *)osal_mem_alloc(MT_ZDO_END_DEVICE_ANNCE_IND_LEN)))
  {
    uint8 *pTmp = pBuf;

    *pTmp++ = LO_UINT16(srcAddr);
    *pTmp++ = HI_UINT16(srcAddr);

    *pTmp++ = LO_UINT16(pMsg->nwkAddr);
    *pTmp++ = HI_UINT16(pMsg->nwkAddr);

    osal_cpyExtAddr(pTmp, pMsg->extAddr);
    pTmp += Z_EXTADDR_LEN;

    *pTmp = pMsg->capabilities;

    MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_ZDO),
                                         MT_ZDO_END_DEVICE_ANNCE_IND,
                                         MT_ZDO_END_DEVICE_ANNCE_IND_LEN, pBuf);
    osal_mem_free(pBuf);
  }
}

void* MT_ZdoSrcRtgCB( void *pStr )
{
  uint8 len, *pBuf;
  zdoSrcRtg_t *pSrcRtg = pStr;

  // srcAddr (2) + relayCnt (1) + relayList( relaycnt * 2 )
  len = 2 + 1 + pSrcRtg->relayCnt * sizeof(uint16);

  if (NULL != (pBuf = (uint8 *)osal_mem_alloc(len)))
  {
    uint8 idx, *pTmp = pBuf;
    uint16 *pRelay;

    // Packet payload
    *pTmp++ = LO_UINT16(pSrcRtg->srcAddr);
    *pTmp++ = HI_UINT16(pSrcRtg->srcAddr);
    *pTmp++ = pSrcRtg->relayCnt;

    // Relay List
    if( ( pRelay = pSrcRtg->pRelayList ) != NULL )
    {
      for( idx = 0; idx < pSrcRtg->relayCnt; idx ++ )
      {
        *pTmp++ = LO_UINT16(*pRelay);
        *pTmp++ = HI_UINT16(*pRelay);
        pRelay++;
      }
    }
    MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_ZDO),
                                         MT_ZDO_SRC_RTG_IND, len, pBuf);
    osal_mem_free(pBuf);
  }

  return NULL;
}

static void *MT_ZdoConcentratorIndCB(void *pStr)
{
  uint8 buf[MT_ZDO_CONCENTRATOR_IND_LEN], *pTmp = buf;
  zdoConcentratorInd_t *pInd = (zdoConcentratorInd_t *)pStr;

  *pTmp++ = LO_UINT16(pInd->nwkAddr);
  *pTmp++ = HI_UINT16(pInd->nwkAddr);
  pTmp = osal_memcpy(pTmp, pInd->extAddr, Z_EXTADDR_LEN);
  *pTmp = pInd->pktCost;

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_ZDO),
                                    MT_ZDO_CONCENTRATOR_IND_CB, MT_ZDO_CONCENTRATOR_IND_LEN, buf);
  return NULL;
}

static void *MT_ZdoLeaveInd(void *vPtr)
{
  NLME_LeaveInd_t *pInd = (NLME_LeaveInd_t *)vPtr;
  uint8 buf[sizeof(NLME_LeaveInd_t)];

  buf[0] = LO_UINT16(pInd->srcAddr);
  buf[1] = HI_UINT16(pInd->srcAddr);
  (void)osal_memcpy(buf+2, pInd->extAddr, Z_EXTADDR_LEN);
  buf[2+Z_EXTADDR_LEN] = pInd->request;
  buf[3+Z_EXTADDR_LEN] = pInd->removeChildren;
  buf[4+Z_EXTADDR_LEN] = pInd->rejoin;

  MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_ZDO),
                                       MT_ZDO_LEAVE_IND, 5+Z_EXTADDR_LEN, buf);
  return NULL;
}
#endif // MT_ZDO_CB_FUNC

void MT_ZdoSendMsgCB(zdoIncomingMsg_t *pMsg)
{
  uint8 len = pMsg->asduLen + 9;
  uint8 *pBuf = (uint8 *)osal_mem_alloc(len);

  if (pBuf != NULL)
  {
    uint8 *pTmp = pBuf;

    // Assuming exclusive use of network short addresses.
    *pTmp++ = LO_UINT16(pMsg->srcAddr.addr.shortAddr);
    *pTmp++ = HI_UINT16(pMsg->srcAddr.addr.shortAddr);
    *pTmp++ = pMsg->wasBroadcast;
    *pTmp++ = LO_UINT16(pMsg->clusterID);
    *pTmp++ = HI_UINT16(pMsg->clusterID);
    *pTmp++ = pMsg->SecurityUse;
    *pTmp++ = pMsg->TransSeq;
    // Skipping asduLen since it can be deduced from the RPC packet length.
    *pTmp++ = LO_UINT16(pMsg->macDestAddr);
    *pTmp++ = HI_UINT16(pMsg->macDestAddr);
    (void)osal_memcpy(pTmp, pMsg->asdu, pMsg->asduLen);

    MT_BuildAndSendZToolResponse(((uint8)MT_RPC_CMD_AREQ | (uint8)MT_RPC_SYS_ZDO),
                                         MT_ZDO_MSG_CB_INCOMING, len, pBuf);

    osal_mem_free(pBuf);
  }
}

#endif   /*ZDO Command Processing in MT*/

MT__ZDO.h

#include "ZComDef.h"
#include "MT.h"
#include "APSMEDE.h"
#include "AF.h"
#include "ZDProfile.h"
#include "ZDObject.h"
#include "ZDApp.h"

#if !defined( WIN32 )
  #include "OnBoard.h"
#endif

extern uint32 _zdoCallbackSub;


#define ZDOCB_CHECK(cbi) (_zdoCallbackSub & (cbi))


extern void MT_ZdoInit(void);


extern uint8 MT_ZdoCommandProcessing(uint8* pBuf);

extern void MT_ZdoStateChangeCB(osal_event_hdr_t *pMsg);

extern void MT_ZdoDirectCB( afIncomingMSGPacket_t *pData,  zdoIncomingMsg_t *inMsg );

void MT_ZdoSendMsgCB(zdoIncomingMsg_t *pMsg);

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不吃橘子的橘猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值