| /* |
| * |
| * Copyright (c) 2020 Project CHIP Authors |
| * All rights reserved. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /** |
| * @file |
| * This file contains definitions for a base Cluster class. This class will |
| * be derived by various ZCL clusters supported by CHIP. The objects of the |
| * ZCL cluster class will be used by Controller applications to interact with |
| * the CHIP device. |
| */ |
| |
| #pragma once |
| |
| #include "app/ConcreteCommandPath.h" |
| #include <app/DeviceProxy.h> |
| #include <app/util/error-mapping.h> |
| #include <controller/InvokeInteraction.h> |
| #include <controller/ReadInteraction.h> |
| #include <controller/WriteInteraction.h> |
| |
| namespace chip { |
| namespace Controller { |
| |
| template <typename T> |
| using CommandResponseSuccessCallback = void(void * context, const T & responseObject); |
| using CommandResponseFailureCallback = void(void * context, EmberAfStatus status); |
| using WriteResponseSuccessCallback = void (*)(void * context); |
| using WriteResponseFailureCallback = void (*)(void * context, EmberAfStatus status); |
| template <typename T> |
| using ReadResponseSuccessCallback = void (*)(void * context, T responseData); |
| using ReadResponseFailureCallback = void (*)(void * context, EmberAfStatus status); |
| |
| class DLL_EXPORT ClusterBase |
| { |
| public: |
| virtual ~ClusterBase() {} |
| |
| CHIP_ERROR Associate(DeviceProxy * device, EndpointId endpoint); |
| CHIP_ERROR AssociateWithGroup(DeviceProxy * device, GroupId groupId); |
| |
| void Dissociate(); |
| |
| ClusterId GetClusterId() const { return mClusterId; } |
| |
| /* |
| * This function permits sending an invoke request using cluster objects that represent the request and response data payloads. |
| * |
| * Success and Failure callbacks must be passed in through which the decoded response is provided as well as notification of any |
| * failure. |
| */ |
| template <typename RequestDataT> |
| CHIP_ERROR InvokeCommand(const RequestDataT & requestData, void * context, |
| CommandResponseSuccessCallback<typename RequestDataT::ResponseType> successCb, |
| CommandResponseFailureCallback failureCb) |
| { |
| VerifyOrReturnError(mDevice != nullptr, CHIP_ERROR_INCORRECT_STATE); |
| |
| auto onSuccessCb = [context, successCb](const app::ConcreteCommandPath & commandPath, const app::StatusIB & aStatus, |
| const typename RequestDataT::ResponseType & responseData) { |
| successCb(context, responseData); |
| }; |
| |
| auto onFailureCb = [context, failureCb](const app::StatusIB & aStatus, CHIP_ERROR aError) { |
| failureCb(context, app::ToEmberAfStatus(aStatus.mStatus)); |
| }; |
| |
| return InvokeCommandRequest(mDevice->GetExchangeManager(), mDevice->GetSecureSession().Value(), mEndpoint, requestData, |
| onSuccessCb, onFailureCb); |
| }; |
| |
| /** |
| * Functions for writing attributes. We have lots of different |
| * AttributeInfo but a fairly small set of types that get written. So we |
| * want to keep the template on AttributeInfo very small, and put all the |
| * work in the template with a small number of instantiations (one per |
| * type). |
| */ |
| template <typename AttrType> |
| CHIP_ERROR WriteAttribute(const AttrType & requestData, void * context, ClusterId clusterId, AttributeId attributeId, |
| WriteResponseSuccessCallback successCb, WriteResponseFailureCallback failureCb) |
| { |
| VerifyOrReturnError(mDevice != nullptr, CHIP_ERROR_INCORRECT_STATE); |
| |
| auto onSuccessCb = [context, successCb](const app::ConcreteAttributePath & commandPath) { |
| if (successCb != nullptr) |
| { |
| successCb(context); |
| } |
| }; |
| |
| auto onFailureCb = [context, failureCb](const app::ConcreteAttributePath * commandPath, app::StatusIB status, |
| CHIP_ERROR aError) { |
| if (failureCb != nullptr) |
| { |
| failureCb(context, app::ToEmberAfStatus(status.mStatus)); |
| } |
| }; |
| |
| return chip::Controller::WriteAttribute<AttrType>((mSessionHandle.HasValue()) ? mSessionHandle.Value() |
| : mDevice->GetSecureSession().Value(), |
| mEndpoint, clusterId, attributeId, requestData, onSuccessCb, onFailureCb); |
| } |
| |
| template <typename AttributeInfo> |
| CHIP_ERROR WriteAttribute(const typename AttributeInfo::Type & requestData, void * context, |
| WriteResponseSuccessCallback successCb, WriteResponseFailureCallback failureCb) |
| { |
| return WriteAttribute(requestData, context, AttributeInfo::GetClusterId(), AttributeInfo::GetAttributeId(), successCb, |
| failureCb); |
| } |
| |
| /** |
| * Read an attribute and get a type-safe callback with the attribute value. |
| */ |
| template <typename AttributeInfo> |
| CHIP_ERROR ReadAttribute(void * context, ReadResponseSuccessCallback<typename AttributeInfo::DecodableArgType> successCb, |
| ReadResponseFailureCallback failureCb) |
| { |
| return ReadAttribute<typename AttributeInfo::DecodableType, typename AttributeInfo::DecodableArgType>( |
| context, AttributeInfo::GetClusterId(), AttributeInfo::GetAttributeId(), successCb, failureCb); |
| } |
| |
| template <typename DecodableType, typename DecodableArgType> |
| CHIP_ERROR ReadAttribute(void * context, ClusterId clusterId, AttributeId attributeId, |
| ReadResponseSuccessCallback<DecodableArgType> successCb, ReadResponseFailureCallback failureCb) |
| { |
| VerifyOrReturnError(mDevice != nullptr, CHIP_ERROR_INCORRECT_STATE); |
| |
| auto onSuccessCb = [context, successCb](const app::ConcreteAttributePath & commandPath, const DecodableType & aData) { |
| if (successCb != nullptr) |
| { |
| successCb(context, aData); |
| } |
| }; |
| |
| auto onFailureCb = [context, failureCb](const app::ConcreteAttributePath * commandPath, app::StatusIB status, |
| CHIP_ERROR aError) { |
| if (failureCb != nullptr) |
| { |
| failureCb(context, app::ToEmberAfStatus(status.mStatus)); |
| } |
| }; |
| |
| return Controller::ReadAttribute<DecodableType>(mDevice->GetExchangeManager(), mDevice->GetSecureSession().Value(), |
| mEndpoint, clusterId, attributeId, onSuccessCb, onFailureCb); |
| } |
| |
| protected: |
| ClusterBase(uint16_t cluster) : mClusterId(cluster) {} |
| |
| /** |
| * @brief |
| * Request attribute reports from the device. Add a callback |
| * handler, that'll be called when the reports are received from the device. |
| * |
| * @param[in] attributeId The report target attribute id |
| * @param[in] reportHandler The handler function that's called on receiving attribute reports |
| * The reporting handler continues to be called as long as the callback |
| * is active. The user can stop the reporting by cancelling the callback. |
| * Reference: chip::Callback::Cancel() |
| * @param[in] tlvDataFilter Filter interface for processing data from TLV |
| */ |
| CHIP_ERROR RequestAttributeReporting(AttributeId attributeId, Callback::Cancelable * reportHandler, |
| app::TLVDataFilter tlvDataFilter); |
| |
| const ClusterId mClusterId; |
| DeviceProxy * mDevice; |
| EndpointId mEndpoint; |
| chip::Optional<SessionHandle> mSessionHandle; |
| }; |
| |
| } // namespace Controller |
| } // namespace chip |