Example #1
0
// Cluster: Identify, server
EmberAfStatus emberAfIdentifyClusterServerCommandParse(EmberAfClusterCommand *cmd)
{
  boolean wasHandled = FALSE;
  if (!cmd->mfgSpecific) {
    switch (cmd->commandId) {
    case ZCL_IDENTIFY_COMMAND_ID:
      {
        int16u payloadOffset = cmd->payloadStartIndex;
        int16u identifyTime;  // Ver.: always
        // Command is fixed length: 2
        if (cmd->bufLen < payloadOffset + 2) return EMBER_ZCL_STATUS_MALFORMED_COMMAND;
        identifyTime = emberAfGetInt16u(cmd->buffer, payloadOffset, cmd->bufLen);
        wasHandled = emberAfIdentifyClusterIdentifyCallback(identifyTime);
        break;
      }
    case ZCL_IDENTIFY_QUERY_COMMAND_ID:
      {
        // Command is fixed length: 0
        wasHandled = emberAfIdentifyClusterIdentifyQueryCallback();
        break;
      }
    }
  }
  return status(wasHandled, cmd->mfgSpecific);
}
Example #2
0
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;
}
Example #3
0
bool emberAfGroupsClusterGetGroupMembershipResponseCallback(uint8_t capacity,
                                                               uint8_t groupCount,
                                                               uint8_t* groupList)
{
  uint8_t i;
  emberAfGroupsClusterPrint("RX: GetGroupMembershipResponse 0x%x, 0x%x,",
                            capacity,
                            groupCount);
  for (i = 0; i < groupCount; i++) {
    emberAfGroupsClusterPrint(" [0x%2x]",
                              emberAfGetInt16u(groupList + (i << 1), 0, 2));
  }
  emberAfGroupsClusterPrintln("");
   emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_SUCCESS);
  return true;
}
Example #4
0
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: 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);
}
// 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);
}
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;
}
Example #9
0
// 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);
}
Example #10
0
// 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);
}
Example #11
0
// 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);
}