Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add laundry-washer-controls-cluster server implementation #27503

Merged
merged 29 commits into from
Jul 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
4f7ee38
Add laundry-washer-controls-cluster server implementation
crlonxp Jun 27, 2023
440f57b
Restyled by clang-format
restyled-commits Jun 27, 2023
ef282db
Refine the definition
crlonxp Jun 28, 2023
6ae46e2
Restyled by clang-format
restyled-commits Jun 28, 2023
665b2e3
* Remove unnecessary code to read the attribute
crlonxp Jul 10, 2023
bb9b0b1
Restyled by clang-format
restyled-commits Jul 10, 2023
45fde9d
* Add "const" to the read-only attribute
crlonxp Jul 13, 2023
3998529
* Add LaundryWasherServer get/set API to access the attributes
crlonxp Jul 14, 2023
b92715f
* Add the API to get/set the SpinSpeeds and SupportedRinses attribute…
crlonxp Jul 19, 2023
9e98b96
Restyled by whitespace
restyled-commits Jul 19, 2023
59934be
Restyled by clang-format
restyled-commits Jul 19, 2023
14f1ed7
* Move the release / clean member functions to public
crlonxp Jul 20, 2023
845d1ea
Restyled by clang-format
restyled-commits Jul 20, 2023
461d6e3
* Add back the delegate interface and report the items one by one
crlonxp Jul 21, 2023
21fa5ee
Restyled by whitespace
restyled-commits Jul 21, 2023
7bef9a0
Restyled by clang-format
restyled-commits Jul 21, 2023
bbe0590
* Remove the unused definition for storage-key-alloc
crlonxp Jul 21, 2023
72d6279
Update src/app/clusters/laundry-washer-controls-server/laundry-washer…
crlonxp Jul 22, 2023
9f38b00
Update src/app/clusters/laundry-washer-controls-server/laundry-washer…
crlonxp Jul 22, 2023
f619a52
Update src/app/clusters/laundry-washer-controls-server/laundry-washer…
crlonxp Jul 22, 2023
b4f1b01
Update src/app/clusters/laundry-washer-controls-server/laundry-washer…
crlonxp Jul 22, 2023
402da53
Update src/app/clusters/laundry-washer-controls-server/laundry-washer…
crlonxp Jul 22, 2023
db5a449
* Use MutableCharSpan to replace CharSpan
crlonxp Jul 22, 2023
550253f
Restyled by clang-format
restyled-commits Jul 22, 2023
cc8b13f
* Refine the comment
crlonxp Jul 22, 2023
de033f2
Update src/app/clusters/laundry-washer-controls-server/laundry-washer…
crlonxp Jul 22, 2023
1da8c1a
Update src/app/clusters/laundry-washer-controls-server/laundry-washer…
crlonxp Jul 22, 2023
866b712
Update src/app/clusters/laundry-washer-controls-server/laundry-washer…
crlonxp Jul 22, 2023
3703648
Restyled by clang-format
restyled-commits Jul 22, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
*
* 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 <app-common/zap-generated/cluster-objects.h>
#include <app/AttributeAccessInterface.h>

