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;
}
/** @brief Identify Cluster Identify Query Response
 *
 *
 *
 * @param timeout   Ver.: always
 */
boolean emberAfIdentifyClusterIdentifyQueryResponseCallback(int16u timeout) {
  // TODO: !!! IMPORTANT !!! add  handling for several responses
  // now the state machine might be broken as we use only one global variable
  // for storing incoming connection information like Short ID and endpoint
  //
  // ignore broadcasts from yourself and from devices that are not
  // in the identifying state
  const EmberAfClusterCommand *const current_cmd = emberAfCurrentCommand();
  if (emberAfGetNodeId() != current_cmd->source && timeout != 0) {
    emberAfDebugPrintln("DEBUG: Got ID Query response");
    emberAfDebugPrintln("DEBUG: Sender 0x%2X", emberAfCurrentCommand()->source);
    // Queue is empty, so we can start commissioning process
    // otherwise we push it in the queue and will process later
    if (GetQueueSize() == 0) {
      // ID Query received -> go to the discover state for getting clusters info
      emberAfDebugPrintln("DEBUG: QUEUE IS EMPTY");
      SetNextState(SC_EZ_DISCOVER);
      SetNextEvent(SC_EZEV_CHECK_CLUSTERS);
      emberEventControlSetActive(StateMachineEvent);
    }
    // Store information about endpoint and short ID of the incoming response
    // for further processing in the Matching (SC_EZ_MATCH) state
    SetInConnBaseInfo(current_cmd->source,
                      current_cmd->apsFrame->sourceEndpoint);
    emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_SUCCESS);
  }

  return TRUE;
}
bool emberAfEventsClusterClearEventLogResponseCallback(uint8_t clearedEventsLogs)
{
  emberAfEventsClusterPrintln("RX: ClearEventLogResponse 0x%x",
                              clearedEventsLogs);

  emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_SUCCESS);
  return true;
}
Beispiel #4
0
bool emberAfBasicClusterResetToFactoryDefaultsCallback(void)
{
  emberAfBasicClusterPrintln("RX: ResetToFactoryDefaultsCallback");
  emberAfResetAttributes(emberAfCurrentEndpoint());
  emberAfPluginBasicResetToFactoryDefaultsCallback(emberAfCurrentEndpoint());
  emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_SUCCESS);
  return true;
}
bool emberAfGroupsClusterAddGroupResponseCallback(uint8_t status,
                                                     uint16_t groupId)
{
  emberAfGroupsClusterPrintln("RX: AddGroupResponse 0x%x, 0x%2x",
                              status,
                              groupId);
  emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_SUCCESS);
  return true;
}
bool emberAfScenesClusterCopySceneResponseCallback(uint8_t status,
                                                      uint16_t groupIdFrom,
                                                      uint8_t sceneIdFrom)
{
  emberAfScenesClusterPrintln("RX: CopySceneResponse 0x%x, 0x%2x, 0x%x",
                              status,
                              groupIdFrom,
                              sceneIdFrom);
  emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_SUCCESS);
  return true;
}
bool emberAfGroupsClusterViewGroupResponseCallback(uint8_t status,
                                                      uint16_t groupId,
                                                      uint8_t* groupName)
{
  emberAfGroupsClusterPrint("RX: ViewGroupResponse 0x%x, 0x%2x, \"",
                            status,
                            groupId);
  emberAfGroupsClusterPrintString(groupName);
  emberAfGroupsClusterPrintln("\"");
   emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_SUCCESS);
  return true;
}
bool emberAfMessagingClusterMessageConfirmationCallback(uint32_t messageId,
                                                           uint32_t confirmationTime,
                                                           uint8_t messageConfirmationContral,
                                                           uint8_t *messageResponse)
