blob: f118006e317a650222359e2210f1c1312a6af725 [file] [log] [blame]
/**
*
* Copyright (c) 2020-2021 Project CHIP Authors
*
* 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
#ifndef CONFIGURATION_HEADER
#define CONFIGURATION_HEADER <app/util/config.h>
#endif
#include CONFIGURATION_HEADER
#ifdef EZSP_HOST
// Includes needed for ember related functions for the EZSP host
#include "app/util/ezsp/ezsp-protocol.h"
#include "app/util/ezsp/ezsp-utils.h"
#include "app/util/ezsp/ezsp.h"
#include "app/util/ezsp/serial-interface.h"
#include "stack/include/ember-random-api.h"
#include "stack/include/ember-types.h"
#include "stack/include/error.h"
#endif // EZSP_HOST
#include <app/util/af-types.h>
#include <app/util/debug-printing.h>
#include <app/util/ember-print.h>
#include <lib/core/DataModelTypes.h>
#include <lib/support/Iterators.h>
#include <lib/support/SafeInt.h>
/** @name Attribute Storage */
// @{
static constexpr uint16_t kEmberInvalidEndpointIndex = 0xFFFF;
/**
* @brief locate attribute metadata
*
* Function returns pointer to the attribute metadata structure,
* or NULL if attribute was not found.
*
* @param endpoint Zigbee endpoint number.
* @param clusterId Cluster ID of the sought cluster.
* @param attributeId Attribute ID of the sought attribute.
*
* @return Returns pointer to the attribute metadata location.
*/
const EmberAfAttributeMetadata * emberAfLocateAttributeMetadata(chip::EndpointId endpoint, chip::ClusterId clusterId,
chip::AttributeId attributeId);
/**
* @brief Returns true if endpoint contains the ZCL server with specified id.
*
* This function returns true if
* the endpoint contains server of a given cluster.
*/
bool emberAfContainsServer(chip::EndpointId endpoint, chip::ClusterId clusterId);
/**
* @brief Returns true if endpoint of given index contains the ZCL server with specified id.
*
* This function returns true if
* the endpoint of given index contains server of a given cluster.
* If this function is used with a manufacturer specific clusterId
* then this will return the first cluster that it finds in the Cluster table.
* and will not return any other clusters that share that id.
*/
bool emberAfContainsServerFromIndex(uint16_t index, chip::ClusterId clusterId);
/**
* @brief Returns true if endpoint contains the ZCL client with specified id.
*
* This function returns true if
* the endpoint contains client of a given cluster.
*/
bool emberAfContainsClient(chip::EndpointId endpoint, chip::ClusterId clusterId);
/**
* @brief write an attribute, performing all the checks.
*
* This function will attempt to write the attribute value from
* the provided pointer. This function will only check that the
* attribute exists. If it does it will write the value into
* the attribute table for the given attribute.
*
* This function will not check to see if the attribute is
* writable since the read only / writable characteristic
* of an attribute only pertains to external devices writing
* over the air. Because this function is being called locally
* it assumes that the device knows what it is doing and has permission
* to perform the given operation.
*/
EmberAfStatus emberAfWriteAttribute(chip::EndpointId endpoint, chip::ClusterId cluster, chip::AttributeId attributeID,
uint8_t * dataPtr, EmberAfAttributeType dataType);
/**
* @brief Read the attribute value, performing all the checks.
*
* This function will attempt to read the attribute and store it into the
* pointer.
*
* dataPtr may be NULL, signifying that we don't need the value, just the status
* (i.e. whether the attribute can be read).
*/
EmberAfStatus emberAfReadAttribute(chip::EndpointId endpoint, chip::ClusterId cluster, chip::AttributeId attributeID,
uint8_t * dataPtr, uint16_t readLength);
/**
* @brief macro that returns size of attribute in bytes.
*
* @param metadata EmberAfAttributeMetadata* to consider.
*/
#define emberAfAttributeSize(metadata) ((metadata)->size)
#if !defined(DOXYGEN_SHOULD_SKIP_THIS)
// master array of all defined endpoints
extern EmberAfDefinedEndpoint emAfEndpoints[];
#endif
/**
* @brief Macro that takes index of endpoint, and returns Zigbee endpoint
*/
chip::EndpointId emberAfEndpointFromIndex(uint16_t index);
/**
* @brief Returns root endpoint of a composed bridged device
*/
chip::EndpointId emberAfParentEndpointFromIndex(uint16_t index);
/**
* Returns the index of a given endpoint. Will return 0xFFFF if this is not a
* valid endpoint id or if the endpoint is disabled.
*/
uint16_t emberAfIndexFromEndpoint(chip::EndpointId endpoint);
/**
* Returns the index of a given endpoint; Does not ignore disabled endpoints.
* Will return 0xFFFF if this is not a valid endpoint id.
*/
uint16_t emberAfIndexFromEndpointIncludingDisabledEndpoints(chip::EndpointId endpoint);
/**
* Returns the index of the given endpoint in the list of all defined endpoints
* (including disabled ones) that support the given cluster.
*
* Returns kEmberInvalidEndpointIndex if the given endpoint does not support the
* given cluster.
*
* For fixed endpoints, the returned value never changes, but for dynamic
* endpoints it can change if a dynamic endpoint is defined at a lower index
* that also supports the given cluster.
*
* For example, if a device has 4 fixed endpoints (ids 0-3) and 2 dynamic
* endpoints, and cluster X is supported on endpoints 1 and 3, then:
*
* 1) emberAfFindClusterServerEndpointIndex(0, X) returns kEmberInvalidEndpointIndex
* 2) emberAfFindClusterServerEndpointIndex(1, X) returns 0
* 3) emberAfFindClusterServerEndpointIndex(2, X) returns kEmberInvalidEndpointIndex
* 4) emberAfFindClusterServerEndpointIndex(3, X) returns 1
*
* If the second dynamic endpoint is defined (via
* emberAfSetDynamicEndpoint(1, 7, ...)) to
* have endpoint id 7, and supports cluster X, but the first dynamic endpoint is
* not defined, then emberAfFindClusterServerEndpointIndex(7, X) returns 2.
*
* If now the first dynamic endpoint is defined (via
* emberAfSetDynamicEndpoint(0, 9, ...))
* to have endpoint id 9, and supports cluster X, then
* emberAfFindClusterServerEndpointIndex(7, X) starts returning 3 and
* emberAfFindClusterServerEndpointIndex(9, X) returns 2.
*/
uint16_t emberAfFindClusterServerEndpointIndex(chip::EndpointId endpoint, chip::ClusterId clusterId);
/**
* @brief Returns the index of the given endpoint in the list of all endpoints that might support the given cluster server.
*
* Returns kEmberInvalidEndpointIndex if the given endpoint does not support the
* given cluster or if the given endpoint is disabled.
*
* Unlike emberAfFindClusterServerEndpointIndex, this function always returns the same index
* for a given endpointId instance, fixed or dynamic, if it does not return kEmberInvalidEndpointIndex.
*
* The return index is identical to emberAfFindClusterServerEndpointIndex for fixed endpoints,
* but for dynamic endpoints the indexing assumes that any dynamic endpoint could start supporting
* the given server cluster.
*
* For example, if a device has 4 fixed endpoints (ids 0-3) and 2 dynamic
* endpoints, and cluster X is supported on endpoints 1 and 3, then
* fixedClusterServerEndpointCount should be 2 and
*
* 1) emberAfGetClusterServerEndpointIndex(0, X) returns kEmberInvalidEndpointIndex
* 2) emberAfGetClusterServerEndpointIndex(1, X) returns 0
* 3) emberAfGetClusterServerEndpointIndex(2, X) returns kEmberInvalidEndpointIndex
* 4) emberAfGetClusterServerEndpointIndex(3, X) returns 1
* The Dynamic endpoints are placed after the fixed ones;
* therefore their return index will always be >= to fixedClusterServerEndpointCount
*
* If a dynamic endpoint, supporting cluster X, is defined to dynamic index 1 with endpoint id 7,
* (via emberAfSetDynamicEndpoint(1, 7, ...))
* then emberAfGetClusterServerEndpointIndex(7, X) returns 3 (fixedClusterServerEndpointCount{2} + DynamicEndpointIndex {1}).
*
* If now a second dynamic endpoint, also supporting cluster X, is defined to dynamic index 0
* with endpoint id 9 (via emberAfSetDynamicEndpoint(0, 9, ...)),
* emberAfGetClusterServerEndpointIndex(9, X) returns 2. (fixedClusterServerEndpointCount{2} + DynamicEndpointIndex {0}).
* and emberAfGetClusterServerEndpointIndex(7, X) still returns 3
*
* @param endpoint Endpoint number
* @param cluster Id the of the Cluster server you are interrested on
* @param fixedClusterServerEndpointCount The number of fixed endpoints containing this cluster server. Typically one of the
EMBER_AF_*_CLUSTER_SERVER_ENDPOINT_COUNT constants.
*/
uint16_t emberAfGetClusterServerEndpointIndex(chip::EndpointId endpoint, chip::ClusterId cluster,
uint16_t fixedClusterServerEndpointCount);
/**
* @brief Returns the total number of endpoints (dynamic and pre-compiled).
*/
uint16_t emberAfEndpointCount(void);
/**
* @brief Returns the number of pre-compiled endpoints.
*/
uint16_t emberAfFixedEndpointCount(void);
/**
*@brief Returns true if type is signed, false otherwise.
*/
bool emberAfIsTypeSigned(EmberAfAttributeType dataType);
/**
* @brief Function that extracts a 16-bit integer from the message buffer
*/
uint16_t emberAfGetInt16u(const uint8_t * message, uint16_t currentIndex, uint16_t msgLen);
/**
* @brief Macro for consistency, that extracts single byte out of the message
*/
#define emberAfGetInt8u(message, currentIndex, msgLen) message[currentIndex]
/**
* @brief Macro for consistency that copies a uint8_t from variable into buffer.
*/
#define emberAfCopyInt8u(data, index, x) (data[index] = (x))
/**
* @brief function that copies a uint16_t value into a buffer
*/
void emberAfCopyInt16u(uint8_t * data, uint16_t index, uint16_t x);
/*
* @brief Function that copies a ZCL string type into a buffer. The size
* parameter should indicate the maximum number of characters to copy to the
* destination buffer not including the length byte.
*/
void emberAfCopyString(uint8_t * dest, const uint8_t * src, size_t size);
/*
* @brief Function that copies a ZCL long string into a buffer. The size
* parameter should indicate the maximum number of characters to copy to the
* destination buffer not including the length bytes.
*/
void emberAfCopyLongString(uint8_t * dest, const uint8_t * src, size_t size);
/** @} END Attribute Storage */
/** @name Device Control */
// @{
/**
* @brief Function that checks if endpoint is identifying
*
* This function returns true if device at a given endpoint is
* identifying.
*
* @param endpoint Zigbee endpoint number
*/
bool emberAfIsDeviceIdentifying(chip::EndpointId endpoint);
/** @} END Device Control */
/** @name Miscellaneous */
// @{
/**
* @brief Enable/disable endpoints
*/
bool emberAfEndpointEnableDisable(chip::EndpointId endpoint, bool enable);
/**
* @brief Determine if an endpoint at the specified index is enabled or disabled
*/
bool emberAfEndpointIndexIsEnabled(uint16_t index);
/** @brief Returns true if a given ZCL data type is a list type. */
bool emberAfIsThisDataTypeAListType(EmberAfAttributeType dataType);
/**
* @brief Simple integer comparison function.
* Compares two values of a known length as integers.
* Signed integer comparison are supported for numbers with length of
* 4 (bytes) or less.
* The integers are in native endianness.
*
* @return -1, if val1 is smaller
* 0, if they are the same or if two negative numbers with length
* greater than 4 is being compared
* 1, if val2 is smaller.
*/
int8_t emberAfCompareValues(const uint8_t * val1, const uint8_t * val2, uint16_t len, bool signedNumber);
/** @} END Miscellaneous */
/** @} END addtogroup */
#if !defined(DOXYGEN_SHOULD_SKIP_THIS)
#if defined(EMBER_TEST)
#define EMBER_TEST_ASSERT(x) assert(x)
#else
#define EMBER_TEST_ASSERT(x)
#endif
#endif
/**
* Returns the pointer to the data version storage for the given endpoint and
* cluster. Can return null in the following cases:
*
* 1) There is no such endpoint.
* 2) There is no such server cluster on the given endpoint.
* 3) No storage for a data version was provided for the endpoint.
*/
chip::DataVersion * emberAfDataVersionStorage(const chip::app::ConcreteClusterPath & aConcreteClusterPath);
namespace chip {
namespace app {
class EnabledEndpointsWithServerCluster
{
public:
EnabledEndpointsWithServerCluster(ClusterId clusterId);
// Instead of having a separate Iterator class, optimize for codesize by
// just reusing ourselves as our own iterator. We could do a bit better
// here with C++17 and using a different type for the end iterator, but this
// is the best I've found with C++14 so far.
//
// This does mean that you can only iterate a given
// EnabledEndpointsWithServerCluster once, but that's OK given how we use it
// in practice.
EnabledEndpointsWithServerCluster & begin() { return *this; }
const EnabledEndpointsWithServerCluster & end() const { return *this; }
bool operator!=(const EnabledEndpointsWithServerCluster & other) const { return mEndpointIndex != mEndpointCount; }
EnabledEndpointsWithServerCluster & operator++();
EndpointId operator*() const { return emberAfEndpointFromIndex(mEndpointIndex); }
private:
void EnsureMatchingEndpoint();
uint16_t mEndpointIndex = 0;
uint16_t mEndpointCount = emberAfEndpointCount();
ClusterId mClusterId;
};
} // namespace app
} // namespace chip