1 /* 2 * Copyright (c) 2016-2017, The OpenThread Authors. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. Neither the name of the copyright holder nor the 13 * names of its contributors may be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /** 30 * @file 31 * This file defines OpenThread Notifier class. 32 */ 33 34 #ifndef NOTIFIER_HPP_ 35 #define NOTIFIER_HPP_ 36 37 #include "openthread-core-config.h" 38 39 #include <stdbool.h> 40 #include <stdint.h> 41 42 #include <openthread/instance.h> 43 #include <openthread/platform/toolchain.h> 44 45 #include "common/callback.hpp" 46 #include "common/error.hpp" 47 #include "common/locator.hpp" 48 #include "common/non_copyable.hpp" 49 #include "common/tasklet.hpp" 50 51 namespace ot { 52 53 /** 54 * @addtogroup core-notifier 55 * 56 * @brief 57 * This module includes definitions for OpenThread Notifier class. 58 * 59 * @{ 60 * 61 */ 62 63 /** 64 * Type represents events emitted from OpenThread Notifier. 65 * 66 */ 67 enum Event : uint32_t 68 { 69 kEventIp6AddressAdded = OT_CHANGED_IP6_ADDRESS_ADDED, ///< IPv6 address was added 70 kEventIp6AddressRemoved = OT_CHANGED_IP6_ADDRESS_REMOVED, ///< IPv6 address was removed 71 kEventThreadRoleChanged = OT_CHANGED_THREAD_ROLE, ///< Role changed 72 kEventThreadLinkLocalAddrChanged = OT_CHANGED_THREAD_LL_ADDR, ///< Link-local address changed 73 kEventThreadMeshLocalAddrChanged = OT_CHANGED_THREAD_ML_ADDR, ///< Mesh-local address changed 74 kEventThreadRlocAdded = OT_CHANGED_THREAD_RLOC_ADDED, ///< RLOC was added 75 kEventThreadRlocRemoved = OT_CHANGED_THREAD_RLOC_REMOVED, ///< RLOC was removed 76 kEventThreadPartitionIdChanged = OT_CHANGED_THREAD_PARTITION_ID, ///< Partition ID changed 77 kEventThreadKeySeqCounterChanged = OT_CHANGED_THREAD_KEY_SEQUENCE_COUNTER, ///< Key Sequence changed 78 kEventThreadNetdataChanged = OT_CHANGED_THREAD_NETDATA, ///< Network Data changed 79 kEventThreadChildAdded = OT_CHANGED_THREAD_CHILD_ADDED, ///< Child was added 80 kEventThreadChildRemoved = OT_CHANGED_THREAD_CHILD_REMOVED, ///< Child was removed 81 kEventIp6MulticastSubscribed = OT_CHANGED_IP6_MULTICAST_SUBSCRIBED, ///< Multicast address added 82 kEventIp6MulticastUnsubscribed = OT_CHANGED_IP6_MULTICAST_UNSUBSCRIBED, ///< Multicast address removed 83 kEventThreadChannelChanged = OT_CHANGED_THREAD_CHANNEL, ///< Network channel changed 84 kEventThreadPanIdChanged = OT_CHANGED_THREAD_PANID, ///< Network PAN ID changed 85 kEventThreadNetworkNameChanged = OT_CHANGED_THREAD_NETWORK_NAME, ///< Network name changed 86 kEventThreadExtPanIdChanged = OT_CHANGED_THREAD_EXT_PANID, ///< Extended PAN ID changed 87 kEventNetworkKeyChanged = OT_CHANGED_NETWORK_KEY, ///< Network Key changed 88 kEventPskcChanged = OT_CHANGED_PSKC, ///< PSKc changed 89 kEventSecurityPolicyChanged = OT_CHANGED_SECURITY_POLICY, ///< Security Policy changed 90 kEventChannelManagerNewChannelChanged = OT_CHANGED_CHANNEL_MANAGER_NEW_CHANNEL, ///< New Channel (channel-manager) 91 kEventSupportedChannelMaskChanged = OT_CHANGED_SUPPORTED_CHANNEL_MASK, ///< Channel mask changed 92 kEventCommissionerStateChanged = OT_CHANGED_COMMISSIONER_STATE, ///< Commissioner state changed 93 kEventThreadNetifStateChanged = OT_CHANGED_THREAD_NETIF_STATE, ///< Netif state changed 94 kEventThreadBackboneRouterStateChanged = OT_CHANGED_THREAD_BACKBONE_ROUTER_STATE, ///< Backbone Router state changed 95 kEventThreadBackboneRouterLocalChanged = OT_CHANGED_THREAD_BACKBONE_ROUTER_LOCAL, ///< Local Backbone Router changed 96 kEventJoinerStateChanged = OT_CHANGED_JOINER_STATE, ///< Joiner state changed 97 kEventActiveDatasetChanged = OT_CHANGED_ACTIVE_DATASET, ///< Active Dataset changed 98 kEventPendingDatasetChanged = OT_CHANGED_PENDING_DATASET, ///< Pending Dataset changed 99 kEventNat64TranslatorStateChanged = OT_CHANGED_NAT64_TRANSLATOR_STATE, ///< Nat64Translator state changed 100 kEventParentLinkQualityChanged = OT_CHANGED_PARENT_LINK_QUALITY, ///< Parent link quality changed 101 }; 102 103 /** 104 * Represents a list of events. 105 * 106 */ 107 class Events 108 { 109 public: 110 /** 111 * Represents a bit-field indicating a list of events (with values from `Event`) 112 * 113 */ 114 typedef otChangedFlags Flags; 115 116 /** 117 * Initializes the `Events` list (as empty). 118 * 119 */ Events(void)120 Events(void) 121 : mEventFlags(0) 122 { 123 } 124 125 /** 126 * Clears the `Events` list. 127 * 128 */ Clear(void)129 void Clear(void) { mEventFlags = 0; } 130 131 /** 132 * Indicates whether the `Events` list contains a given event. 133 * 134 * @param[in] aEvent The event to check. 135 * 136 * @returns TRUE if the list contains the @p aEvent, FALSE otherwise. 137 * 138 */ Contains(Event aEvent) const139 bool Contains(Event aEvent) const { return (mEventFlags & aEvent) != 0; } 140 141 /** 142 * Indicates whether the `Events` list contains any of a given set of events. 143 * 144 * @param[in] aEvents The events set to check (must be a collection of `Event` constants combined using `|`). 145 * 146 * @returns TRUE if the list contains any of the @p aEvents set, FALSE otherwise. 147 * 148 */ ContainsAny(Flags aEvents) const149 bool ContainsAny(Flags aEvents) const { return (mEventFlags & aEvents) != 0; } 150 151 /** 152 * Indicates whether the `Events` list contains all of a given set of events. 153 * 154 * @param[in] aEvents The events set to check (must be collection of `Event` constants combined using `|`). 155 * 156 * @returns TRUE if the list contains all of the @p aEvents set, FALSE otherwise. 157 * 158 */ ContainsAll(Flags aEvents) const159 bool ContainsAll(Flags aEvents) const { return (mEventFlags & aEvents) == aEvents; } 160 161 /** 162 * Adds a given event to the `Events` list. 163 * 164 * @param[in] aEvent The event to add. 165 * 166 */ Add(Event aEvent)167 void Add(Event aEvent) { mEventFlags |= aEvent; } 168 169 /** 170 * Indicates whether the `Events` list is empty. 171 * 172 * @returns TRUE if the list is empty, FALSE otherwise. 173 * 174 */ IsEmpty(void) const175 bool IsEmpty(void) const { return (mEventFlags == 0); } 176 177 /** 178 * Gets the `Events` list as bit-field `Flags` value. 179 * 180 * @returns The list as bit-field `Flags` value. 181 * 182 */ GetAsFlags(void) const183 Flags GetAsFlags(void) const { return mEventFlags; } 184 185 private: 186 Flags mEventFlags; 187 }; 188 189 /** 190 * Implements the OpenThread Notifier. 191 * 192 * For core internal modules, `Notifier` class emits events directly to them by invoking method `HandleNotifierEvents()` 193 * on the module instance. 194 * 195 * A `otStateChangedCallback` callback can be explicitly registered with the `Notifier`. This is mainly intended for use 196 * by external users (i.e.provided as an OpenThread public API). Max number of such callbacks that can be registered at 197 * the same time is specified by `OPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS` configuration parameter. 198 * 199 */ 200 class Notifier : public InstanceLocator, private NonCopyable 201 { 202 public: 203 /** 204 * Initializes a `Notifier` instance. 205 * 206 * @param[in] aInstance A reference to OpenThread instance. 207 * 208 */ 209 explicit Notifier(Instance &aInstance); 210 211 /** 212 * Registers an `otStateChangedCallback` handler. 213 * 214 * @param[in] aCallback A pointer to the handler function that is called to notify of the changes. 215 * @param[in] aContext A pointer to arbitrary context information. 216 * 217 * @retval kErrorNone Successfully registered the callback. 218 * @retval kErrorAlready The callback was already registered. 219 * @retval kErrorNoBufs Could not add the callback due to resource constraints. 220 * 221 */ 222 Error RegisterCallback(otStateChangedCallback aCallback, void *aContext); 223 224 /** 225 * Removes/unregisters a previously registered `otStateChangedCallback` handler. 226 * 227 * @param[in] aCallback A pointer to the callback function pointer. 228 * @param[in] aContext A pointer to arbitrary context information. 229 * 230 */ 231 void RemoveCallback(otStateChangedCallback aCallback, void *aContext); 232 233 /** 234 * Schedules signaling of an event. 235 * 236 * @param[in] aEvent The event to signal. 237 * 238 */ 239 void Signal(Event aEvent); 240 241 /** 242 * Schedules signaling of am event only if the event has not been signaled before (first time signal). 243 * 244 * @param[in] aEvent The event to signal. 245 * 246 */ 247 void SignalIfFirst(Event aEvent); 248 249 /** 250 * Indicates whether or not an event signal callback is pending/scheduled. 251 * 252 * @returns TRUE if a callback is pending, FALSE otherwise. 253 * 254 */ IsPending(void) const255 bool IsPending(void) const { return !mEventsToSignal.IsEmpty(); } 256 257 /** 258 * Indicates whether or not an event has been signaled before. 259 * 260 * @param[in] aEvent The event to check. 261 * 262 * @retval TRUE The event @p aEvent have been signaled before. 263 * @retval FALSE The event @p aEvent has not been signaled before. 264 * 265 */ HasSignaled(Event aEvent) const266 bool HasSignaled(Event aEvent) const { return mSignaledEvents.Contains(aEvent); } 267 268 /** 269 * Updates a variable of a type `Type` with a new value and signals the given event. 270 * 271 * If the variable is already set to the same value, this method returns `kErrorAlready` and the event is 272 * signaled using `SignalIfFirst()` (i.e., signal is scheduled only if event has not been signaled before). 273 * 274 * The template `Type` should support comparison operator `==` and assignment operator `=`. 275 * 276 * @param[in,out] aVariable A reference to the variable to update. 277 * @param[in] aNewValue The new value. 278 * @param[in] aEvent The event to signal. 279 * 280 * @retval kErrorNone The variable was update successfully and @p aEvent was signaled. 281 * @retval kErrorAlready The variable was already set to the same value. 282 * 283 */ Update(Type & aVariable,const Type & aNewValue,Event aEvent)284 template <typename Type> Error Update(Type &aVariable, const Type &aNewValue, Event aEvent) 285 { 286 Error error = kErrorNone; 287 288 if (aVariable == aNewValue) 289 { 290 SignalIfFirst(aEvent); 291 error = kErrorAlready; 292 } 293 else 294 { 295 aVariable = aNewValue; 296 Signal(aEvent); 297 } 298 299 return error; 300 } 301 302 private: 303 static constexpr uint16_t kMaxExternalHandlers = OPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS; 304 305 // Character limit to divide the log into multiple lines in `LogChangedFlags()`. 306 static constexpr uint16_t kFlagsStringLineLimit = 70; 307 308 // Max length for string representation of a flag by `FlagToString()`. 309 static constexpr uint8_t kMaxFlagNameLength = 25; 310 311 static constexpr uint16_t kFlagsStringBufferSize = kFlagsStringLineLimit + kMaxFlagNameLength; 312 313 typedef Callback<otStateChangedCallback> ExternalCallback; 314 315 void EmitEvents(void); 316 317 void LogEvents(Events aEvents) const; 318 const char *EventToString(Event aEvent) const; 319 320 using EmitEventsTask = TaskletIn<Notifier, &Notifier::EmitEvents>; 321 322 Events mEventsToSignal; 323 Events mSignaledEvents; 324 EmitEventsTask mTask; 325 ExternalCallback mExternalCallbacks[kMaxExternalHandlers]; 326 }; 327 328 /** 329 * @} 330 * 331 */ 332 333 } // namespace ot 334 335 #endif // NOTIFIER_HPP_ 336