• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2022, 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 strain 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 #include "cli.hpp"
30 
31 #include <assert.h>
32 #include <errno.h>
33 #include <getopt.h>
34 #include <stdbool.h>
35 #include <stdint.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 
41 #include "power.hpp"
42 #include "common/code_utils.hpp"
43 
44 namespace ot {
45 namespace Fct {
46 
47 const struct Cli::Command Cli::sCommands[] = {
48     {"powercalibrationtable", &Cli::ProcessCalibrationTable},
49     {"targetpowertable", &Cli::ProcessTargetPowerTable},
50     {"regiondomaintable", &Cli::ProcessRegionDomainTable},
51 };
52 
GetNextTargetPower(const Power::Domain & aDomain,int & aIterator,Power::TargetPower & aTargetPower)53 otError Cli::GetNextTargetPower(const Power::Domain &aDomain, int &aIterator, Power::TargetPower &aTargetPower)
54 {
55     otError error = OT_ERROR_NOT_FOUND;
56     char    value[kMaxValueSize];
57     char   *domain;
58     char   *psave;
59 
60     while (mProductConfigFile.Get(kKeyTargetPower, aIterator, value, sizeof(value)) == OT_ERROR_NONE)
61     {
62         if (((domain = strtok_r(value, kCommaDelimiter, &psave)) == nullptr) || (aDomain != domain))
63         {
64             continue;
65         }
66 
67         error = aTargetPower.FromString(psave);
68         break;
69     }
70 
71     return error;
72 }
73 
GetNextDomain(int & aIterator,Power::Domain & aDomain)74 otError Cli::GetNextDomain(int &aIterator, Power::Domain &aDomain)
75 {
76     otError error = OT_ERROR_NOT_FOUND;
77     char    value[kMaxValueSize];
78     char   *str;
79 
80     while (mProductConfigFile.Get(kKeyRegionDomainMapping, aIterator, value, sizeof(value)) == OT_ERROR_NONE)
81     {
82         if ((str = strtok(value, kCommaDelimiter)) == nullptr)
83         {
84             continue;
85         }
86 
87         error = aDomain.Set(str);
88         break;
89     }
90 
91     return error;
92 }
93 
ProcessTargetPowerTable(Utils::CmdLineParser::Arg aArgs[])94 otError Cli::ProcessTargetPowerTable(Utils::CmdLineParser::Arg aArgs[])
95 {
96     otError       error    = OT_ERROR_NONE;
97     int           iterator = 0;
98     Power::Domain domain;
99 
100     VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
101 
102     printf("|  Domain  | ChStart |  ChEnd  | TargetPower(0.01dBm) |\r\n");
103     printf("+----------+---------+---------+----------------------+\r\n");
104     while (GetNextDomain(iterator, domain) == OT_ERROR_NONE)
105     {
106         int                iter = 0;
107         Power::TargetPower targetPower;
108 
109         while (GetNextTargetPower(domain, iter, targetPower) == OT_ERROR_NONE)
110         {
111             printf("| %-8s | %-7d | %-7d | %-20d |\r\n", domain.AsCString(), targetPower.GetChannelStart(),
112                    targetPower.GetChannelEnd(), targetPower.GetTargetPower());
113         }
114     }
115 
116 exit:
117     return error;
118 }
119 
ProcessRegionDomainTable(Utils::CmdLineParser::Arg aArgs[])120 otError Cli::ProcessRegionDomainTable(Utils::CmdLineParser::Arg aArgs[])
121 {
122     otError error    = OT_ERROR_NONE;
123     int     iterator = 0;
124     char    value[kMaxValueSize];
125 
126     VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
127 
128     while (mProductConfigFile.Get(kKeyRegionDomainMapping, iterator, value, sizeof(value)) == OT_ERROR_NONE)
129     {
130         printf("%s\r\n", value);
131     }
132 
133 exit:
134     return error;
135 }
136 
ParseNextCalibratedPower(char * aCalibratedPowerString,uint16_t aLength,uint16_t & aIterator,Power::CalibratedPower & aCalibratedPower)137 otError Cli::ParseNextCalibratedPower(char                   *aCalibratedPowerString,
138                                       uint16_t                aLength,
139                                       uint16_t               &aIterator,
140                                       Power::CalibratedPower &aCalibratedPower)
141 {
142     otError                    error = OT_ERROR_NONE;
143     char                      *start = aCalibratedPowerString + aIterator;
144     char                      *end;
145     char                      *subString;
146     int16_t                    actualPower;
147     ot::Power::RawPowerSetting rawPowerSetting;
148 
149     VerifyOrExit(aIterator < aLength, error = OT_ERROR_PARSE);
150 
151     end = strstr(start, "/");
152     if (end != nullptr)
153     {
154         aIterator = end - aCalibratedPowerString + 1; // +1 to skip '/'
155         *end      = '\0';
156     }
157     else
158     {
159         aIterator = aLength;
160         end       = aCalibratedPowerString + aLength;
161     }
162 
163     subString = strstr(start, kCommaDelimiter);
164     VerifyOrExit(subString != nullptr, error = OT_ERROR_PARSE);
165     *subString = '\0';
166     subString++;
167 
168     SuccessOrExit(error = Utils::CmdLineParser::ParseAsInt16(start, actualPower));
169     aCalibratedPower.SetActualPower(actualPower);
170 
171     VerifyOrExit(subString < end, error = OT_ERROR_PARSE);
172     SuccessOrExit(error = rawPowerSetting.Set(subString));
173     aCalibratedPower.SetRawPowerSetting(rawPowerSetting);
174 
175 exit:
176     return error;
177 }
178 
ProcessCalibrationTable(Utils::CmdLineParser::Arg aArgs[])179 otError Cli::ProcessCalibrationTable(Utils::CmdLineParser::Arg aArgs[])
180 {
181     otError error = OT_ERROR_NONE;
182 
183     if (aArgs[0].IsEmpty())
184     {
185         int  iterator = 0;
186         char value[kMaxValueSize];
187 
188         ot::Power::CalibratedPower calibratedPower;
189 
190         printf("| ChStart |  ChEnd  | ActualPower(0.01dBm) | RawPowerSetting |\r\n");
191         printf("+---------+---------+----------------------+-----------------+\r\n");
192 
193         while (mFactoryConfigFile.Get(kKeyCalibratedPower, iterator, value, sizeof(value)) == OT_ERROR_NONE)
194         {
195             SuccessOrExit(error = calibratedPower.FromString(value));
196             printf("| %-7d | %-7d | %-20d | %-15s |\r\n", calibratedPower.GetChannelStart(),
197                    calibratedPower.GetChannelEnd(), calibratedPower.GetActualPower(),
198                    calibratedPower.GetRawPowerSetting().ToString().AsCString());
199         }
200     }
201     else if (aArgs[0] == "add")
202     {
203         constexpr uint16_t kStateSearchDomain = 0;
204         constexpr uint16_t kStateSearchPower  = 1;
205 
206         uint8_t                state = kStateSearchDomain;
207         char                  *subString;
208         uint8_t                channel;
209         Power::CalibratedPower calibratedPower;
210 
211         for (Utils::CmdLineParser::Arg *arg = &aArgs[1]; !arg->IsEmpty(); arg++)
212         {
213             if ((state == kStateSearchDomain) && (*arg == "-b"))
214             {
215                 arg++;
216                 VerifyOrExit(!arg->IsEmpty(), error = OT_ERROR_INVALID_ARGS);
217 
218                 subString = strtok(arg->GetCString(), kCommaDelimiter);
219                 VerifyOrExit(subString != nullptr, error = OT_ERROR_PARSE);
220                 SuccessOrExit(error = Utils::CmdLineParser::ParseAsUint8(subString, channel));
221                 calibratedPower.SetChannelStart(channel);
222 
223                 subString = strtok(NULL, kCommaDelimiter);
224                 VerifyOrExit(subString != nullptr, error = OT_ERROR_PARSE);
225                 SuccessOrExit(error = Utils::CmdLineParser::ParseAsUint8(subString, channel));
226                 calibratedPower.SetChannelEnd(channel);
227                 VerifyOrExit(calibratedPower.GetChannelStart() <= calibratedPower.GetChannelEnd(),
228                              error = OT_ERROR_INVALID_ARGS);
229 
230                 state = kStateSearchPower;
231             }
232             else if ((state == kStateSearchPower) && (*arg == "-c"))
233             {
234                 uint16_t length;
235                 uint16_t iterator = 0;
236 
237                 arg++;
238                 VerifyOrExit(!arg->IsEmpty(), error = OT_ERROR_INVALID_ARGS);
239 
240                 length = strlen(arg->GetCString());
241                 while (ParseNextCalibratedPower(arg->GetCString(), length, iterator, calibratedPower) == OT_ERROR_NONE)
242                 {
243                     SuccessOrExit(
244                         error = mFactoryConfigFile.Add(kKeyCalibratedPower, calibratedPower.ToString().AsCString()));
245                 }
246 
247                 state = kStateSearchDomain;
248             }
249             else
250             {
251                 error = OT_ERROR_INVALID_ARGS;
252                 break;
253             }
254         }
255 
256         if (state == kStateSearchPower)
257         {
258             error = OT_ERROR_INVALID_ARGS;
259         }
260     }
261     else if (aArgs[0] == "clear")
262     {
263         error = mFactoryConfigFile.Clear(kKeyCalibratedPower);
264     }
265     else
266     {
267         error = OT_ERROR_INVALID_ARGS;
268     }
269 
270 exit:
271     return error;
272 }
273 
ProcessCommand(Utils::CmdLineParser::Arg aArgs[])274 void Cli::ProcessCommand(Utils::CmdLineParser::Arg aArgs[])
275 {
276     otError error = OT_ERROR_NOT_FOUND;
277     size_t  i;
278 
279     for (i = 0; i < (sizeof(sCommands) / sizeof(sCommands[0])); i++)
280     {
281         if (strcmp(aArgs[0].GetCString(), sCommands[i].mName) == 0)
282         {
283             error = (this->*sCommands[i].mCommand)(aArgs + 1);
284             break;
285         }
286     }
287 
288     AppendErrorResult(error);
289 }
290 
ProcessLine(char * aLine)291 void Cli::ProcessLine(char *aLine)
292 {
293     const int                 kMaxArgs = 20;
294     Utils::CmdLineParser::Arg args[kMaxArgs + 1];
295 
296     SuccessOrExit(ot::Utils::CmdLineParser::ParseCmd(aLine, args, kMaxArgs));
297     VerifyOrExit(!args[0].IsEmpty());
298 
299     ProcessCommand(args);
300 
301 exit:
302     OutputPrompt();
303 }
304 
OutputPrompt(void)305 void Cli::OutputPrompt(void)
306 {
307     printf("> ");
308     fflush(stdout);
309 }
310 
AppendErrorResult(otError aError)311 void Cli::AppendErrorResult(otError aError)
312 {
313     if (aError != OT_ERROR_NONE)
314     {
315         printf("failed\r\nstatus %#x\r\n", aError);
316     }
317     else
318     {
319         printf("Done\r\n");
320     }
321 
322     fflush(stdout);
323 }
324 } // namespace Fct
325 } // namespace ot
326