/********************************************************************* * @fn zclElectricalMeasurement_HdlIncoming * * @brief Callback from ZCL to process incoming Commands specific * to this cluster library or Profile commands for attributes * that aren't in the attribute list * * @param pInMsg - pointer to the incoming message * * @return ZStatus_t */ static ZStatus_t zclElectricalMeasurement_HdlIncoming( zclIncoming_t *pInMsg ) { ZStatus_t stat = ZSuccess; #if defined ( INTER_PAN ) if ( StubAPS_InterPan( pInMsg->msg->srcAddr.panId, pInMsg->msg->srcAddr.endPoint ) ) { return ( stat ); // Cluster not supported thru Inter-PAN } #endif if ( zcl_ClusterCmd( pInMsg->hdr.fc.type ) ) { // Is this a manufacturer specific command? if ( pInMsg->hdr.fc.manuSpecific == 0 ) { stat = zclElectricalMeasurement_HdlInSpecificCommands( pInMsg ); } else { // We don't support any manufacturer specific command. stat = ZFailure; } } else { // Handle all the normal (Read, Write...) commands -- should never get here stat = ZFailure; } return ( stat ); }
/*************************************************************************************************** * @fn MT_AfInterPanCtl * * @brief Process the AF Inter Pan control command. * * @param pBuf - pointer to the received buffer * * @return none ***************************************************************************************************/ 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); }
afStatus_t AF_DataRequest( afAddrType_t *dstAddr, endPointDesc_t *srcEP, uint16 cID, uint16 len, uint8 *buf, uint8 *transID, uint8 options, uint8 radius ) { pDescCB pfnDescCB; ZStatus_t stat; APSDE_DataReq_t req; afDataReqMTU_t mtu; // Verify source end point if ( srcEP == NULL ) { return afStatus_INVALID_PARAMETER; } #if !defined( REFLECTOR ) if ( dstAddr->addrMode == afAddrNotPresent ) { return afStatus_INVALID_PARAMETER; } #endif // Validate broadcasting if ( ( dstAddr->addrMode == afAddr16Bit ) || ( dstAddr->addrMode == afAddrBroadcast ) ) { // Check for valid broadcast values if( ADDR_NOT_BCAST != NLME_IsAddressBroadcast( dstAddr->addr.shortAddr ) ) { // Force mode to broadcast dstAddr->addrMode = afAddrBroadcast; } else { // Address is not a valid broadcast type if ( dstAddr->addrMode == afAddrBroadcast ) { return afStatus_INVALID_PARAMETER; } } } else if ( dstAddr->addrMode != afAddr64Bit && dstAddr->addrMode != afAddrGroup && dstAddr->addrMode != afAddrNotPresent ) { return afStatus_INVALID_PARAMETER; } // Set destination address req.dstAddr.addrMode = dstAddr->addrMode; if ( dstAddr->addrMode == afAddr64Bit ) osal_cpyExtAddr( req.dstAddr.addr.extAddr, dstAddr->addr.extAddr ); else req.dstAddr.addr.shortAddr = dstAddr->addr.shortAddr; req.profileID = ZDO_PROFILE_ID; if ( (pfnDescCB = afGetDescCB( srcEP )) ) { uint16 *pID = (uint16 *)(pfnDescCB( AF_DESCRIPTOR_PROFILE_ID, srcEP->endPoint )); if ( pID ) { req.profileID = *pID; osal_mem_free( pID ); } } else if ( srcEP->simpleDesc ) { req.profileID = srcEP->simpleDesc->AppProfId; } req.txOptions = 0; if ( ( options & AF_ACK_REQUEST ) && ( req.dstAddr.addrMode != AddrBroadcast ) && ( req.dstAddr.addrMode != AddrGroup ) ) { req.txOptions |= APS_TX_OPTIONS_ACK; } if ( options & AF_SKIP_ROUTING ) { req.txOptions |= APS_TX_OPTIONS_SKIP_ROUTING; } if ( options & AF_EN_SECURITY ) { req.txOptions |= APS_TX_OPTIONS_SECURITY_ENABLE; mtu.aps.secure = TRUE; } else { mtu.aps.secure = FALSE; } mtu.kvp = FALSE; req.transID = *transID; req.srcEP = srcEP->endPoint; req.dstEP = dstAddr->endPoint; req.clusterID = cID; req.asduLen = len; req.asdu = buf; req.discoverRoute = AF_DataRequestDiscoverRoute;//(uint8)((options & AF_DISCV_ROUTE) ? 1 : 0); req.radiusCounter = radius; #if defined ( INTER_PAN ) req.dstPanId = dstAddr->panId; if ( StubAPS_InterPan( dstAddr->panId, dstAddr->endPoint ) ) { if ( len > INTERP_DataReqMTU() ) { stat = afStatus_INVALID_PARAMETER; } else { stat = INTERP_DataReq( &req ); } } else #endif // INTER_PAN { if (len > afDataReqMTU( &mtu ) ) { if (apsfSendFragmented) { stat = (*apsfSendFragmented)( &req ); } else { stat = afStatus_INVALID_PARAMETER; } } else { stat = APSDE_DataReq( &req ); } } /* * If this is an EndPoint-to-EndPoint message on the same device, it will not * get added to the NWK databufs. So it will not go OTA and it will not get * a MACCB_DATA_CONFIRM_CMD callback. Thus it is necessary to generate the * AF_DATA_CONFIRM_CMD here. Note that APSDE_DataConfirm() only generates one * message with the first in line TransSeqNumber, even on a multi message. * Also note that a reflected msg will not have its confirmation generated * here. */ if ( (req.dstAddr.addrMode == Addr16Bit) && (req.dstAddr.addr.shortAddr == NLME_GetShortAddr()) ) { afDataConfirm( srcEP->endPoint, *transID, stat ); } if ( stat == afStatus_SUCCESS ) { (*transID)++; } return (afStatus_t)stat; }
/*************************************************************************************************** * @fn MT_AfIncomingMsg * * @brief Process the callback subscription for AF Incoming data. * * @param pkt - Incoming AF data. * * @return none ***************************************************************************************************/ 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); }
/****************************************************************************** * @fn INTERP_DataReq * * @brief This function requests the transfer of data from the next * higher layer to a single peer entity. * * @param req - APSDE_DataReq_t * * @return ZStatus_t */ ZStatus_t INTERP_DataReq( APSDE_DataReq_t *req ) { uint8 apsFrmCtrl; uint16 groupID = 0; uint8 *buf; uint8 hdrLen; ZMacDataReq_t dataReq; ZStatus_t status; if ( channelChangeInProgress || !StubAPS_InterPan( req->dstPanId, req->dstEP ) ) return ( ZFailure ); osal_memset( &dataReq, 0, sizeof( ZMacDataReq_t ) ); // Build Stub APS header status = StubAPS_BuildFrameControl( &apsFrmCtrl, &(dataReq.DstAddr), &groupID, req ); if ( status != ZSuccess ) return ( status ); // set default Stub APS header length hdrLen = APS_FRAME_CTRL_FIELD_LEN; // add group ID length if ( ( apsFrmCtrl & APS_DELIVERYMODE_MASK ) == APS_FC_DM_GROUP ) hdrLen += APS_GROUP_ID_FIELD_LEN; // add cluster ID length hdrLen += APS_CLUSTERID_FIELD_LEN; // add profile ID length hdrLen += APS_PROFILEID_FIELD_LEN; // add default Stub NWK header length hdrLen += STUB_NWK_HDR_LEN; // calculate MSDU length dataReq.msduLength = hdrLen + req->asduLen; // allocate buffer buf = osal_mem_alloc( dataReq.msduLength ); if ( buf != NULL ) { dataReq.msdu = buf; // Add Stub APS header and data StubAPS_BuildMsg( &buf[STUB_APS_HDR_FRAME_CTRL], apsFrmCtrl, groupID, req ); // Add Stub NWK header StubNWK_BuildMsg( buf ); // Set ZMac data request dataReq.DstPANId = req->dstPanId; dataReq.SrcAddrMode = Addr64Bit; dataReq.Handle = req->transID; if ( ( apsFrmCtrl & APS_DELIVERYMODE_MASK ) == APS_FC_DM_UNICAST ) dataReq.TxOptions = NWK_TXOPTIONS_ACK; else dataReq.TxOptions = 0; // send the frame status = ZMacDataReq( &dataReq ); // free the frame osal_mem_free( buf ); } else { // flag a memory error status = ZMemError; } return ( status ); } /* INTERP_DataReq */
/*************************************************************************************************** * @fn MT_AfIncomingMsg * * @brief Process the callback subscription for AF Incoming data. * * @param pkt - Incoming AF data. * * @return none ***************************************************************************************************/ void MT_AfIncomingMsg(afIncomingMSGPacket_t *pMsg) { uint8 dataLen = pMsg->cmd.DataLength; /* Length of the data section in the response packet */ uint8 respLen = 17 + dataLen; /* Length of the whole response packet */ uint8 cmd = MT_AF_INCOMING_MSG; uint8 *pRsp, *tempPtr; #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) { cmd = MT_AF_INCOMING_MSG_EXT; } if (cmd == MT_AF_INCOMING_MSG_EXT) { respLen += 9; } // Attempt to allocate memory for the response packet. if ((pRsp = osal_mem_alloc(respLen)) == NULL) { return; } tempPtr = pRsp; /* Fill in the data */ /* Group ID */ *tempPtr++ = LO_UINT16(pMsg->groupId); *tempPtr++ = HI_UINT16(pMsg->groupId); /* Cluster ID */ *tempPtr++ = LO_UINT16(pMsg->clusterId); *tempPtr++ = HI_UINT16(pMsg->clusterId); if (cmd == MT_AF_INCOMING_MSG_EXT) { *tempPtr++ = pMsg->srcAddr.addrMode; if (pMsg->srcAddr.addrMode == afAddr64Bit) { (void)osal_memcpy(tempPtr, pMsg->srcAddr.addr.extAddr, Z_EXTADDR_LEN); } else { tempPtr[0] = LO_UINT16(pMsg->srcAddr.addr.shortAddr); tempPtr[1] = HI_UINT16(pMsg->srcAddr.addr.shortAddr); } tempPtr += Z_EXTADDR_LEN; *tempPtr++ = pMsg->srcAddr.endPoint; #if defined INTER_PAN *tempPtr++ = LO_UINT16(pMsg->srcAddr.panId); *tempPtr++ = HI_UINT16(pMsg->srcAddr.panId); #else *tempPtr++ = 0; *tempPtr++ = 0; #endif } else { /* Source Address */ *tempPtr++ = LO_UINT16(pMsg->srcAddr.addr.shortAddr); *tempPtr++ = HI_UINT16(pMsg->srcAddr.addr.shortAddr); /* Source EP */ *tempPtr++ = pMsg->srcAddr.endPoint; } /* Destination EP */ *tempPtr++ = pMsg->endPoint; /* WasBroadCast */ *tempPtr++ = pMsg->wasBroadcast; /* LinkQuality */ *tempPtr++ = pMsg->LinkQuality; /* SecurityUse */ *tempPtr++ = pMsg->SecurityUse; /* Timestamp */ *tempPtr++ = BREAK_UINT32(pMsg->timestamp, 0); *tempPtr++ = BREAK_UINT32(pMsg->timestamp, 1); *tempPtr++ = BREAK_UINT32(pMsg->timestamp, 2); *tempPtr++ = BREAK_UINT32(pMsg->timestamp, 3); /* Transmit Sequence Number */ *tempPtr++ = pMsg->cmd.TransSeqNumber; /* Data Length */ *tempPtr++ = dataLen; /* Data */ if (dataLen) { osal_memcpy(tempPtr, 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); /* Free memory */ osal_mem_free(pRsp); }
afStatus_t AF_DataRequest( afAddrType_t *dstAddr, endPointDesc_t *srcEP, uint16 cID, uint16 len, uint8 *buf, uint8 *transID, uint8 options, uint8 radius ) { pDescCB pfnDescCB; ZStatus_t stat; APSDE_DataReq_t req; afDataReqMTU_t mtu; epList_t *pList; // Verify source end point if ( srcEP == NULL ) { return afStatus_INVALID_PARAMETER; } #if !defined( REFLECTOR ) if ( dstAddr->addrMode == afAddrNotPresent ) { return afStatus_INVALID_PARAMETER; } #endif // Check if route is available before sending data if ( options & AF_LIMIT_CONCENTRATOR ) { if ( dstAddr->addrMode != afAddr16Bit ) { return ( afStatus_INVALID_PARAMETER ); } // First, make sure the destination is not its self, then check for an existing route. if ( (dstAddr->addr.shortAddr != NLME_GetShortAddr()) && (RTG_CheckRtStatus( dstAddr->addr.shortAddr, RT_ACTIVE, (MTO_ROUTE | NO_ROUTE_CACHE) ) != RTG_SUCCESS) ) { // A valid route to a concentrator wasn't found return ( afStatus_NO_ROUTE ); } } // Validate broadcasting if ( ( dstAddr->addrMode == afAddr16Bit ) || ( dstAddr->addrMode == afAddrBroadcast ) ) { // Check for valid broadcast values if( ADDR_NOT_BCAST != NLME_IsAddressBroadcast( dstAddr->addr.shortAddr ) ) { // Force mode to broadcast dstAddr->addrMode = afAddrBroadcast; } else { // Address is not a valid broadcast type if ( dstAddr->addrMode == afAddrBroadcast ) { return afStatus_INVALID_PARAMETER; } } } else if ( dstAddr->addrMode != afAddr64Bit && dstAddr->addrMode != afAddrGroup && dstAddr->addrMode != afAddrNotPresent ) { return afStatus_INVALID_PARAMETER; } // Set destination address req.dstAddr.addrMode = dstAddr->addrMode; if ( dstAddr->addrMode == afAddr64Bit ) { osal_cpyExtAddr( req.dstAddr.addr.extAddr, dstAddr->addr.extAddr ); } else { req.dstAddr.addr.shortAddr = dstAddr->addr.shortAddr; } // This option is to use Wildcard ProfileID in outgoing packets if ( options & AF_WILDCARD_PROFILEID ) { req.profileID = ZDO_WILDCARD_PROFILE_ID; } else { req.profileID = ZDO_PROFILE_ID; if ( (pfnDescCB = afGetDescCB( srcEP )) ) { uint16 *pID = (uint16 *)(pfnDescCB( AF_DESCRIPTOR_PROFILE_ID, srcEP->endPoint )); if ( pID ) { req.profileID = *pID; osal_mem_free( pID ); } } else if ( srcEP->simpleDesc ) { req.profileID = srcEP->simpleDesc->AppProfId; } } req.txOptions = 0; if ( ( options & AF_ACK_REQUEST ) && ( req.dstAddr.addrMode != AddrBroadcast ) && ( req.dstAddr.addrMode != AddrGroup ) ) { req.txOptions |= APS_TX_OPTIONS_ACK; } if ( options & AF_SKIP_ROUTING ) { req.txOptions |= APS_TX_OPTIONS_SKIP_ROUTING; } if ( options & AF_EN_SECURITY ) { req.txOptions |= APS_TX_OPTIONS_SECURITY_ENABLE; mtu.aps.secure = TRUE; } else { mtu.aps.secure = FALSE; } if ( options & AF_PREPROCESS ) { req.txOptions |= APS_TX_OPTIONS_PREPROCESS; } mtu.kvp = FALSE; if ( options & AF_SUPRESS_ROUTE_DISC_NETWORK ) { req.discoverRoute = DISC_ROUTE_INITIATE; } else { req.discoverRoute = AF_DataRequestDiscoverRoute; } req.transID = *transID; req.srcEP = srcEP->endPoint; req.dstEP = dstAddr->endPoint; req.clusterID = cID; req.asduLen = len; req.asdu = buf; req.radiusCounter = radius; #if defined ( INTER_PAN ) req.dstPanId = dstAddr->panId; #endif // INTER_PAN // Look if there is a Callback function registered for this endpoint // The callback is used to control the AF Transaction ID used when sending messages pList = afFindEndPointDescList( srcEP->endPoint ); if ( ( pList != NULL ) && ( pList->pfnApplCB != NULL ) ) { pList->pfnApplCB( &req ); } #if defined ( INTER_PAN ) if ( StubAPS_InterPan( dstAddr->panId, dstAddr->endPoint ) ) { if ( len > INTERP_DataReqMTU() ) { stat = afStatus_INVALID_PARAMETER; } else { stat = INTERP_DataReq( &req ); } } else #endif // INTER_PAN { if (len > afDataReqMTU( &mtu ) ) { if (apsfSendFragmented) { stat = (*apsfSendFragmented)( &req ); } else { stat = afStatus_INVALID_PARAMETER; } } else { stat = APSDE_DataReq( &req ); } } /* * If this is an EndPoint-to-EndPoint message on the same device, it will not * get added to the NWK databufs. So it will not go OTA and it will not get * a MACCB_DATA_CONFIRM_CMD callback. Thus it is necessary to generate the * AF_DATA_CONFIRM_CMD here. Note that APSDE_DataConfirm() only generates one * message with the first in line TransSeqNumber, even on a multi message. * Also note that a reflected msg will not have its confirmation generated * here. */ if ( (req.dstAddr.addrMode == Addr16Bit) && (req.dstAddr.addr.shortAddr == NLME_GetShortAddr()) ) { afDataConfirm( srcEP->endPoint, *transID, stat ); } if ( stat == afStatus_SUCCESS ) { (*transID)++; } return (afStatus_t)stat; }