1 /*
2  *  Copyright (c) 2024, 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 contains definitions for the RCP capability diagnostics module.
32  */
33 
34 #ifndef OT_POSIX_PLATFORM_RCP_CAPS_DIAG_HPP_
35 #define OT_POSIX_PLATFORM_RCP_CAPS_DIAG_HPP_
36 
37 #include "platform-posix.h"
38 
39 #if OPENTHREAD_POSIX_CONFIG_RCP_CAPS_DIAG_ENABLE
40 #include <openthread/platform/diag.h>
41 
42 #include "lib/spinel/radio_spinel.hpp"
43 #include "lib/spinel/spinel.h"
44 
45 #if !OPENTHREAD_CONFIG_DIAG_ENABLE
46 #error "OPENTHREAD_CONFIG_DIAG_ENABLE is required for OPENTHREAD_POSIX_CONFIG_RCP_CAPS_DIAG_ENABLE"
47 #endif
48 
49 namespace ot {
50 namespace Posix {
51 
52 class RcpCapsDiag
53 {
54 public:
55     /**
56      * Constructor initializes the object.
57      *
58      * @param[in]  aRadioSpinel  A reference to the Spinel::RadioSpinel instance.
59      */
RcpCapsDiag(Spinel::RadioSpinel & aRadioSpinel)60     explicit RcpCapsDiag(Spinel::RadioSpinel &aRadioSpinel)
61         : mRadioSpinel(aRadioSpinel)
62         , mOutputCallback(nullptr)
63         , mOutputContext(nullptr)
64         , mDiagOutput(nullptr)
65         , mDiagOutputLength(0)
66     {
67     }
68 
69     /**
70      * Processes RCP capability diagnostics commands.
71      *
72      * @param[in]   aArgs           The arguments of diagnostics command line.
73      * @param[in]   aArgsLength     The number of arguments in @p aArgs.
74      *
75      * @retval  OT_ERROR_INVALID_ARGS       The command is supported but invalid arguments provided.
76      * @retval  OT_ERROR_NONE               The command is successfully processed.
77      * @retval  OT_ERROR_INVALID_COMMAND    The command is not valid or not supported.
78      */
79     otError DiagProcess(char *aArgs[], uint8_t aArgsLength);
80 
81     /**
82      * Sets the diag output callback.
83      *
84      * @param[in]  aCallback   A pointer to a function that is called on outputting diag messages.
85      * @param[in]  aContext    A user context pointer.
86      */
87     void SetDiagOutputCallback(otPlatDiagOutputCallback aCallback, void *aContext);
88 
89 private:
90     template <uint32_t aCommand, spinel_prop_key_t aKey> otError HandleSpinelCommand(void);
91     typedef otError (RcpCapsDiag::*SpinelCommandHandler)(void);
92 
93     enum Category : uint8_t
94     {
95         kCategoryBasic,
96         kCategoryThread1_1,
97         kCategoryThread1_2,
98         kCategoryUtils,
99         kNumCategories,
100     };
101 
102     struct SpinelEntry
103     {
104         Category                          mCategory;
105         uint32_t                          mCommand;
106         spinel_prop_key_t                 mKey;
107         RcpCapsDiag::SpinelCommandHandler mHandler;
108     };
109 
110     static constexpr uint16_t kMaxNumChildren = 512;
111 
112     void ProcessSpinel(void);
113     void ProcessSpinelSpeed(void);
114     void ProcessCapabilityFlags(void);
115     void ProcessSrcMatchTable(void);
116     void TestSpinelCommands(Category aCategory);
117     void TestRadioCapbilityFlags(void);
118     void OutputRadioCapFlags(Category aCategory, uint32_t aRadioCaps, const uint32_t *aFlags, uint16_t aNumbFlags);
119     void TestSpinelCapbilityFlags(void);
120     void OutputSpinelCapFlags(Category        aCategory,
121                               const uint8_t  *aCapsData,
122                               spinel_size_t   aCapsLength,
123                               const uint32_t *aFlags,
124                               uint16_t        aNumbFlags);
125     bool IsSpinelCapabilitySupported(const uint8_t *aCapsData, spinel_size_t aCapsLength, uint32_t aCapability);
126     void OutputExtendedSrcMatchTableSize(void);
127     void OutputShortSrcMatchTableSize(void);
128 
129     static void HandleDiagOutput(const char *aFormat, va_list aArguments, void *aContext);
130     void        HandleDiagOutput(const char *aFormat, va_list aArguments);
131 
132     void OutputFormat(const char *aName, const char *aValue);
133     void OutputFormat(const char *aName, uint32_t aValue);
134     void OutputResult(const SpinelEntry &aEntry, otError error);
135     void Output(const char *aFormat, ...);
136 
137     static const char *SupportToString(bool aSupport);
138     static const char *RadioCapbilityToString(uint32_t aCapability);
139     static const char *CategoryToString(Category aCategory);
140 
141     static const struct SpinelEntry sSpinelEntries[];
142 
143     Spinel::RadioSpinel     &mRadioSpinel;
144     otPlatDiagOutputCallback mOutputCallback;
145     void                    *mOutputContext;
146     char                    *mDiagOutput;
147     uint16_t                 mDiagOutputLength;
148 };
149 
150 } // namespace Posix
151 } // namespace ot
152 #endif // OPENTHREAD_POSIX_CONFIG_RCP_CAPS_DIAG_ENABLE
153 #endif // OT_POSIX_PLATFORM_RCP_CAPS_DIAG_HPP_
154