blob: 489e6788be77f9b3dc1c75f9c0c20ffb0c54c1d5 [file] [log] [blame]
/*
*
* Copyright (c) 2023 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.
*/
#include "ExtensionFieldSetsImpl.h"
namespace chip {
namespace scenes {
// ExtensionFieldSetsImpl::ExtensionFieldSetsImpl() : ExtensionFieldSets() {}
CHIP_ERROR ExtensionFieldSetsImpl::Serialize(TLV::TLVWriter & writer, TLV::Tag structTag) const
{
TLV::TLVType structureContainer;
ReturnErrorOnFailure(writer.StartContainer(structTag, TLV::kTLVType_Structure, structureContainer));
TLV::TLVType arrayContainer;
ReturnErrorOnFailure(
writer.StartContainer(TLV::ContextTag(TagEFS::kFieldSetArrayContainer), TLV::kTLVType_Array, arrayContainer));
for (uint8_t i = 0; i < mFieldSetsCount; i++)
{
ReturnErrorOnFailure(mFieldSets[i].Serialize(writer));
}
ReturnErrorOnFailure(writer.EndContainer(arrayContainer));
return writer.EndContainer(structureContainer);
}
CHIP_ERROR ExtensionFieldSetsImpl::Deserialize(TLV::TLVReader & reader, TLV::Tag structTag)
{
TLV::TLVType structureContainer;
ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, structTag));
ReturnErrorOnFailure(reader.EnterContainer(structureContainer));
TLV::TLVType arrayContainer;
ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Array, TLV::ContextTag(TagEFS::kFieldSetArrayContainer)));
ReturnErrorOnFailure(reader.EnterContainer(arrayContainer));
uint8_t i = 0;
CHIP_ERROR err;
while ((err = reader.Next(TLV::AnonymousTag())) == CHIP_NO_ERROR && i < kMaxClustersPerScene)
{
ReturnErrorOnFailure(mFieldSets[i].Deserialize(reader));
i++;
}
mFieldSetsCount = i;
// In the event of an OTA where the maximum number of clusters per scene has been reduced, the extension field set will be
// considered "corrupted" if we don't manage to load it all (if err == CHIP_NO_ERROR after the loop). We therefore return an
// error and this scene will have to be deleted. This is done because truncating an EFS doesn't guarantee the order of the
// clusters loaded, which might lead to loading clusters that are no longer supported and losing supported ones.
if (err != CHIP_END_OF_TLV)
{
if (err == CHIP_NO_ERROR)
return CHIP_ERROR_BUFFER_TOO_SMALL;
return err;
}
ReturnErrorOnFailure(reader.ExitContainer(arrayContainer));
return reader.ExitContainer(structureContainer);
}
void ExtensionFieldSetsImpl::Clear()
{
for (uint8_t i = 0; i < mFieldSetsCount; i++)
{
mFieldSets[i].Clear();
}
mFieldSetsCount = 0;
}
/// @brief Inserts a field Set set into the array of extension field Set sets for a scene entry.
/// If the same ID is present in the EFS array, it will overwrite it.
/// @param fieldSet field set to be inserted
/// @return CHIP_NO_ERROR if insertion worked, CHIP_ERROR_NO_MEMORY if the array is already full
CHIP_ERROR ExtensionFieldSetsImpl::InsertFieldSet(const ExtensionFieldSet & fieldSet)
{
uint8_t firstEmptyPosition = kInvalidPosition;
VerifyOrReturnError(fieldSet.mID != kInvalidClusterId, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(!fieldSet.IsEmpty(), CHIP_ERROR_INVALID_ARGUMENT);
for (uint8_t i = 0; i < kMaxClustersPerScene; i++)
{
if (mFieldSets[i].mID == fieldSet.mID)
{
mFieldSets[i] = fieldSet;
return CHIP_NO_ERROR;
}
if (mFieldSets[i].IsEmpty() && firstEmptyPosition == kInvalidPosition)
{
firstEmptyPosition = i;
}
}
// if found, replace at found position, otherwise insert at first free position, otherwise return error
if (firstEmptyPosition < kMaxClustersPerScene)
{
mFieldSets[firstEmptyPosition] = fieldSet;
mFieldSetsCount++;
return CHIP_NO_ERROR;
}
return CHIP_ERROR_NO_MEMORY;
}
CHIP_ERROR ExtensionFieldSetsImpl::GetFieldSetAtPosition(ExtensionFieldSet & fieldSet, uint8_t position) const
{
VerifyOrReturnError(position < mFieldSetsCount, CHIP_ERROR_INVALID_ARGUMENT);
fieldSet = mFieldSets[position];
return CHIP_NO_ERROR;
}
CHIP_ERROR ExtensionFieldSetsImpl::RemoveFieldAtPosition(uint8_t position)
{
VerifyOrReturnValue(position < mFieldSetsCount, CHIP_NO_ERROR);
uint8_t nextPos = static_cast<uint8_t>(position + 1);
uint8_t moveNum = static_cast<uint8_t>(kMaxClustersPerScene - nextPos);
// TODO: Implement general array management methods
// Compress array after removal, if the removed position is not the last
if (moveNum)
{
memmove(&mFieldSets[position], &mFieldSets[nextPos], sizeof(ExtensionFieldSet) * moveNum);
}
mFieldSetsCount--;
// Clear last occupied position
mFieldSets[mFieldSetsCount].Clear();
return CHIP_NO_ERROR;
}
} // namespace scenes
} // namespace chip