Implement TC-SWTCH-2.4 and all-clusters button simulator (#34406)

* Implement TC-SWTCH-2.4 and all-clusters button simulator

- Implement TC-SWTCH-2.4
- Implement action switch button simulator to drive the test

Testing done:

- New test (TC-SWTCH-2.4) works using the button simulator

* Restyled by clang-format

* Restyled by autopep8

* Restyled by isort

* Enable TC_SWTCH.py in CI

* Fix lint

* Fix typo that arose on file saving

* Handle EOF in reading user input in matter testing support

* Do not provide a stdin on python test runner and handle EOF on matter_testing_support

* Fix up PICS execution for CI

---------

Co-authored-by: Restyled.io <commits@restyled.io>
Co-authored-by: Andrei Litvin <andreilitvin@google.com>
diff --git a/examples/all-clusters-app/linux/ButtonEventsSimulator.cpp b/examples/all-clusters-app/linux/ButtonEventsSimulator.cpp
new file mode 100644
index 0000000..44bf565
--- /dev/null
+++ b/examples/all-clusters-app/linux/ButtonEventsSimulator.cpp
@@ -0,0 +1,210 @@
+/*
+ *
+ *    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.
+ */
+
+#include "ButtonEventsSimulator.h"
+
+#include <functional>
+#include <inttypes.h>
+#include <stdint.h>
+#include <utility>
+
+#include <app-common/zap-generated/attributes/Accessors.h>
+#include <app-common/zap-generated/cluster-objects.h>
+#include <app/EventLogging.h>
+#include <lib/core/CHIPError.h>
+#include <lib/core/DataModelTypes.h>
+#include <lib/support/CodeUtils.h>
+#include <lib/support/logging/CHIPLogging.h>
+#include <platform/CHIPDeviceLayer.h>
+#include <system/SystemClock.h>
+#include <system/SystemLayer.h>
+
+namespace chip {
+namespace app {
+
+namespace {
+
+void SetButtonPosition(EndpointId endpointId, uint8_t position)
+{
+    Clusters::Switch::Attributes::CurrentPosition::Set(endpointId, position);
+}
+
+void EmitInitialPress(EndpointId endpointId, uint8_t newPosition)
+{
+    Clusters::Switch::Events::InitialPress::Type event{ newPosition };
+    EventNumber eventNumber = 0;
+
+    CHIP_ERROR err = LogEvent(event, endpointId, eventNumber);
+    if (err != CHIP_NO_ERROR)
+    {
+        ChipLogError(NotSpecified, "Failed to log InitialPress event: %" CHIP_ERROR_FORMAT, err.Format());
+    }
+    else
+    {
+        ChipLogProgress(NotSpecified, "Logged InitialPress(%u) on Endpoint %u", static_cast<unsigned>(newPosition),
+                        static_cast<unsigned>(endpointId));
+    }
+}
+
+void EmitLongPress(EndpointId endpointId, uint8_t newPosition)
+{
+    Clusters::Switch::Events::LongPress::Type event{ newPosition };
+    EventNumber eventNumber = 0;
+
+    CHIP_ERROR err = LogEvent(event, endpointId, eventNumber);
+    if (err != CHIP_NO_ERROR)
+    {
+        ChipLogError(NotSpecified, "Failed to log LongPress event: %" CHIP_ERROR_FORMAT, err.Format());
+    }
+    else
+    {
+        ChipLogProgress(NotSpecified, "Logged LongPress(%u) on Endpoint %u", static_cast<unsigned>(newPosition),
+                        static_cast<unsigned>(endpointId));
+    }
+}
+
+void EmitLongRelease(EndpointId endpointId, uint8_t previousPosition)
+{
+    Clusters::Switch::Events::LongRelease::Type event{};
+    event.previousPosition  = previousPosition;
+    EventNumber eventNumber = 0;
+
+    CHIP_ERROR err = LogEvent(event, endpointId, eventNumber);
+    if (err != CHIP_NO_ERROR)
+    {
+        ChipLogError(NotSpecified, "Failed to log LongRelease event: %" CHIP_ERROR_FORMAT, err.Format());
+    }
+    else
+    {
+        ChipLogProgress(NotSpecified, "Logged LongRelease on Endpoint %u", static_cast<unsigned>(endpointId));
+    }
+}
+
+void EmitMultiPressComplete(EndpointId endpointId, uint8_t previousPosition, uint8_t count)
+{
+    Clusters::Switch::Events::MultiPressComplete::Type event{};
+    event.previousPosition            = previousPosition;
+    event.totalNumberOfPressesCounted = count;
+    EventNumber eventNumber           = 0;
+
+    CHIP_ERROR err = LogEvent(event, endpointId, eventNumber);
+    if (err != CHIP_NO_ERROR)
+    {
+        ChipLogError(NotSpecified, "Failed to log MultiPressComplete event: %" CHIP_ERROR_FORMAT, err.Format());
+    }
+    else
+    {
+        ChipLogProgress(NotSpecified, "Logged MultiPressComplete(count=%u) on Endpoint %u", static_cast<unsigned>(count),
+                        static_cast<unsigned>(endpointId));
+    }
+}
+
+} // namespace
+
+void ButtonEventsSimulator::OnTimerDone(System::Layer * layer, void * appState)
+{
+    ButtonEventsSimulator * that = reinterpret_cast<ButtonEventsSimulator *>(appState);
+    that->Next();
+}
+
+bool ButtonEventsSimulator::Execute(DoneCallback && doneCallback)
+{
+    VerifyOrReturnValue(mIdleButtonId != mPressedButtonId, false);
+
+    switch (mMode)
+    {
+    case Mode::kModeLongPress:
+        VerifyOrReturnValue(mLongPressDurationMillis > mLongPressDelayMillis, false);
+        SetState(State::kEmitStartOfLongPress);
+        break;
+    case Mode::kModeMultiPress:
+        VerifyOrReturnValue(mMultiPressPressedTimeMillis.count() > 0, false);
+        VerifyOrReturnValue(mMultiPressReleasedTimeMillis.count() > 0, false);
+        VerifyOrReturnValue(mMultiPressNumPresses > 0, false);
+        SetState(State::kEmitStartOfMultiPress);
+        break;
+    default:
+        return false;
+    }
+    mDoneCallback = std::move(doneCallback);
+    Next();
+    return true;
+}
+
+void ButtonEventsSimulator::SetState(ButtonEventsSimulator::State newState)
+{
+    ButtonEventsSimulator::State oldState = mState;
+    if (oldState != newState)
+    {
+        ChipLogProgress(NotSpecified, "ButtonEventsSimulator state change %u -> %u", static_cast<unsigned>(oldState),
+                        static_cast<unsigned>(newState));
+    }
+
+    mState = newState;
+}
+
+void ButtonEventsSimulator::StartTimer(System::Clock::Timeout duration)
+{
+    chip::DeviceLayer::SystemLayer().StartTimer(duration, &ButtonEventsSimulator::OnTimerDone, this);
+}
+
+void ButtonEventsSimulator::Next()
+{
+    switch (mState)
+    {
+    case ButtonEventsSimulator::State::kIdle: {
+        ChipLogError(NotSpecified, "Found idle state where not expected!");
+        break;
+    }
+    case ButtonEventsSimulator::State::kEmitStartOfLongPress: {
+        SetButtonPosition(mEndpointId, mPressedButtonId);
+        EmitInitialPress(mEndpointId, mPressedButtonId);
+        SetState(ButtonEventsSimulator::State::kEmitLongPress);
+        StartTimer(mLongPressDelayMillis);
+        break;
+    }
+    case ButtonEventsSimulator::State::kEmitLongPress: {
+        EmitLongPress(mEndpointId, mPressedButtonId);
+        SetState(ButtonEventsSimulator::State::kEmitLongRelease);
+        StartTimer(mLongPressDurationMillis - mLongPressDelayMillis);
+        break;
+    }
+    case ButtonEventsSimulator::State::kEmitLongRelease: {
+        SetButtonPosition(mEndpointId, mIdleButtonId);
+        EmitLongRelease(mEndpointId, mPressedButtonId);
+        SetState(ButtonEventsSimulator::State::kIdle);
+        mDoneCallback();
+        break;
+    }
+    case ButtonEventsSimulator::State::kEmitStartOfMultiPress: {
+        EmitInitialPress(mEndpointId, mPressedButtonId);
+        StartTimer(mMultiPressNumPresses * (mMultiPressPressedTimeMillis + mMultiPressReleasedTimeMillis));
+        SetState(ButtonEventsSimulator::State::kEmitEndOfMultiPress);
+        break;
+    }
+    case ButtonEventsSimulator::State::kEmitEndOfMultiPress: {
+        EmitMultiPressComplete(mEndpointId, mPressedButtonId, mMultiPressNumPresses);
+        SetState(ButtonEventsSimulator::State::kIdle);
+        mDoneCallback();
+        break;
+    }
+    }
+}
+
+} // namespace app
+} // namespace chip