diff --git a/.github/.wordlist.txt b/.github/.wordlist.txt index 1e24bdb65838d1..eb27e5855e1bc5 100644 --- a/.github/.wordlist.txt +++ b/.github/.wordlist.txt @@ -1562,3 +1562,5 @@ zhengyaohan Zigbee zigbeealliance zigbeethread +PIXIT +RVC \ No newline at end of file diff --git a/docs/examples/index.md b/docs/examples/index.md index 9c74b1f5360e6a..b28c7c6e2ebd7f 100644 --- a/docs/examples/index.md +++ b/docs/examples/index.md @@ -292,3 +292,12 @@ window-app/**/README resource-monitoring-app/**/README ``` + +## Air Quality Sensor example + +```{toctree} +:glob: +:maxdepth: 1 + +rvc-app/README +``` diff --git a/examples/rvc-app/README.md b/examples/rvc-app/README.md new file mode 100644 index 00000000000000..a5d68613fc88bc --- /dev/null +++ b/examples/rvc-app/README.md @@ -0,0 +1,125 @@ +# RVC example app + +This example app is meant to demonstrate an implementation of a Matter Robotic +Vacuum Cleaner device. + +## State machine + +Below is a diagram describing the state machine for this app. + +![state machine](RVC_app_state_diagram.png) + +This app can support most of the tests in the test plans. + +## Out-of-band messages + +Out-of-band messages are available to simulate typical device behaviors and +allow the app to navigate to all the states. To send an out-of-band message, +echo the JSON message to the `/tmp/chip_rvc_fifo_` file. The JSON message +must have a `"Name"` key that contains the command name. This name is shown in +the state machine diagram above. Example +`echo '{"Name": "Charged"}' > /tmp/chip_rvc_fifo_42`. + +### `ErrorEvent` message + +The error event message requires the additional key `"Error"` which specifies +the error state ID. This can be one of `UnableToStartOrResume`, +`UnableToCompleteOperation`, `CommandInvalidInState`, +`FailedToFindChargingDock`, `Stuck`, `DustBinMissing`, `DustBinFull`, +`WaterTankEmpty`, `WaterTankMissing`, `WaterTankLidOpen`, +`MopCleaningPadMissing`. + +## Testing + +A PICS file that details what this app supports testing is available in the +`pics` directory as a txt file. After building the RVC example app, chip-tool, +and setting up the testing environment, python tests can be executed with +`./scripts/tests/run_python_test.py --script src/python_testing/.py --script-args "--storage-path admin_storage.json --PICS examples/rvc-app/rvc-common/pics/RVC_App_Test_Plan.txt --int-arg "` + +**Note:** If the testing environment has not been commissioned with the RVC app, +use chip-tool to switch on the commissioning window +`chip-tool pairing open-commissioning-window`, and add the following flags to +the `--script-args` above. +`--commissioning-method on-network --discriminator XXXX --passcode XXXX`. + +Below are the PIXIT definitions required for the different python tests. + +### RVC Clean Mode cluster + +#### TC 1.2 + +PIXIT: `PIXIT_ENDPOINT:1` +Example command: +`./scripts/tests/run_python_test.py --script src/python_testing/TC_RVCCLEANM_1_2.py --script-args "--storage-path admin_storage.json --PICS examples/rvc-app/rvc-common/pics/RVC_App_Test_Plan.txt --int-arg PIXIT_ENDPOINT:1"` + +#### TC 2.1 + +PIXIT: +`PIXIT_ENDPOINT:1 PIXIT.RVCCLEANM.MODE_CHANGE_FAIL:1 PIXIT.RVCCLEANM.MODE_CHANGE_OK:2` +Example command: +`/scripts/tests/run_python_test.py --script src/python_testing/TC_RVCCLEANM_2_1.py --script-args "--storage-path admin_storage.json --PICS examples/rvc-app/rvc-common/pics/RVC_App_Test_Plan.txt --int-arg PIXIT_ENDPOINT:1 PIXIT.RVCCLEANM.MODE_CHANGE_FAIL:1 PIXIT.RVCCLEANM.MODE_CHANGE_OK:2"` + +When asked "Manually put the device in a state from which it will FAIL to +transition to mode 1", set the `RvcRunMode` to 1. +`chip-tool rvcrunmode change-to-mode 1` + +When asked "Manually put the device in a state from which it will SUCCESSFULLY +transition to mode 2", set the `RvcRunMode` to 0. +`chip-tool rvcrunmode change-to-mode 0` + +#### TC 3.2 + +This is not applicable because this RVC device does not support the +`StartUpMode` attribute. + +### RVC Run Mode cluster + +#### TC 1.2 + +PIXIT: `PIXIT_ENDPOINT:1` Example command: +`./scripts/tests/run_python_test.py --script src/python_testing/TC_RVCRUNM_1_2.py --script-args "--storage-path admin_storage.json --PICS examples/rvc-app/rvc-common/pics/RVC_App_Test_Plan.txt --int-arg PIXIT_ENDPOINT:1"` + +#### TC 2.1 + +PIXIT: +`PIXIT_ENDPOINT:1 PIXIT.RVCRUNM.MODE_CHANGE_FAIL:2 PIXIT.RVCRUNM.MODE_CHANGE_OK:0` +Example command: +`./scripts/tests/run_python_test.py --script src/python_testing/TC_RVCRUNM_2_1.py --script-args "--storage-path admin_storage.json --PICS examples/rvc-app/rvc-common/pics/RVC_App_Test_Plan.txt --int-arg PIXIT_ENDPOINT:1 PIXIT.RVCRUNM.MODE_CHANGE_FAIL:2 PIXIT.RVCRUNM.MODE_CHANGE_OK:0"` + +When asked "Manually put the device in a state from which it will FAIL to +transition to mode 2", set the `RvcRunMode` to 1. +`chip-tool rvcrunmode change-to-mode 1` + +When asked "Manually put the device in a state from which it will SUCCESSFULLY +transition to mode 0", do nothing. + +#### TC 3.2 + +This is not applicable because this RVC device does not support the +`StartUpMode` attribute. + +### RVC Operational State cluster + +#### TC 2.1 + +PIXIT: `PIXIT_ENDPOINT:1` +Example command: +`./scripts/tests/run_python_test.py --script src/python_testing/TC_RVCOPSTATE_2_1.py --script-args "--storage-path admin_storage.json --PICS examples/rvc-app/rvc-common/pics/RVC_App_Test_Plan.txt --int-arg PIXIT_ENDPOINT:1"` + +Use the out-of-band messages, chip-tool messages and the state machine diagram +to navigate to the required states. + +#### TC 2.3 + +PIXIT: `PIXIT_ENDPOINT:1` +Example command: +`./scripts/tests/run_python_test.py --script src/python_testing/TC_RVCOPSTATE_2_3.py --script-args "--storage-path admin_storage.json --PICS examples/rvc-app/rvc-common/pics/RVC_App_Test_Plan.txt --int-arg PIXIT_ENDPOINT:1"` + +Use the out-of-band messages, chip-tool messages and the state machine diagram +to transition to the required states. + +### Running the yaml tests + +After commissioning the device, all the yaml tests can be run by running the +`run_all_yaml_tests.sh` script from the root dir with the node ID that the +device was commissioned with. diff --git a/examples/rvc-app/RVC_app_state_diagram.png b/examples/rvc-app/RVC_app_state_diagram.png new file mode 100644 index 00000000000000..5b8cd90807bae7 Binary files /dev/null and b/examples/rvc-app/RVC_app_state_diagram.png differ diff --git a/examples/rvc-app/RVC_app_state_diagram_drawio.xml b/examples/rvc-app/RVC_app_state_diagram_drawio.xml index 590f1db1d542bd..69b82a62543f48 100644 --- a/examples/rvc-app/RVC_app_state_diagram_drawio.xml +++ b/examples/rvc-app/RVC_app_state_diagram_drawio.xml @@ -1,2 +1,2 @@ - \ No newline at end of file +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 \ No newline at end of file diff --git a/examples/rvc-app/linux/BUILD.gn b/examples/rvc-app/linux/BUILD.gn index 7c865a380c9a9c..2db48c20b27357 100644 --- a/examples/rvc-app/linux/BUILD.gn +++ b/examples/rvc-app/linux/BUILD.gn @@ -27,6 +27,7 @@ executable("chip-rvc-app") { "${chip_root}/examples/rvc-app/rvc-common/src/rvc-device.cpp", "${chip_root}/examples/rvc-app/rvc-common/src/rvc-mode-delegates.cpp", "${chip_root}/examples/rvc-app/rvc-common/src/rvc-operational-state-delegate.cpp", + "RvcAppCommandDelegate.cpp", "include/CHIPProjectAppConfig.h", "main.cpp", ] @@ -35,6 +36,7 @@ executable("chip-rvc-app") { "${chip_root}/examples/platform/linux:app-main", "${chip_root}/examples/rvc-app/rvc-common", "${chip_root}/src/lib", + "${chip_root}/third_party/jsoncpp", ] include_dirs = [ diff --git a/examples/rvc-app/linux/RvcAppCommandDelegate.cpp b/examples/rvc-app/linux/RvcAppCommandDelegate.cpp new file mode 100644 index 00000000000000..da2908cf65e6ec --- /dev/null +++ b/examples/rvc-app/linux/RvcAppCommandDelegate.cpp @@ -0,0 +1,164 @@ +/* + * + * 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. + */ + +#include "RvcAppCommandDelegate.h" +#include + +#include "rvc-device.h" +#include + +using namespace chip; +using namespace chip::app::Clusters; + +RvcAppCommandHandler * RvcAppCommandHandler::FromJSON(const char * json) +{ + Json::Reader reader; + Json::Value value; + + if (!reader.parse(json, value)) + { + ChipLogError(NotSpecified, "RVC App: Error parsing JSON with error %s:", reader.getFormattedErrorMessages().c_str()); + return nullptr; + } + + if (value.empty() || !value.isObject()) + { + ChipLogError(NotSpecified, "RVC App: Invalid JSON command received"); + return nullptr; + } + + if (!value.isMember("Name") || !value["Name"].isString()) + { + ChipLogError(NotSpecified, "RVC App: Invalid JSON command received: command name is missing"); + return nullptr; + } + + return Platform::New(std::move(value)); +} + +void RvcAppCommandHandler::HandleCommand(intptr_t context) +{ + auto * self = reinterpret_cast(context); + std::string name = self->mJsonValue["Name"].asString(); + + VerifyOrExit(!self->mJsonValue.empty(), ChipLogError(NotSpecified, "Invalid JSON event command received")); + + if (name == "Charged") + { + self->OnChargedHandler(); + } + else if (name == "Charging") + { + self->OnChargingHandler(); + } + else if (name == "Docked") + { + self->OnDockedHandler(); + } + else if (name == "ChargerFound") + { + self->OnChargerFoundHandler(); + } + else if (name == "LowCharge") + { + self->OnLowChargeHandler(); + } + else if (name == "ActivityComplete") + { + self->OnActivityCompleteHandler(); + } + else if (name == "ErrorEvent") + { + std::string error = self->mJsonValue["Error"].asString(); + self->OnErrorEventHandler(error); + } + else if (name == "ClearError") + { + self->OnClearErrorHandler(); + } + else + { + ChipLogError(NotSpecified, "Unhandled command: Should never happens"); + } + +exit: + Platform::Delete(self); +} + +void RvcAppCommandHandler::SetRvcDevice(chip::app::Clusters::RvcDevice * aRvcDevice) +{ + mRvcDevice = aRvcDevice; +} + +void RvcAppCommandHandler::OnChargedHandler() +{ + mRvcDevice->HandleChargedMessage(); +} + +void RvcAppCommandHandler::OnChargingHandler() +{ + mRvcDevice->HandleChargingMessage(); +} + +void RvcAppCommandHandler::OnDockedHandler() +{ + mRvcDevice->HandleDockedMessage(); +} + +void RvcAppCommandHandler::OnChargerFoundHandler() +{ + mRvcDevice->HandleChargerFoundMessage(); +} + +void RvcAppCommandHandler::OnLowChargeHandler() +{ + mRvcDevice->HandleLowChargeMessage(); +} + +void RvcAppCommandHandler::OnActivityCompleteHandler() +{ + mRvcDevice->HandleActivityCompleteEvent(); +} + +void RvcAppCommandHandler::OnErrorEventHandler(const std::string & error) +{ + mRvcDevice->HandleErrorEvent(error); +} + +void RvcAppCommandHandler::OnClearErrorHandler() +{ + mRvcDevice->HandleClearErrorMessage(); +} + +void RvcAppCommandDelegate::SetRvcDevice(chip::app::Clusters::RvcDevice * aRvcDevice) +{ + mRvcDevice = aRvcDevice; +} + +void RvcAppCommandDelegate::OnEventCommandReceived(const char * json) +{ + auto handler = RvcAppCommandHandler::FromJSON(json); + if (nullptr == handler) + { + ChipLogError(NotSpecified, "RVC App: Unable to instantiate a command handler"); + return; + } + + handler->SetRvcDevice(mRvcDevice); + chip::DeviceLayer::PlatformMgr().ScheduleWork(RvcAppCommandHandler::HandleCommand, reinterpret_cast(handler)); +} diff --git a/examples/rvc-app/linux/RvcAppCommandDelegate.h b/examples/rvc-app/linux/RvcAppCommandDelegate.h new file mode 100644 index 00000000000000..8be8943172b37a --- /dev/null +++ b/examples/rvc-app/linux/RvcAppCommandDelegate.h @@ -0,0 +1,69 @@ +/* + * + * 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 "NamedPipeCommands.h" +#include "rvc-device.h" +#include +#include + +class RvcAppCommandHandler +{ +public: + static RvcAppCommandHandler * FromJSON(const char * json); + + static void HandleCommand(intptr_t context); + + RvcAppCommandHandler(Json::Value && jasonValue) : mJsonValue(std::move(jasonValue)) {} + + void SetRvcDevice(chip::app::Clusters::RvcDevice * aRvcDevice); + +private: + Json::Value mJsonValue; + chip::app::Clusters::RvcDevice * mRvcDevice; + + /** + * Should be called to notify that the device has finished charging. + */ + void OnChargedHandler(); + + void OnChargingHandler(); + + void OnDockedHandler(); + + void OnChargerFoundHandler(); + + void OnLowChargeHandler(); + + void OnActivityCompleteHandler(); + + void OnErrorEventHandler(const std::string & error); + + void OnClearErrorHandler(); +}; + +class RvcAppCommandDelegate : public NamedPipeCommandDelegate +{ +private: + chip::app::Clusters::RvcDevice * mRvcDevice; + +public: + void SetRvcDevice(chip::app::Clusters::RvcDevice * aRvcDevice); + void OnEventCommandReceived(const char * json) override; +}; diff --git a/examples/rvc-app/linux/main.cpp b/examples/rvc-app/linux/main.cpp index 462bc6febfec29..3800e8e501d168 100644 --- a/examples/rvc-app/linux/main.cpp +++ b/examples/rvc-app/linux/main.cpp @@ -15,25 +15,46 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include "RvcAppCommandDelegate.h" #include "rvc-device.h" #include +#define RVC_ENDPOINT 1 + using namespace chip; using namespace chip::app; using namespace chip::app::Clusters; -RvcDevice * rvcDevice = nullptr; +namespace { +constexpr const char kChipEventFifoPathPrefix[] = "/tmp/chip_rvc_fifo_"; +NamedPipeCommands sChipNamedPipeCommands; +RvcAppCommandDelegate sRvcAppCommandDelegate; +} // namespace + +RvcDevice * gRvcDevice = nullptr; void ApplicationInit() { - rvcDevice = new RvcDevice(1); - rvcDevice->Init(); + std::string path = kChipEventFifoPathPrefix + std::to_string(getpid()); + + if (sChipNamedPipeCommands.Start(path, &sRvcAppCommandDelegate) != CHIP_NO_ERROR) + { + ChipLogError(NotSpecified, "Failed to start CHIP NamedPipeCommands"); + sChipNamedPipeCommands.Stop(); + } + + gRvcDevice = new RvcDevice(RVC_ENDPOINT); + gRvcDevice->Init(); + + sRvcAppCommandDelegate.SetRvcDevice(gRvcDevice); } void ApplicationShutdown() { - delete rvcDevice; - rvcDevice = nullptr; + delete gRvcDevice; + gRvcDevice = nullptr; + + sChipNamedPipeCommands.Stop(); } int main(int argc, char * argv[]) diff --git a/examples/rvc-app/run_all_yaml_tests.sh b/examples/rvc-app/run_all_yaml_tests.sh new file mode 100755 index 00000000000000..a599a6139cdf95 --- /dev/null +++ b/examples/rvc-app/run_all_yaml_tests.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +## --- +# This is a helper script that runs all the yaml tests for all the application clusters enabled in the RVC App. +# Run the script from the root dir. +# The script takes the node ID that the device was commissioned with. +## --- + +NODEID=$1 +RVC_DEVICE_ENDPOINT=1 + +PICS_RUN="examples/rvc-app/rvc-common/pics/RVC_App_Test_Plan.txt" +PICS_CLEAN="examples/rvc-app/rvc-common/pics/RVC_App_Test_Plan.txt" +PICS_OP_STATE="examples/rvc-app/rvc-common/pics/RVC_App_Test_Plan.txt" + +if [ -z "$NODEID" ]; then + echo "Usage: run_all_yaml_tests [Node ID]" + exit +fi + +# RVC Clean Mode cluster +./scripts/tests/yaml/chiptool.py tests Test_TC_RVCCLEANM_1_1 --PICS "$PICS_CLEAN" --nodeId "$NODEID" --endpoint "$RVC_DEVICE_ENDPOINT" && + + # RVC Operational State cluster + ./scripts/tests/yaml/chiptool.py tests Test_TC_RVCOPSTATE_1_1 --PICS "$PICS_OP_STATE" --nodeId "$NODEID" --endpoint "$RVC_DEVICE_ENDPOINT" && + ./scripts/tests/yaml/chiptool.py tests Test_TC_RVCOPSTATE_2_2 --PICS "$PICS_OP_STATE" --nodeId "$NODEID" --endpoint "$RVC_DEVICE_ENDPOINT" && + + # RVC Run Mode cluster + ./scripts/tests/yaml/chiptool.py tests Test_TC_RVCRUNM_1_1 --PICS "$PICS_RUN" --nodeId "$NODEID" --endpoint "$RVC_DEVICE_ENDPOINT" && + echo done diff --git a/examples/rvc-app/rvc-common/include/rvc-device.h b/examples/rvc-app/rvc-common/include/rvc-device.h index 9ded6e76b8fbee..6064bcea3e9f73 100644 --- a/examples/rvc-app/rvc-common/include/rvc-device.h +++ b/examples/rvc-app/rvc-common/include/rvc-device.h @@ -21,6 +21,9 @@ class RvcDevice RvcOperationalState::RvcOperationalStateDelegate mOperationalStateDelegate; OperationalState::Instance mOperationalStateInstance; + bool mDocked = false; + bool mCharging = false; + public: /** * This class is responsible for initialising all the RVC clusters and manging the interactions between them as required by @@ -34,8 +37,9 @@ class RvcDevice { // set the current-mode at start-up mRunModeInstance.UpdateCurrentMode(RvcRunMode::ModeIdle); - // Assume that the device is not docked. - mOperationalStateInstance.SetOperationalState(to_underlying(OperationalState::OperationalStateEnum::kStopped)); + + // Hypothetically, the device checks if it is physically docked or charging + SetDeviceToIdleState(); // set callback functions mRunModeDelegate.SetHandleChangeToMode(&RvcDevice::HandleRvcRunChangeToMode, this); @@ -49,6 +53,12 @@ class RvcDevice */ void Init(); + /** + * Sets the device to an idle state, that is either the STOPPED, DOCKED or CHARGING state, depending on physical information. + * Note: in this example this is based on the mDocked and mChanging boolean variables. + */ + void SetDeviceToIdleState(); + /** * Handles the RvcRunMode command requesting a mode change. */ @@ -68,6 +78,31 @@ class RvcDevice * Handles the RvcOperationalState resume command. */ void HandleOpStateResumeCallback(Clusters::OperationalState::GenericOperationalError & err); + + /** + * Updates the state machine when the device becomes fully-charged. + */ + void HandleChargedMessage(); + + void HandleChargingMessage(); + + void HandleDockedMessage(); + + void HandleChargerFoundMessage(); + + void HandleLowChargeMessage(); + + void HandleActivityCompleteEvent(); + + /** + * Sets the device to an error state with the error state ID matching the error name given. + * @param error The error name. Could be one of UnableToStartOrResume, UnableToCompleteOperation, CommandInvalidInState, + * FailedToFindChargingDock, Stuck, DustBinMissing, DustBinFull, WaterTankEmpty, WaterTankMissing, WaterTankLidOpen or + * MopCleaningPadMissing. + */ + void HandleErrorEvent(const std::string & error); + + void HandleClearErrorMessage(); }; } // namespace Clusters diff --git a/examples/rvc-app/rvc-common/pics/RVC Clean Mode Cluster Test Plan.xml b/examples/rvc-app/rvc-common/pics/RVC Clean Mode Cluster Test Plan.xml new file mode 100644 index 00000000000000..ce0ddaa38b5307 --- /dev/null +++ b/examples/rvc-app/rvc-common/pics/RVC Clean Mode Cluster Test Plan.xml @@ -0,0 +1,132 @@ + + + RVC Clean Mode Cluster Test Plan + + + + + + RVCCLEANM.S + Does the device implement the RVCCLEANM cluster as a server? + 89.1. Role - allclusters.html[pdf] + O + true + + + + + + PIXIT.RVCCLEANM.MODE_CHANGE_FAIL + Id of mode the device will fail to transition to, given its current state + 90. PIXIT Definition - allclusters.html[pdf] + O + 0x01 + + + PIXIT.RVCCLEANM.MODE_CHANGE_OK + Id of mode the device will successfully transition to, given its current state + 90. PIXIT Definition - allclusters.html[pdf] + O + 0x01 + + + + + + + + RVCCLEANM.S.A0000 + Does the device implement the SupportedModes attribute? + 89.2.2. Attributes - allclusters.html[pdf] + M + true + + + RVCCLEANM.S.A0001 + Does the device implement the CurrentMode attribute? + 89.2.2. Attributes - allclusters.html[pdf] + M + true + + + RVCCLEANM.S.A0002 + Does the device implement the StartUpMode attribute? + 89.2.2. Attributes - allclusters.html[pdf] + O + false + + + RVCCLEANM.S.A0003 + Does the device implement the OnMode attribute? + 89.2.2. Attributes - allclusters.html[pdf] + M + false + + + + + + + + RVCCLEANM.S.C01.Tx + Does the device implement sending the ChangeToModeResponse command? + 89.2.4. Commands generated - allclusters.html[pdf] + M + true + + + + + + RVCCLEANM.S.C00.Rsp + Does the device implement receiving the ChangeToMode command? + 89.2.3. Commands received - allclusters.html[pdf] + M + true + + + + + + RVCCLEANM.S.F00 + Does the device support depending on an On/Off cluster implemented on the same endpoint? + 89.2.1. Features - allclusters.html[pdf] + O + false + + + + + + RVCCLEANM.S.M.CAN_TEST_MODE_FAILURE + Does the DUT support testing the failed ChangeToMode command? + 89.2.5. Manual controllable - allclusters.html[pdf] + O + true + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/rvc-app/rvc-common/pics/RVC Operational State Cluster Test Plan.xml b/examples/rvc-app/rvc-common/pics/RVC Operational State Cluster Test Plan.xml new file mode 100644 index 00000000000000..c600445a35964a --- /dev/null +++ b/examples/rvc-app/rvc-common/pics/RVC Operational State Cluster Test Plan.xml @@ -0,0 +1,285 @@ + + + RVC Operational State Cluster Test Plan + + + + + + RVCOPSTATE.S + Does the device implement the RVC Operational State cluster as a server? + 223.1. Role - allclusters.html[pdf] + O + true + + + + + + + + + + RVCOPSTATE.S.A0000 + Does the device implement the PhaseList attribute? + 223.2.1. Attributes - allclusters.html[pdf] + M + true + + + RVCOPSTATE.S.A0001 + Does the device implement the CurrentPhase attribute? + 223.2.1. Attributes - allclusters.html[pdf] + M + true + + + RVCOPSTATE.S.A0002 + Does the device implement the CountdownTime attribute? + 223.2.1. Attributes - allclusters.html[pdf] + O + false + + + RVCOPSTATE.S.A0003 + Does the device implement the OperationalStateList attribute? + 223.2.1. Attributes - allclusters.html[pdf] + M + true + + + RVCOPSTATE.S.A0004 + Does the device implement the OperationalState attribute? + 223.2.1. Attributes - allclusters.html[pdf] + M + true + + + RVCOPSTATE.S.A0005 + Does the device implement the OperationalError attribute? + 223.2.1. Attributes - allclusters.html[pdf] + M + true + + + + + + RVCOPSTATE.S.E00 + Does the device implement the OperationalError Event ? + 223.2.4. Events - allclusters.html[pdf] + M + true + + + RVCOPSTATE.S.E01 + Does the device implement the OperationCompletion Event ? + 223.2.4. Events - allclusters.html[pdf] + O + true + + + + + + RVCOPSTATE.S.C04.Tx + Does the device implement generating the OperationalCommandResponse command? + 223.2.3. Commands generated - allclusters.html[pdf] + M + true + + + + + + RVCOPSTATE.S.C00.Rsp + Does the device implement receiving the Pause command? + 223.2.2. Commands received - allclusters.html[pdf] + O + true + + + RVCOPSTATE.S.C01.Rsp + Does the device implement receiving the Stop command? + 223.2.2. Commands received - allclusters.html[pdf] + O + false + + + RVCOPSTATE.S.C02.Rsp + Does the device implement receiving the Start command? + 223.2.2. Commands received - allclusters.html[pdf] + O + false + + + RVCOPSTATE.S.C03.Rsp + Does the device implement receiving the Resume command? + 223.2.2. Commands received - allclusters.html[pdf] + O + true + + + + + + + + RVCOPSTATE.S.M.ST_STOPPED + Does the DUT support testing the Stopped(0x00) operational state? + 223.2.5. Manual controllable - allclusters.html[pdf] + O + true + + + RVCOPSTATE.S.M.ST_RUNNING + Does the DUT support testing the Running(0x01) operational state? + 223.2.5. Manual controllable - allclusters.html[pdf] + O + true + + + RVCOPSTATE.S.M.ST_PAUSED + Does the DUT support testing the Paused(0x02) operational state? + 223.2.5. Manual controllable - allclusters.html[pdf] + O + true + + + RVCOPSTATE.S.M.ST_ERROR + Does the DUT support testing the Error(0x03) operational state? + 223.2.5. Manual controllable - allclusters.html[pdf] + O + true + + + RVCOPSTATE.S.M.ST_SEEKING_CHARGER + Does the DUT support testing the SeekingCharger(0x40) operational state? + 223.2.5. Manual controllable - allclusters.html[pdf] + O + true + + + RVCOPSTATE.S.M.ST_CHARGING + Does the DUT support testing the Charging(0x41) operational state? + 223.2.5. Manual controllable - allclusters.html[pdf] + O + true + + + RVCOPSTATE.S.M.ST_DOCKED + Does the DUT support testing the Docked(0x42) operational state? + 223.2.5. Manual controllable - allclusters.html[pdf] + O + true + + + RVCOPSTATE.S.M.ERR_NO_ERROR + Does the DUT support testing the NoError(0x00) error state? + 223.2.5. Manual controllable - allclusters.html[pdf] + O + true + + + RVCOPSTATE.S.M.ERR_UNABLE_TO_START_OR_RESUME + Does the DUT support testing the UnableToStartOrResume(0x01) error state? + 223.2.5. Manual controllable - allclusters.html[pdf] + O + true + + + RVCOPSTATE.S.M.ERR_UNABLE_TO_COMPLETE_OPERATION + Does the DUT support testing the UnableToCompleteOperation(0x02) error state? + 223.2.5. Manual controllable - allclusters.html[pdf] + O + true + + + RVCOPSTATE.S.M.ERR_COMMAND_INVALID_IN_STATE + Does the DUT support testing the CommandInvalidInState(0x03) error state? + 223.2.5. Manual controllable - allclusters.html[pdf] + O + true + + + RVCOPSTATE.S.M.ERR_FAILED_TO_FIND_CHARGING_DOCK + Does the DUT support testing the FailedToFindChargingDock(0x40) error state? + 223.2.5. Manual controllable - allclusters.html[pdf] + O + true + + + RVCOPSTATE.S.M.ERR_STUCK + Does the DUT support testing the Stuck(0x41) error state? + 223.2.5. Manual controllable - allclusters.html[pdf] + O + true + + + RVCOPSTATE.S.M.ERR_DUST_BIN_MISSING + Does the DUT support testing the DustBinMissing(0x42) error state? + 223.2.5. Manual controllable - allclusters.html[pdf] + O + true + + + RVCOPSTATE.S.M.ERR_DUST_BIN_FULL + Does the DUT support testing the DustBinFull(0x43) error state? + 223.2.5. Manual controllable - allclusters.html[pdf] + O + true + + + RVCOPSTATE.S.M.ERR_WATER_TANK_EMPTY + Does the DUT support testing the WaterTankEmpty(0x44) error state? + 223.2.5. Manual controllable - allclusters.html[pdf] + O + true + + + RVCOPSTATE.S.M.ERR_WATER_TANK_MISSING + Does the DUT support testing the WaterTankMissing(0x45) error state? + 223.2.5. Manual controllable - allclusters.html[pdf] + O + true + + + RVCOPSTATE.S.M.ERR_WATER_TANK_LID_OPEN + Does the DUT support testing the WaterTankLidOpen(0x46) error state? + 223.2.5. Manual controllable - allclusters.html[pdf] + O + true + + + RVCOPSTATE.S.M.ERR_MOP_CLEANING_PAD_MISSING + Does the DUT support testing the MopCleaningPadMissing(0x47) error state? + 223.2.5. Manual controllable - allclusters.html[pdf] + O + true + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/rvc-app/rvc-common/pics/RVC Run Mode Cluster Test Plan.xml b/examples/rvc-app/rvc-common/pics/RVC Run Mode Cluster Test Plan.xml new file mode 100644 index 00000000000000..0bdd95322e213b --- /dev/null +++ b/examples/rvc-app/rvc-common/pics/RVC Run Mode Cluster Test Plan.xml @@ -0,0 +1,132 @@ + + + RVC Run Mode Cluster Test Plan + + + + + + RVCRUNM.S + Does the device implement the RVCRUNM cluster as a server? + 84.1. Role - allclusters.html[pdf] + O + true + + + + + + PIXIT.RVCRUNM.MODE_CHANGE_FAIL + Id of mode the device will fail to transition to, given its current state + 85. PIXIT Definition - allclusters.html[pdf] + O + 0x02 + + + PIXIT.RVCRUNM.MODE_CHANGE_OK + Id of mode the device will successfully transition to, given its current state + 85. PIXIT Definition - allclusters.html[pdf] + O + 0x00 + + + + + + + + RVCRUNM.S.A0000 + Does the device implement the SupportedModes attribute? + 84.2.2. Attributes - allclusters.html[pdf] + M + true + + + RVCRUNM.S.A0001 + Does the device implement the CurrentMode attribute? + 84.2.2. Attributes - allclusters.html[pdf] + M + true + + + RVCRUNM.S.A0002 + Does the device implement the StartUpMode attribute? + 84.2.2. Attributes - allclusters.html[pdf] + O + false + + + RVCRUNM.S.A0003 + Does the device implement the OnMode attribute? + 84.2.2. Attributes - allclusters.html[pdf] + M + false + + + + + + + + RVCRUNM.S.C01.Tx + Does the device implement sending the ChangeToModeResponse command? + 84.2.4. Commands generated - allclusters.html[pdf] + M + true + + + + + + RVCRUNM.S.C00.Rsp + Does the device implement receiving the ChangeToMode command? + 84.2.3. Commands received - allclusters.html[pdf] + M + true + + + + + + RVCRUNM.S.F00 + Does the device support depending on an On/Off cluster implemented on the same endpoint? + 84.2.1. Features - allclusters.html[pdf] + O + false + + + + + + RVCRUNM.S.M.CAN_TEST_MODE_FAILURE + Does the DUT support testing the failed ChangeToMode command? + 84.2.5. Manual controllable - allclusters.html[pdf] + O + true + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/rvc-app/rvc-common/pics/RVC_App_Test_Plan.txt b/examples/rvc-app/rvc-common/pics/RVC_App_Test_Plan.txt new file mode 100644 index 00000000000000..d0c8529a83d2e0 --- /dev/null +++ b/examples/rvc-app/rvc-common/pics/RVC_App_Test_Plan.txt @@ -0,0 +1,53 @@ +RVCCLEANM.S=1 +RVCCLEANM.S.A0000=1 +RVCCLEANM.S.A0001=1 +RVCCLEANM.S.A0002=0 +RVCCLEANM.S.A0003=0 +RVCCLEANM.S.C01.Tx=1 +RVCCLEANM.S.C00.Rsp=1 +RVCCLEANM.S.F00=0 +RVCCLEANM.S.M.CAN_TEST_MODE_FAILURE=1 + +RVCOPSTATE.S=1 +RVCOPSTATE.S.A0000=1 +RVCOPSTATE.S.A0001=1 +RVCOPSTATE.S.A0002=0 +RVCOPSTATE.S.A0003=1 +RVCOPSTATE.S.A0004=1 +RVCOPSTATE.S.A0005=1 +RVCOPSTATE.S.E00=1 +RVCOPSTATE.S.E01=1 +RVCOPSTATE.S.C04.Tx=1 +RVCOPSTATE.S.C00.Rsp=1 +RVCOPSTATE.S.C01.Rsp=0 +RVCOPSTATE.S.C02.Rsp=0 +RVCOPSTATE.S.C03.Rsp=1 +RVCOPSTATE.S.M.ST_STOPPED=1 +RVCOPSTATE.S.M.ST_RUNNING=1 +RVCOPSTATE.S.M.ST_PAUSED=1 +RVCOPSTATE.S.M.ST_ERROR=1 +RVCOPSTATE.S.M.ST_SEEKING_CHARGER=1 +RVCOPSTATE.S.M.ST_CHARGING=1 +RVCOPSTATE.S.M.ST_DOCKED=1 +RVCOPSTATE.S.M.ERR_NO_ERROR=1 +RVCOPSTATE.S.M.ERR_UNABLE_TO_START_OR_RESUME=1 +RVCOPSTATE.S.M.ERR_UNABLE_TO_COMPLETE_OPERATION=1 +RVCOPSTATE.S.M.ERR_COMMAND_INVALID_IN_STATE=1 +RVCOPSTATE.S.M.ERR_FAILED_TO_FIND_CHARGING_DOCK=1 +RVCOPSTATE.S.M.ERR_STUCK=1 +RVCOPSTATE.S.M.ERR_DUST_BIN_MISSING=1 +RVCOPSTATE.S.M.ERR_DUST_BIN_FULL=1 +RVCOPSTATE.S.M.ERR_WATER_TANK_EMPTY=1 +RVCOPSTATE.S.M.ERR_WATER_TANK_MISSING=1 +RVCOPSTATE.S.M.ERR_WATER_TANK_LID_OPEN=1 +RVCOPSTATE.S.M.ERR_MOP_CLEANING_PAD_MISSING=1 + +RVCRUNM.S=1 +RVCRUNM.S.A0000=1 +RVCRUNM.S.A0001=1 +RVCRUNM.S.A0002=0 +RVCRUNM.S.A0003=0 +RVCRUNM.S.C01.Tx=1 +RVCRUNM.S.C00.Rsp=1 +RVCRUNM.S.F00=0 +RVCRUNM.S.M.CAN_TEST_MODE_FAILURE=1 \ No newline at end of file diff --git a/examples/rvc-app/rvc-common/src/rvc-device.cpp b/examples/rvc-app/rvc-common/src/rvc-device.cpp index f085e6dada9f1c..d450a635e2e978 100644 --- a/examples/rvc-app/rvc-common/src/rvc-device.cpp +++ b/examples/rvc-app/rvc-common/src/rvc-device.cpp @@ -9,37 +9,67 @@ void RvcDevice::Init() mOperationalStateInstance.Init(); } +void RvcDevice::SetDeviceToIdleState() +{ + if (mCharging) + { + mOperationalStateInstance.SetOperationalState(to_underlying(RvcOperationalState::OperationalStateEnum::kCharging)); + } + else if (mDocked) + { + mOperationalStateInstance.SetOperationalState(to_underlying(RvcOperationalState::OperationalStateEnum::kDocked)); + } + else + { + mOperationalStateInstance.SetOperationalState(to_underlying(OperationalState::OperationalStateEnum::kStopped)); + } +} + void RvcDevice::HandleRvcRunChangeToMode(uint8_t newMode, ModeBase::Commands::ChangeToModeResponse::Type & response) { - uint8_t currentMode = mRunModeInstance.GetCurrentMode(); + uint8_t currentState = mOperationalStateInstance.GetCurrentOperationalState(); + uint8_t currentMode = mRunModeInstance.GetCurrentMode(); - switch (newMode) + switch (currentState) { - case RvcRunMode::ModeMapping: { - // change to mapping only allowed from the Idle state. - if (currentMode != RvcRunMode::ModeIdle) + case to_underlying(OperationalState::OperationalStateEnum::kStopped): + case to_underlying(RvcOperationalState::OperationalStateEnum::kDocked): + case to_underlying(RvcOperationalState::OperationalStateEnum::kCharging): { + // We could be in the charging state with an RvcRun mode != idle. + if (currentMode != RvcRunMode::ModeIdle && newMode != RvcRunMode::ModeIdle) { response.status = to_underlying(ModeBase::StatusCode::kGenericFailure); - response.statusText.SetValue(chip::CharSpan::fromCharString("Change to the mapping mode is only allowed from idle")); + response.statusText.SetValue( + chip::CharSpan::fromCharString("Change to the mapping or cleaning mode is only allowed from idle")); return; } mRunModeInstance.UpdateCurrentMode(newMode); mOperationalStateInstance.SetOperationalState(to_underlying(OperationalState::OperationalStateEnum::kRunning)); - break; - } - case RvcRunMode::ModeCleaning: { - mRunModeInstance.UpdateCurrentMode(newMode); - mOperationalStateInstance.SetOperationalState(to_underlying(OperationalState::OperationalStateEnum::kRunning)); + response.status = to_underlying(ModeBase::StatusCode::kSuccess); + return; } break; - case RvcRunMode::ModeIdle: { + case to_underlying(OperationalState::OperationalStateEnum::kRunning): { + if (newMode != RvcRunMode::ModeIdle) + { + response.status = to_underlying(ModeBase::StatusCode::kGenericFailure); + response.statusText.SetValue( + chip::CharSpan::fromCharString("Change to the mapping or cleaning mode is only allowed from idle")); + return; + } + mRunModeInstance.UpdateCurrentMode(newMode); - mOperationalStateInstance.SetOperationalState(to_underlying(OperationalState::OperationalStateEnum::kStopped)); + mOperationalStateInstance.SetOperationalState(to_underlying(RvcOperationalState::OperationalStateEnum::kSeekingCharger)); + response.status = to_underlying(ModeBase::StatusCode::kSuccess); + return; } + break; } - response.status = to_underlying(ModeBase::StatusCode::kSuccess); + // If we fall through at any point, it's because the change is not supported in the current state. + response.status = to_underlying(ModeBase::StatusCode::kGenericFailure); + response.statusText.SetValue(chip::CharSpan::fromCharString("This change is not allowed at this time. ")); } void RvcDevice::HandleRvcCleanChangeToMode(uint8_t newMode, ModeBase::Commands::ChangeToModeResponse::Type & response) @@ -81,3 +111,171 @@ void RvcDevice::HandleOpStateResumeCallback(Clusters::OperationalState::GenericO err.Set(to_underlying(OperationalState::ErrorStateEnum::kUnableToCompleteOperation)); } } + +void RvcDevice::HandleChargedMessage() +{ + if (mOperationalStateInstance.GetCurrentOperationalState() != + to_underlying(RvcOperationalState::OperationalStateEnum::kCharging)) + { + ChipLogError(NotSpecified, "RVC App: The 'Charged' command is only accepted when the device is in the 'Charging' state."); + return; + } + + mCharging = false; + + if (mRunModeInstance.GetCurrentMode() == RvcRunMode::ModeIdle) + { + if (mDocked) // assuming that we can't be charging the device while it is not docked. + { + mOperationalStateInstance.SetOperationalState(to_underlying(RvcOperationalState::OperationalStateEnum::kDocked)); + } + else + { + mOperationalStateInstance.SetOperationalState(to_underlying(OperationalState::OperationalStateEnum::kStopped)); + } + } + else + { + mOperationalStateInstance.SetOperationalState(to_underlying(OperationalState::OperationalStateEnum::kRunning)); + } +} + +void RvcDevice::HandleChargingMessage() +{ + if (mOperationalStateInstance.GetCurrentOperationalState() != to_underlying(RvcOperationalState::OperationalStateEnum::kDocked)) + { + ChipLogError(NotSpecified, "RVC App: The 'Charging' command is only accepted when the device is in the 'Docked' state."); + return; + } + + mCharging = true; + + mOperationalStateInstance.SetOperationalState(to_underlying(RvcOperationalState::OperationalStateEnum::kCharging)); +} + +void RvcDevice::HandleDockedMessage() +{ + if (mOperationalStateInstance.GetCurrentOperationalState() != to_underlying(OperationalState::OperationalStateEnum::kStopped)) + { + ChipLogError(NotSpecified, "RVC App: The 'Docked' command is only accepted when the device is in the 'Stopped' state."); + return; + } + + mDocked = true; + + mOperationalStateInstance.SetOperationalState(to_underlying(RvcOperationalState::OperationalStateEnum::kDocked)); +} + +void RvcDevice::HandleChargerFoundMessage() +{ + if (mOperationalStateInstance.GetCurrentOperationalState() != + to_underlying(RvcOperationalState::OperationalStateEnum::kSeekingCharger)) + { + ChipLogError(NotSpecified, + "RVC App: The 'ChargerFound' command is only accepted when the device is in the 'SeekingCharger' state."); + return; + } + + mCharging = true; + mDocked = true; + + mOperationalStateInstance.SetOperationalState(to_underlying(RvcOperationalState::OperationalStateEnum::kCharging)); +} + +void RvcDevice::HandleLowChargeMessage() +{ + if (mOperationalStateInstance.GetCurrentOperationalState() != to_underlying(OperationalState::OperationalStateEnum::kRunning)) + { + ChipLogError(NotSpecified, "RVC App: The 'LowCharge' command is only accepted when the device is in the 'Running' state."); + return; + } + + mOperationalStateInstance.SetOperationalState(to_underlying(RvcOperationalState::OperationalStateEnum::kSeekingCharger)); +} + +void RvcDevice::HandleActivityCompleteEvent() +{ + if (mOperationalStateInstance.GetCurrentOperationalState() != to_underlying(OperationalState::OperationalStateEnum::kRunning)) + { + ChipLogError(NotSpecified, + "RVC App: The 'ActivityComplete' command is only accepted when the device is in the 'Running' state."); + return; + } + + mRunModeInstance.UpdateCurrentMode(RvcRunMode::ModeIdle); + + Optional> a(DataModel::Nullable(100)); + Optional> b(DataModel::Nullable(10)); + mOperationalStateInstance.OnOperationCompletionDetected(0, a, b); + + mOperationalStateInstance.SetOperationalState(to_underlying(RvcOperationalState::OperationalStateEnum::kSeekingCharger)); +} + +void RvcDevice::HandleErrorEvent(const std::string & error) +{ + detail::Structs::ErrorStateStruct::Type err; + + if (error == "UnableToStartOrResume") + { + err.errorStateID = to_underlying(OperationalState::ErrorStateEnum::kUnableToStartOrResume); + } + else if (error == "UnableToCompleteOperation") + { + err.errorStateID = to_underlying(OperationalState::ErrorStateEnum::kUnableToCompleteOperation); + } + else if (error == "CommandInvalidInState") + { + err.errorStateID = to_underlying(OperationalState::ErrorStateEnum::kCommandInvalidInState); + } + else if (error == "FailedToFindChargingDock") + { + err.errorStateID = to_underlying(RvcOperationalState::ErrorStateEnum::kFailedToFindChargingDock); + } + else if (error == "Stuck") + { + err.errorStateID = to_underlying(RvcOperationalState::ErrorStateEnum::kStuck); + } + else if (error == "DustBinMissing") + { + err.errorStateID = to_underlying(RvcOperationalState::ErrorStateEnum::kDustBinMissing); + } + else if (error == "DustBinFull") + { + err.errorStateID = to_underlying(RvcOperationalState::ErrorStateEnum::kDustBinFull); + } + else if (error == "WaterTankEmpty") + { + err.errorStateID = to_underlying(RvcOperationalState::ErrorStateEnum::kWaterTankEmpty); + } + else if (error == "WaterTankMissing") + { + err.errorStateID = to_underlying(RvcOperationalState::ErrorStateEnum::kWaterTankMissing); + } + else if (error == "WaterTankLidOpen") + { + err.errorStateID = to_underlying(RvcOperationalState::ErrorStateEnum::kWaterTankLidOpen); + } + else if (error == "MopCleaningPadMissing") + { + err.errorStateID = to_underlying(RvcOperationalState::ErrorStateEnum::kMopCleaningPadMissing); + } + else + { + ChipLogError(NotSpecified, "Unhandled command: The 'Error' key of the 'ErrorEvent' message is not valid."); + return; + } + + mOperationalStateInstance.OnOperationalErrorDetected(err); +} + +void RvcDevice::HandleClearErrorMessage() +{ + if (mOperationalStateInstance.GetCurrentOperationalState() != to_underlying(OperationalState::OperationalStateEnum::kError)) + { + ChipLogError(NotSpecified, "RVC App: The 'ClearError' command is only excepted when the device is in the 'Error' state."); + return; + } + + mRunModeInstance.UpdateCurrentMode(RvcRunMode::ModeIdle); + SetDeviceToIdleState(); +} diff --git a/src/app/clusters/operational-state-server/operational-state-server.h b/src/app/clusters/operational-state-server/operational-state-server.h index 4d093318ac4833..0978f613723533 100644 --- a/src/app/clusters/operational-state-server/operational-state-server.h +++ b/src/app/clusters/operational-state-server/operational-state-server.h @@ -79,7 +79,7 @@ class Instance : public CommandHandlerInterface, public AttributeAccessInterface CHIP_ERROR SetCurrentPhase(const app::DataModel::Nullable & aPhase); /** - * Set current operational state. + * Set current operational state to aOpState and the operational error to kNoError. * NOTE: This method cannot be used to set the error state. The error state must be set via the * OnOperationalErrorDetected method. * @param aOpState The operational state that should now be the current one.