text: /*
   *  Copyright (c) 2016-2018, 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 includes definition for AnnounceSender.
   */
  
  #ifndef ANNOUNCE_SENDER_HPP_
  #define ANNOUNCE_SENDER_HPP_
  
  #include "openthread-core-config.h"
  
  #include "common/locator.hpp"
  #include "common/non_copyable.hpp"
  #include "common/notifier.hpp"
  #include "common/timer.hpp"
  #include "common/trickle_timer.hpp"
  #include "mac/mac.hpp"
  
  namespace ot {
  
  /**
   * This class implements the base class for an `AnnounceSender` and `AnnounceBeginSever`.
   *
   * This class provides APIs to schedule periodic transmission of MLE Announcement messages for a given number
   * transmissions per channel.
   */
  class AnnounceSenderBase : public InstanceLocator, private NonCopyable
  {
  protected:
      enum : uint8_t
      {
          /**
           * This constant defines the special channel value to start from the first channel in the channel mask.
           *
           */
          kChannelIteratorFirst = Mac::ChannelMask::kChannelIteratorFirst,
      };
  
      /**
       * This constructor initializes the object.
       *
       * @param[in]  aInstance   A reference to the OpenThread instance.
       * @param[in]  aHandler    A timer handler provided by sub-class.
       *
       */
      AnnounceSenderBase(Instance &aInstance, Timer::Handler aHandler);
  
      /**
       * This method schedules the MLE Announce transmissions.
       *
       * This method requests @p aCount additional MLE transmission cycles to be scheduled. Each cycle covers all the
       * channels in the specified channel mask from `GetChannelMask()`, with `GetPeriod()` as the time interval between
       * any two successive MLE Announcement transmissions (possibly) on different channels from the mask. The
       * `GetJitter()` value is used to add a random interval from `[-jitter, jitter]` to each period interval.
       *
       * If a "starting channel" is specified using `SetStartingChannel()`, then the cycle starts with MLE Announce
       * transmission on the given starting channel. Otherwise the cycle starts with the first channel (with smallest
       * channel number) in the mask.
       *
       * If a previously requested MLE Announce transmission is still ongoing, a subsequent call to this method adds
       * the @p aCount cycles to the schedule.
       *
       * If there is no active MLE Announce transmission, after call to `SendAnnounce()`, the first MLE Announce
       * transmission happens within a short random interval selected from range `[0, jitter]`.
       *
       * @param[in]  aCount     The number of cycles to schedule.
       *
       */
      void SendAnnounce(uint8_t aCount);
  
      /**
       * This method stops the ongoing MLE Announce transmissions.
       *
       */
      void Stop(void);
  
      /**
       * This method indicates whether a previously scheduled MLE Announce transmission is currently in progress or is
       * finished.
       *
       * @returns TRUE if the MLE Announce transmission is in progress, FALSE otherwise.
       *
       */
      bool IsRunning(void) const { return mTimer.IsRunning(); }
  
      /**
       * This method gets the period interval.
       *
       * @returns The period interval (in milliseconds).
       *
       */
      uint32_t GetPeriod(void) const { return mPeriod; }
  
      /**
       * This method sets the period interval.
       *
       * The period along with jitter value from (`Get/SetJitter()`) determines the interval between two successive MLE
       * Announcement transmissions (possibly) on different channels from the specified channel mask.
       *
       * @param[in] aPeriod   The period interval (in milliseconds).
       *
       */
      void SetPeriod(uint32_t aPeriod) { mPeriod = aPeriod; }
  
      /**
       * This method gets the current jitter interval.
       *
       * @returns The jitter interval (in milliseconds).
       *
       */
      uint16_t GetJitter(void) const { return mJitter; }
  
      /**
       * This method sets the jitter interval.
       *
       * @param[in] aJitter  The jitter interval (in milliseconds).
       *
       */
      void SetJitter(uint16_t aJitter) { mJitter = aJitter; }
  
      /**
       * This method gets the channel mask.
       *
       * @returns The channel mask.
       *
       */
      const Mac::ChannelMask GetChannelMask(void) const { return mChannelMask; }
  
      /**
       * This method sets the channel mask.
       *
       * @param[in] aChannelMask   The channel mask.
       *
       */
      void SetChannelMask(Mac::ChannelMask aChannelMask);
  
      /**
       * This method gets the starting channel, i.e., the first channel in a TX cycle to send MLE Announcement on.
       *
       * @returns The current starting channel.
       *
       */
      uint8_t GetStartingChannel(void) const { return mStartingChannel; }
  
      /**
       * This method sets the starting channel, i.e., the first channel in a TX cycle to send MLE Announcement on.
       *
       * @p aStartingChannel MUST be present in the current channel mask (from `GetChannelMask()`), otherwise it is
       * ignored and an MLE transmission cycle starts with the first channel (with smallest channel number) in the channel
       * mask.
       *
       * @param[in] aStartingChannel  The starting channel.
       *
       */
      void SetStartingChannel(uint8_t aStartingChannel);
  
      /**
       * This method is the timer handler and must be invoked by sub-class when the timer expires from the `aHandler`
       * callback function provided in the constructor.
       *
       */
      void HandleTimer(void);
  
  private:
      void SelectStartingChannel(void);
  
      Mac::ChannelMask mChannelMask;
      uint32_t         mPeriod;
      uint16_t         mJitter;
      uint8_t          mCount;
      uint8_t          mChannel;
      uint8_t          mStartingChannel;
      TimerMilli       mTimer;
  };
  
  #if OPENTHREAD_CONFIG_ANNOUNCE_SENDER_ENABLE
  
  /**
   * This class implements an AnnounceSender.
   *
   */
  class AnnounceSender : public AnnounceSenderBase
  {
      friend class ot::Notifier;
  
  public:
      /**
       * This constructor initializes the object.
       *
       * @param[in]  aInstance   A reference to the OpenThread instance.
       *
       */
      AnnounceSender(Instance &aInstance);
  
      /**
       * This method notifies the `AnnounceSender` that a MLE Announcement message was received with a current timestamp
       * to update its internal state (decide whether or not to skip transmission of MLE Announcement in this cycle).
       *
       */
      void UpdateOnReceivedAnnounce(void);
  
  private:
      enum : uint32_t
      {
          // Specifies the time interval (in milliseconds) between
          // `AnnounceSender` transmit cycles. With in a cycle, device
          // sends MLE Announcements on all channels from Active
          // Dataset's channel mask.
          kInterval = OPENTHREAD_CONFIG_ANNOUNCE_SENDER_INTERVAL,
  
          // Specifies the sub-interval (in millisecond) within a cycle
          // to send MLE announcement messages. We use half of the cycle
          // interval length for transmission. This ensures that the
          // transmissions are finished before device needs to make a
          // decision about the next cycle. This time is divided by the
          // number of channels to determine the time between two
          // successive Announce tx (on different channels).
          kTxInterval = (kInterval / 2 + 1),
      };
  
      enum : uint16_t
      {
          // Specifies the number of MLE Announcement messages that the
          // device must receive within a cycle interval to skip sending the
          // Announcement itself. This is used as `mTrickleTimer` redundancy
          // constant in `AnnounceSender`.
          kRedundancyConstant = OPENTHREAD_CONFIG_ANNOUNCE_SENDER_REDUNDANCY_CONSTANT,
  
          // Jitter interval (in milliseconds) applied to the period
          // between any two successive MLE Announcement transmissions
          // (possibly) on different channels.
          kMaxJitter = OPENTHREAD_CONFIG_ANNOUNCE_SENDER_JITTER_INTERVAL,
      };
  
      void        Stop(void);
      static void HandleTimer(Timer &aTimer);
      static void HandleTrickleTimer(TrickleTimer &aTimer);
      void        HandleTrickleTimer(void);
      void        HandleNotifierEvents(Events aEvents);
      void        HandleRoleChanged(void);
      void        HandleActiveDatasetChanged(void);
      void        HandleThreadChannelChanged(void);
  
      TrickleTimer mTrickleTimer;
  };
  
  #endif // OPENTHREAD_CONFIG_ANNOUNCE_SENDER_ENABLE
  
  /**
   * @}
   */
  
  } // namespace ot
  
  #endif // ANNOUNCE_SENDER_HPP_
  