// Cluster: ZLL Commissioning, server EmberAfStatus emberAfZllCommissioningClusterServerCommandParse(EmberAfClusterCommand *cmd) { boolean wasHandled = FALSE; if (!cmd->mfgSpecific) { switch (cmd->commandId) { case ZCL_GET_GROUP_IDENTIFIERS_REQUEST_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int8u startIndex; // Ver.: always // Command is fixed length: 1 if (cmd->bufLen < payloadOffset + 1) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; startIndex = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); wasHandled = emberAfZllCommissioningClusterGetGroupIdentifiersRequestCallback(startIndex); break; } case ZCL_GET_ENDPOINT_LIST_REQUEST_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int8u startIndex; // Ver.: always // Command is fixed length: 1 if (cmd->bufLen < payloadOffset + 1) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; startIndex = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); wasHandled = emberAfZllCommissioningClusterGetEndpointListRequestCallback(startIndex); break; } } } return status(wasHandled, cmd->mfgSpecific); }
bool emberAfEventsClusterPublishEventLogCallback(uint16_t totalNumberOfEvents, uint8_t commandIndex, uint8_t totalCommands, uint8_t logPayloadControl, uint8_t* logPayload) { emberAfEventsClusterPrint("RX: PublishEventLog 0x%2x, 0x%x, 0x%x, 0x%x", totalNumberOfEvents, commandIndex, totalCommands, logPayloadControl); #if defined(EMBER_AF_PRINT_ENABLE) && defined(EMBER_AF_PRINT_EVENTS_CLUSTER) uint16_t logPayloadLen = (emberAfCurrentCommand()->bufLen - (emberAfCurrentCommand()->payloadStartIndex + sizeof(totalNumberOfEvents) + sizeof(commandIndex) + sizeof(totalCommands) + sizeof(logPayloadControl))); uint16_t logPayloadIndex = 0; uint8_t i; if (NULL != logPayload) { for (i = 0; i < numberOfEvents(logPayloadControl); i++) { uint8_t logId; uint16_t eventId; uint32_t eventTime; uint8_t *eventData; uint8_t eventDataLen; logId = emberAfGetInt8u(logPayload, logPayloadIndex, logPayloadLen); logPayloadIndex++; eventId = emberAfGetInt16u(logPayload, logPayloadIndex, logPayloadLen); logPayloadIndex += 2; eventTime = emberAfGetInt32u(logPayload, logPayloadIndex, logPayloadLen); logPayloadIndex += 4; eventData = logPayload + logPayloadIndex; eventDataLen = emberAfGetInt8u(logPayload, logPayloadIndex, logPayloadLen); logPayloadIndex += (1 + eventDataLen); emberAfEventsClusterPrint(" ["); emberAfEventsClusterPrint("0x%x, 0x%2x, 0x%4x, 0x%x", logId, eventId, eventTime, eventDataLen); if (eventDataLen > 0) { emberAfEventsClusterPrint(", "); emberAfEventsClusterPrintString(eventData); } emberAfEventsClusterPrint("]"); } } emberAfEventsClusterPrintln(""); #endif // defined(EMBER_AF_PRINT_ENABLE) && defined(EMBER_AF_PRINT_EVENTS_CLUSTER) emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_SUCCESS); return true; }
// Cluster: Messaging, server EmberAfStatus emberAfMessagingClusterServerCommandParse(EmberAfClusterCommand *cmd) { boolean wasHandled = FALSE; if (!cmd->mfgSpecific) { switch (cmd->commandId) { case ZCL_GET_LAST_MESSAGE_COMMAND_ID: { // Command is fixed length: 0 wasHandled = emberAfMessagingClusterGetLastMessageCallback(); break; } case ZCL_MESSAGE_CONFIRMATION_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int32u messageId; // Ver.: always int32u confirmationTime; // Ver.: always int8u messageConfirmationControl; // Ver.: since se-1.2a-14-0256-03 int8u* messageResponse; // Ver.: since se-1.2a-14-0256-03 // Command is not a fixed length if (cmd->bufLen < payloadOffset + 4) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; messageId = emberAfGetInt32u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 4; if (cmd->bufLen < payloadOffset + 4) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; confirmationTime = emberAfGetInt32u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 4; if ( ( cmd->bufLen < payloadOffset + 1)) { // Argument is not always present: // - it is present only in versions higher than: se-1.2a-14-0256-03 messageConfirmationControl = 0xFF; } else { messageConfirmationControl = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 1; } if ( ( cmd->bufLen < payloadOffset + emberAfStringLength(cmd->buffer + payloadOffset) + 1)) { // Argument is not always present: // - it is present only in versions higher than: se-1.2a-14-0256-03 messageResponse = NULL; } else { messageResponse = emberAfGetString(cmd->buffer, payloadOffset, cmd->bufLen); } wasHandled = emberAfMessagingClusterMessageConfirmationCallback(messageId, confirmationTime, messageConfirmationControl, messageResponse); break; } } } return status(wasHandled, cmd->mfgSpecific); }
bool emberAfReportAttributesCallback(EmberAfClusterId clusterId, uint8_t *buffer, uint16_t bufLen) { EmberEUI64 sendersEui; uint16_t bufIndex = 0; uint8_t endpoint; uint8_t index; bool attributeReportingComplete = false; if (EMBER_SUCCESS != emberLookupEui64ByNodeId(emberAfCurrentCommand()->source, sendersEui)) { emberAfSimpleMeteringClusterPrintln("Error: Meter Mirror plugin cannot determine EUI64 for node ID 0x%2X", emberAfCurrentCommand()->source); emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_FAILURE); return true; } if (emberAfCurrentCommand()->direction == ZCL_DIRECTION_CLIENT_TO_SERVER) { emberAfSimpleMeteringClusterPrintln("Error: Meter Mirror Plugin does not accept client to server attributes.\n", emberAfCurrentCommand()->direction); emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_FAILURE); return true; } index = findMirrorIndex(sendersEui); if (index == INVALID_INDEX) { emberAfSimpleMeteringClusterPrint("Error: Meter mirror plugin received unknown report from "); emberAfPrintBigEndianEui64(sendersEui); emberAfSimpleMeteringClusterPrintln(""); emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_NOT_AUTHORIZED); return true; } if (emberAfCurrentCommand()->mfgSpecific) { // Here is where we could handle a MFG specific Report attributes and interpret // it. This code does not do that, just politely returns an error. emberAfSimpleMeteringClusterPrintln("Error: Unknown MFG Code for mirror: 0x%2X", emberAfCurrentCommand()->mfgCode); emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_UNSUP_MANUF_GENERAL_COMMAND); return true; } endpoint = (index + EMBER_AF_PLUGIN_METER_MIRROR_ENDPOINT_START); while (bufIndex + ATTRIBUTE_OVERHEAD < bufLen) { EmberAfStatus status; EmberAfAttributeId attributeId; EmberAfAttributeType dataType; uint8_t dataSize; attributeId = (EmberAfAttributeId)emberAfGetInt16u(buffer, bufIndex, bufLen); bufIndex += 2; dataType = (EmberAfAttributeType)emberAfGetInt8u(buffer, bufIndex, bufLen); bufIndex++; // For strings, the data size is the length of the string (specified by the // first byte of data) plus one for the length byte itself. For everything // else, the size is just the size of the data type. dataSize = (emberAfIsThisDataTypeAStringType(dataType) ? emberAfStringLength(buffer + bufIndex) + 1 : emberAfGetDataSize(dataType)); { #if (BIGENDIAN_CPU) uint8_t data[ATTRIBUTE_LARGEST]; if (isThisDataTypeSentLittleEndianOTA(dataType)) { emberReverseMemCopy(data, buffer + bufIndex, dataSize); } else { MEMMOVE(data, buffer + bufIndex, dataSize); } #else uint8_t *data = buffer + bufIndex; #endif if (attributeId == ZCL_ATTRIBUTE_REPORTING_STATUS_ATTRIBUTE_ID) { // From the SE 1.2a Specification within the ConfigureMirror command // description.. // 1. On powering up, the BOMD will send one or more Report Attribute // commands to the Metering client on the mirror endpoint. The last // attribute to be reported to the mirror shall be an Attribute // Reporting Status attribute, as defined in section A.2. // 2. If MirrorReportAttributeResponse is enabled, the server does not // need to request an APS ACK. If the server requests an APS ACK, // the Metering client on the mirror endpoint shall respond first // with an APS ACK and then send the MirrorReportAttributeResponse. // // If Mirror Notification Reporting is set to false, the // MirrorReportAttributeResponse command shall not be enabled; the // Metering server may poll the Notification flags by means of a normal // ReadAttribute command, as shown in Figure D 29: attributeReportingComplete = (data[0] == EMBER_ZCL_ATTRIBUTE_REPORTING_STATUS_ATTRIBUTE_REPORTING_COMPLETE); status = EMBER_ZCL_STATUS_SUCCESS; } else { if (attributeId == ZCL_METERING_DEVICE_TYPE_ATTRIBUTE_ID && data[0] < EMBER_ZCL_METERING_DEVICE_TYPE_MIRRORED_ELECTRIC_METERING) { data[0] += 127; } status = emberAfWriteServerAttribute(endpoint, clusterId, attributeId, data, dataType); } } emberAfSimpleMeteringClusterPrintln("Mirror attribute 0x%2x: 0x%x", attributeId, status); bufIndex += dataSize; } // If reporting is complete then callback to the application so that if it needs // to do any post processing on the reported attributes it can do it now. if (attributeReportingComplete) { emberAfPluginMeterMirrorReportingCompleteCallback(endpoint); } // Notification flags emberAfSimpleMeteringClusterPrintln("Mirror reporting ep: 0x%x, reporting: 0x%x, scheme: 0x%x", endpoint, mirrorList[index].mirrorNotificationReporting, mirrorList[index].notificationScheme); if (mirrorList[index].mirrorNotificationReporting && attributeReportingComplete) { if (mirrorList[index].notificationScheme == EMBER_ZCL_NOTIFICATION_SCHEME_PREDEFINED_NOTIFICATION_SCHEME_A || mirrorList[index].notificationScheme == EMBER_ZCL_NOTIFICATION_SCHEME_PREDEFINED_NOTIFICATION_SCHEME_B) { return sendMirrorReportAttributeResponse(endpoint, index); } else { // TODO: for custom notification schemes callback to application // return emberAfMeterMirrorSendMirrorReportAttributeResponseCallback(...) } } emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_SUCCESS); return true; }
// Cluster: Scenes, server EmberAfStatus emberAfScenesClusterServerCommandParse(EmberAfClusterCommand *cmd) { boolean wasHandled = FALSE; if (!cmd->mfgSpecific) { switch (cmd->commandId) { case ZCL_ADD_SCENE_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int16u groupId; // Ver.: always int8u sceneId; // Ver.: always int16u transitionTime; // Ver.: always int8u* sceneName; // Ver.: always int8u* extensionFieldSets; // Ver.: always // Command is not a fixed length if (cmd->bufLen < payloadOffset + 2) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; groupId = emberAfGetInt16u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 2; if (cmd->bufLen < payloadOffset + 1) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; sceneId = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 1; if (cmd->bufLen < payloadOffset + 2) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; transitionTime = emberAfGetInt16u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 2; if (cmd->bufLen < payloadOffset + emberAfStringLength(cmd->buffer + payloadOffset) + 1) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; sceneName = emberAfGetString(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += emberAfStringLength(cmd->buffer + payloadOffset) + 1; extensionFieldSets = cmd->buffer + payloadOffset; wasHandled = emberAfScenesClusterAddSceneCallback(groupId, sceneId, transitionTime, sceneName, extensionFieldSets); break; } case ZCL_VIEW_SCENE_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int16u groupId; // Ver.: always int8u sceneId; // Ver.: always // Command is fixed length: 3 if (cmd->bufLen < payloadOffset + 3) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; groupId = emberAfGetInt16u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 2; sceneId = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); wasHandled = emberAfScenesClusterViewSceneCallback(groupId, sceneId); break; } case ZCL_REMOVE_SCENE_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int16u groupId; // Ver.: always int8u sceneId; // Ver.: always // Command is fixed length: 3 if (cmd->bufLen < payloadOffset + 3) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; groupId = emberAfGetInt16u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 2; sceneId = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); wasHandled = emberAfScenesClusterRemoveSceneCallback(groupId, sceneId); break; } case ZCL_REMOVE_ALL_SCENES_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int16u groupId; // Ver.: always // Command is fixed length: 2 if (cmd->bufLen < payloadOffset + 2) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; groupId = emberAfGetInt16u(cmd->buffer, payloadOffset, cmd->bufLen); wasHandled = emberAfScenesClusterRemoveAllScenesCallback(groupId); break; } case ZCL_STORE_SCENE_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int16u groupId; // Ver.: always int8u sceneId; // Ver.: always // Command is fixed length: 3 if (cmd->bufLen < payloadOffset + 3) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; groupId = emberAfGetInt16u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 2; sceneId = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); wasHandled = emberAfScenesClusterStoreSceneCallback(groupId, sceneId); break; } case ZCL_RECALL_SCENE_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int16u groupId; // Ver.: always int8u sceneId; // Ver.: always // Command is fixed length: 3 if (cmd->bufLen < payloadOffset + 3) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; groupId = emberAfGetInt16u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 2; sceneId = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); wasHandled = emberAfScenesClusterRecallSceneCallback(groupId, sceneId); break; } case ZCL_GET_SCENE_MEMBERSHIP_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int16u groupId; // Ver.: always // Command is fixed length: 2 if (cmd->bufLen < payloadOffset + 2) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; groupId = emberAfGetInt16u(cmd->buffer, payloadOffset, cmd->bufLen); wasHandled = emberAfScenesClusterGetSceneMembershipCallback( groupId); break; } } } return status(wasHandled, cmd->mfgSpecific); }
// Cluster: Groups, server EmberAfStatus emberAfGroupsClusterServerCommandParse(EmberAfClusterCommand *cmd) { boolean wasHandled = FALSE; if (!cmd->mfgSpecific) { switch (cmd->commandId) { case ZCL_ADD_GROUP_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int16u groupId; // Ver.: always int8u* groupName; // Ver.: always // Command is not a fixed length if (cmd->bufLen < payloadOffset + 2) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; groupId = emberAfGetInt16u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 2; if (cmd->bufLen < payloadOffset + emberAfStringLength(cmd->buffer + payloadOffset) + 1) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; groupName = emberAfGetString(cmd->buffer, payloadOffset, cmd->bufLen); wasHandled = emberAfGroupsClusterAddGroupCallback(groupId, groupName); break; } case ZCL_VIEW_GROUP_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int16u groupId; // Ver.: always // Command is fixed length: 2 if (cmd->bufLen < payloadOffset + 2) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; groupId = emberAfGetInt16u(cmd->buffer, payloadOffset, cmd->bufLen); wasHandled = emberAfGroupsClusterViewGroupCallback(groupId); break; } case ZCL_GET_GROUP_MEMBERSHIP_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int8u groupCount; // Ver.: always int8u* groupList; // Ver.: always // Command is fixed length: 1 if (cmd->bufLen < payloadOffset + 1) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; groupCount = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 1; groupList = cmd->buffer + payloadOffset; wasHandled = emberAfGroupsClusterGetGroupMembershipCallback( groupCount, groupList); break; } case ZCL_REMOVE_GROUP_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int16u groupId; // Ver.: always // Command is fixed length: 2 if (cmd->bufLen < payloadOffset + 2) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; groupId = emberAfGetInt16u(cmd->buffer, payloadOffset, cmd->bufLen); wasHandled = emberAfGroupsClusterRemoveGroupCallback(groupId); break; } case ZCL_REMOVE_ALL_GROUPS_COMMAND_ID: { // Command is fixed length: 0 wasHandled = emberAfGroupsClusterRemoveAllGroupsCallback(); break; } case ZCL_ADD_GROUP_IF_IDENTIFYING_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int16u groupId; // Ver.: always int8u* groupName; // Ver.: always // Command is not a fixed length if (cmd->bufLen < payloadOffset + 2) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; groupId = emberAfGetInt16u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 2; if (cmd->bufLen < payloadOffset + emberAfStringLength(cmd->buffer + payloadOffset) + 1) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; groupName = emberAfGetString(cmd->buffer, payloadOffset, cmd->bufLen); wasHandled = emberAfGroupsClusterAddGroupIfIdentifyingCallback( groupId, groupName); break; } } } return status(wasHandled, cmd->mfgSpecific); }
static void deviceInformationResponseHandler(const EmberEUI64 source, uint32_t transaction, uint8_t numberOfSubDevices, uint8_t startIndex, uint8_t deviceInformationRecordCount, uint8_t *deviceInformationRecordList) { uint16_t deviceInformationRecordListLen = (deviceInformationRecordCount * ZLL_DEVICE_INFORMATION_RECORD_SIZE); uint16_t deviceInformationRecordListIndex = 0; uint8_t i; bool validResponse = (emberEventControlGetActive(emberAfPluginZllCommissioningTouchLinkEventControl) && (network.securityAlgorithm.transactionId == transaction) && MEMCOMPARE(network.eui64, source, EUI64_SIZE) == 0); emberAfZllCommissioningClusterFlush(); emberAfZllCommissioningClusterPrint("RX: DeviceInformationResponse 0x%4x, 0x%x, 0x%x, 0x%x,", transaction, numberOfSubDevices, startIndex, deviceInformationRecordCount); emberAfZllCommissioningClusterFlush(); for (i = 0; i < deviceInformationRecordCount; i++) { uint8_t *ieeeAddress; uint8_t endpointId; uint16_t profileId; uint16_t deviceId; uint8_t version; uint8_t groupIdCount; uint8_t sort; ieeeAddress = &deviceInformationRecordList[deviceInformationRecordListIndex]; deviceInformationRecordListIndex += EUI64_SIZE; endpointId = emberAfGetInt8u(deviceInformationRecordList, deviceInformationRecordListIndex, deviceInformationRecordListLen); deviceInformationRecordListIndex++; profileId = emberAfGetInt16u(deviceInformationRecordList, deviceInformationRecordListIndex, deviceInformationRecordListLen); deviceInformationRecordListIndex += 2; deviceId = emberAfGetInt16u(deviceInformationRecordList, deviceInformationRecordListIndex, deviceInformationRecordListLen); deviceInformationRecordListIndex += 2; version = emberAfGetInt8u(deviceInformationRecordList, deviceInformationRecordListIndex, deviceInformationRecordListLen); deviceInformationRecordListIndex++; groupIdCount = emberAfGetInt8u(deviceInformationRecordList, deviceInformationRecordListIndex, deviceInformationRecordListLen); deviceInformationRecordListIndex++; sort = emberAfGetInt8u(deviceInformationRecordList, deviceInformationRecordListIndex, deviceInformationRecordListLen); deviceInformationRecordListIndex++; emberAfZllCommissioningClusterPrint(" ["); emberAfZllCommissioningClusterDebugExec(emberAfPrintBigEndianEui64(ieeeAddress)); emberAfZllCommissioningClusterPrint(" 0x%x 0x%2x 0x%2x 0x%x 0x%x 0x%x", endpointId, profileId, deviceId, version, groupIdCount, sort); emberAfZllCommissioningClusterFlush(); if (validResponse && (subDeviceCount < EMBER_AF_PLUGIN_ZLL_COMMISSIONING_SUB_DEVICE_TABLE_SIZE)) { MEMMOVE(subDevices[subDeviceCount].ieeeAddress, ieeeAddress, EUI64_SIZE); subDevices[subDeviceCount].endpointId = endpointId; subDevices[subDeviceCount].profileId = profileId; subDevices[subDeviceCount].deviceId = deviceId; subDevices[subDeviceCount].version = version; subDevices[subDeviceCount].groupIdCount = groupIdCount; subDeviceCount++; } else { emberAfZllCommissioningClusterPrint(" (ignored)"); } emberAfZllCommissioningClusterPrint("]"); emberAfZllCommissioningClusterFlush(); } emberAfZllCommissioningClusterPrintln(""); if (validResponse && (subDeviceCount < EMBER_AF_PLUGIN_ZLL_COMMISSIONING_SUB_DEVICE_TABLE_SIZE) && subDeviceCount < numberOfSubDevices) { sendDeviceInformationRequest(startIndex + deviceInformationRecordCount); } }
bool emberAfPluginInterpanPreMessageReceivedCallback(const EmberAfInterpanHeader *header, uint8_t msgLen, uint8_t *message) { uint32_t transaction; uint8_t frameControl, commandId, msgIndex; // If the message isn't for the ZLL Commissioning cluster, drop it with an // indication that we didn't handle it. After this, everything else will be // considered handled so that the message doesn't end up going through the // normal ZCL processing. if (header->profileId != EMBER_ZLL_PROFILE_ID || header->clusterId != ZCL_ZLL_COMMISSIONING_CLUSTER_ID) { return false; } if (header->messageType != EMBER_AF_INTER_PAN_UNICAST || !(header->options & EMBER_AF_INTERPAN_OPTION_MAC_HAS_LONG_ADDRESS) || msgLen < ZLL_HEADER_OVERHEAD) { return true; } // Verify that the frame control byte makes sense. Accept only the legacy // format or simple client-to-server or server-to-client messages (i.e., no // manufacturer-specific commands, etc.) For non-legacy messages, check that // the frame control is correct for the command. The check is based on // DeviceInformationResponse because it is the only server-to-client command // we care about. frameControl = message[ZLL_HEADER_FRAME_CONTROL_OFFSET]; commandId = message[ZLL_HEADER_COMMAND_ID_OFFSET]; if (frameControl != ZLL_FRAME_CONTROL_LEGACY && (frameControl != ZLL_FRAME_CONTROL_CLIENT_TO_SERVER || commandId == ZCL_DEVICE_INFORMATION_RESPONSE_COMMAND_ID) && (frameControl != ZLL_FRAME_CONTROL_SERVER_TO_CLIENT || commandId != ZCL_DEVICE_INFORMATION_RESPONSE_COMMAND_ID)) { return true; } msgIndex = ZLL_HEADER_TRANSACTION_ID_OFFSET; transaction = emberAfGetInt32u(message, msgIndex, msgLen); msgIndex += 4; switch (commandId) { case ZCL_DEVICE_INFORMATION_REQUEST_COMMAND_ID: if (msgIndex + 1 <= msgLen) { uint8_t startIndex = emberAfGetInt8u(message, msgIndex, msgLen); deviceInformationRequestHandler(header->longAddress, transaction, startIndex); } break; #ifdef EMBER_AF_PLUGIN_ZLL_COMMISSIONING_LINK_INITIATOR case ZCL_DEVICE_INFORMATION_RESPONSE_COMMAND_ID: if (msgIndex + 3 <= msgLen) { uint8_t numberOfSubDevices, startIndex, deviceInformationRecordCount; numberOfSubDevices = emberAfGetInt8u(message, msgIndex, msgLen); msgIndex++; startIndex = emberAfGetInt8u(message, msgIndex, msgLen); msgIndex++; deviceInformationRecordCount = emberAfGetInt8u(message, msgIndex, msgLen); msgIndex++; if ((msgIndex + deviceInformationRecordCount * ZLL_DEVICE_INFORMATION_RECORD_SIZE) <= msgLen) { uint8_t *deviceInformationRecordList = message + msgIndex; deviceInformationResponseHandler(header->longAddress, transaction, numberOfSubDevices, startIndex, deviceInformationRecordCount, deviceInformationRecordList); } } break; #endif //EMBER_AF_PLUGIN_ZLL_COMMISSIONING_LINK_INITIATOR case ZCL_IDENTIFY_REQUEST_COMMAND_ID: if (msgIndex + 2 <= msgLen) { uint16_t identifyDurationS = emberAfGetInt16u(message, msgIndex, msgLen); identifyRequestHandler(header->longAddress, transaction, identifyDurationS); } break; case ZCL_RESET_TO_FACTORY_NEW_REQUEST_COMMAND_ID: resetToFactoryNewRequestHandler(header->longAddress, transaction); break; } // All ZLL Commissioning cluster messages are considered handled, even if we // ended up dropping them because they were malformed, etc. return true; }
// Cluster: Price, server EmberAfStatus emberAfPriceClusterServerCommandParse(EmberAfClusterCommand *cmd) { boolean wasHandled = FALSE; if (!cmd->mfgSpecific) { switch (cmd->commandId) { case ZCL_GET_CURRENT_PRICE_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int8u commandOptions; // Ver.: always // Command is fixed length: 1 if (cmd->bufLen < payloadOffset + 1) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; commandOptions = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); wasHandled = emberAfPriceClusterGetCurrentPriceCallback(commandOptions); break; } case ZCL_GET_SCHEDULED_PRICES_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int32u startTime; // Ver.: always int8u numberOfEvents; // Ver.: always // Command is fixed length: 5 if (cmd->bufLen < payloadOffset + 5) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; startTime = emberAfGetInt32u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 4; numberOfEvents = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); wasHandled = emberAfPriceClusterGetScheduledPricesCallback(startTime, numberOfEvents); break; } case ZCL_GET_TARIFF_INFORMATION_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int32u earliestStartTime; // Ver.: always int32u minIssuerEventId; // Ver.: always int8u numberOfCommands; // Ver.: always int8u tariffType; // Ver.: always // Command is fixed length: 10 if (cmd->bufLen < payloadOffset + 10) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; earliestStartTime = emberAfGetInt32u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 4; minIssuerEventId = emberAfGetInt32u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 4; numberOfCommands = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 1; tariffType = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); wasHandled = emberAfPriceClusterGetTariffInformationCallback(earliestStartTime, minIssuerEventId, numberOfCommands, tariffType); break; } case ZCL_GET_PRICE_MATRIX_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int32u issuerTariffId; // Ver.: always // Command is fixed length: 4 if (cmd->bufLen < payloadOffset + 4) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; issuerTariffId = emberAfGetInt32u(cmd->buffer, payloadOffset, cmd->bufLen); wasHandled = emberAfPriceClusterGetPriceMatrixCallback(issuerTariffId); break; } } } return status(wasHandled, cmd->mfgSpecific); }
// Cluster: Key Establishment, server EmberAfStatus emberAfKeyEstablishmentClusterServerCommandParse(EmberAfClusterCommand *cmd) { boolean wasHandled = FALSE; if (!cmd->mfgSpecific) { switch (cmd->commandId) { case ZCL_INITIATE_KEY_ESTABLISHMENT_REQUEST_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int16u keyEstablishmentSuite; // Ver.: always int8u ephemeralDataGenerateTime; // Ver.: always int8u confirmKeyGenerateTime; // Ver.: always int8u* identity; // Ver.: always // Command is fixed length: 52 if (cmd->bufLen < payloadOffset + 52) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; keyEstablishmentSuite = emberAfGetInt16u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 2; ephemeralDataGenerateTime = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 1; confirmKeyGenerateTime = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 1; identity = cmd->buffer + payloadOffset; wasHandled = emberAfKeyEstablishmentClusterInitiateKeyEstablishmentRequestCallback(keyEstablishmentSuite, ephemeralDataGenerateTime, confirmKeyGenerateTime, identity); break; } case ZCL_EPHEMERAL_DATA_REQUEST_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int8u* ephemeralData; // Ver.: always // Command is fixed length: 22 if (cmd->bufLen < payloadOffset + 22) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; ephemeralData = cmd->buffer + payloadOffset; wasHandled = emberAfKeyEstablishmentClusterEphemeralDataRequestCallback(ephemeralData); break; } case ZCL_CONFIRM_KEY_DATA_REQUEST_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int8u* secureMessageAuthenticationCode; // Ver.: always // Command is fixed length: 16 if (cmd->bufLen < payloadOffset + 16) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; secureMessageAuthenticationCode = cmd->buffer + payloadOffset; wasHandled = emberAfKeyEstablishmentClusterConfirmKeyDataRequestCallback(secureMessageAuthenticationCode); break; } case ZCL_TERMINATE_KEY_ESTABLISHMENT_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int8u statusCode; // Ver.: always int8u waitTime; // Ver.: always int16u keyEstablishmentSuite; // Ver.: always // Command is fixed length: 4 if (cmd->bufLen < payloadOffset + 4) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; statusCode = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 1; waitTime = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 1; keyEstablishmentSuite = emberAfGetInt16u(cmd->buffer, payloadOffset, cmd->bufLen); wasHandled = emberAfKeyEstablishmentClusterTerminateKeyEstablishmentCallback(statusCode, waitTime, keyEstablishmentSuite); break; } } } return status(wasHandled, cmd->mfgSpecific); }
// Cluster: Tunneling, server EmberAfStatus emberAfTunnelingClusterServerCommandParse(EmberAfClusterCommand *cmd) { boolean wasHandled = FALSE; if (!cmd->mfgSpecific) { switch (cmd->commandId) { case ZCL_REQUEST_TUNNEL_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int8u protocolId; // Ver.: always int16u manufacturerCode; // Ver.: always int8u flowControlSupport; // Ver.: always int16u maximumIncomingTransferSize; // Ver.: since se-1.1a-07-5356-17 // Command is not a fixed length if (cmd->bufLen < payloadOffset + 1) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; protocolId = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 1; if (cmd->bufLen < payloadOffset + 2) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; manufacturerCode = emberAfGetInt16u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 2; if (cmd->bufLen < payloadOffset + 1) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; flowControlSupport = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 1; if ( ( cmd->bufLen < payloadOffset + 2)) { // Argument is not always present: // - it is present only in versions higher than: se-1.1a-07-5356-17 maximumIncomingTransferSize = 0xFFFF; } else { maximumIncomingTransferSize = emberAfGetInt16u(cmd->buffer, payloadOffset, cmd->bufLen); } wasHandled = emberAfTunnelingClusterRequestTunnelCallback(protocolId, manufacturerCode, flowControlSupport, maximumIncomingTransferSize); break; } case ZCL_CLOSE_TUNNEL_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int16u tunnelId; // Ver.: always // Command is fixed length: 2 if (cmd->bufLen < payloadOffset + 2) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; tunnelId = emberAfGetInt16u(cmd->buffer, payloadOffset, cmd->bufLen); wasHandled = emberAfTunnelingClusterCloseTunnelCallback(tunnelId); break; } case ZCL_TRANSFER_DATA_CLIENT_TO_SERVER_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int16u tunnelId; // Ver.: always int8u* data; // Ver.: always // Command is fixed length: 2 if (cmd->bufLen < payloadOffset + 2) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; tunnelId = emberAfGetInt16u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 2; data = cmd->buffer + payloadOffset; wasHandled = emberAfTunnelingClusterTransferDataClientToServerCallback(tunnelId, data); break; } case ZCL_TRANSFER_DATA_ERROR_CLIENT_TO_SERVER_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int16u tunnelId; // Ver.: always int8u transferDataStatus; // Ver.: always // Command is fixed length: 3 if (cmd->bufLen < payloadOffset + 3) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; tunnelId = emberAfGetInt16u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 2; transferDataStatus = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); wasHandled = emberAfTunnelingClusterTransferDataErrorClientToServerCallback(tunnelId, transferDataStatus); break; } } } return status(wasHandled, cmd->mfgSpecific); }
// Cluster: Simple Metering, server EmberAfStatus emberAfSimpleMeteringClusterServerCommandParse(EmberAfClusterCommand *cmd) { boolean wasHandled = FALSE; if (!cmd->mfgSpecific) { switch (cmd->commandId) { case ZCL_GET_PROFILE_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int8u intervalChannel; // Ver.: always int32u endTime; // Ver.: always int8u numberOfPeriods; // Ver.: always // Command is fixed length: 6 if (cmd->bufLen < payloadOffset + 6) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; intervalChannel = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 1; endTime = emberAfGetInt32u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 4; numberOfPeriods = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); wasHandled = emberAfSimpleMeteringClusterGetProfileCallback(intervalChannel, endTime, numberOfPeriods); break; } case ZCL_REQUEST_FAST_POLL_MODE_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int8u fastPollUpdatePeriod; // Ver.: always int8u duration; // Ver.: always // Command is fixed length: 2 if (cmd->bufLen < payloadOffset + 2) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; fastPollUpdatePeriod = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 1; duration = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); wasHandled = emberAfSimpleMeteringClusterRequestFastPollModeCallback(fastPollUpdatePeriod, duration); break; } case ZCL_SCHEDULE_SNAPSHOT_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int32u issuerEventId; // Ver.: always int8u commandIndex; // Ver.: always int8u commandCount; // Ver.: always int8u* snapshotSchedulePayload; // Ver.: always // Command is fixed length: 6 if (cmd->bufLen < payloadOffset + 6) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; issuerEventId = emberAfGetInt32u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 4; commandIndex = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 1; commandCount = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 1; snapshotSchedulePayload = cmd->buffer + payloadOffset; wasHandled = emberAfSimpleMeteringClusterScheduleSnapshotCallback(issuerEventId, commandIndex, commandCount, snapshotSchedulePayload); break; } case ZCL_TAKE_SNAPSHOT_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int32u snapshotCause; // Ver.: always // Command is fixed length: 4 if (cmd->bufLen < payloadOffset + 4) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; snapshotCause = emberAfGetInt32u(cmd->buffer, payloadOffset, cmd->bufLen); wasHandled = emberAfSimpleMeteringClusterTakeSnapshotCallback(snapshotCause); break; } case ZCL_GET_SNAPSHOT_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int32u earliestStartTime; // Ver.: always int32u latestEndTime; // Ver.: always int8u snapshotOffset; // Ver.: always int32u snapshotCause; // Ver.: always // Command is fixed length: 13 if (cmd->bufLen < payloadOffset + 13) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; earliestStartTime = emberAfGetInt32u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 4; latestEndTime = emberAfGetInt32u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 4; snapshotOffset = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 1; snapshotCause = emberAfGetInt32u(cmd->buffer, payloadOffset, cmd->bufLen); wasHandled = emberAfSimpleMeteringClusterGetSnapshotCallback(earliestStartTime, latestEndTime, snapshotOffset, snapshotCause); break; } } } return status(wasHandled, cmd->mfgSpecific); }
// Cluster: Simple Metering, client EmberAfStatus emberAfSimpleMeteringClusterClientCommandParse(EmberAfClusterCommand *cmd) { boolean wasHandled = FALSE; if (!cmd->mfgSpecific) { switch (cmd->commandId) { case ZCL_GET_PROFILE_RESPONSE_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int32u endTime; // Ver.: always int8u status; // Ver.: always int8u profileIntervalPeriod; // Ver.: always int8u numberOfPeriodsDelivered; // Ver.: always int8u* intervals; // Ver.: always // Command is fixed length: 7 if (cmd->bufLen < payloadOffset + 7) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; endTime = emberAfGetInt32u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 4; status = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 1; profileIntervalPeriod = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 1; numberOfPeriodsDelivered = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 1; intervals = cmd->buffer + payloadOffset; wasHandled = emberAfSimpleMeteringClusterGetProfileResponseCallback(endTime, status, profileIntervalPeriod, numberOfPeriodsDelivered, intervals); break; } case ZCL_REQUEST_MIRROR_COMMAND_ID: { // Command is fixed length: 0 wasHandled = emberAfSimpleMeteringClusterRequestMirrorCallback(); break; } case ZCL_REMOVE_MIRROR_COMMAND_ID: { // Command is fixed length: 0 wasHandled = emberAfSimpleMeteringClusterRemoveMirrorCallback(); break; } case ZCL_REQUEST_FAST_POLL_MODE_RESPONSE_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int8u appliedUpdatePeriod; // Ver.: always int32u fastPollModeEndtime; // Ver.: always // Command is fixed length: 5 if (cmd->bufLen < payloadOffset + 5) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; appliedUpdatePeriod = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 1; fastPollModeEndtime = emberAfGetInt32u(cmd->buffer, payloadOffset, cmd->bufLen); wasHandled = emberAfSimpleMeteringClusterRequestFastPollModeResponseCallback(appliedUpdatePeriod, fastPollModeEndtime); break; } case ZCL_CONFIGURE_MIRROR_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int32u issuerEventId; // Ver.: always int32u reportingInterval; // Ver.: always int8u mirrorNotificationReporting; // Ver.: always int8u notificationScheme; // Ver.: always // Command is fixed length: 9 if (cmd->bufLen < payloadOffset + 9) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; issuerEventId = emberAfGetInt32u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 4; reportingInterval = emberAfGetInt24u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 3; mirrorNotificationReporting = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 1; notificationScheme = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); wasHandled = emberAfSimpleMeteringClusterConfigureMirrorCallback(issuerEventId, reportingInterval, mirrorNotificationReporting, notificationScheme); break; } } } return status(wasHandled, cmd->mfgSpecific); }
// Cluster: ZLL Commissioning, client EmberAfStatus emberAfZllCommissioningClusterClientCommandParse(EmberAfClusterCommand *cmd) { boolean wasHandled = FALSE; if (!cmd->mfgSpecific) { switch (cmd->commandId) { case ZCL_ENDPOINT_INFORMATION_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int8u* ieeeAddress; // Ver.: always int16u networkAddress; // Ver.: always int8u endpointId; // Ver.: always int16u profileId; // Ver.: always int16u deviceId; // Ver.: always int8u version; // Ver.: always // Command is fixed length: 16 if (cmd->bufLen < payloadOffset + 16) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; ieeeAddress = cmd->buffer + payloadOffset; payloadOffset += 8; networkAddress = emberAfGetInt16u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 2; endpointId = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 1; profileId = emberAfGetInt16u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 2; deviceId = emberAfGetInt16u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 2; version = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); wasHandled = emberAfZllCommissioningClusterEndpointInformationCallback(ieeeAddress, networkAddress, endpointId, profileId, deviceId, version); break; } case ZCL_GET_GROUP_IDENTIFIERS_RESPONSE_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int8u total; // Ver.: always int8u startIndex; // Ver.: always int8u count; // Ver.: always int8u* groupInformationRecordList; // Ver.: always // Command is fixed length: 3 if (cmd->bufLen < payloadOffset + 3) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; total = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 1; startIndex = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 1; count = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 1; groupInformationRecordList = cmd->buffer + payloadOffset; wasHandled = emberAfZllCommissioningClusterGetGroupIdentifiersResponseCallback(total, startIndex, count, groupInformationRecordList); break; } case ZCL_GET_ENDPOINT_LIST_RESPONSE_COMMAND_ID: { int16u payloadOffset = cmd->payloadStartIndex; int8u total; // Ver.: always int8u startIndex; // Ver.: always int8u count; // Ver.: always int8u* endpointInformationRecordList; // Ver.: always // Command is fixed length: 3 if (cmd->bufLen < payloadOffset + 3) return EMBER_ZCL_STATUS_MALFORMED_COMMAND; total = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 1; startIndex = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 1; count = emberAfGetInt8u(cmd->buffer, payloadOffset, cmd->bufLen); payloadOffset += 1; endpointInformationRecordList = cmd->buffer + payloadOffset; wasHandled = emberAfZllCommissioningClusterGetEndpointListResponseCallback(total, startIndex, count, endpointInformationRecordList); break; } } } return status(wasHandled, cmd->mfgSpecific); }