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" AND
17  *    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  *    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  *    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20  *    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  *    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  *    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  *    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  *    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  *    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 /**
29  * @file
30  *   This file contains definitions a spinel interface to the OpenThread stack.
31  */
32 
33 #ifndef CHANGED_PROPS_SET_HPP_
34 #define CHANGED_PROPS_SET_HPP_
35 
36 #include "openthread-core-config.h"
37 
38 #include <stddef.h>
39 
40 #include <openthread/error.h>
41 
42 #include "lib/spinel/spinel.h"
43 
44 namespace ot {
45 namespace Ncp {
46 
47 /**
48  * Defines a class to track a set of property/status changes that require update to host. The properties that can
49  * be added to this set must support sending unsolicited updates. This class also provides mechanism for user
50  * to block certain filterable properties disallowing the unsolicited update from them.
51  *
52  */
53 class ChangedPropsSet
54 {
55 public:
56     /**
57      * Defines an entry in the set/list.
58      *
59      */
60     struct Entry
61     {
62         spinel_prop_key_t mPropKey;    ///< The spinel property key.
63         spinel_status_t   mStatus;     ///< The spinel status (used only if prop key is `LAST_STATUS`).
64         bool              mFilterable; ///< Indicates whether the entry can be filtered
65     };
66 
67     /**
68      * This constructor initializes the set.
69      *
70      */
ChangedPropsSet(void)71     ChangedPropsSet(void)
72         : mChangedSet(0)
73         , mFilterSet(0)
74     {
75     }
76 
77     /**
78      * This method clears the set.
79      *
80      */
Clear(void)81     void Clear(void) { mChangedSet = 0; }
82 
83     /**
84      * This method indicates if the set is empty or not.
85      *
86      * @returns TRUE if the set if empty, FALSE otherwise.
87      *
88      */
IsEmpty(void) const89     bool IsEmpty(void) const { return (mChangedSet == 0); }
90 
91     /**
92      * This method adds a property to the set. The property added must be in the list of supported properties
93      * capable of sending unsolicited update, otherwise the input is ignored.
94      *
95      * Note that if the property is already in the set, adding it again does not change the set.
96      *
97      * @param[in] aPropKey    The spinel property key to be added to the set
98      *
99      */
AddProperty(spinel_prop_key_t aPropKey)100     void AddProperty(spinel_prop_key_t aPropKey) { Add(aPropKey, SPINEL_STATUS_OK); }
101 
102     /**
103      * This method adds a `LAST_STATUS` update to the set. The update must be in list of supported entries.
104      *
105      * @param[in] aStatus     The spinel status update to be added to set.
106      *
107      */
AddLastStatus(spinel_status_t aStatus)108     void AddLastStatus(spinel_status_t aStatus) { Add(SPINEL_PROP_LAST_STATUS, aStatus); }
109 
110     /**
111      * This method returns a pointer to array of entries of supported property/status updates. The list includes
112      * all properties that can generate unsolicited update.
113      *
114      * @param[out]  aNumEntries  A reference to output the number of entries in the list.
115      *
116      * @returns A pointer to the supported entries array.
117      *
118      */
GetSupportedEntries(uint8_t & aNumEntries) const119     const Entry *GetSupportedEntries(uint8_t &aNumEntries) const
120     {
121         aNumEntries = GetNumEntries();
122         return &mSupportedProps[0];
123     }
124 
125     /**
126      * This method returns a pointer to the entry associated with a given index.
127      *
128      * @param[in] aIndex     The index to an entry.
129      *
130      * @returns A pointer to the entry associated with @p aIndex, or nullptr if the index is beyond end of array.
131      *
132      */
GetEntry(uint8_t aIndex) const133     const Entry *GetEntry(uint8_t aIndex) const
134     {
135         return (aIndex < GetNumEntries()) ? &mSupportedProps[aIndex] : nullptr;
136     }
137 
138     /**
139      * This method indicates if the entry associated with an index is in the set (i.e., it has been changed and
140      * requires an unsolicited update).
141      *
142      * @param[in] aIndex     The index to an entry.
143      *
144      * @returns TRUE if the entry is in the set, FALSE otherwise.
145      *
146      */
IsEntryChanged(uint8_t aIndex) const147     bool IsEntryChanged(uint8_t aIndex) const { return IsBitSet(mChangedSet, aIndex); }
148 
149     /**
150      * This method removes an entry associated with an index in the set.
151      *
152      * Note that if the property/entry is not in the set, removing it simply does nothing.
153      *
154      * @param[in] aIndex               Index of entry to be removed.
155      *
156      */
RemoveEntry(uint8_t aIndex)157     void RemoveEntry(uint8_t aIndex) { ClearBit(mChangedSet, aIndex); }
158 
159     /**
160      * This method enables/disables filtering of a given property.
161      *
162      * @param[in] aPropKey             The property key to filter.
163      * @param[in] aEnable              TRUE to enable filtering, FALSE to disable.
164      *
165      * @retval OT_ERROR_NONE           Filter state for given property updated successfully.
166      * @retval OT_ERROR_INVALID_ARGS   The given property is not valid (i.e., not capable of unsolicited update).
167      *
168      */
169     otError EnablePropertyFilter(spinel_prop_key_t aPropKey, bool aEnable);
170 
171     /**
172      * This method determines whether filtering is enabled for an entry associated with an index.
173      *
174      * @param[in] aIndex               Index of entry to be checked.
175      *
176      * @returns TRUE if the filter is enabled for the given entry, FALSE otherwise.
177      *
178      */
IsEntryFiltered(uint8_t aIndex) const179     bool IsEntryFiltered(uint8_t aIndex) const { return IsBitSet(mFilterSet, aIndex); }
180 
181     /**
182      * This method determines whether filtering is enabled for a given property key.
183      *
184      * @param[in] aPropKey             The property key to check.
185      *
186      * @returns TRUE if the filter is enabled for the given property, FALSE if the property is not filtered or if
187      *          it is not filterable.
188      *
189      */
190     bool IsPropertyFiltered(spinel_prop_key_t aPropKey) const;
191 
192     /**
193      * This method clears the filter.
194      *
195      */
ClearFilter(void)196     void ClearFilter(void) { mFilterSet = 0; }
197 
198 private:
199     uint8_t GetNumEntries(void) const;
200     void    Add(spinel_prop_key_t aPropKey, spinel_status_t aStatus);
201 
SetBit(uint64_t & aBitset,uint8_t aBitIndex)202     static void SetBit(uint64_t &aBitset, uint8_t aBitIndex) { aBitset |= (1ULL << aBitIndex); }
ClearBit(uint64_t & aBitset,uint8_t aBitIndex)203     static void ClearBit(uint64_t &aBitset, uint8_t aBitIndex) { aBitset &= ~(1ULL << aBitIndex); }
IsBitSet(uint64_t aBitset,uint8_t aBitIndex)204     static bool IsBitSet(uint64_t aBitset, uint8_t aBitIndex) { return (aBitset & (1ULL << aBitIndex)) != 0; }
205 
206     static const Entry mSupportedProps[];
207 
208     uint64_t mChangedSet;
209     uint64_t mFilterSet;
210 };
211 
212 } // namespace Ncp
213 } // namespace ot
214 
215 #endif // CHANGED_PROPS_SET_HPP
216