1 /*
2  *  Copyright (c) 2016-2018, 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 includes definitions for MAC Channel Mask
32  */
33 
34 #ifndef MAC_CHANNEL_MASK_HPP_
35 #define MAC_CHANNEL_MASK_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #include <openthread/platform/radio.h>
40 
41 #include "common/equatable.hpp"
42 #include "common/numeric_limits.hpp"
43 #include "common/string.hpp"
44 #include "radio/radio.hpp"
45 
46 namespace ot {
47 namespace Mac {
48 
49 /**
50  * @addtogroup core-mac
51  *
52  * @brief
53  *   This module includes definitions for MAC Channel Mask.
54  *
55  * @{
56  */
57 
58 /**
59  * Defines a channel mask.
60  *
61  * It is a wrapper class around a `uint32_t` bit vector representing a set of channels.
62  */
63 class ChannelMask : public Unequatable<ChannelMask>
64 {
65 public:
66     /**
67      * This constant specifies the value to pass in `GetNextChannel()` to get the first channel in the mask.
68      */
69     static constexpr uint8_t kChannelIteratorFirst = 0xff;
70 
71     static constexpr uint16_t kInfoStringSize = 45; ///< Recommended buffer size to use with `ToString()`.
72 
73     /**
74      * Defines the fixed-length `String` object returned from `ToString()`.
75      */
76     typedef String<kInfoStringSize> InfoString;
77 
78     /**
79      * Initializes a `ChannelMask` instance.
80      */
ChannelMask(void)81     ChannelMask(void)
82         : mMask(0)
83     {
84     }
85 
86     /**
87      * Initializes a `ChannelMask` instance with a given mask.
88      *
89      * @param[in]  aMask   A channel mask (as a `uint32_t` bit-vector mask with bit 0 (lsb) -> channel 0, and so on).
90      */
ChannelMask(uint32_t aMask)91     explicit ChannelMask(uint32_t aMask)
92         : mMask(aMask)
93     {
94     }
95 
96     /**
97      * Clears the channel mask.
98      */
Clear(void)99     void Clear(void) { mMask = 0; }
100 
101     /**
102      * Gets the channel mask (as a `uint32_t` bit-vector mask with bit 0 (lsb) -> channel 0, and so on).
103      *
104      * @returns The channel mask.
105      */
GetMask(void) const106     uint32_t GetMask(void) const { return mMask; }
107 
108     /**
109      * Sets the channel mask.
110      *
111      * @param[in]  aMask   A channel mask (as a `uint32_t` bit-vector mask with bit 0 (lsb) -> channel 0, and so on).
112      */
SetMask(uint32_t aMask)113     void SetMask(uint32_t aMask) { mMask = aMask; }
114 
115     /**
116      * Indicates if the mask is empty.
117      *
118      * @returns TRUE if the mask is empty, FALSE otherwise.
119      */
IsEmpty(void) const120     bool IsEmpty(void) const { return (mMask == 0); }
121 
122     /**
123      * Indicates if the mask contains only a single channel.
124      *
125      * @returns TRUE if channel mask contains a single channel, FALSE otherwise
126      */
IsSingleChannel(void) const127     bool IsSingleChannel(void) const { return ((mMask != 0) && ((mMask & (mMask - 1)) == 0)); }
128 
129     /**
130      * Indicates if the mask contains a given channel.
131      *
132      * @param[in]  aChannel  A channel.
133      *
134      * @returns TRUE if the channel @p aChannel is included in the mask, FALSE otherwise.
135      */
ContainsChannel(uint8_t aChannel) const136     bool ContainsChannel(uint8_t aChannel) const
137     {
138         return (aChannel < BitSizeOf(mMask)) ? ((1UL << aChannel) & mMask) != 0 : false;
139     }
140 
141     /**
142      * Adds a channel to the channel mask.
143      *
144      * @param[in]  aChannel  A channel
145      */
AddChannel(uint8_t aChannel)146     void AddChannel(uint8_t aChannel)
147     {
148         if (aChannel < BitSizeOf(mMask))
149         {
150             mMask |= (1UL << aChannel);
151         }
152     }
153 
154     /**
155      * Removes a channel from the channel mask.
156      *
157      * @param[in]  aChannel  A channel
158      */
RemoveChannel(uint8_t aChannel)159     void RemoveChannel(uint8_t aChannel)
160     {
161         if (aChannel < BitSizeOf(mMask))
162         {
163             mMask &= ~(1UL << aChannel);
164         }
165     }
166 
167     /**
168      * Updates the channel mask by intersecting it with another mask.
169      *
170      * @param[in]  aOtherMask  Another channel mask.
171      */
Intersect(const ChannelMask & aOtherMask)172     void Intersect(const ChannelMask &aOtherMask) { mMask &= aOtherMask.mMask; }
173 
174     /**
175      * Returns the number of channels in the mask.
176      *
177      * @returns Number of channels in the mask.
178      */
179     uint8_t GetNumberOfChannels(void) const;
180 
181     /**
182      * Gets the next channel in the channel mask.
183      *
184      * Can be used to iterate over all channels in the channel mask. To get the first channel (channel with
185      * lowest number) in the mask the @p aChannel should be set to `kChannelIteratorFirst`.
186      *
187      * @param[in,out] aChannel       A reference to a `uint8_t`.
188      *                               On entry it should contain the previous channel or `kChannelIteratorFirst`.
189      *                               On exit it contains the next channel.
190      *
191      * @retval  kErrorNone       Got the next channel, @p aChannel updated successfully.
192      * @retval  kErrorNotFound   No next channel in the channel mask (note: @p aChannel may be changed).
193      */
194     Error GetNextChannel(uint8_t &aChannel) const;
195 
196     /**
197      * Randomly chooses a channel from the channel mask.
198      *
199      * @returns A randomly chosen channel from the given mask, or `kChannelIteratorFirst` if the mask is empty.
200      */
201     uint8_t ChooseRandomChannel(void) const;
202 
203     /**
204      * Overloads `==` operator to indicate whether two masks are equal.
205      *
206      * @param[in] aAnother   A reference to another mask to compare with the current one.
207      *
208      * @returns TRUE if the two masks are equal, FALSE otherwise.
209      */
operator ==(const ChannelMask & aAnother) const210     bool operator==(const ChannelMask &aAnother) const { return (mMask == aAnother.mMask); }
211 
212     /**
213      * Converts the channel mask into a human-readable string.
214      *
215      * Examples of possible output:
216      *  -  empty mask      ->  "{ }"
217      *  -  all channels    ->  "{ 11-26 }"
218      *  -  single channel  ->  "{ 20 }"
219      *  -  multiple ranges ->  "{ 11, 14-17, 20-22, 24, 25 }"
220      *  -  no range        ->  "{ 14, 21, 26 }"
221      *
222      * @returns  An `InfoString` object representing the channel mask.
223      */
224     InfoString ToString(void) const;
225 
226 private:
227     static_assert((Radio::kChannelMin < 32) && (Radio::kChannelMax < 32),
228                   "The channel number is larger than 32. `ChannelMask` uses 32 bit mask.");
229     uint32_t mMask;
230 };
231 
232 /**
233  * @}
234  */
235 
236 } // namespace Mac
237 } // namespace ot
238 
239 #endif // MAC_CHANNEL_MASK_HPP_
240