namespace chip {
namespace app {
namespace Clusters {
namespace LaundryWasherControls {

/** @brief
* Defines methods for implementing application-specific logic for the laundry washer controls cluster.
*/
class Delegate
{
public:
Delegate() = default;
virtual ~Delegate() = default;

/**
* Get the list of supported spin_speed list.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@crlonxp This was merged without addressing review comments (e.g. #27503 (comment)), even though those comments got marked resolved.

I am sorry, but I will no longer be marking your PRs as "approved if you address these comments". All comments will need to be addressed before I can approve.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I create another PR to address these remaining comments? Or should I keep modify the code I have and push?
Thank you

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I create another PR to address these remaining comments?

Yes, please, since this PR is now merged...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I add the change in #28264
Please review. Thank you

* Fills in the provided spin_speed at index `index` if there is one,
* or returns CHIP_ERROR_PROVIDER_LIST_EXHAUSTED if the index is out of range for the list of spin_speed.
* @param index The index of the spin_speed, with 0 representing the first one.
* @param spinSpeed The spin speed is filled.
*/
virtual CHIP_ERROR GetSpinSpeedAtIndex(size_t index, MutableCharSpan & spinSpeed) = 0;

/**
* Get the list of supported rinses list.
crlonxp marked this conversation as resolved.
Show resolved Hide resolved
* Fills in the provided rinses at index `index` if there is one,
* or returns CHIP_ERROR_PROVIDER_LIST_EXHAUSTED if the index is out of range for the list of rinses.
* @param index The index of the supported rinses with 0 representing the first one.
* @param supportedRinse The supported rinse is filled.
*/
virtual CHIP_ERROR GetSupportedRinseAtIndex(size_t index, NumberOfRinsesEnum & supportedRinse) = 0;
crlonxp marked this conversation as resolved.
Show resolved Hide resolved
};

} // namespace LaundryWasherControls
} // namespace Clusters
} // namespace app
} // namespace chip
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
/**
*
* 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 <app/util/af.h>
#include <app/util/attribute-storage.h>
#include <app/util/config.h>

#include "laundry-washer-controls-delegate.h"
#include "laundry-washer-controls-server.h"
#include <app-common/zap-generated/attributes/Accessors.h>
#include <app-common/zap-generated/callback.h>
#include <app-common/zap-generated/cluster-objects.h>
#include <app-common/zap-generated/enums.h>
#include <app-common/zap-generated/ids/Attributes.h>
#include <app-common/zap-generated/ids/Clusters.h>
#include <app/AttributeAccessInterface.h>
#include <app/CommandHandler.h>
#include <app/ConcreteAttributePath.h>
#include <app/ConcreteCommandPath.h>
#include <app/server/Server.h>
#include <app/util/error-mapping.h>
#include <lib/core/CHIPEncoding.h>

using namespace chip;
using namespace chip::app;
using namespace chip::app::Clusters;
using namespace chip::app::Clusters::LaundryWasherControls;
using namespace chip::app::Clusters::LaundryWasherControls::Attributes;
using chip::Protocols::InteractionModel::Status;

static constexpr size_t kLaundryWasherControlsDelegateTableSize =
EMBER_AF_LAUNDRY_WASHER_CONTROLS_CLUSTER_SERVER_ENDPOINT_COUNT + CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT;

// -----------------------------------------------------------------------------
// Delegate Implementation
//
namespace {
Delegate * gDelegateTable[kLaundryWasherControlsDelegateTableSize] = { nullptr };
}

namespace {
Delegate * GetDelegate(EndpointId endpoint)
{
uint16_t ep = emberAfGetClusterServerEndpointIndex(endpoint, LaundryWasherControls::Id,
EMBER_AF_LAUNDRY_WASHER_CONTROLS_CLUSTER_SERVER_ENDPOINT_COUNT);
return (ep >= kLaundryWasherControlsDelegateTableSize ? nullptr : gDelegateTable[ep]);
}

} // namespace

LaundryWasherControlsServer LaundryWasherControlsServer::sInstance;

/**********************************************************
* LaundryWasherControlsServer public methods
*********************************************************/
void LaundryWasherControlsServer::SetDefaultDelegate(EndpointId endpoint, Delegate * delegate)
{
uint16_t ep = emberAfGetClusterServerEndpointIndex(endpoint, LaundryWasherControls::Id,
EMBER_AF_LAUNDRY_WASHER_CONTROLS_CLUSTER_SERVER_ENDPOINT_COUNT);
// if endpoint is found
if (ep < kLaundryWasherControlsDelegateTableSize)
{
gDelegateTable[ep] = delegate;
}
}

LaundryWasherControlsServer & LaundryWasherControlsServer::Instance()
{
return sInstance;
}

EmberAfStatus LaundryWasherControlsServer::SetSpinSpeedCurrent(EndpointId endpointId,
DataModel::Nullable<uint8_t> newSpinSpeedCurrent)
{
DataModel::Nullable<uint8_t> spinSpeedCurrent;
EmberAfStatus res = SpinSpeedCurrent::Get(endpointId, spinSpeedCurrent);
if ((res == EMBER_ZCL_STATUS_SUCCESS) && (spinSpeedCurrent != newSpinSpeedCurrent))
{
res = SpinSpeedCurrent::Set(endpointId, newSpinSpeedCurrent);
}

return res;
}

