blob: 8887671aff41c0e13417698b02a454c7ab3fd6e7 [file] [log] [blame]
/*
* Copyright (c) 2016-2017, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file defines OpenThread Notifier class.
*/
#ifndef NOTIFIER_HPP_
#define NOTIFIER_HPP_
#include "openthread-core-config.h"
#include <stdbool.h>
#include <stdint.h>
#include <openthread/instance.h>
#include <openthread/platform/toolchain.h>
#include "common/error.hpp"
#include "common/locator.hpp"
#include "common/non_copyable.hpp"
#include "common/tasklet.hpp"
namespace ot {
/**
* @addtogroup core-notifier
*
* @brief
* This module includes definitions for OpenThread Notifier class.
*
* @{
*
*/
/**
* This enumeration type represents events emitted from OpenThread Notifier.
*
*/
enum Event : uint32_t
{
kEventIp6AddressAdded = OT_CHANGED_IP6_ADDRESS_ADDED, ///< IPv6 address was added
kEventIp6AddressRemoved = OT_CHANGED_IP6_ADDRESS_REMOVED, ///< IPv6 address was removed
kEventThreadRoleChanged = OT_CHANGED_THREAD_ROLE, ///< Role changed
kEventThreadLinkLocalAddrChanged = OT_CHANGED_THREAD_LL_ADDR, ///< Link-local address changed
kEventThreadMeshLocalAddrChanged = OT_CHANGED_THREAD_ML_ADDR, ///< Mesh-local address changed
kEventThreadRlocAdded = OT_CHANGED_THREAD_RLOC_ADDED, ///< RLOC was added
kEventThreadRlocRemoved = OT_CHANGED_THREAD_RLOC_REMOVED, ///< RLOC was removed
kEventThreadPartitionIdChanged = OT_CHANGED_THREAD_PARTITION_ID, ///< Partition ID changed
kEventThreadKeySeqCounterChanged = OT_CHANGED_THREAD_KEY_SEQUENCE_COUNTER, ///< Key Sequence changed
kEventThreadNetdataChanged = OT_CHANGED_THREAD_NETDATA, ///< Network Data changed
kEventThreadChildAdded = OT_CHANGED_THREAD_CHILD_ADDED, ///< Child was added
kEventThreadChildRemoved = OT_CHANGED_THREAD_CHILD_REMOVED, ///< Child was removed
kEventIp6MulticastSubscribed = OT_CHANGED_IP6_MULTICAST_SUBSCRIBED, ///< Multicast address added
kEventIp6MulticastUnsubscribed = OT_CHANGED_IP6_MULTICAST_UNSUBSCRIBED, ///< Multicast address removed
kEventThreadChannelChanged = OT_CHANGED_THREAD_CHANNEL, ///< Network channel changed
kEventThreadPanIdChanged = OT_CHANGED_THREAD_PANID, ///< Network PAN ID changed
kEventThreadNetworkNameChanged = OT_CHANGED_THREAD_NETWORK_NAME, ///< Network name changed
kEventThreadExtPanIdChanged = OT_CHANGED_THREAD_EXT_PANID, ///< Extended PAN ID changed
kEventNetworkKeyChanged = OT_CHANGED_NETWORK_KEY, ///< Network Key changed
kEventPskcChanged = OT_CHANGED_PSKC, ///< PSKc changed
kEventSecurityPolicyChanged = OT_CHANGED_SECURITY_POLICY, ///< Security Policy changed
kEventChannelManagerNewChannelChanged = OT_CHANGED_CHANNEL_MANAGER_NEW_CHANNEL, ///< New Channel (channel-manager)
kEventSupportedChannelMaskChanged = OT_CHANGED_SUPPORTED_CHANNEL_MASK, ///< Channel mask changed
kEventCommissionerStateChanged = OT_CHANGED_COMMISSIONER_STATE, ///< Commissioner state changed
kEventThreadNetifStateChanged = OT_CHANGED_THREAD_NETIF_STATE, ///< Netif state changed
kEventThreadBackboneRouterStateChanged = OT_CHANGED_THREAD_BACKBONE_ROUTER_STATE, ///< Backbone Router state changed
kEventThreadBackboneRouterLocalChanged = OT_CHANGED_THREAD_BACKBONE_ROUTER_LOCAL, ///< Local Backbone Router changed
kEventJoinerStateChanged = OT_CHANGED_JOINER_STATE, ///< Joiner state changed
kEventActiveDatasetChanged = OT_CHANGED_ACTIVE_DATASET, ///< Active Dataset changed
kEventPendingDatasetChanged = OT_CHANGED_PENDING_DATASET, ///< Pending Dataset changed
};
/**
* This type represents a list of events.
*
*/
class Events
{
public:
/**
* This type represents a bit-field indicating a list of events (with values from `Event`)
*
*/
typedef otChangedFlags Flags;
/**
* This constructor initializes the `Events` list (as empty).
*
*/
Events(void)
: mEventFlags(0)
{
}
/**
* This method clears the `Events` list.
*
*/
void Clear(void) { mEventFlags = 0; }
/**
* This method indicates whether the `Events` list contains a given event.
*
* @param[in] aEvent The event to check.
*
* @returns TRUE if the list contains the @p aEvent, FALSE otherwise.
*
*/
bool Contains(Event aEvent) const { return (mEventFlags & aEvent) != 0; }
/**
* This method indicates whether the `Events` list contains any of a given set of events.
*
* @param[in] aEvents The events set to check (must be a collection of `Event` constants combined using `|`).
*
* @returns TRUE if the list contains any of the @p aEvents set, FALSE otherwise.
*
*/
bool ContainsAny(Flags aEvents) const { return (mEventFlags & aEvents) != 0; }
/**
* This method indicates whether the `Events` list contains all of a given set of events.
*
* @param[in] aEvents The events set to check (must be collection of `Event` constants combined using `|`).
*
* @returns TRUE if the list contains all of the @p aEvents set, FALSE otherwise.
*
*/
bool ContainsAll(Flags aEvents) const { return (mEventFlags & aEvents) == aEvents; }
/**
* This method adds a given event to the `Events` list.
*
* @param[in] aEvent The event to add.
*
*/
void Add(Event aEvent) { mEventFlags |= aEvent; }
/**
* This method indicates whether the `Events` list is empty.
*
* @returns TRUE if the list is empty, FALSE otherwise.
*
*/
bool IsEmpty(void) const { return (mEventFlags == 0); }
/**
* This method gets the `Events` list as bit-field `Flags` value.
*
* @returns The list as bit-field `Flags` value.
*
*/
Flags GetAsFlags(void) const { return mEventFlags; }
private:
Flags mEventFlags;
};
/**
* This class implements the OpenThread Notifier.
*
* For core internal modules, `Notifier` class emits events directly to them by invoking method `HandleNotifierEvents()`
* on the module instance.
*
* A `otStateChangedCallback` callback can be explicitly registered with the `Notifier`. This is mainly intended for use
* by external users (i.e.provided as an OpenThread public API). Max number of such callbacks that can be registered at
* the same time is specified by `OPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS` configuration parameter.
*
*/
class Notifier : public InstanceLocator, private NonCopyable
{
public:
/**
* This constructor initializes a `Notifier` instance.
*
* @param[in] aInstance A reference to OpenThread instance.
*
*/
explicit Notifier(Instance &aInstance);
/**
* This method registers an `otStateChangedCallback` handler.
*
* @param[in] aCallback A pointer to the handler function that is called to notify of the changes.
* @param[in] aContext A pointer to arbitrary context information.
*
* @retval kErrorNone Successfully registered the callback.
* @retval kErrorAlready The callback was already registered.
* @retval kErrorNoBufs Could not add the callback due to resource constraints.
*
*/
Error RegisterCallback(otStateChangedCallback aCallback, void *aContext);
/**
* This method removes/unregisters a previously registered `otStateChangedCallback` handler.
*
* @param[in] aCallback A pointer to the callback function pointer.
* @param[in] aContext A pointer to arbitrary context information.
*
*/
void RemoveCallback(otStateChangedCallback aCallback, void *aContext);
/**
* This method schedules signaling of an event.
*
* @param[in] aEvent The event to signal.
*
*/
void Signal(Event aEvent);
/**
* This method schedules signaling of am event only if the event has not been signaled before (first time signal).
*
* @param[in] aEvent The event to signal.
*
*/
void SignalIfFirst(Event aEvent);
/**
* This method indicates whether or not an event signal callback is pending/scheduled.
*
* @returns TRUE if a callback is pending, FALSE otherwise.
*
*/
bool IsPending(void) const { return !mEventsToSignal.IsEmpty(); }
/**
* This method indicates whether or not an event has been signaled before.
*
* @param[in] aEvent The event to check.
*
* @retval TRUE The event @p aEvent have been signaled before.
* @retval FALSE The event @p aEvent has not been signaled before.
*
*/
bool HasSignaled(Event aEvent) const { return mSignaledEvents.Contains(aEvent); }
/**
* This template method updates a variable of a type `Type` with a new value and signals the given event.
*
* If the variable is already set to the same value, this method returns `kErrorAlready` and the event is
* signaled using `SignalIfFirst()` (i.e., signal is scheduled only if event has not been signaled before).
*
* The template `Type` should support comparison operator `==` and assignment operator `=`.
*
* @param[in,out] aVariable A reference to the variable to update.
* @param[in] aNewValue The new value.
* @param[in] aEvent The event to signal.
*
* @retval kErrorNone The variable was update successfully and @p aEvent was signaled.
* @retval kErrorAlready The variable was already set to the same value.
*
*/
template <typename Type> Error Update(Type &aVariable, const Type &aNewValue, Event aEvent)
{
Error error = kErrorNone;
if (aVariable == aNewValue)
{
SignalIfFirst(aEvent);
error = kErrorAlready;
}
else
{
aVariable = aNewValue;
Signal(aEvent);
}
return error;
}
private:
static constexpr uint16_t kMaxExternalHandlers = OPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS;
// Character limit to divide the log into multiple lines in `LogChangedFlags()`.
static constexpr uint16_t kFlagsStringLineLimit = 70;
// Max length for string representation of a flag by `FlagToString()`.
static constexpr uint8_t kMaxFlagNameLength = 25;
static constexpr uint16_t kFlagsStringBufferSize = kFlagsStringLineLimit + kMaxFlagNameLength;
struct ExternalCallback
{
otStateChangedCallback mHandler;
void * mContext;
};
static void EmitEvents(Tasklet &aTasklet);
void EmitEvents(void);
void LogEvents(Events aEvents) const;
const char *EventToString(Event aEvent) const;
Events mEventsToSignal;
Events mSignaledEvents;
Tasklet mTask;
ExternalCallback mExternalCallbacks[kMaxExternalHandlers];
};
/**
* @}
*
*/
} // namespace ot
#endif // NOTIFIER_HPP_