blob: 3e1b77bcbf7e2a9060588d91ba190cbe353627d4 [file] [log] [blame]
/*
*
* Copyright (c) 2023 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.
*/
#pragma once
#include "mode-base-cluster-objects.h"
#include <app/AttributeAccessInterface.h>
#include <app/AttributePersistenceProvider.h>
#include <app/CommandHandlerInterface.h>
#include <app/util/af.h>
#include <lib/support/IntrusiveList.h>
namespace chip {
namespace app {
namespace Clusters {
namespace ModeBase {
class Delegate;
class Instance : public CommandHandlerInterface, public AttributeAccessInterface, public IntrusiveListNodeBase<>
{
private:
Delegate * mDelegate;
EndpointId mEndpointId{};
ClusterId mClusterId{};
// Attribute data store
uint8_t mCurrentMode;
DataModel::Nullable<uint8_t> mStartUpMode;
DataModel::Nullable<uint8_t> mOnMode;
uint32_t mFeature;
// CommandHandlerInterface
void InvokeCommand(HandlerContext & ctx) override;
CHIP_ERROR EnumerateAcceptedCommands(const ConcreteClusterPath & cluster, CommandIdCallback callback, void * context) override;
CHIP_ERROR EnumerateGeneratedCommands(const ConcreteClusterPath & cluster, CommandIdCallback callback, void * context) override;
// AttributeAccessInterface
CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override;
CHIP_ERROR Write(const ConcreteDataAttributePath & aPath, AttributeValueDecoder & aDecoder) override;
/**
* Register this ModeBase instance.
*/
void RegisterInstance();
/**
* Unregister this ModeBase instance.
*/
void UnregisterInstance();
/**
* Internal change-to-mode command handler function.
*/
void HandleChangeToMode(HandlerContext & ctx, const Commands::ChangeToMode::DecodableType & req);
/**
* Helper function that loads all the persistent attributes from the KVS. These attributes are CurrentMode,
* StartUpMode and OnMode.
*/
void LoadPersistentAttributes();
/**
* Helper function that encodes the supported modes.
* @param encoder The encoder to encode the supported modes into.
*/
CHIP_ERROR EncodeSupportedModes(const AttributeValueEncoder::ListEncodeHelper & encoder);
public:
/**
* Initialise the ModeBase server instance.
* @return Returns an error if the given endpoint and cluster ID have not been enabled in zap, if the
* CommandHandler or AttributeHandler registration fails or if the Delegate::Init() returns an error.
*/
CHIP_ERROR Init();
// Attribute setters
/**
* Sets the Start-Up attribute. Note, this also handles writing the new value into non-volatile storage.
* @param aNewStartUpMode The value to which the Start-Up mode is to be set.
* @return Returns a ConstraintError if the aNewStartUpMode value is not valid. Returns Success otherwise.
*/
Protocols::InteractionModel::Status UpdateStartUpMode(DataModel::Nullable<uint8_t> aNewStartUpMode);
/**
* Sets the On-Mode attribute. Note, this also handles writing the new value into non-volatile storage.
* @param aNewOnMode The value to which the On-Mode mode is to be set.
* @return Returns a ConstraintError if the aNewOnMode value is not valid. Returns Success otherwise.
*/
Protocols::InteractionModel::Status UpdateOnMode(DataModel::Nullable<uint8_t> aNewOnMode);
/**
* Sets the Current-Mode attribute. Note, this also handles writing the new value into non-volatile storage.
* @param aNewMode The value to which the Current-Mode mode is to be set.
* @return Returns a ConstraintError if the aNewMode value is not valid. Returns Success otherwise.
*/
Protocols::InteractionModel::Status UpdateCurrentMode(uint8_t aNewMode);
// Attribute getters.
/**
* @return The Start-Up mode.
*/
DataModel::Nullable<uint8_t> GetStartUpMode() const;
/**
* @return The On mode.
*/
DataModel::Nullable<uint8_t> GetOnMode() const;
/**
* @return The Current mode.
*/
uint8_t GetCurrentMode() const;
/**
* @return The endpoint ID.
*/
EndpointId GetEndpointId() const { return mEndpointId; }
// Cluster constants, from the spec.
static constexpr uint8_t kMaxModeLabelSize = 64;
static constexpr uint8_t kMaxNumOfModeTags = 8;
/**
* Returns true if the feature is supported.
* @param feature the feature to check.
*/
bool HasFeature(Feature feature) const;
/**
* This function returns true if the mode value given matches one of the supported modes, otherwise it returns false.
* @param mode
*/
bool IsSupportedMode(uint8_t mode);
/**
* Creates a mode base cluster instance. The Init() function needs to be called for this instance to be registered and
* called by the interaction model at the appropriate times.
* @param aEndpointId The endpoint on which this cluster exists. This must match the zap configuration.
* @param aClusterId The ID of the ModeBase aliased cluster to be instantiated.
* @param aFeature The bitmask value that identifies which features are supported by this instance.
*/
Instance(Delegate * aDelegate, EndpointId aEndpointId, ClusterId aClusterId, uint32_t aFeature);
~Instance() override;
template <typename RequestT, typename FuncT>
void HandleCommand(HandlerContext & handlerContext, FuncT func);
};
class Delegate
{
protected:
Instance * mInstance = nullptr;
public:
Delegate() = default;
virtual ~Delegate() = default;
/**
* This method is used by the SDK to set the instance pointer. This is done during the instantiation of an Instance object.
* @param aInstance A pointer to the Instance object related to this delegate object.
*/
void SetInstance(Instance * aInstance) { mInstance = aInstance; }
// The following functions should be overridden by the SDK user to implement the business logic of their application.
/**
* This init function will be called during the ModeBase server initialization after the Instance information has been
* validated and the Instance has been registered. This can be used to initialise app logic.
*/
virtual CHIP_ERROR Init() = 0;
/**
* Get the mode label of the Nth mode in the list of modes.
* @param modeIndex The index of the mode to be returned. It is assumed that modes are indexable from 0 and with no gaps.
* @param label A reference to the mutable char span which will be mutated to receive the label on success. Use
* CopyCharSpanToMutableCharSpan to copy into the MutableCharSpan.
* @return Returns a CHIP_NO_ERROR if there was no error and the label was returned successfully.
* CHIP_ERROR_PROVIDER_LIST_EXHAUSTED if the modeIndex in beyond the list of available labels.
*/
virtual CHIP_ERROR GetModeLabelByIndex(uint8_t modeIndex, MutableCharSpan & label) = 0;
/**
* Get the mode value of the Nth mode in the list of modes.
* @param modeIndex The index of the mode to be returned. It is assumed that modes are indexable from 0 and with no gaps.
* @param value a reference to the uint8_t variable that is to contain the mode value.
* @return Returns a CHIP_NO_ERROR if there was no error and the value was returned successfully.
* CHIP_ERROR_PROVIDER_LIST_EXHAUSTED if the modeIndex in beyond the list of available values.
*/
virtual CHIP_ERROR GetModeValueByIndex(uint8_t modeIndex, uint8_t & value) = 0;
/**
* Get the mode tags of the Nth mode in the list of modes.
* The caller will make sure the List points to an existing buffer of sufficient size to hold the spec-required number
* of tags, and the size of the List is the size of the buffer.
*
* The implementation must place its desired ModeTagStructType instances in that buffer and call tags.reduce_size
* on the list to indicate how many entries were initialized.
* @param modeIndex The index of the mode to be returned. It is assumed that modes are indexable from 0 and with no gaps.
* @param tags a reference to an existing and initialised buffer that is to contain the mode tags. std::copy can be used
* to copy into the buffer.
* @return Returns a CHIP_NO_ERROR if there was no error and the mode tags were returned successfully.
* CHIP_ERROR_PROVIDER_LIST_EXHAUSTED if the modeIndex in beyond the list of available mode tags.
*/
virtual CHIP_ERROR GetModeTagsByIndex(uint8_t modeIndex, DataModel::List<detail::Structs::ModeTagStruct::Type> & modeTags) = 0;
/**
* When a ChangeToMode command is received, if the NewMode value is a supported mode, this method is called to 1) decide if
* we should go ahead with transitioning to this mode and 2) formulate the ChangeToModeResponse that will be sent back to the
* client. If this function returns a response.status of StatusCode::kSuccess, the change request is accepted
* and the CurrentMode is set to the NewMode. Else, the CurrentMode is left untouched. The response is sent as a
* ChangeToModeResponse command.
*
* This function is to be overridden by a user implemented function that makes this decision based on the application logic.
* @param NewMode The new made that the device is requested to transition to.
* @param response A reference to a response that will be sent to the client. The contents of which con be modified by the
* application.
*
*/
virtual void HandleChangeToMode(uint8_t NewMode, ModeBase::Commands::ChangeToModeResponse::Type & response) = 0;
};
// A set of pointers to all initialised ModeBase instances. It provides a way to access all ModeBase derived clusters.
// todo change once there is a clear public interface for the OnOff cluster data dependencies (#27508)
static IntrusiveList<Instance> gModeBaseAliasesInstances;
// This does not return a refernce to const IntrusiveList, because the caller might need
// to change the state of the instances in the list and const IntrusiveList only allows
// access to const Instance.
IntrusiveList<Instance> & GetModeBaseInstanceList();
} // namespace ModeBase
} // namespace Clusters
} // namespace app
} // namespace chip