blob: 18e2f9727812e84daab1964d2d0c6667774b8628 [file] [log] [blame]
/*
* 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 <app/EventManagement.h>
#include <app/MessageDef/EventLoggingTypes.h>
#include <lib/core/ErrorStr.h>
#include <platform/CHIPDeviceLayer.h>
#include <protocols/secure_channel/PASESession.h>
#include <system/SystemPacketBuffer.h>
#include <transport/SessionManager.h>
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<int32_t>(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<MockEventGeneratorImpl *>(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;
}