#endif
{
  emberAfMessagingClusterPrintln("RX: MessageConfirmation 0x%4x, 0x%4x",
                                 messageId,
                                 confirmationTime);
  emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_SUCCESS);
  return true;
}
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;
}
Beispiel #10
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;
}
Beispiel #11
0
bool emberAfSimpleMeteringClusterConfigureMirrorCallback(uint32_t issuerEventId,
                                                            uint32_t reportingInterval,
                                                            uint8_t mirrorNotificationReporting,
                                                            uint8_t notificationScheme)
{
  EmberAfStatus status = EMBER_ZCL_STATUS_SUCCESS;
  uint8_t endpoint = emberAfCurrentEndpoint();
  EmberEUI64 sendersEui;
  uint8_t index;

  emberAfSimpleMeteringClusterPrintln("ConfigureMirror on endpoint 0x%x", endpoint);

  if (EMBER_SUCCESS != emberLookupEui64ByNodeId(emberAfCurrentCommand()->source, sendersEui)) {
    emberAfSimpleMeteringClusterPrintln("Error: Meter Mirror plugin cannot determine EUI64 for node ID 0x%2X",
                                        emberAfCurrentCommand()->source);
    status = EMBER_ZCL_STATUS_FAILURE;
    goto kickout;
  }

  index = findMirrorIndex(sendersEui);
  if (index == INVALID_INDEX) {
    emberAfSimpleMeteringClusterPrint("Error: Meter mirror plugin received unknown report from ");
    emberAfPrintBigEndianEui64(sendersEui);
    emberAfSimpleMeteringClusterPrintln("");
    status = EMBER_ZCL_STATUS_NOT_AUTHORIZED;
    goto kickout;
  }
  
  if (mirrorList[index].issuerEventId == 0
      || issuerEventId > mirrorList[index].issuerEventId) {
    if(notificationScheme > 0x02) {
      status = EMBER_ZCL_STATUS_INVALID_FIELD;
      goto kickout;
    }

    mirrorList[index].issuerEventId = issuerEventId;
    mirrorList[index].reportingInterval = reportingInterval;
    mirrorList[index].mirrorNotificationReporting = mirrorNotificationReporting;
    mirrorList[index].notificationScheme = notificationScheme;
  }

kickout:
  emberAfSendImmediateDefaultResponse(status);
  return true;
}
bool emberAfMessagingClusterGetLastMessageCallback(void)
{
  uint8_t endpoint = emberAfCurrentEndpoint();
  EmberAfPluginMessagingServerMessage message;
  emberAfMessagingClusterPrintln("RX: GetLastMessage");
  if (emberAfPluginMessagingServerGetMessage(endpoint, &message)) {
    emberAfFillCommandMessagingClusterDisplayMessage(message.messageId,
                                                     message.messageControl,
                                                     message.startTime,
                                                     message.durationInMinutes,
                                                     message.message,
                                                     message.extendedMessageControl);
    emberAfGetCommandApsFrame()->options |= EMBER_APS_OPTION_SOURCE_EUI64;
    emberAfSendResponse();
  } else {
    emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_NOT_FOUND);
  }
  return true;
}
Beispiel #13
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;
}
Beispiel #14
0
// Move hue to a given hue, taking transitionTime until completed.
bool emberAfColorControlClusterMoveToHueCallback(uint8_t hue,
                                                    uint8_t direction,
                                                    uint16_t transitionTime)
{
  ColorControlState *state = getColorControlState(emberAfCurrentEndpoint());
  EmberAfStatus status;
  uint8_t currentHue, currentSaturation;

  emberAfColorControlClusterPrintln("ColorControl: MoveToHue (%x, %x, %2x)",
                                    hue,
                                    direction,
                                    transitionTime);

  if (state == NULL) {
    status = EMBER_ZCL_STATUS_FAILURE;
    goto send_default_response;
  }

  // If the color specified is not achievable by the hardware, then the
  // color shall not be set and a ZCL default response command shall be
  // generated with status code equal to INVALID_VALUE.
  status = colorControlReadCurrentSaturation(emberAfCurrentEndpoint(), 
                                             &currentSaturation);
  if (status != EMBER_ZCL_STATUS_SUCCESS) {
    goto send_default_response;
  }
  if(!emberAfPluginColorControlIsColorSupportedCallback(hue, currentSaturation)) {
    status = EMBER_ZCL_STATUS_INVALID_VALUE;
    goto send_default_response;
  }

  status = colorControlReadCurrentHue(emberAfCurrentEndpoint(), &currentHue);
  if (status != EMBER_ZCL_STATUS_SUCCESS) {
    goto send_default_response;
  }

  // Nothing to do, prevents divide-by-zero
  if ( hue == currentHue ) {
    status = EMBER_ZCL_STATUS_SUCCESS;
    goto send_default_response;
  }

  // As hue is effectively measured on a circle, the new hue may be moved to in
  // either direction.  The direction of hue change is given by the Direction
  // field. If Directionis "Shortest distance," the direction is taken that
  // involves the shortest path round the circle.  This case corresponds to
  // expected normal usage.  If Direction is "Longest distance," the direction
  // is taken that involves the longest path round the circle.  This case can be
  // used for "rainbow effects."  In both cases, if both distances are the same,
  // the Up direction shall be taken.
  switch (direction) {
    case EMBER_ZCL_HUE_DIRECTION_SHORTEST_DISTANCE:
      state->hueMoveDirection = ((uint8_t) (hue - currentHue) <= 127 ? true : false);
      break;
    case EMBER_ZCL_HUE_DIRECTION_LONGEST_DISTANCE:
      state->hueMoveDirection = ((uint8_t) (hue - currentHue) >= 127 ? true : false);
      break;
    case EMBER_ZCL_HUE_DIRECTION_UP:
      state->hueMoveDirection = true;
      break;
    case EMBER_ZCL_HUE_DIRECTION_DOWN:
      state->hueMoveDirection = false;
      break;
    default:
      status = EMBER_ZCL_STATUS_INVALID_FIELD;
      goto send_default_response;
  }

  state->commandId = ZCL_MOVE_TO_HUE_COMMAND_ID;
  state->elapsedTime = 0;
  state->hueMoveToLevel = hue;
  state->transitionTime = transitionTime * MILLISECOND_TICKS_PER_SECOND / 10; 
  state->eventDuration = state->transitionTime / ((state->hueMoveDirection) ? 
                                                  (hue - currentHue) : 
                                                  (currentHue - hue));
  // Set the Color Mode attribute to zero as per the spec, ignoring any errors.
  colorControlSetColorModeToZero();

  // Schedule the next tick
  if (emberAfScheduleServerTick(emberAfCurrentEndpoint(),
                                ZCL_COLOR_CONTROL_CLUSTER_ID,
                                state->eventDuration)
      != EMBER_SUCCESS)
    status = EMBER_ZCL_STATUS_SOFTWARE_FAILURE;
  else
    status = EMBER_ZCL_STATUS_SUCCESS;

  state->active = true;
  goto send_default_response;

send_default_response:
  emberAfSendImmediateDefaultResponse(status);
  return true;
}
Beispiel #15
0
// Step hue by one step, taking time as specified.
bool emberAfColorControlClusterStepHueCallback(uint8_t stepMode,
                                                  uint8_t stepSize,
                                                  uint8_t transitionTime)
{
  ColorControlState *state = getColorControlState(emberAfCurrentEndpoint());
  EmberAfStatus status;
  uint8_t currentHue, currentSaturation;

  emberAfColorControlClusterPrintln("ColorControl: StepHue (%x, %x, %x)",
                                    stepMode,
                                    stepSize,
                                    transitionTime);

  if (state == NULL) {
    status = EMBER_ZCL_STATUS_FAILURE;
    goto send_default_response;
  }

  status = colorControlReadCurrentHue(emberAfCurrentEndpoint(), &currentHue);
  if (status != EMBER_ZCL_STATUS_SUCCESS) {
    goto send_default_response;
  }

  // Add or subtract the step size to/from the current hue to get the final hue.
  // However, the range for hues is 0x00 to 0xFE, so if we land on 0xFF or if we
  // roll past it, we have to add or subtract one to the final hue, effectively
  // skipping over the invalid 0xFF.
  switch (stepMode) {
    case EMBER_ZCL_HUE_STEP_MODE_UP:
      state->hueMoveToLevel = currentHue + stepSize;
      if (stepSize == 0xFF - currentHue) {
        state->hueMoveToLevel++;
      }
      state->hueMoveDirection = true;
      break;
    case EMBER_ZCL_HUE_STEP_MODE_DOWN:
      state->hueMoveToLevel = currentHue - stepSize;
      if (stepSize == currentHue - 1) {
        state->hueMoveToLevel--;
      }
      state->hueMoveDirection = false;
      break;
    default:
      status = EMBER_ZCL_STATUS_INVALID_FIELD;
      goto send_default_response;
  }

  // If the color specified is not achievable by the hardware, then the
  // color shall not be set and a ZCL default response command shall be
  // generated with status code equal to INVALID_VALUE.
  status = colorControlReadCurrentSaturation(emberAfCurrentEndpoint(), 
                                             &currentSaturation);
  if (status != EMBER_ZCL_STATUS_SUCCESS) {
    goto send_default_response;
  }

  if(!emberAfPluginColorControlIsColorSupportedCallback(state->hueMoveToLevel, 
                                                        currentSaturation)
     || stepSize == 0 ) {
    status = EMBER_ZCL_STATUS_INVALID_VALUE;
    goto send_default_response;
  }

  state->commandId = ZCL_STEP_HUE_COMMAND_ID;
  state->transitionTime = transitionTime * MILLISECOND_TICKS_PER_SECOND / 10; 
  state->elapsedTime = 0;
  state->eventDuration = state->transitionTime / stepSize;

  state->active = true;

  // Set the Color Mode attribute to zero as per the spec, ignoring any errors.
  colorControlSetColorModeToZero();

  //schedule the next tick
  if (emberAfScheduleServerTick(emberAfCurrentEndpoint(),
                                ZCL_COLOR_CONTROL_CLUSTER_ID,
                                state->eventDuration)
      != EMBER_SUCCESS)
    status = EMBER_ZCL_STATUS_SOFTWARE_FAILURE;
  else
    status = EMBER_ZCL_STATUS_SUCCESS;

  goto send_default_response;

send_default_response:
  emberAfSendImmediateDefaultResponse(status);

  return true;
}
Beispiel #16
0
// Move saturation to a given saturation, taking transitionTime until completed.
bool emberAfColorControlClusterMoveToSaturationCallback(uint8_t saturation,
                                                           uint16_t transitionTime)
{
  ColorControlState *state = getColorControlState(emberAfCurrentEndpoint());
  EmberAfStatus status;
  uint8_t currentHue, currentSaturation;

  emberAfColorControlClusterPrintln("ColorControl: MoveToSaturation (%x, %2x)",
                                    saturation,
                                    transitionTime);

  if (state == NULL) {
    status = EMBER_ZCL_STATUS_FAILURE;
    goto send_default_response;
  }

  // If the color specified is not achievable by the hardware, then the
  // color shall not be set and a ZCL default response command shall be
  // generated with status code equal to INVALID_VALUE.
  status = colorControlReadCurrentHue(emberAfCurrentEndpoint(), 
                                      &currentHue);
  if (status != EMBER_ZCL_STATUS_SUCCESS) {
    goto send_default_response;
  }
  if(!emberAfPluginColorControlIsColorSupportedCallback(currentHue, saturation)) {
    status = EMBER_ZCL_STATUS_INVALID_VALUE;
    goto send_default_response;
  }

  status = colorControlReadCurrentSaturation(emberAfCurrentEndpoint(),
                                             &currentSaturation);
  if (status != EMBER_ZCL_STATUS_SUCCESS) {
    goto send_default_response;
  }

  // Nothing to do, prevent divide-by-zero
  if ( saturation == currentSaturation ) {
    status = EMBER_ZCL_STATUS_SUCCESS;
    goto send_default_response;
  }

  state->commandId = ZCL_MOVE_TO_SATURATION_COMMAND_ID;
  state->elapsedTime = 0;
  state->saturationMoveToLevel = saturation;
  state->satMoveDirection = 
    (saturation > currentSaturation ? true : false);
  state->eventDuration = state->transitionTime / ((state->satMoveDirection) ? 
                                                  (saturation - currentSaturation) : 
                                                  (currentSaturation - saturation));

  // Set the Color Mode attribute to zero as per the spec, ignoring any errors.
  colorControlSetColorModeToZero();

  //schedule the next tick
  if (emberAfScheduleServerTick(emberAfCurrentEndpoint(),
                                ZCL_COLOR_CONTROL_CLUSTER_ID,
                                state->eventDuration)
      != EMBER_SUCCESS)
    status = EMBER_ZCL_STATUS_SOFTWARE_FAILURE;
  else
    status = EMBER_ZCL_STATUS_SUCCESS;

  goto send_default_response;

send_default_response:
  emberAfSendImmediateDefaultResponse(status);

  return true;
}
Beispiel #17
0
// Move hue and saturation to a given values, taking time as specified.
bool emberAfColorControlClusterMoveToHueAndSaturationCallback(uint8_t hue,
                                                                 uint8_t saturation,
                                                                 uint16_t transitionTime)
{
  ColorControlState *state = getColorControlState(emberAfCurrentEndpoint());
  EmberAfStatus status;
  uint8_t currentSaturation, currentHue, hueDiff, satDiff;

  emberAfColorControlClusterPrintln("ColorControl: MoveToHueAndSaturation (%x, %x, %2x)",
                                    hue,
                                    saturation,
                                    transitionTime);

  if (state == NULL) {
    status = EMBER_ZCL_STATUS_FAILURE;
    goto send_default_response;
  }

  // If the color specified is not achievable by the hardware, then the
  // color shall not be set and a ZCL default response command shall be
  // generated with status code equal to INVALID_VALUE.
  if (!emberAfPluginColorControlIsColorSupportedCallback(hue, saturation)) {
    status = EMBER_ZCL_STATUS_INVALID_VALUE;
    goto send_default_response;
  }

  status = colorControlReadCurrentSaturation(emberAfCurrentEndpoint(),
                                             &currentSaturation);
  if (status != EMBER_ZCL_STATUS_SUCCESS) {
    goto send_default_response;
  }

  status = colorControlReadCurrentHue(emberAfCurrentEndpoint(), &currentHue);
  if (status != EMBER_ZCL_STATUS_SUCCESS) {
    goto send_default_response;
  }

  state->commandId = ZCL_MOVE_TO_HUE_AND_SATURATION_COMMAND_ID;
  state->hueMoveToLevel = hue;
  state->hueMoveDirection = (hue - currentHue <= 127 ? true : false);
  hueDiff = (state->hueMoveDirection ? hue - currentHue : currentHue - hue);

  state->saturationMoveToLevel = saturation;
  state->satMoveDirection = (saturation - currentSaturation <= 127 ? true : false);
  satDiff = (state->satMoveDirection 
             ? saturation - currentSaturation 
             : currentSaturation - saturation);

  if (hueDiff == 0) {
    return emberAfColorControlClusterMoveToSaturationCallback(saturation,
                                                              transitionTime);
  } else if (satDiff == 0) {
    return emberAfColorControlClusterMoveToHueCallback(hue,
                                                       EMBER_ZCL_HUE_DIRECTION_SHORTEST_DISTANCE,
                                                       transitionTime);
  }

  state->elapsedTime = 0;
  state->acceleratedHue = hueDiff > satDiff;
  state->acceleratedMoveRate = (state->acceleratedHue
                                ? hueDiff / satDiff
                                : satDiff / hueDiff);

  state->transitionTime = transitionTime * MILLISECOND_TICKS_PER_SECOND / 10; 
  state->eventDuration = state->transitionTime / ((state->acceleratedHue) 
                                                  ? hueDiff
                                                  : satDiff);

  // Set the Color Mode attribute to zero as per the spec, ignoring any errors.
  colorControlSetColorModeToZero();

  state->active = true;

  //schedule the next tick
  if (emberAfScheduleServerTick(emberAfCurrentEndpoint(),
                                ZCL_COLOR_CONTROL_CLUSTER_ID,
                                state->eventDuration)
      != EMBER_SUCCESS)
    status = EMBER_ZCL_STATUS_SOFTWARE_FAILURE;
  else
    status = EMBER_ZCL_STATUS_SUCCESS;

  goto send_default_response;

send_default_response:
  emberAfSendImmediateDefaultResponse(status);

  return true;
}
Beispiel #18
0
// Step sat by one step, taking time as specified.
bool emberAfColorControlClusterStepSaturationCallback(uint8_t stepMode,
                                                         uint8_t stepSize,
                                                         uint8_t transitionTime)
{
  ColorControlState *state = getColorControlState(emberAfCurrentEndpoint());
  EmberAfStatus status;
  uint8_t currentHue, currentSaturation;

  emberAfColorControlClusterPrintln("ColorControl: StepSaturation (%x, %x, %x)",
                                    stepMode,
                                    stepSize,
                                    transitionTime);

  if (state == NULL) {
    status = EMBER_ZCL_STATUS_FAILURE;
    goto send_default_response;
  }

  status = colorControlReadCurrentSaturation(emberAfCurrentEndpoint(),
                                             &currentSaturation);
  if (status != EMBER_ZCL_STATUS_SUCCESS) {
    goto send_default_response;
  }

  // Add or subtract the step size to/from the current saturation to get the
  // final saturation.  However, the range for saturations is 0x00 to 0xFE, so
  // don't increment or decrement past those bounds.
  switch (stepMode) {
    case EMBER_ZCL_SATURATION_STEP_MODE_UP:
      state->saturationMoveToLevel = (stepSize > 0xFE - currentSaturation
                                      ? 0xFE
                                      : currentSaturation + stepSize);
      state->satMoveDirection = true;
      break;
    case EMBER_ZCL_SATURATION_STEP_MODE_DOWN:
      state->saturationMoveToLevel = (stepSize > currentSaturation
                                      ? 0x00
                                      : currentSaturation - stepSize);
      state->satMoveDirection = false;
      break;
    default:
      status = EMBER_ZCL_STATUS_INVALID_FIELD;
      goto send_default_response;
  }

  // If the color specified is not achievable by the hardware, then the
  // color shall not be set and a ZCL default response command shall be
  // generated with status code equal to INVALID_VALUE.
  status = colorControlReadCurrentHue(emberAfCurrentEndpoint(), 
                                      &currentHue);
  if (status != EMBER_ZCL_STATUS_SUCCESS) {
    goto send_default_response;
  }

  if(!emberAfPluginColorControlIsColorSupportedCallback(currentHue, 
                                                        state->saturationMoveToLevel)
     || stepSize == 0 ) {
    status = EMBER_ZCL_STATUS_INVALID_VALUE;
    goto send_default_response;
  }

  state->commandId = ZCL_STEP_SATURATION_COMMAND_ID;
  state->transitionTime = transitionTime * MILLISECOND_TICKS_PER_SECOND / 10;
  state->elapsedTime = 0;
  state->eventDuration = state->transitionTime / stepSize;

  state->active = true;

  // Set the Color Mode attribute to zero as per the spec, ignoring any errors.
  colorControlSetColorModeToZero();

  //schedule the next tick
  if (emberAfScheduleServerTick(emberAfCurrentEndpoint(),
                                ZCL_COLOR_CONTROL_CLUSTER_ID,
                                state->eventDuration)
      != EMBER_SUCCESS)
    status = EMBER_ZCL_STATUS_SOFTWARE_FAILURE;
  else
    status = EMBER_ZCL_STATUS_SUCCESS;

  goto send_default_response;

send_default_response:
  emberAfSendImmediateDefaultResponse(status);

  return true;
}
Beispiel #19
0
// Move sat continuously at the given rate. If mode is stop, then stop.
bool emberAfColorControlClusterMoveSaturationCallback(uint8_t moveMode, uint8_t rate)
{
  ColorControlState *state = getColorControlState(emberAfCurrentEndpoint());
  EmberAfStatus status;

  emberAfColorControlClusterPrintln("ColorControl: MoveSaturation (%x, %x)",
                                    moveMode,
                                    rate);

  if (state == NULL) {
    status = EMBER_ZCL_STATUS_FAILURE;
    goto send_default_response;
  }

  // If the rate is set to 0, then the command shall have no effect
  // and a ZCL default response command shall be generated with status 
  // code equal to INVALID_VALUE.

  if (rate == 0) {
    status = EMBER_ZCL_STATUS_INVALID_FIELD;
    goto send_default_response;
  }

  state->active = true;

  switch (moveMode) {
    case EMBER_ZCL_SATURATION_MOVE_MODE_STOP:
      state->active = false;
      emberAfDeactivateServerTick(emberAfCurrentEndpoint(),
                                  ZCL_COLOR_CONTROL_CLUSTER_ID);
#ifdef ZCL_USING_COLOR_CONTROL_CLUSTER_COLOR_CONTROL_REMAINING_TIME_ATTRIBUTE
      colorControlClearRemainingTime(emberAfCurrentEndpoint());
#endif // ZCL_USING_COLOR_CONTROL_CLUSTER_COLOR_CONTROL_REMAINING_TIME_ATTRIBUTE
      status = EMBER_ZCL_STATUS_SUCCESS;
      goto send_default_response;
    case EMBER_ZCL_SATURATION_MOVE_MODE_UP:
      state->satMoveDirection = true;
      break;
    case EMBER_ZCL_SATURATION_MOVE_MODE_DOWN:
      state->satMoveDirection = false;
      break;
    default:
      status = EMBER_ZCL_STATUS_INVALID_FIELD;
      goto send_default_response;
  }

  state->commandId = ZCL_MOVE_SATURATION_COMMAND_ID;
  if (state->active) {
    state->eventDuration = MILLISECOND_TICKS_PER_SECOND / rate;
  }

  // Set the Color Mode attribute to zero as per the spec, ignoring any errors.
  colorControlSetColorModeToZero();

  //schedule the next tick
  if (emberAfScheduleServerTick(emberAfCurrentEndpoint(),
                                ZCL_COLOR_CONTROL_CLUSTER_ID,
                                state->eventDuration)
      != EMBER_SUCCESS)
    status = EMBER_ZCL_STATUS_SOFTWARE_FAILURE;
  else
    status = EMBER_ZCL_STATUS_SUCCESS;
  goto send_default_response;

send_default_response:
  emberAfSendImmediateDefaultResponse(status);

  return true;
}