bool emberAfEventsClusterPublishEventCallback(uint8_t logId, uint16_t eventId, uint32_t eventTime, uint8_t eventControl, uint8_t* eventData) { emberAfEventsClusterPrint("RX: PublishEvent 0x%x, 0x%2x, 0x%4x, 0x%x, 0x%x", logId, eventId, eventTime, eventControl, *eventData); #if defined(EMBER_AF_PRINT_ENABLE) && defined(EMBER_AF_PRINT_EVENTS_CLUSTER) uint8_t eventDataLen = emberAfStringLength(eventData); if (eventDataLen > 0) { emberAfEventsClusterPrint(", "); emberAfEventsClusterPrintString(eventData); } 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); }