/* * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include 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(newPosition), static_cast(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(newPosition), static_cast(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(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(count), static_cast(endpointId)); } } void EmitShortRelease(EndpointId endpointId, uint8_t previousPosition) { Clusters::Switch::Events::ShortRelease::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 ShortRelease event: %" CHIP_ERROR_FORMAT, err.Format()); } else { ChipLogProgress(NotSpecified, "Logged ShortRelease on Endpoint %u", static_cast(endpointId)); } } void EmitMultiPressOngoing(EndpointId endpointId, uint8_t newPosition, uint8_t count) { Clusters::Switch::Events::MultiPressOngoing::Type event{}; event.newPosition = newPosition; event.currentNumberOfPressesCounted = count; EventNumber eventNumber = 0; CHIP_ERROR err = LogEvent(event, endpointId, eventNumber); if (err != CHIP_NO_ERROR) { ChipLogError(NotSpecified, "Failed to log MultiPressOngoing event: %" CHIP_ERROR_FORMAT, err.Format()); } else { ChipLogProgress(NotSpecified, "Logged MultiPressOngoing on Endpoint %u position %u, count %u", static_cast(endpointId), newPosition, count); } } } // namespace void ButtonEventsSimulator::OnTimerDone(System::Layer * layer, void * appState) { ButtonEventsSimulator * that = reinterpret_cast(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(oldState), static_cast(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); if (mFeatureMap & static_cast(Clusters::Switch::Feature::kMomentarySwitchLongPress)) { EmitLongRelease(mEndpointId, mPressedButtonId); } else if (mFeatureMap & static_cast(Clusters::Switch::Feature::kMomentarySwitchRelease)) { EmitShortRelease(mEndpointId, mPressedButtonId); } SetState(ButtonEventsSimulator::State::kIdle); mDoneCallback(); break; } case ButtonEventsSimulator::State::kEmitStartOfMultiPress: { SetButtonPosition(mEndpointId, mPressedButtonId); EmitInitialPress(mEndpointId, mPressedButtonId); if (mFeatureMap & static_cast(Clusters::Switch::Feature::kActionSwitch)) { StartTimer(mMultiPressNumPresses * (mMultiPressPressedTimeMillis + mMultiPressReleasedTimeMillis)); SetState(ButtonEventsSimulator::State::kEmitEndOfMultiPress); } else { SetState(ButtonEventsSimulator::State::kMultiPressButtonRelease); StartTimer(mMultiPressPressedTimeMillis); } break; } case ButtonEventsSimulator::State::kMultiPressButtonRelease: { ++mMultiPressPressesDone; if (mMultiPressPressesDone > 1) { EmitMultiPressOngoing(mEndpointId, mPressedButtonId, mMultiPressPressesDone); } if (mMultiPressPressesDone == mMultiPressNumPresses) { SetState(ButtonEventsSimulator::State::kEmitEndOfMultiPress); } else { SetState(ButtonEventsSimulator::State::kEmitStartOfMultiPress); } if (mFeatureMap & static_cast(Clusters::Switch::Feature::kMomentarySwitchRelease)) { EmitShortRelease(mEndpointId, mPressedButtonId); } SetButtonPosition(mEndpointId, mIdleButtonId); StartTimer(mMultiPressReleasedTimeMillis); break; } case ButtonEventsSimulator::State::kEmitEndOfMultiPress: { if (mFeatureMap & static_cast(Clusters::Switch::Feature::kActionSwitch) && mMultiPressNumPresses > mMultiPressMax) { EmitMultiPressComplete(mEndpointId, mPressedButtonId, 0); } else { EmitMultiPressComplete(mEndpointId, mPressedButtonId, mMultiPressNumPresses); } SetState(ButtonEventsSimulator::State::kIdle); mDoneCallback(); break; } } } } // namespace app } // namespace chip