EmberAfStatus LaundryWasherControlsServer::GetSpinSpeedCurrent(EndpointId endpointId,
DataModel::Nullable<uint8_t> & spinSpeedCurrent)
{
return SpinSpeedCurrent::Get(endpointId, spinSpeedCurrent);
}

EmberAfStatus LaundryWasherControlsServer::SetNumberOfRinses(EndpointId endpointId, NumberOfRinsesEnum newNumberOfRinses)
{
NumberOfRinsesEnum numberOfRinses;
EmberAfStatus res = NumberOfRinses::Get(endpointId, &numberOfRinses);

if ((res == EMBER_ZCL_STATUS_SUCCESS) && (numberOfRinses != newNumberOfRinses))
{
res = NumberOfRinses::Set(endpointId, newNumberOfRinses);
}

return res;
}

EmberAfStatus LaundryWasherControlsServer::GetNumberOfRinses(EndpointId endpointId, NumberOfRinsesEnum & numberOfRinses)
{
return NumberOfRinses::Get(endpointId, &numberOfRinses);
}

/**********************************************************
* LaundryWasherControlsServer private methods
*********************************************************/
CHIP_ERROR LaundryWasherControlsServer::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder)
{
if (aPath.mClusterId != LaundryWasherControls::Id)
{
// We shouldn't have been called at all.
return CHIP_ERROR_INVALID_ARGUMENT;
}
switch (aPath.mAttributeId)
{
case Attributes::SpinSpeeds::Id:
return ReadSpinSpeeds(aPath, aEncoder);
case Attributes::SupportedRinses::Id:
return ReadSupportedRinses(aPath, aEncoder);
default:
break;
}
return CHIP_NO_ERROR;
}

CHIP_ERROR LaundryWasherControlsServer::ReadSpinSpeeds(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder)
{
Delegate * delegate = GetDelegate(aPath.mEndpointId);
VerifyOrReturnError(delegate != nullptr, CHIP_ERROR_INCORRECT_STATE, ChipLogError(Zcl, "Delegate is nullptr"));

return aEncoder.EncodeList([delegate](const auto & encoder) -> CHIP_ERROR {
for (uint8_t i = 0; true; i++)
{
char buffer[kMaxSpinSpeedLength];
MutableCharSpan spinSpeed(buffer);
auto err = delegate->GetSpinSpeedAtIndex(i, spinSpeed);
if (err == CHIP_ERROR_PROVIDER_LIST_EXHAUSTED)
crlonxp marked this conversation as resolved.
Show resolved Hide resolved
{
return CHIP_NO_ERROR;
}
ReturnErrorOnFailure(err);
ReturnErrorOnFailure(encoder.Encode(spinSpeed));
}
});
}

CHIP_ERROR LaundryWasherControlsServer::ReadSupportedRinses(const ConcreteReadAttributePath & aPath,
AttributeValueEncoder & aEncoder)
{
Delegate * delegate = GetDelegate(aPath.mEndpointId);
VerifyOrReturnError(delegate != nullptr, CHIP_ERROR_INCORRECT_STATE, ChipLogError(Zcl, "Delegate is nullptr"));

return aEncoder.EncodeList([delegate](const auto & encoder) -> CHIP_ERROR {
for (uint8_t i = 0; true; i++)
{
NumberOfRinsesEnum supportedRinse;
auto err = delegate->GetSupportedRinseAtIndex(i, supportedRinse);
if (err == CHIP_ERROR_PROVIDER_LIST_EXHAUSTED)
{
return CHIP_NO_ERROR;
}
ReturnErrorOnFailure(err);
ReturnErrorOnFailure(encoder.Encode(supportedRinse));
}
});
}

/**********************************************************
* Register LaundryWasherControlsServer
*********************************************************/

void MatterLaundryWasherControlsPluginServerInitCallback()
{
LaundryWasherControlsServer & laundryWasherControlsServer = LaundryWasherControlsServer::Instance();
registerAttributeAccessOverride(&laundryWasherControlsServer);
}
crlonxp marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/**
*
* 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.
*/

#pragma once

#include "laundry-washer-controls-delegate.h"
#include <app-common/zap-generated/cluster-objects.h>
#include <app/AttributeAccessInterface.h>
#include <app/util/af.h>

