/* * Copyright (c) 2020 Project CHIP Authors * Copyright (c) 2018 Google LLC. * Copyright (c) 2017 Nest Labs, Inc. * 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. */ /** * @file * This file declares mock event generator and example * */ #include "MockEvents.h" #include "common.h" #include #include #include #include #include #include #include static chip::TLV::Tag kLivenessDeviceStatus = chip::TLV::ContextTag(1); static bool gMockEventStop = false; static bool gEventIsStopped = false; EventGenerator::EventGenerator(size_t aNumStates, size_t aInitialState) : mNumStates(aNumStates), mState(aInitialState) {} size_t EventGenerator::GetNumStates() { return mNumStates; } LivenessEventGenerator::LivenessEventGenerator() : EventGenerator(10, 0) {} void LivenessEventGenerator::Generate() { // Scenario: monitoring liveness for two devices -- self and remote. Remote device goes offline and returns. switch (mState) { case 0: LogLiveness(kTestNodeId, kTestEndpointId, LIVENESS_DEVICE_STATUS_ONLINE, kTestChangeEvent1, chip::app::PriorityLevel::Critical); break; case 1: LogLiveness(kTestNodeId, kTestEndpointId, LIVENESS_DEVICE_STATUS_ONLINE, kTestChangeEvent2, chip::app::PriorityLevel::Debug); break; case 2: LogLiveness(kTestNodeId, kTestEndpointId, LIVENESS_DEVICE_STATUS_ONLINE, kTestChangeEvent1, chip::app::PriorityLevel::Critical); break; case 3: LogLiveness(kTestNodeId, kTestEndpointId, LIVENESS_DEVICE_STATUS_UNREACHABLE, kTestChangeEvent2, chip::app::PriorityLevel::Debug); break; case 4: LogLiveness(kTestNodeId, kTestEndpointId, LIVENESS_DEVICE_STATUS_ONLINE, kTestChangeEvent1, chip::app::PriorityLevel::Critical); break; case 5: LogLiveness(kTestNodeId, kTestEndpointId, LIVENESS_DEVICE_STATUS_REBOOTING, kTestChangeEvent2, chip::app::PriorityLevel::Debug); break; case 6: LogLiveness(kTestNodeId, kTestEndpointId, LIVENESS_DEVICE_STATUS_ONLINE, kTestChangeEvent1, chip::app::PriorityLevel::Critical); break; case 7: LogLiveness(kTestNodeId, kTestEndpointId, LIVENESS_DEVICE_STATUS_ONLINE, kTestChangeEvent2, chip::app::PriorityLevel::Debug); break; case 8: LogLiveness(kTestNodeId, kTestEndpointId, LIVENESS_DEVICE_STATUS_ONLINE, kTestChangeEvent1, chip::app::PriorityLevel::Critical); break; case 9: LogLiveness(kTestNodeId, kTestEndpointId, LIVENESS_DEVICE_STATUS_ONLINE, kTestChangeEvent2, chip::app::PriorityLevel::Debug); break; default: mState = 0; } mState = (mState + 1) % mNumStates; } CHIP_ERROR LivenessEventGenerator::WriteEvent(chip::TLV::TLVWriter & aWriter) { chip::TLV::TLVType dataContainerType; ReturnErrorOnFailure(aWriter.StartContainer(chip::TLV::ContextTag(chip::to_underlying(chip::app::EventDataIB::Tag::kData)), chip::TLV::kTLVType_Structure, dataContainerType)); ReturnErrorOnFailure(aWriter.Put(kLivenessDeviceStatus, mStatus)); return aWriter.EndContainer(dataContainerType); } chip::EventNumber LivenessEventGenerator::LogLiveness(chip::NodeId aNodeId, chip::EndpointId aEndpointId, LivenessDeviceStatus aStatus, chip::EventId aEventId, chip::app::PriorityLevel aPriorityLevel) { chip::app::EventManagement & logManager = chip::app::EventManagement::GetInstance(); chip::EventNumber number = 0; chip::app::EventOptions options; options.mPath = { aEndpointId, kTestClusterId, aEventId }; options.mPriority = aPriorityLevel; mStatus = static_cast(aStatus); logManager.LogEvent(this, options, number); return number; } MockEventGenerator * MockEventGenerator::GetInstance() { static MockEventGeneratorImpl gMockEventGenerator; return &gMockEventGenerator; } MockEventGeneratorImpl::MockEventGeneratorImpl() : mpExchangeMgr(nullptr), mTimeBetweenEvents(0), mEventWraparound(false), mpEventGenerator(nullptr), mEventsLeft(0) {} CHIP_ERROR MockEventGeneratorImpl::Init(chip::Messaging::ExchangeManager * apExchangeMgr, EventGenerator * apEventGenerator, uint32_t aDelayBetweenEvents, bool aWraparound) { CHIP_ERROR err = CHIP_NO_ERROR; mpExchangeMgr = apExchangeMgr; mpEventGenerator = apEventGenerator; mTimeBetweenEvents = aDelayBetweenEvents; mEventWraparound = aWraparound; if (mEventWraparound) mEventsLeft = INT32_MAX; else mEventsLeft = mpEventGenerator->GetNumStates(); if (mTimeBetweenEvents != 0) mpExchangeMgr->GetSessionManager()->SystemLayer()->StartTimer(chip::System::Clock::Milliseconds32(mTimeBetweenEvents), HandleNextEvent, this); return err; } void MockEventGeneratorImpl::HandleNextEvent(chip::System::Layer * apSystemLayer, void * apAppState) { MockEventGeneratorImpl * generator = static_cast(apAppState); if (gMockEventStop) { gEventIsStopped = true; apSystemLayer->CancelTimer(HandleNextEvent, generator); } else { generator->mpEventGenerator->Generate(); generator->mEventsLeft--; if ((generator->mEventWraparound) || (generator->mEventsLeft > 0)) { apSystemLayer->StartTimer(chip::System::Clock::Milliseconds32(generator->mTimeBetweenEvents), HandleNextEvent, generator); } } } void MockEventGeneratorImpl::SetEventGeneratorStop() { gMockEventStop = true; // If the timer is running, make it expire right away. // This helps quit the standalone app in an orderly way without // spurious leaked timers. if (mTimeBetweenEvents != 0) mpExchangeMgr->GetSessionManager()->SystemLayer()->StartTimer(chip::System::Clock::kZero, HandleNextEvent, this); } bool MockEventGeneratorImpl::IsEventGeneratorStopped() { if (gEventIsStopped) { gMockEventStop = false; gEventIsStopped = false; return true; } return false; }