blob: 6e381149c083b8ad90b4e3bb3b46fd91b28107ed [file] [log] [blame]
/**
*
* Copyright (c) 2020 Project CHIP Authors
*
* 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 <app/util/af-event.h>
#include <app/util/af.h>
#include <app/util/attribute-storage.h>
#include <platform/CHIPDeviceLayer.h>
#define EMBER_MAX_EVENT_CONTROL_DELAY_MS (UINT32_MAX / 2)
#define EMBER_MAX_EVENT_CONTROL_DELAY_QS (EMBER_MAX_EVENT_CONTROL_DELAY_MS >> 8)
#define EMBER_MAX_EVENT_CONTROL_DELAY_MINUTES (EMBER_MAX_EVENT_CONTROL_DELAY_MS >> 16)
#include <app-common/zap-generated/callback.h>
#include <zap-generated/af-gen-event.h>
using namespace chip;
struct EmberEventData
{
/** The control structure for the event. */
EmberEventControl * control;
/** The procedure to call when the event fires. */
void (*handler)(void);
};
// *****************************************************************************
// Globals
#ifdef EMBER_AF_GENERATED_EVENT_CODE
EMBER_AF_GENERATED_EVENT_CODE
#endif // EMBER_AF_GENERATED_EVENT_CODE
#if defined(EMBER_AF_GENERATED_EVENT_CONTEXT)
uint16_t emAfAppEventContextLength = EMBER_AF_EVENT_CONTEXT_LENGTH;
EmberAfEventContext emAfAppEventContext[] = { EMBER_AF_GENERATED_EVENT_CONTEXT };
#endif // EMBER_AF_GENERATED_EVENT_CONTEXT
const char * emAfEventStrings[] = {
#ifdef EMBER_AF_GENERATED_EVENTS
EMBER_AF_GENERATED_EVENT_STRINGS
#endif
nullptr,
};
EmberEventData emAfEvents[] = {
#ifdef EMBER_AF_GENERATED_EVENTS
EMBER_AF_GENERATED_EVENTS
#endif
{ nullptr, nullptr }
};
void EventControlHandler(chip::System::Layer * systemLayer, void * appState)
{
EmberEventControl * control = reinterpret_cast<EmberEventControl *>(appState);
if (control->status != EMBER_EVENT_INACTIVE)
{
control->status = EMBER_EVENT_INACTIVE;
if (control->callback != nullptr)
{
(control->callback)(control->endpoint);
return;
}
for (const EmberEventData & event : emAfEvents)
{
if (event.control != control)
continue;
control->status = EMBER_EVENT_INACTIVE;
event.handler();
break;
}
}
}
// *****************************************************************************
// Functions
static EmberAfEventContext * findEventContext(EndpointId endpoint, ClusterId clusterId, bool isClient)
{
#if defined(EMBER_AF_GENERATED_EVENT_CONTEXT)
uint16_t i;
for (i = 0; i < emAfAppEventContextLength; i++)
{
EmberAfEventContext * context = &(emAfAppEventContext[i]);
if (context->endpoint == endpoint && context->clusterId == clusterId && context->isClient == isClient)
{
return context;
}
}
#endif // EMBER_AF_GENERATED_EVENT_CONTEXT
return nullptr;
}
EmberStatus emberEventControlSetDelayMS(EmberEventControl * control, uint32_t delayMs)
{
if (delayMs <= EMBER_MAX_EVENT_CONTROL_DELAY_MS)
{
control->status = EMBER_EVENT_MS_TIME;
#if !CHIP_DEVICE_LAYER_NONE
chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Milliseconds32(delayMs), EventControlHandler, control);
#endif
}
else
{
return EMBER_BAD_ARGUMENT;
}
return EMBER_SUCCESS;
}
void emberEventControlSetInactive(EmberEventControl * control)
{
if (control->status != EMBER_EVENT_INACTIVE)
{
control->status = EMBER_EVENT_INACTIVE;
#if !CHIP_DEVICE_LAYER_NONE
chip::DeviceLayer::SystemLayer().CancelTimer(EventControlHandler, control);
#endif
}
}
bool emberEventControlGetActive(EmberEventControl * control)
{
return control->status != EMBER_EVENT_INACTIVE;
}
void emberEventControlSetActive(EmberEventControl * control)
{
control->status = EMBER_EVENT_ZERO_DELAY;
#if !CHIP_DEVICE_LAYER_NONE
chip::DeviceLayer::SystemLayer().ScheduleWork(EventControlHandler, control);
#endif
}
EmberStatus emberAfScheduleTickExtended(EndpointId endpoint, ClusterId clusterId, bool isClient, uint32_t delayMs,
EmberAfEventPollControl pollControl, EmberAfEventSleepControl sleepControl)
{
EmberAfEventContext * context = findEventContext(endpoint, clusterId, isClient);
// Disabled endpoints cannot schedule events. This will catch the problem in
// simulation.
EMBER_TEST_ASSERT(emberAfEndpointIsEnabled(endpoint));
if (context != nullptr && emberAfEndpointIsEnabled(endpoint) &&
(emberEventControlSetDelayMS(context->eventControl, delayMs) == EMBER_SUCCESS))
{
context->pollControl = pollControl;
context->sleepControl = sleepControl;
return EMBER_SUCCESS;
}
return EMBER_BAD_ARGUMENT;
}
EmberStatus emberAfScheduleClusterTick(EndpointId endpoint, ClusterId clusterId, bool isClient, uint32_t delayMs,
EmberAfEventSleepControl sleepControl)
{
return emberAfScheduleTickExtended(endpoint, clusterId, isClient, delayMs,
(sleepControl == EMBER_AF_OK_TO_HIBERNATE ? EMBER_AF_LONG_POLL : EMBER_AF_SHORT_POLL),
(sleepControl == EMBER_AF_STAY_AWAKE ? EMBER_AF_STAY_AWAKE : EMBER_AF_OK_TO_SLEEP));
}
EmberStatus emberAfScheduleServerTickExtended(EndpointId endpoint, ClusterId clusterId, uint32_t delayMs,
EmberAfEventPollControl pollControl, EmberAfEventSleepControl sleepControl)
{
return emberAfScheduleTickExtended(endpoint, clusterId, EMBER_AF_SERVER_CLUSTER_TICK, delayMs, pollControl, sleepControl);
}
EmberStatus emberAfScheduleServerTick(EndpointId endpoint, ClusterId clusterId, uint32_t delayMs)
{
return emberAfScheduleServerTickExtended(endpoint, clusterId, delayMs, EMBER_AF_LONG_POLL, EMBER_AF_OK_TO_SLEEP);
}
EmberStatus emberAfDeactivateClusterTick(EndpointId endpoint, ClusterId clusterId, bool isClient)
{
EmberAfEventContext * context = findEventContext(endpoint, clusterId, isClient);
if (context != nullptr)
{
emberEventControlSetInactive(context->eventControl);
return EMBER_SUCCESS;
}
return EMBER_BAD_ARGUMENT;
}
EmberStatus emberAfDeactivateServerTick(EndpointId endpoint, ClusterId clusterId)
{
return emberAfDeactivateClusterTick(endpoint, clusterId, EMBER_AF_SERVER_CLUSTER_TICK);
}