/* * * Copyright (c) 2024 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 #include namespace chip { namespace app { namespace Clusters { namespace ServiceArea { // These limits are defined in the spec. inline constexpr size_t kMaxNumSupportedAreas = 255; inline constexpr size_t kMaxNumSupportedMaps = 255; inline constexpr size_t kMaxNumSelectedAreas = 255; inline constexpr size_t kMaxNumProgressElements = 255; inline constexpr size_t kMaxSizeStatusText = 256; inline constexpr size_t kAreaNameMaxSize = 128u; inline constexpr size_t kMapNameMaxSize = 64u; /** * This class is used to wrap the AreaStruct object and provide a more user-friendly interface for the data. * It provides a way to store the location name in a buffer, and provides a way to compare the location name with a given string. */ struct AreaStructureWrapper : public chip::app::Clusters::ServiceArea::Structs::AreaStruct::Type { /** * @brief This is a default constructor that initializes the location object with the following * values: areaID = 0, mapID = null, locationInfo = null, landmarkInfo = null. */ AreaStructureWrapper() { areaID = 0; mapID = DataModel::NullNullable; SetLocationInfoNull(); SetLandmarkInfoNull(); } /** * @brief This is a copy constructor that initializes the location object with the values from another location object. All * values are deep copied. * @param[in] aOther The location object to copy. * * @note If the locationName is empty string and aFloorNumber and aAreaTypeTag are null, locationInfo will be set to null. */ AreaStructureWrapper(const AreaStructureWrapper & aOther) { *this = aOther; } /** * @brief This is an assignment operator that initializes the location object with the values from another location object. All * values are deep copied. * @param[in] aOther The location object to copy. * * @note If the locationName is empty string and aFloorNumber and aAreaTypeTag are null, locationInfo will be set to null. */ AreaStructureWrapper & operator=(const AreaStructureWrapper & aOther) { areaID = aOther.areaID; mapID = aOther.mapID; SetLocationInfo(aOther.areaInfo.locationInfo); SetLandmarkInfo(aOther.areaInfo.landmarkInfo); return *this; } bool operator==(const AreaStructureWrapper & aOther) const { BitMask config = 0; // Do not ignore the AreaID or the MapID. return IsEqual(aOther, config); } AreaStructureWrapper & SetAreaId(uint32_t aAreaID) { areaID = aAreaID; return *this; } AreaStructureWrapper & SetMapId(const DataModel::Nullable & aMapId) { mapID = aMapId; return *this; } AreaStructureWrapper & SetLocationInfoNull() { areaInfo.locationInfo.SetNull(); return *this; } /** * @brief Set the location information. * @param[in] locationName The name of the location. If the name is larger than kAreaNameMaxSize, it will be truncated. * @param[in] floorNumber The floor number of the location. * @param[in] areaType The type of the area. */ AreaStructureWrapper & SetLocationInfo(const CharSpan & locationName, const DataModel::Nullable & floorNumber, const DataModel::Nullable & areaType) { areaInfo.locationInfo.SetNonNull(); // Copy the name. If the name is larger than kAreaNameMaxSize, truncate it to fit. auto sizeToCopy = std::min(kAreaNameMaxSize, locationName.size()); memcpy(mAreaNameBuffer, locationName.data(), sizeToCopy); areaInfo.locationInfo.Value().locationName = CharSpan(mAreaNameBuffer, sizeToCopy); areaInfo.locationInfo.Value().floorNumber = floorNumber; areaInfo.locationInfo.Value().areaType = areaType; return *this; } /** * @brief Set the location information form a LocationDescriptorStruct object. * * @note If the locationName is larger than kAreaNameMaxSize, it will be truncated. */ AreaStructureWrapper & SetLocationInfo(DataModel::Nullable locationInfo) { if (locationInfo.IsNull()) { return SetLocationInfoNull(); } return SetLocationInfo(locationInfo.Value().locationName, locationInfo.Value().floorNumber, locationInfo.Value().areaType); } AreaStructureWrapper & SetLandmarkInfoNull() { areaInfo.landmarkInfo.SetNull(); return *this; } /** * @brief Set the landmark information. * @param[in] landmarkTag The landmark tag. * @param[in] relativePositionTag The relative position tag. */ AreaStructureWrapper & SetLandmarkInfo(const Globals::LandmarkTag & landmarkTag, const DataModel::Nullable & relativePositionTag) { areaInfo.landmarkInfo.SetNonNull(); areaInfo.landmarkInfo.Value().landmarkTag = landmarkTag; areaInfo.landmarkInfo.Value().relativePositionTag = relativePositionTag; return *this; } /** * @brief Set the landmark information from a LandmarkInfoStruct object. */ AreaStructureWrapper & SetLandmarkInfo(DataModel::Nullable landmarkInfo) { if (landmarkInfo.IsNull()) { return SetLandmarkInfoNull(); } return SetLandmarkInfo(landmarkInfo.Value().landmarkTag, landmarkInfo.Value().relativePositionTag); } /** * @brief Compare the area's name with the given text. * @param[in] aAreaName The name to compare. * @return true if the area structure's name field matches aAreaName. * False otherwise, including if the location structure's LocationInfo structure is null. */ bool IsNameEqual(const CharSpan & aAreaName) const { if (!areaInfo.locationInfo.IsNull()) { return areaInfo.locationInfo.Value().locationName.data_equal(aAreaName); } return false; } /** * This is used for configuring the IsEqual method. * If kIgnoreAreaID is set, the area IDs are ignored when checking for equality. * If kIgnoreMapId is set, the map IDs are ignored when checking for equality. */ enum class IsEqualConfig : uint8_t { kIgnoreAreaID = 0x1, kIgnoreMapId = 0x2, }; /** * @brief Checks if the given AreaStructureWrapper is equal to this one. * @param aOther The location to compare with. * @param aConfig Set if the area IDs and/or the map IDs should be ignored when checking for equality. * @return True if both locations are equal. False otherwise. */ bool IsEqual(const AreaStructureWrapper & aOther, BitMask aConfig) const { if (!aConfig.Has(IsEqualConfig::kIgnoreAreaID) && (areaID != aOther.areaID)) { return false; } if (!aConfig.Has(IsEqualConfig::kIgnoreMapId) && (mapID != aOther.mapID)) { return false; } if (areaInfo.locationInfo.IsNull() != aOther.areaInfo.locationInfo.IsNull()) { return false; } if (!areaInfo.locationInfo.IsNull()) { if (!IsNameEqual(aOther.areaInfo.locationInfo.Value().locationName)) { return false; } if (areaInfo.locationInfo.Value().floorNumber != aOther.areaInfo.locationInfo.Value().floorNumber) { return false; } if (areaInfo.locationInfo.Value().areaType != aOther.areaInfo.locationInfo.Value().areaType) { return false; } } if (areaInfo.landmarkInfo.IsNull() != aOther.areaInfo.landmarkInfo.IsNull()) { return false; } if (!areaInfo.landmarkInfo.IsNull()) { if (areaInfo.landmarkInfo.Value().landmarkTag != aOther.areaInfo.landmarkInfo.Value().landmarkTag) { return false; } if (areaInfo.landmarkInfo.Value().relativePositionTag != aOther.areaInfo.landmarkInfo.Value().relativePositionTag) { return false; } } return true; } /** * @return The location name. */ CharSpan GetName() { if (areaInfo.locationInfo.IsNull()) { return { mAreaNameBuffer, 0 }; } return areaInfo.locationInfo.Value().locationName; } private: char mAreaNameBuffer[kAreaNameMaxSize] = { 0 }; }; /** * This class wraps the MapStruct object and provides a more user-friendly interface for the data. */ struct MapStructureWrapper : public chip::app::Clusters::ServiceArea::Structs::MapStruct::Type { MapStructureWrapper() { Set(0, CharSpan()); } /** * @brief This is a full constructor that initializes the map object with the given values. All values are deep copied. * @param[in] aMapId The identifier of this map. * @param[in] aMapName A human readable name (should not be empty string). * * @note Requirements regarding what combinations of fields and values are 'valid' are not checked by this class. * @note If aMapName is larger than kMapNameMaxSize, it will be truncated. */ MapStructureWrapper(uint32_t aMapId, const CharSpan & aMapName) { Set(aMapId, aMapName); } /** * @brief This is a copy constructor that initializes the map object with the values from another map object. All values are * deep copied. * @param[in] aOther The map object to copy. */ MapStructureWrapper(const MapStructureWrapper & aOther) { *this = aOther; } /** * @brief This is an assignment operator that initializes the map object with the values from another map object. All values are * deep copied. * @param[in] aOther The map object to copy. */ MapStructureWrapper & operator=(const MapStructureWrapper & aOther) { Set(aOther.mapID, aOther.name); return *this; } /** * @brief Set all fields of the map object. All values are deep copied. * @param[in] aMapId The identifier of this map. * @param[in] aMapName A human readable name (should not be empty string). * * @note Requirements regarding what combinations of fields and values are 'valid' are not checked by this class. * @note if aMapName is larger than kMapNameMaxSize, it will be truncated. */ void Set(uint32_t aMapId, const CharSpan & aMapName) { mapID = aMapId; // Copy the name. If the name is larger than kMapNameMaxSize, truncate it to fit. auto sizeToCopy = std::min(kMapNameMaxSize, aMapName.size()); memcpy(mMapNameBuffer, aMapName.data(), sizeToCopy); name = CharSpan(mMapNameBuffer, sizeToCopy); } /** * @brief Compare the map's name with given text. * @param[in] aMapName The name to compare. * @return true if the map structure's name field matches aMapName. */ bool IsNameEqual(const CharSpan & aMapName) const { return name.data_equal(aMapName); } /** * @return The map name. */ CharSpan GetName() const { return name; } private: char mMapNameBuffer[kMapNameMaxSize] = { 0 }; }; } // namespace ServiceArea } // namespace Clusters } // namespace app } // namespace chip