namespace chip {
namespace app {
namespace Clusters {
namespace LaundryWasherControls {

/**
* @brief LaundryWasherControls Server Plugin class
*/
class LaundryWasherControlsServer : public AttributeAccessInterface
{
public:
LaundryWasherControlsServer() : AttributeAccessInterface(Optional<EndpointId>::Missing(), LaundryWasherControls::Id) {}
static LaundryWasherControlsServer & Instance();

static constexpr uint8_t kMaxSpinSpeedLength = 64;
crlonxp marked this conversation as resolved.
Show resolved Hide resolved

/**
* Set the default delegate of laundry washer server at endpoint x
* @param endpoint ID of the endpoint
* @param delegate The default delegate at the endpoint
* @return CHIP_ERROR CHIP_NO_ERROR on success, or corresponding error code.
*/
static void SetDefaultDelegate(EndpointId endpoint, Delegate * delegate);

/**
* Init the laundry washer server.
* @param void
* @return CHIP_ERROR CHIP_NO_ERROR on success, or corresponding error code.
*/
// CHIP_ERROR Init();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this commented-out thing here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I registered the LaundryWasherControlServer instance to registerAttributeAccessOverride() before. But it's moved to MatterLaundryWasherControlsPluginServerInitCallback() that it's no specific behavior needed for now.
Should I keep the empty function?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would just remove it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the suggestion.


/**
* @brief Set the attribute newSpinSpeedCurrent
*
* @param endpointId ID of the endpoint
* @param newSpinSpeedCurrent attribute SpinSpeedCurrent
* @return true on success, false on failure
*/
EmberAfStatus SetSpinSpeedCurrent(EndpointId endpointId, DataModel::Nullable<uint8_t> newSpinSpeedCurrent);

/**
* @brief Get the attribute newSpinSpeedCurrent
*
* @param endpointId ID of the endpoint
* @param SpinSpeedCurrent attribute SpinSpeedCurrent
* @return true on success, false on failure
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

commenting post merge, so I do not block the PR: these return EmberAfStatus, so probably not true on success/false on failure. Also the comment seems redundant - when something returns CHIP_ERROR or EmberAfStatus the return is reasonably clear.

Overall we can save vertical space a lot (it is obvious GetSpinSpeedCurrent gets the speed speed current). I guess it is unclear what newSpinSpeedCurrent is (what is new) but the comment does not help me much ... it seems everything is called newSpinSpeedCurrent.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the suggestions. I will change these in the next PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I add the change in #28264
Please review. Thank you

*/
EmberAfStatus GetSpinSpeedCurrent(EndpointId endpointId, DataModel::Nullable<uint8_t> & spinSpeedCurrent);

/**
* @brief Set the attribute NumberOfRinses
*
* @param endpointId ID of the endpoint
* @param newNumberOfRinses attribute NumberOfRinses
* @return true on success, false on failure
*/
EmberAfStatus SetNumberOfRinses(EndpointId endpointId, NumberOfRinsesEnum newNumberOfRinses);

/**
* @brief Get the attribute NumberOfRinses
*
* @param endpointId ID of the endpoint
* @param NumberOfRinses attribute NumberOfRinses
* @return true on success, false on failure
*/
EmberAfStatus GetNumberOfRinses(EndpointId endpointId, NumberOfRinsesEnum & numberOfRinses);

private:
CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override;
CHIP_ERROR ReadSpinSpeeds(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder);
CHIP_ERROR ReadSupportedRinses(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder);

static LaundryWasherControlsServer sInstance;
};

} // namespace LaundryWasherControls
} // namespace Clusters
} // namespace app
} // namespace chip
1 change: 1 addition & 0 deletions src/app/zap_cluster_list.json
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@
"UNIT_TESTING_CLUSTER": ["test-cluster-server"],
"USER_LABEL_CLUSTER": ["user-label-server"],
"WAKE_ON_LAN_CLUSTER": ["wake-on-lan-server"],
"LAUNDRY_WASHER_CONTROLS_CLUSTER": ["laundry-washer-controls-server"],
"WIFI_NETWORK_DIAGNOSTICS_CLUSTER": ["wifi-network-diagnostics-server"],
"WINDOW_COVERING_CLUSTER": ["window-covering-server"],
"ZLL_COMMISSIONING_CLUSTER": []
Expand Down