1 /*
2  *  Copyright (c) 2020-22, 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 generating and processing Link Metrics TLVs.
32  *
33  */
34 
35 #ifndef LINK_METRICS_TYPES_HPP_
36 #define LINK_METRICS_TYPES_HPP_
37 
38 #include "openthread-core-config.h"
39 
40 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
41 
42 #include <openthread/link_metrics.h>
43 
44 #include "common/as_core_type.hpp"
45 #include "common/clearable.hpp"
46 #include "common/encoding.hpp"
47 #include "common/message.hpp"
48 
49 namespace ot {
50 namespace LinkMetrics {
51 
52 constexpr uint8_t kMaxTypeIds = 4; ///< Maximum number of Type IDs in a `Metrics`.
53 
54 /**
55  * Represents Link Metric Flags indicating a set of metrics.
56  *
57  * @sa otLinkMetrics
58  *
59  */
60 class Metrics : public otLinkMetrics, public Clearable<Metrics>
61 {
62 public:
63     /**
64      * Converts the `Metrics` into an array of Type IDs.
65      *
66      * @param[out] aTypeIds   The array of Type IDs to populate. MUST have at least `kMaxTypeIds` elements.
67      *
68      * @returns Number of entries added in the array @p aTypeIds.
69      *
70      */
71     uint8_t ConvertToTypeIds(uint8_t aTypeIds[]) const;
72 };
73 
74 /**
75  * Represents the results (values) for a set of metrics.
76  *
77  * @sa otLinkMetricsValues
78  *
79  */
80 class MetricsValues : public otLinkMetricsValues, public Clearable<MetricsValues>
81 {
82 public:
83     /**
84      * Gets the metrics flags.
85      *
86      * @returns The metrics flags.
87      *
88      */
GetMetrics(void)89     Metrics &GetMetrics(void) { return static_cast<Metrics &>(mMetrics); }
90 
91     /**
92      * Gets the metrics flags.
93      *
94      * @returns The metrics flags.
95      *
96      */
GetMetrics(void) const97     const Metrics &GetMetrics(void) const { return static_cast<const Metrics &>(mMetrics); }
98 
99     /**
100      * Set the metrics flags.
101      *
102      * @param[in] aMetrics  The metrics flags to set from.
103      *
104      */
SetMetrics(const Metrics & aMetrics)105     void SetMetrics(const Metrics &aMetrics) { mMetrics = aMetrics; }
106 };
107 
108 class TypeId
109 {
110     // Type ID Flags
111     //
112     //   7   6   5   4   3   2   1   0
113     // +---+---+---+---+---+---+---+---+
114     // | E | L |   Type    |   Metric  |
115     // +---+---+---+---+---+---+---+---+
116     //
117 
118     static constexpr uint8_t kExtendedFlag = 1 << 7;
119     static constexpr uint8_t kLengthFlag   = 1 << 6;
120     static constexpr uint8_t kTypeOffset   = 3;
121     static constexpr uint8_t kMetricOffset = 0;
122     static constexpr uint8_t kTypeMask     = (7 << kTypeOffset);
123 
124     static constexpr uint8_t kTypeCount    = (0 << kTypeOffset); // Count/summation
125     static constexpr uint8_t kTypeAve      = (1 << kTypeOffset); // Exponential Moving average
126     static constexpr uint8_t kTypeReserved = (2 << kTypeOffset); // Reserved
127 
128     static constexpr uint8_t kMetricPdu        = (0 << kMetricOffset); // Number of PDUs received.
129     static constexpr uint8_t kMetricLqi        = (1 << kMetricOffset);
130     static constexpr uint8_t kMetricLinkMargin = (2 << kMetricOffset);
131     static constexpr uint8_t kMetricRssi       = (3 << kMetricOffset);
132 
133 public:
134     static constexpr uint8_t kPdu        = (kMetricPdu | kTypeCount | kLengthFlag); ///< Type ID for num PDU received.
135     static constexpr uint8_t kLqi        = (kMetricLqi | kTypeAve);                 ///< Type ID for LQI.
136     static constexpr uint8_t kLinkMargin = (kMetricLinkMargin | kTypeAve);          ///< Type ID for Link Margin.
137     static constexpr uint8_t kRssi       = (kMetricRssi | kTypeAve);                ///< Type ID for RSSI.
138 
139     /**
140      * Indicates whether or not a given Type ID is extended.
141      *
142      * Extended Type IDs are reserved for future use. When set an additional second byte follows the current ID flags.
143      *
144      * @param[in] aTypeId   The Type ID to check.
145      *
146      * @retval TRUE  The @p aTypeId is extended.
147      * @retval FALSE The @p aTypeId is not extended.
148      *
149      */
IsExtended(uint8_t aTypeId)150     static bool IsExtended(uint8_t aTypeId) { return (aTypeId & kExtendedFlag); }
151 
152     /**
153      * Determines the value length (number of bytes) associated with a given Type ID.
154      *
155      * Type IDs can either have a short value as a `uint8_t` (e.g., `kLqi`, `kLinkMargin` or `kRssi`) or a long value as
156      * a `uint32_t` (`kPdu`).
157      *
158      * @param[in] aTypeId   The Type ID.
159      *
160      * @returns the associated value length of @p aTypeId.
161      *
162      */
GetValueLength(uint8_t aTypeId)163     static uint8_t GetValueLength(uint8_t aTypeId)
164     {
165         return (aTypeId & kLengthFlag) ? sizeof(uint32_t) : sizeof(uint8_t);
166     }
167 
168     /**
169      * Updates a Type ID to mark it as reversed.
170      *
171      * This is used for testing only.
172      *
173      * @param[in, out] aTypeId    A reference to a Type ID variable to update.
174      *
175      */
MarkAsReserved(uint8_t & aTypeId)176     static void MarkAsReserved(uint8_t &aTypeId) { aTypeId = (aTypeId & ~kTypeMask) | kTypeReserved; }
177 
178     TypeId(void) = delete;
179 };
180 
181 /**
182  * Represents the Series Flags for Forward Tracking Series.
183  *
184  */
185 class SeriesFlags : public otLinkMetricsSeriesFlags
186 {
187 public:
188     /**
189      * Converts the `SeriesFlags` to `uint8_t` bit-mask (for inclusion in TLVs).
190      *
191      * @returns The bit-mask representation.
192      *
193      */
194     uint8_t ConvertToMask(void) const;
195 
196     /**
197      * Sets the `SeriesFlags` from a given bit-mask value.
198      *
199      * @param[in] aFlagsMask  The bit-mask flags.
200      *
201      */
202     void SetFrom(uint8_t aFlagsMask);
203 
204     /**
205      * Indicates whether or not the Link Probe flag is set.
206      *
207      * @retval true   The Link Probe flag is set.
208      * @retval false  The Link Probe flag is not set.
209      *
210      */
IsLinkProbeFlagSet(void) const211     bool IsLinkProbeFlagSet(void) const { return mLinkProbe; }
212 
213     /**
214      * Indicates whether or not the MAC Data flag is set.
215      *
216      * @retval true   The MAC Data flag is set.
217      * @retval false  The MAC Data flag is not set.
218      *
219      */
IsMacDataFlagSet(void) const220     bool IsMacDataFlagSet(void) const { return mMacData; }
221 
222     /**
223      * Indicates whether or not the MAC Data Request flag is set.
224      *
225      * @retval true   The MAC Data Request flag is set.
226      * @retval false  The MAC Data Request flag is not set.
227      *
228      */
IsMacDataRequestFlagSet(void) const229     bool IsMacDataRequestFlagSet(void) const { return mMacDataRequest; }
230 
231     /**
232      * Indicates whether or not the Mac Ack flag is set.
233      *
234      * @retval true   The Mac Ack flag is set.
235      * @retval false  The Mac Ack flag is not set.
236      *
237      */
IsMacAckFlagSet(void) const238     bool IsMacAckFlagSet(void) const { return mMacAck; }
239 
240 private:
241     static constexpr uint8_t kLinkProbeFlag      = 1 << 0;
242     static constexpr uint8_t kMacDataFlag        = 1 << 1;
243     static constexpr uint8_t kMacDataRequestFlag = 1 << 2;
244     static constexpr uint8_t kMacAckFlag         = 1 << 3;
245 };
246 
247 /**
248  * Type represent Enhanced-ACK Flags.
249  *
250  */
251 enum EnhAckFlags : uint8_t
252 {
253     kEnhAckClear    = OT_LINK_METRICS_ENH_ACK_CLEAR,    ///< Clear.
254     kEnhAckRegister = OT_LINK_METRICS_ENH_ACK_REGISTER, ///< Register.
255 };
256 
257 /**
258  * Represents one Series that is being tracked by the Subject.
259  *
260  * When an Initiator successfully configured a Forward Tracking Series, the Subject would use an instance of this class
261  * to track the information of the Series. The Subject has a `Pool` of `SeriesInfo`. It would allocate one when a new
262  * Series comes, and free it when a Series finishes.
263  *
264  * Inherits `LinkedListEntry` and each `Neighbor` has a list of `SeriesInfo` so that the Subject could track
265  * per Series initiated by neighbors as long as it has available resources.
266  *
267  */
268 class SeriesInfo : public LinkedListEntry<SeriesInfo>
269 {
270     friend class LinkedList<SeriesInfo>;
271     friend class LinkedListEntry<SeriesInfo>;
272 
273 public:
274     /**
275      * This constant represents Link Probe when filtering frames to be accounted using Series Flag. There's
276      * already `Mac::Frame::kTypeData`, `Mac::Frame::kTypeAck` and `Mac::Frame::kTypeMacCmd`. This item is
277      * added so that we can filter a Link Probe for series in the same way as other frames.
278      *
279      */
280     static constexpr uint8_t kSeriesTypeLinkProbe = 0;
281 
282     /**
283      * Initializes the SeriesInfo object.
284      *
285      * @param[in]  aSeriesId          The Series ID.
286      * @param[in]  aSeriesFlagsMask   The Series Flags bitmask which specify what types of frames are to be accounted.
287      * @param[in]  aMetrics           Metrics to query.
288      *
289      */
290     void Init(uint8_t aSeriesId, uint8_t aSeriesFlagsMask, const Metrics &aMetrics);
291 
292     /**
293      * Gets the Series ID.
294      *
295      * @returns  The Series ID.
296      *
297      */
GetSeriesId(void) const298     uint8_t GetSeriesId(void) const { return mSeriesId; }
299 
300     /**
301      * Gets the PDU count.
302      *
303      * @returns  The PDU count.
304      *
305      */
GetPduCount(void) const306     uint32_t GetPduCount(void) const { return mPduCount; }
307 
308     /**
309      * Gets the average LQI.
310      *
311      * @returns  The average LQI.
312      *
313      */
GetAverageLqi(void) const314     uint8_t GetAverageLqi(void) const { return mLqiAverager.GetAverage(); }
315 
316     /**
317      * Gets the average RSS.
318      *
319      * @returns  The average RSS.
320      *
321      */
GetAverageRss(void) const322     int8_t GetAverageRss(void) const { return mRssAverager.GetAverage(); }
323 
324     /**
325      * Aggregates the Link Metrics data of a frame into this series.
326      *
327      * @param[in]  aFrameType    The type of the frame.
328      * @param[in]  aLqi          The LQI value.
329      * @param[in]  aRss          The RSS value.
330      *
331      */
332     void AggregateLinkMetrics(uint8_t aFrameType, uint8_t aLqi, int8_t aRss);
333 
334     /**
335      * Gets the metrics.
336      *
337      * @returns  The metrics associated with `SeriesInfo`.
338      *
339      */
GetLinkMetrics(void) const340     const Metrics &GetLinkMetrics(void) const { return mMetrics; }
341 
342 private:
Matches(const uint8_t & aSeriesId) const343     bool Matches(const uint8_t &aSeriesId) const { return mSeriesId == aSeriesId; }
344     bool IsFrameTypeMatch(uint8_t aFrameType) const;
345 
346     SeriesInfo *mNext;
347     uint8_t     mSeriesId;
348     SeriesFlags mSeriesFlags;
349     Metrics     mMetrics;
350     RssAverager mRssAverager;
351     LqiAverager mLqiAverager;
352     uint32_t    mPduCount;
353 };
354 
355 /**
356  * Type represents Link Metrics Status.
357  *
358  */
359 enum Status : uint8_t
360 {
361     kStatusSuccess                   = OT_LINK_METRICS_STATUS_SUCCESS,
362     kStatusCannotSupportNewSeries    = OT_LINK_METRICS_STATUS_CANNOT_SUPPORT_NEW_SERIES,
363     kStatusSeriesIdAlreadyRegistered = OT_LINK_METRICS_STATUS_SERIESID_ALREADY_REGISTERED,
364     kStatusSeriesIdNotRecognized     = OT_LINK_METRICS_STATUS_SERIESID_NOT_RECOGNIZED,
365     kStatusNoMatchingFramesReceived  = OT_LINK_METRICS_STATUS_NO_MATCHING_FRAMES_RECEIVED,
366     kStatusOtherError                = OT_LINK_METRICS_STATUS_OTHER_ERROR,
367 };
368 
369 } // namespace LinkMetrics
370 
371 DefineCoreType(otLinkMetrics, LinkMetrics::Metrics);
372 DefineCoreType(otLinkMetricsValues, LinkMetrics::MetricsValues);
373 DefineCoreType(otLinkMetricsSeriesFlags, LinkMetrics::SeriesFlags);
374 DefineMapEnum(otLinkMetricsEnhAckFlags, LinkMetrics::EnhAckFlags);
375 DefineMapEnum(otLinkMetricsStatus, LinkMetrics::Status);
376 
377 } // namespace ot
378 
379 #endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
380 
381 #endif // LINK_METRICS_TYPES_HPP_
382