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 <limits.h>
40 #include <openthread/platform/radio.h>
41 
42 #include "common/equatable.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 /**
60  * This class defines a channel mask.
61  *
62  * It is a wrapper class around a `uint32_t` bit vector representing a set of channels.
63  *
64  */
65 class ChannelMask : public Unequatable<ChannelMask>
66 {
67 public:
68     /**
69      * This constant specifies the value to pass in `GetNextChannel()` to get the first channel in the mask.
70      *
71      */
72     static constexpr uint8_t kChannelIteratorFirst = 0xff;
73 
74     static constexpr uint16_t kInfoStringSize = 45; ///< Recommended buffer size to use with `ToString()`.
75 
76     /**
77      * This type defines the fixed-length `String` object returned from `ToString()`.
78      *
79      */
80     typedef String<kInfoStringSize> InfoString;
81 
82     /**
83      * This constructor initializes a `ChannelMask` instance.
84      *
85      */
ChannelMask(void)86     ChannelMask(void)
87         : mMask(0)
88     {
89     }
90 
91     /**
92      * This constructor initializes a `ChannelMask` instance with a given mask.
93      *
94      * @param[in]  aMask   A channel mask (as a `uint32_t` bit-vector mask with bit 0 (lsb) -> channel 0, and so on).
95      *
96      */
ChannelMask(uint32_t aMask)97     explicit ChannelMask(uint32_t aMask)
98         : mMask(aMask)
99     {
100     }
101 
102     /**
103      * This method clears the channel mask.
104      *
105      */
Clear(void)106     void Clear(void) { mMask = 0; }
107 
108     /**
109      * This method gets the channel mask (as a `uint32_t` bit-vector mask with bit 0 (lsb) -> channel 0, and so on).
110      *
111      * @returns The channel mask.
112      *
113      */
GetMask(void) const114     uint32_t GetMask(void) const { return mMask; }
115 
116     /**
117      * This method sets the channel mask.
118      *
119      * @param[in]  aMask   A channel mask (as a `uint32_t` bit-vector mask with bit 0 (lsb) -> channel 0, and so on).
120      *
121      */
SetMask(uint32_t aMask)122     void SetMask(uint32_t aMask) { mMask = aMask; }
123 
124     /**
125      * This method indicates if the mask is empty.
126      *
127      * @returns TRUE if the mask is empty, FALSE otherwise.
128      *
129      */
IsEmpty(void) const130     bool IsEmpty(void) const { return (mMask == 0); }
131 
132     /**
133      * This method indicates if the mask contains only a single channel.
134      *
135      * @returns TRUE if channel mask contains a single channel, FALSE otherwise
136      *
137      */
IsSingleChannel(void) const138     bool IsSingleChannel(void) const { return ((mMask != 0) && ((mMask & (mMask - 1)) == 0)); }
139 
140     /**
141      * This method indicates if the mask contains a given channel.
142      *
143      * @param[in]  aChannel  A channel.
144      *
145      * @returns TRUE if the channel @p aChannel is included in the mask, FALSE otherwise.
146      *
147      */
ContainsChannel(uint8_t aChannel) const148     bool ContainsChannel(uint8_t aChannel) const
149     {
150         return (aChannel < sizeof(mMask) * CHAR_BIT) ? ((1UL << aChannel) & mMask) != 0 : false;
151     }
152 
153     /**
154      * This method adds a channel to the channel mask.
155      *
156      * @param[in]  aChannel  A channel
157      *
158      */
AddChannel(uint8_t aChannel)159     void AddChannel(uint8_t aChannel)
160     {
161         if (aChannel < sizeof(mMask) * CHAR_BIT)
162         {
163             mMask |= (1UL << aChannel);
164         }
165     }
166 
167     /**
168      * This method removes a channel from the channel mask.
169      *
170      * @param[in]  aChannel  A channel
171      *
172      */
RemoveChannel(uint8_t aChannel)173     void RemoveChannel(uint8_t aChannel)
174     {
175         if (aChannel < sizeof(mMask) * CHAR_BIT)
176         {
177             mMask &= ~(1UL << aChannel);
178         }
179     }
180 
181     /**
182      * This method updates the channel mask by intersecting it with another mask.
183      *
184      * @param[in]  aOtherMask  Another channel mask.
185      *
186      */
Intersect(const ChannelMask & aOtherMask)187     void Intersect(const ChannelMask &aOtherMask) { mMask &= aOtherMask.mMask; }
188 
189     /**
190      * This method returns the number of channels in the mask.
191      *
192      * @returns Number of channels in the mask.
193      *
194      */
195     uint8_t GetNumberOfChannels(void) const;
196 
197     /**
198      * This method gets the next channel in the channel mask.
199      *
200      * This method can be used to iterate over all channels in the channel mask. To get the first channel (channel with
201      * lowest number) in the mask the @p aChannel should be set to `kChannelIteratorFirst`.
202      *
203      * @param[inout] aChannel        A reference to a `uint8_t`.
204      *                               On entry it should contain the previous channel or `kChannelIteratorFirst`.
205      *                               On exit it contains the next channel.
206      *
207      * @retval  kErrorNone       Got the next channel, @p aChannel updated successfully.
208      * @retval  kErrorNotFound   No next channel in the channel mask (note: @p aChannel may be changed).
209      *
210      */
211     Error GetNextChannel(uint8_t &aChannel) const;
212 
213     /**
214      * This method randomly chooses a channel from the channel mask.
215      *
216      * @returns A randomly chosen channel from the given mask, or `kChannelIteratorFirst` if the mask is empty.
217      *
218      */
219     uint8_t ChooseRandomChannel(void) const;
220 
221     /**
222      * This method overloads `==` operator to indicate whether two masks are equal.
223      *
224      * @param[in] aAnother   A reference to another mask to compare with the current one.
225      *
226      * @returns TRUE if the two masks are equal, FALSE otherwise.
227      *
228      */
operator ==(const ChannelMask & aAnother) const229     bool operator==(const ChannelMask &aAnother) const { return (mMask == aAnother.mMask); }
230 
231     /**
232      * This method converts the channel mask into a human-readable string.
233      *
234      * Examples of possible output:
235      *  -  empty mask      ->  "{ }"
236      *  -  all channels    ->  "{ 11-26 }"
237      *  -  single channel  ->  "{ 20 }"
238      *  -  multiple ranges ->  "{ 11, 14-17, 20-22, 24, 25 }"
239      *  -  no range        ->  "{ 14, 21, 26 }"
240      *
241      * @returns  An `InfoString` object representing the channel mask.
242      *
243      */
244     InfoString ToString(void) const;
245 
246 private:
247     static_assert((Radio::kChannelMin < 32) && (Radio::kChannelMax < 32),
248                   "The channel number is larger than 32. `ChannelMask` uses 32 bit mask.");
249     uint32_t mMask;
250 };
251 
252 /**
253  * @}
254  *
255  */
256 
257 } // namespace Mac
258 } // namespace ot
259 
260 #endif // MAC_CHANNEL_MASK_HPP_
261