• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define FAILURE_DEBUG_PREFIX "AtResponse"
18 
19 #include <algorithm>
20 #include <charconv>
21 #include <numeric>
22 #include <string>
23 #include <string_view>
24 
25 #include "atCmds.h"
26 #include "AtResponse.h"
27 #include "Parser.h"
28 #include "debug.h"
29 #include "hexbin.h"
30 
31 namespace aidl {
32 namespace android {
33 namespace hardware {
34 namespace radio {
35 namespace implementation {
36 using namespace std::literals;
37 
38 namespace {
39 constexpr char kCR = '\r';
40 constexpr std::string_view krOKr = "\rOK\r"sv;
41 
42 struct ValueParser {
43     std::string_view cmd;
44     AtResponsePtr (*parse)(std::string_view str);
45     bool multiline;
46 };
47 
48 struct CmdIdVisitor {
operator ()aidl::android::hardware::radio::implementation::__anonc24365290111::CmdIdVisitor49     std::string_view operator()(const AtResponse::OK&) const {
50         return "OK"sv;
51     }
52 
operator ()aidl::android::hardware::radio::implementation::__anonc24365290111::CmdIdVisitor53     std::string_view operator()(const AtResponse::ERROR&) const {
54         return "ERROR"sv;
55     }
56 
operator ()aidl::android::hardware::radio::implementation::__anonc24365290111::CmdIdVisitor57     std::string_view operator()(const AtResponse::RING&) const {
58         return "RING"sv;
59     }
60 
operator ()aidl::android::hardware::radio::implementation::__anonc24365290111::CmdIdVisitor61     std::string_view operator()(const AtResponse::SmsPrompt&) const {
62         return "SmsPrompt"sv;
63     }
64 
operator ()aidl::android::hardware::radio::implementation::__anonc24365290111::CmdIdVisitor65     std::string_view operator()(const AtResponse::ParseError&) const {
66         return "ParseError"sv;
67     }
68 
operator ()aidl::android::hardware::radio::implementation::__anonc24365290111::CmdIdVisitor69     std::string_view operator()(const std::string&) const {
70         return "string"sv;
71     }
72 
operator ()aidl::android::hardware::radio::implementation::__anonc24365290111::CmdIdVisitor73     template <class T> std::string_view operator()(const T&) const {
74         return T::id();
75     }
76 };
77 
ltrim(std::string_view s)78 std::string_view ltrim(std::string_view s) {
79     while (!s.empty()) {
80         if (s.front() <= 0x20) {
81             s.remove_prefix(1);
82         } else {
83             break;
84         }
85     }
86     return s;
87 }
88 
toString(std::string_view s)89 std::string toString(std::string_view s) {
90     return std::string(s.data(), s.size());
91 }
92 
parseCmds(const std::string_view str,const ValueParser * vp,const ValueParser * const vpEnd)93 AtResponse::ParseResult parseCmds(const std::string_view str,
94                                   const ValueParser* vp,
95                                   const ValueParser* const vpEnd) {
96     const std::string_view str1 = str.substr(1);  // skip + or %
97     if (str1.empty()) {
98         return { 0, nullptr };
99     }
100 
101     bool maybeIncomplete = false;
102     for (; vp != vpEnd; ++vp) {
103         const std::string_view& cmd = vp->cmd;
104 
105         if (str1.starts_with(cmd.substr(0, str1.size()))) {
106             size_t skipSize;
107             std::string_view payload;
108 
109             if (str1.size() <= cmd.size()) {
110                 maybeIncomplete = true;
111                 continue;
112             } else if (str1[cmd.size()] == ':') {
113                 skipSize = 1 + cmd.size() + 1; // `+CMD:`
114             } else if (str1[cmd.size()] == '\r') {
115                 skipSize = 1 + cmd.size(); // `+CMD`
116             } else {
117                 continue;
118             }
119 
120             int consumed;
121 
122             if (vp->multiline) {
123                 const size_t payloadEnd = str.find(krOKr, skipSize);
124                 if (payloadEnd != str.npos) {
125                     // keep '+CMD:' and add extra '\r' to keep lines consistent
126                     payload = str.substr(0, payloadEnd + 1);
127                     consumed = payloadEnd + krOKr.size();
128                 } else {
129                     return { 0, nullptr };
130                 }
131             } else {
132                 const size_t payloadEnd = str.find(kCR, skipSize);
133                 if (payloadEnd != str.npos) {
134                     payload = ltrim(str.substr(skipSize, payloadEnd - skipSize));
135                     consumed = payloadEnd + 1;
136                 } else {
137                     return { 0, nullptr };
138                 }
139             }
140 
141             return { consumed, (*vp->parse)(payload) };
142         }
143     }
144 
145     if (maybeIncomplete) {
146         return { 0, nullptr };
147     } else {
148         return { -1, FAILURE(nullptr) };
149     }
150 }
151 }  // namespace
152 
parse(const std::string_view str)153 AtResponse::ParseResult AtResponse::parse(const std::string_view str) {
154 #define CMD(C) AtResponse::C::id(), &AtResponse::C::parse
155     static const ValueParser plusValueParsers[] = {
156         { CMD(CPIN),        false },
157         { CMD(CPINR),       false },
158         { CMD(CRSM),        false },
159         { CMD(CFUN),        false },
160         { CMD(CREG),        false },
161         { CMD(CEREG),       false },
162         { CMD(CGREG),       false },
163         { CMD(CTEC),        false },
164         { CMD(COPS),        true },
165         { CMD(WRMP),        false },
166         { CMD(CCSS),        false },
167         { CMD(CSQ),         false },
168         { CMD(CLCC),        true },
169         { CMD(CCFCU),       true },
170         { CMD(CCWA),        false },
171         { CMD(CUSATD),      false },
172         { CMD(CUSATP),      false },
173         { CMD(CUSATE),      false },
174         { CMD(CUSATT),      false },
175         { CMD(CUSATEND),    false },
176         { CMD(CGDCONT),     true },
177         { CMD(CGCONTRDP),   false },
178         { CMD(CLCK),        false },
179         { CMD(CSIM),        false },
180         { CMD(CGLA),        false },
181         { CMD(CCHC),        false },
182         { CMD(CLIP),        false },
183         { CMD(CLIR),        false },
184         { CMD(CMUT),        false },
185         { CMD(WSOS),        false },
186         { CMD(CSCA),        false },
187         { CMD(CSCB),        false },
188         { CMD(CMGS),        false },
189         { CMD(CMGW),        false },
190         { CMD(CmeError),    false },
191         { CMD(CmsError),    false },
192     };
193 
194     static const ValueParser percentValueParsers[] = {
195         { CMD(CTZV),     false },
196         { CMD(CGFPCCFG), false },
197     };
198 
199     static const ValueParser caretValueParsers[] = {
200         { CMD(MBAU),     false },
201     };
202 #undef CMD
203 
204     static constexpr std::string_view kRING = "RING\r"sv;
205     if (str.starts_with(kRING)) {
206         return { int(kRING.size()), AtResponse::make(RING()) };
207     }
208 
209     static constexpr std::string_view kCMT = "+CMT:"sv;
210     if (str.starts_with(kCMT)) {
211         const std::string_view trimmed = ltrim(str.substr(kCMT.size()));
212         const auto [consumed, response] = AtResponse::CMT::parse(trimmed);
213         if (consumed > 0) {
214             return { int(consumed + str.size() - trimmed.size()), std::move(response) };
215         } else {
216             return { consumed, nullptr };
217         }
218     }
219 
220     static constexpr std::string_view kCDS = "+CDS:"sv;
221     if (str.starts_with(kCDS)) {
222         const std::string_view trimmed = ltrim(str.substr(kCDS.size()));
223         const auto [consumed, response] = AtResponse::CDS::parse(trimmed);
224         if (consumed > 0) {
225             return { int(consumed + str.size() - trimmed.size()), std::move(response) };
226         } else {
227             return { consumed, nullptr };
228         }
229     }
230 
231     switch (str.front()) {
232     case '+': return parseCmds(str,
233                                std::begin(plusValueParsers),
234                                std::end(plusValueParsers));
235 
236     case '%': return parseCmds(str,
237                                std::begin(percentValueParsers),
238                                std::end(percentValueParsers));
239     case '^': return parseCmds(str,
240                                std::begin(caretValueParsers),
241                                std::end(caretValueParsers));
242     }
243 
244     static constexpr std::string_view kSmsPrompt = "> \r"sv;
245     if (str.starts_with(kSmsPrompt)) {
246         return { int(kSmsPrompt.size()), AtResponse::make(SmsPrompt()) };
247     }
248 
249     static constexpr std::string_view kOKr = "OK\r"sv;
250     if (str.starts_with(kOKr)) {
251         return { int(kOKr.size()), AtResponse::make(OK()) };
252     }
253 
254     static constexpr std::string_view kERRORr = "ERROR\r"sv;
255     if (str.starts_with(kERRORr)) {
256         return { int(kERRORr.size()), AtResponse::make(ERROR()) };
257     }
258 
259     const size_t pos = str.find(krOKr);
260     if (pos != str.npos) {
261         std::string value(str.begin(), str.begin() + pos);
262         return { int(pos + krOKr.size()), make(std::move(value)) };
263     }
264 
265     return { 0, nullptr };
266 }
267 
268 #undef FAILURE_DEBUG_PREFIX
269 #define FAILURE_DEBUG_PREFIX "CmeError"
parse(const std::string_view str)270 AtResponsePtr AtResponse::CmeError::parse(const std::string_view str) {
271     RadioError err;
272 
273     if (str.compare(atCmds::kCmeErrorOperationNotAllowed) == 0) {
274         err = RadioError::OPERATION_NOT_ALLOWED;
275     } else if (str.compare(atCmds::kCmeErrorOperationNotSupported) == 0) {
276         err = RadioError::REQUEST_NOT_SUPPORTED;
277     } else if (str.compare(atCmds::kCmeErrorSimNotInserted) == 0) {
278         err = RadioError::SIM_ABSENT;
279     } else if (str.compare(atCmds::kCmeErrorSimPinRequired) == 0) {
280         err = RadioError::SIM_PIN2;
281     } else if (str.compare(atCmds::kCmeErrorSimPukRequired) == 0) {
282         err = RadioError::SIM_PUK2;
283     } else if (str.compare(atCmds::kCmeErrorSimBusy) == 0) {
284         err = RadioError::SIM_BUSY;
285     } else if (str.compare(atCmds::kCmeErrorIncorrectPassword) == 0) {
286         err = RadioError::PASSWORD_INCORRECT;
287     } else if (str.compare(atCmds::kCmeErrorMemoryFull) == 0) {
288         err = RadioError::SIM_FULL;
289     } else if (str.compare(atCmds::kCmeErrorInvalidIndex) == 0) {
290         err = RadioError::INVALID_ARGUMENTS;
291     } else if (str.compare(atCmds::kCmeErrorNotFound) == 0) {
292         err = RadioError::NO_SUCH_ELEMENT;
293     } else if (str.compare(atCmds::kCmeErrorInvalidCharactersInTextString) == 0) {
294         err = RadioError::GENERIC_FAILURE;
295     } else if (str.compare(atCmds::kCmeErrorNoNetworkService) == 0) {
296         err = RadioError::NO_NETWORK_FOUND;
297     } else if (str.compare(atCmds::kCmeErrorNetworkNotAllowedEmergencyCallsOnly) == 0) {
298         err = RadioError::NETWORK_REJECT;
299     } else if (str.compare(atCmds::kCmeErrorInCorrectParameters) == 0) {
300         err = RadioError::INVALID_ARGUMENTS;
301     } else if (str.compare(atCmds::kCmeErrorNetworkNotAttachedDueToMTFunctionalRestrictions) == 0) {
302         err = RadioError::NETWORK_REJECT;
303     } else if (str.compare(atCmds::kCmeErrorFixedDialNumberOnlyAllowed) == 0) {
304         err = RadioError::GENERIC_FAILURE;
305     } else {
306         err = RadioError::GENERIC_FAILURE;
307     }
308 
309     CmeError cmeErr = {
310         .error = err,
311     };
312 
313     return make(std::move(cmeErr));
314 }
315 
getErrorAndLog(const char * klass,const char * func,int line) const316 RadioError AtResponse::CmeError::getErrorAndLog(
317         const char* klass, const char* func, int line) const {
318     RLOGE("%s:%s:%d failure: %s", klass, func, line,
319           toString(error).c_str());
320     return error;
321 }
322 
323 #undef FAILURE_DEBUG_PREFIX
324 #define FAILURE_DEBUG_PREFIX "CmsError"
parse(const std::string_view str)325 AtResponsePtr AtResponse::CmsError::parse(const std::string_view str) {
326     CmsError cmsErr = {
327         .message = toString(str),
328     };
329 
330     return make(std::move(cmsErr));
331 }
332 
333 #undef FAILURE_DEBUG_PREFIX
334 #define FAILURE_DEBUG_PREFIX "CPIN"
parse(const std::string_view str)335 AtResponsePtr AtResponse::CPIN::parse(const std::string_view str) {
336     CPIN cpin;
337     if (str == "READY"sv) {
338         cpin.state = CPIN::State::READY;
339     } else if (str == "SIM PIN"sv) {
340         cpin.state = CPIN::State::PIN;
341     } else if (str == "SIM PUK"sv) {
342         cpin.state = CPIN::State::PUK;
343     } else {
344         return FAILURE_V(makeParseErrorFor<CPIN>(),
345                          "Can't parse: '%*.*s'",
346                          int(str.size()), int(str.size()), str.data());
347     }
348 
349     return make(std::move(cpin));
350 }
351 
352 #undef FAILURE_DEBUG_PREFIX
353 #define FAILURE_DEBUG_PREFIX "CPINR"
parse(const std::string_view str)354 AtResponsePtr AtResponse::CPINR::parse(const std::string_view str) {
355     CPINR cpinr;
356 
357     Parser parser(str);
358     std::string_view unused;
359     if (!parser(&unused, ',')
360                (&cpinr.remainingRetryTimes).skip(',')
361                (&cpinr.maxRetryTimes).fullMatch()) {
362         return FAILURE_V(makeParseErrorFor<CPINR>(),
363                          "Can't parse: '%*.*s'",
364                          int(str.size()), int(str.size()), str.data());
365     }
366 
367     return make(std::move(cpinr));
368 }
369 
370 #undef FAILURE_DEBUG_PREFIX
371 #define FAILURE_DEBUG_PREFIX "CRSM"
parse(const std::string_view str)372 AtResponsePtr AtResponse::CRSM::parse(const std::string_view str) {
373     CRSM crsm;
374 
375     Parser parser(str);
376     if (parser(&crsm.sw1).skip(',')(&crsm.sw2).hasMore()) {
377         if (parser.skip(',').matchSoFar()) {
378             crsm.response = toString(parser.remaining());
379         } else {
380             return FAILURE_V(makeParseErrorFor<CRSM>(),
381                              "Can't parse: '%*.*s'",
382                              int(str.size()), int(str.size()), str.data());
383         }
384     } else if (!parser.fullMatch()) {
385         return FAILURE_V(makeParseErrorFor<CRSM>(),
386                          "Can't parse: '%*.*s'",
387                          int(str.size()), int(str.size()), str.data());
388     }
389 
390     return make(std::move(crsm));
391 }
392 
393 #undef FAILURE_DEBUG_PREFIX
394 #define FAILURE_DEBUG_PREFIX "CFUN"
parse(const std::string_view str)395 AtResponsePtr AtResponse::CFUN::parse(const std::string_view str) {
396     using modem::RadioState;
397 
398     int state;
399     Parser parser(str);
400     if (parser(&state).fullMatch()) {
401         CFUN cfun = {
402             .state = state ? RadioState::ON : RadioState::OFF,
403         };
404         return make(std::move(cfun));
405     } else {
406         return FAILURE_V(makeParseErrorFor<CFUN>(),
407                          "Can't parse: '%*.*s'",
408                          int(str.size()), int(str.size()), str.data());
409     }
410 }
411 
412 #undef FAILURE_DEBUG_PREFIX
413 #define FAILURE_DEBUG_PREFIX "CREG"
parse(const std::string_view str)414 AtResponsePtr AtResponse::CREG::parse(const std::string_view str) {
415     CREG creg;
416     Parser parser(str);
417     std::string_view areaCodeHex;
418     std::string_view cellIdHex;
419     int unsolMode;
420     int state;
421 
422     switch (std::count(str.begin(), str.end(), ',')) {
423     case 0:  // state
424         if (parser(&state).fullMatch()) {
425             creg.state = static_cast<network::RegState>(state);
426             return make(std::move(creg));
427         }
428         break;
429 
430     case 1:  // unsolMode,state
431         if (parser(&unsolMode).skip(',')(&state).fullMatch()) {
432             creg.state = static_cast<network::RegState>(state);
433             return make(std::move(creg));
434         }
435         break;
436 
437     case 3:  // state,areaCode,cellId,networkType
438         if (parser(&state).skip(',').skip('"')(&areaCodeHex, '"')
439                   .skip(',').skip('"')(&cellIdHex, '"').skip(',')
440                   (&creg.networkType).fullMatch()) {
441             std::from_chars(areaCodeHex.begin(), areaCodeHex.end(), creg.areaCode, 16);
442             std::from_chars(cellIdHex.begin(), cellIdHex.end(), creg.cellId, 16);
443             creg.state = static_cast<network::RegState>(state);
444             return make(std::move(creg));
445         }
446         break;
447 
448     case 4:  // unsolMode,state,areaCode,cellId,networkType
449         if (parser(&unsolMode).skip(',')
450                   (&state).skip(',')
451                   .skip('"')(&areaCodeHex, '"').skip(',')
452                   .skip('"')(&cellIdHex, '"').skip(',')
453                   (&creg.networkType).fullMatch()) {
454             std::from_chars(areaCodeHex.begin(), areaCodeHex.end(), creg.areaCode, 16);
455             std::from_chars(cellIdHex.begin(), cellIdHex.end(), creg.cellId, 16);
456             creg.state = static_cast<network::RegState>(state);
457             return make(std::move(creg));
458         }
459         break;
460     }
461 
462     return FAILURE_V(makeParseErrorFor<CREG>(),
463                      "Can't parse: '%*.*s'",
464                      int(str.size()), int(str.size()), str.data());
465 }
466 
467 #undef FAILURE_DEBUG_PREFIX
468 #define FAILURE_DEBUG_PREFIX "CGREG"
parse(const std::string_view str)469 AtResponsePtr AtResponse::CGREG::parse(const std::string_view str) {
470     CGREG cgreg;
471     Parser parser(str);
472     std::string_view areaCodeHex;
473     std::string_view cellIdHex;
474     int unsolMode;
475     int state;
476 
477     switch (std::count(str.begin(), str.end(), ',')) {
478     case 0:  // state
479         if (parser(&state).fullMatch()) {
480             cgreg.state = static_cast<network::RegState>(state);
481             return make(std::move(cgreg));
482         }
483         break;
484 
485     case 1:  // unsolMode,state
486         if (parser(&unsolMode).skip(',')(&state).fullMatch()) {
487             cgreg.state = static_cast<network::RegState>(state);
488             return make(std::move(cgreg));
489         }
490         break;
491 
492     case 3:  // state,areaCode,cellId,networkType
493         if (parser(&state).skip(',').skip('"')(&areaCodeHex, '"')
494                   .skip(',').skip('"')(&cellIdHex, '"').skip(',')
495                   (&cgreg.networkType).fullMatch()) {
496             std::from_chars(areaCodeHex.begin(), areaCodeHex.end(), cgreg.areaCode, 16);
497             std::from_chars(cellIdHex.begin(), cellIdHex.end(), cgreg.cellId, 16);
498             cgreg.state = static_cast<network::RegState>(state);
499             return make(std::move(cgreg));
500         }
501         break;
502 
503     case 4:  // unsolMode,state,areaCode,cellId,networkType
504         if (parser(&unsolMode).skip(',')
505                   (&state).skip(',')
506                   .skip('"')(&areaCodeHex, '"').skip(',')
507                   .skip('"')(&cellIdHex, '"').skip(',')
508                   (&cgreg.networkType).fullMatch()) {
509             std::from_chars(areaCodeHex.begin(), areaCodeHex.end(), cgreg.areaCode, 16);
510             std::from_chars(cellIdHex.begin(), cellIdHex.end(), cgreg.cellId, 16);
511             cgreg.state = static_cast<network::RegState>(state);
512             return make(std::move(cgreg));
513         }
514         break;
515     }
516 
517     return FAILURE_V(makeParseErrorFor<CGREG>(),
518                      "Can't parse: '%*.*s'",
519                      int(str.size()), int(str.size()), str.data());
520 }
521 
522 #undef FAILURE_DEBUG_PREFIX
523 #define FAILURE_DEBUG_PREFIX "CEREG"
parse(const std::string_view str)524 AtResponsePtr AtResponse::CEREG::parse(const std::string_view str) {
525     CEREG cereg;
526     Parser parser(str);
527     std::string_view areaCodeHex;
528     std::string_view cellIdHex;
529     int unsolMode;
530     int state;
531 
532     switch (std::count(str.begin(), str.end(), ',')) {
533     case 0:  // state
534         if (parser(&state).fullMatch()) {
535             cereg.state = static_cast<network::RegState>(state);
536             return make(std::move(cereg));
537         }
538         break;
539 
540     case 1:  // unsolMode,state
541         if (parser(&unsolMode).skip(',')(&state).fullMatch()) {
542             cereg.state = static_cast<network::RegState>(state);
543             return make(std::move(cereg));
544         }
545         break;
546 
547     case 3:  // state,areaCode,cellId,networkType
548         if (parser(&state).skip(',').skip('"')(&areaCodeHex, '"')
549                   .skip(',').skip('"')(&cellIdHex, '"').skip(',')
550                   (&cereg.networkType).fullMatch()) {
551             std::from_chars(areaCodeHex.begin(), areaCodeHex.end(), cereg.areaCode, 16);
552             std::from_chars(cellIdHex.begin(), cellIdHex.end(), cereg.cellId, 16);
553             cereg.state = static_cast<network::RegState>(state);
554             return make(std::move(cereg));
555         }
556         break;
557 
558     case 4:  // unsolMode,state,areaCode,cellId,networkType
559         if (parser(&unsolMode).skip(',')
560                   (&state).skip(',')
561                   .skip('"')(&areaCodeHex, '"').skip(',')
562                   .skip('"')(&cellIdHex, '"').skip(',')
563                   (&cereg.networkType).fullMatch()) {
564             std::from_chars(areaCodeHex.begin(), areaCodeHex.end(), cereg.areaCode, 16);
565             std::from_chars(cellIdHex.begin(), cellIdHex.end(), cereg.cellId, 16);
566             cereg.state = static_cast<network::RegState>(state);
567             return make(std::move(cereg));
568         }
569         break;
570     }
571 
572     return FAILURE_V(makeParseErrorFor<CEREG>(),
573                      "Can't parse: '%*.*s'",
574                      int(str.size()), int(str.size()), str.data());
575 }
576 
577 #undef FAILURE_DEBUG_PREFIX
578 #define FAILURE_DEBUG_PREFIX "CTEC"
579 /*      +CTEC: current (decimal),preferred_bitmask (hex)
580  *  OR
581  *      +CTEC: comma_separated_list_of_supported (decimal)
582  *  OR
583  *      +CTEC: current (decimal)
584  *  OR
585  *      +CTEC: DONE
586 */
parse(const std::string_view str)587 AtResponsePtr AtResponse::CTEC::parse(const std::string_view str) {
588     CTEC ctec;
589 
590     size_t i = 0;
591     while (true) {
592         const size_t comma = str.find(',', i);
593         if (comma != std::string_view::npos) {
594             ctec.values.push_back(std::string(str.substr(i, comma - i)));
595             i = comma + 1;
596         } else {
597             ctec.values.push_back(std::string(str.substr(i)));
598             break;
599         }
600     }
601 
602     return make(std::move(ctec));
603 }
604 
getCurrentModemTechnology() const605 std::optional<ratUtils::ModemTechnology> AtResponse::CTEC::getCurrentModemTechnology() const {
606     using ratUtils::ModemTechnology;
607 
608     if ((values.size() == 0) || (values.size() > 2) ||
609             ((values.size() == 1) && (values[0] == "DONE"))) {
610         return std::nullopt;
611     }
612 
613     int mtech;
614     std::from_chars_result r =
615         std::from_chars(&*values[0].begin(), &*values[0].end(), mtech, 10);
616 
617     if ((r.ec != std::errc()) || (r.ptr != &*values[0].end())) {
618         return FAILURE(std::nullopt);
619     }
620 
621     for (unsigned i = static_cast<unsigned>(ModemTechnology::GSM);
622                   i <= static_cast<unsigned>(ModemTechnology::NR); ++i) {
623         if (mtech & (1U << i)) {
624             return static_cast<ratUtils::ModemTechnology>(i);
625         }
626     }
627 
628     return FAILURE(std::nullopt);
629 }
630 
isDONE() const631 bool AtResponse::CTEC::isDONE() const {
632     return (values.size() == 1) && (values[0] == "DONE");
633 }
634 
635 #undef FAILURE_DEBUG_PREFIX
636 #define FAILURE_DEBUG_PREFIX "COPS"
637 /*      "+COPS: 0,0,longName\r+COPS: 0,1,shortName\r+COPS: 0,2,numeric\r"
638  *  OR
639  *      "+COPS: (state,longName,shortName,numeric),(...),...\r"
640  *  OR
641  *      "+COPS: selectionMode,2,numeric\r"
642  *  OR
643  *      "+COPS: selectionMode,0,0\r"
644  *  OR
645  *      "+COPS: 0,0,0\r"
646  */
parse(const std::string_view str)647 AtResponsePtr AtResponse::COPS::parse(const std::string_view str) {
648     COPS cops;
649 
650     Parser parser(str);
651     if (!parser.skip("+COPS:").skip(' ').hasMore()) { goto err; }
652 
653     if (parser.front() == '(') {
654         while (parser.matchSoFar()) {
655             COPS::OperatorInfo operatorInfo;
656             int state;
657 
658             if (parser.skip('(')(&state).skip(',')
659                                 (&operatorInfo.longName, ',')
660                                 (&operatorInfo.shortName, ',')
661                                 (&operatorInfo.numeric, ')').matchSoFar()) {
662                 operatorInfo.state = static_cast<COPS::OperatorInfo::State>(state);
663                 cops.operators.push_back(std::move(operatorInfo));
664 
665                 if (parser.front() == ',') {
666                     parser.skip(',');
667                 } else {
668                     break;
669                 }
670             } else {
671                 goto err;
672             }
673         }
674 
675         return make(std::move(cops));
676     } else {
677         std::string str;
678         int networkSelectionMode, n;
679 
680         if (!parser(&networkSelectionMode).skip(',')(&n).skip(',')(&str, kCR).matchSoFar()) {
681             goto err;
682         }
683 
684         if ((n == 2) && parser.fullMatch()) {
685             cops.networkSelectionMode = static_cast<COPS::NetworkSelectionMode>(networkSelectionMode);
686             cops.numeric = std::move(str);
687             return make(std::move(cops));
688         } else if (n != 0) {
689             goto err;
690         } else if ((str == "0") && parser.fullMatch()) {
691             cops.networkSelectionMode = static_cast<COPS::NetworkSelectionMode>(networkSelectionMode);
692             return make(std::move(cops));
693         }
694 
695         COPS::OperatorInfo operatorInfo;
696         operatorInfo.state = COPS::OperatorInfo::State::CURRENT;
697         operatorInfo.longName = std::move(str);
698 
699         if (!parser.skip("+COPS:").skip(' ').skip("0,1,")(&operatorInfo.shortName, kCR)
700                    .skip("+COPS:").skip(' ').skip("0,2,")(&operatorInfo.numeric, kCR)
701                    .fullMatch()) {
702             goto err;
703         }
704 
705         cops.operators.push_back(std::move(operatorInfo));
706         return make(std::move(cops));
707     }
708 
709 err:
710     return FAILURE_V(makeParseErrorFor<COPS>(),
711                      "Can't parse: '%*.*s'",
712                      int(str.size()), int(str.size()), str.data());
713 }
714 
715 #undef FAILURE_DEBUG_PREFIX
716 #define FAILURE_DEBUG_PREFIX "WRMP"
parse(const std::string_view str)717 AtResponsePtr AtResponse::WRMP::parse(const std::string_view str) {
718     int cdmaRoamingPreference;
719 
720     Parser parser(str);
721     if (!parser(&cdmaRoamingPreference).fullMatch()) {
722         return FAILURE_V(makeParseErrorFor<WRMP>(),
723                          "Can't parse: '%*.*s'",
724                          int(str.size()), int(str.size()), str.data());
725     }
726 
727     WRMP wrmp = {
728         .cdmaRoamingPreference =
729             static_cast<network::CdmaRoamingType>(cdmaRoamingPreference),
730     };
731 
732     return make(std::move(wrmp));
733 }
734 
735 
736 #undef FAILURE_DEBUG_PREFIX
737 #define FAILURE_DEBUG_PREFIX "CCSS"
parse(const std::string_view str)738 AtResponsePtr AtResponse::CCSS::parse(const std::string_view str) {
739     CCSS ccss;
740     int source;
741 
742     Parser parser(str);
743     if (parser(&source).fullMatch()) {
744         ccss.source = static_cast<sim::CdmaSubscriptionSource>(source);
745         return make(std::move(ccss));
746     } else {
747         return FAILURE_V(makeParseErrorFor<CCSS>(),
748                          "Can't parse: '%*.*s'",
749                          int(str.size()), int(str.size()), str.data());
750     }
751 }
752 
753 #undef FAILURE_DEBUG_PREFIX
754 #define FAILURE_DEBUG_PREFIX "CSQ"
parse(const std::string_view str)755 AtResponsePtr AtResponse::CSQ::parse(const std::string_view str) {
756     constexpr size_t kMaxSize = 22;
757     int values[kMaxSize];
758 
759     Parser parser(str);
760     if (!parser(&values[0]).matchSoFar()) {
761         return FAILURE_V(makeParseErrorFor<CSQ>(),
762                          "Can't parse: '%*.*s'",
763                          int(str.size()), int(str.size()), str.data());
764     }
765 
766     size_t n;
767     for (n = 1; parser.hasMore() && (n < kMaxSize); ++n) {
768         if (!parser.skip(',')(&values[n]).matchSoFar()) {
769             return FAILURE_V(makeParseErrorFor<CSQ>(),
770                              "Can't parse: '%*.*s'",
771                              int(str.size()), int(str.size()), str.data());
772         }
773     }
774 
775     if (!parser.fullMatch()) {
776         return FAILURE_V(makeParseErrorFor<CSQ>(),
777                          "Can't parse: '%*.*s'",
778                          int(str.size()), int(str.size()), str.data());
779     }
780 
781     CSQ csq;
782     switch (n) {
783     case 22:
784         csq.wcdma_signalStrength = values[14];
785         if (csq.wcdma_signalStrength != kUnknown) {
786             csq.wcdma_rscp = 42;
787             csq.wcdma_ecno = 19;
788         }
789         csq.wcdma_bitErrorRate = values[15];
790         csq.nr_ssRsrp = values[16];
791         csq.nr_ssRsrq = values[17];
792         csq.nr_ssSinr = values[18];
793         csq.nr_csiRsrp = values[19];
794         csq.nr_csiRsrq = values[20];
795         csq.nr_csiSinr = values[21];
796         [[fallthrough]];
797 
798     case 14:
799         csq.tdscdma_rscp = values[13];
800         [[fallthrough]];
801 
802     case 13:
803         csq.lte_timingAdvance = values[12];
804         [[fallthrough]];
805 
806     case 12:
807         csq.gsm_signalStrength = values[0];
808         csq.gsm_bitErrorRate = values[1];
809         csq.cdma_dbm = values[2];
810         csq.cdma_ecio = values[3];
811         csq.evdo_dbm = values[4];
812         csq.evdo_ecio = values[5];
813         csq.evdo_signalNoiseRatio = values[6];
814         csq.lte_signalStrength = values[7];
815         csq.lte_rsrp = values[8];
816         csq.lte_rsrq = values[9];
817         csq.lte_rssnr = values[10];
818         csq.lte_cqi = values[11];
819         break;
820 
821     default:
822         return FAILURE_V(makeParseErrorFor<CSQ>(),
823                          "Unexpected size: %zu", n);
824     }
825 
826     return make(std::move(csq));
827 }
828 
toSignalStrength() const829 network::SignalStrength AtResponse::CSQ::toSignalStrength() const {
830     return {
831         .gsm = {
832             .signalStrength = gsm_signalStrength,
833             .bitErrorRate = gsm_bitErrorRate,
834             .timingAdvance = gsm_timingAdvance,
835         },
836         .cdma = {
837             .dbm = cdma_dbm,
838             .ecio = cdma_ecio,
839         },
840         .evdo = {
841             .dbm = evdo_dbm,
842             .ecio = evdo_ecio,
843             .signalNoiseRatio = evdo_signalNoiseRatio,
844         },
845         .lte = {
846             .signalStrength = lte_signalStrength,
847             .rsrp = lte_rsrp,
848             .rsrq = lte_rsrq,
849             .rssnr = lte_rssnr,
850             .cqi = lte_cqi,
851             .timingAdvance = lte_timingAdvance,
852             .cqiTableIndex = lte_cqiTableIndex,
853         },
854         .tdscdma = {
855             .signalStrength = tdscdma_signalStrength,
856             .bitErrorRate = tdscdma_bitErrorRate,
857             .rscp = tdscdma_rscp,
858         },
859         .wcdma = {
860             .signalStrength = wcdma_signalStrength,
861             .bitErrorRate = wcdma_bitErrorRate,
862             .rscp = wcdma_rscp,
863             .ecno = wcdma_ecno,
864         },
865         .nr = {
866             .ssRsrp = nr_ssRsrp,
867             .ssRsrq = nr_ssRsrq,
868             .ssSinr = nr_ssSinr,
869             .csiRsrp = nr_csiRsrp,
870             .csiRsrq = nr_csiRsrq,
871             .csiSinr = nr_csiSinr,
872             .csiCqiTableIndex = nr_csiCqiTableIndex,
873             .timingAdvance = nr_timingAdvance,
874         },
875     };
876 }
877 
878 #undef FAILURE_DEBUG_PREFIX
879 #define FAILURE_DEBUG_PREFIX "CLCC"
parse(const std::string_view str)880 AtResponsePtr AtResponse::CLCC::parse(const std::string_view str) {
881     CLCC clcc;
882 
883     Parser parser(str);
884     while (parser.hasMore()) {
885         int index;
886         int dir;
887         int state;
888         int mode;
889         int mpty;
890         int type;
891         std::string number;
892 
893         // +CLCC: <index>,<dir>,<state>,<mode>,<mpty>,<number>,<type>\r
894         if (parser.skip("+CLCC:").skip(' ')(&index).skip(',')
895                   (&dir).skip(',')(&state).skip(',')
896                   (&mode).skip(',')(&mpty).skip(',')
897                   (&number, ',')(&type).skip(kCR).matchSoFar()) {
898 
899             voice::Call call = {
900                 .state = state,
901                 .index = index,
902                 .toa = type,
903                 .isMpty = (mpty != 0),
904                 .isMT = (dir != 0),
905                 .isVoice = (mode == 0),
906                 .number = std::move(number),
907             };
908 
909             clcc.calls.push_back(std::move(call));
910         } else {
911             return FAILURE_V(makeParseErrorFor<CLCC>(),
912                              "Can't parse '%*.*s'",
913                              int(str.size()), int(str.size()), str.data());
914         }
915     }
916 
917     return make(std::move(clcc));
918 }
919 
920 #undef FAILURE_DEBUG_PREFIX
921 #define FAILURE_DEBUG_PREFIX "CCFCU"
parse(const std::string_view str)922 AtResponsePtr AtResponse::CCFCU::parse(const std::string_view str) {
923     CCFCU ccfcu;
924 
925     Parser parser(str);
926     while (parser.hasMore()) {
927         voice::CallForwardInfo cfi;
928         int numberType;
929         std::string_view ignore;
930         if (parser.skip("+CCFCU:").skip(' ')(&cfi.status).skip(',')
931                 (&cfi.serviceClass).skip(',')(&numberType).skip(',')
932                 (&cfi.toa).skip(',').skip('"')(&cfi.number, '"').matchSoFar()) {
933             switch (parser.front()) {
934             case ',':
935                 if (!parser.skip(',')(&ignore, ',')(&ignore, ',')
936                           (&cfi.timeSeconds).skip(kCR).matchSoFar()) {
937                     return FAILURE_V(makeParseErrorFor<CCFCU>(),
938                                      "Can't parse '%*.*s'",
939                                      int(str.size()), int(str.size()), str.data());
940                 }
941                 break;
942 
943             case kCR:
944                 parser.skip(kCR);
945                 break;
946 
947             default:
948                 return FAILURE_V(makeParseErrorFor<CCFCU>(),
949                                  "Can't parse '%*.*s'",
950                                  int(str.size()), int(str.size()), str.data());
951             }
952 
953             ccfcu.callForwardInfos.push_back(std::move(cfi));
954         } else {
955             return FAILURE_V(makeParseErrorFor<CCFCU>(),
956                              "Can't parse '%*.*s'",
957                              int(str.size()), int(str.size()), str.data());
958         }
959     }
960 
961     return make(std::move(ccfcu));
962 }
963 
964 
965 #undef FAILURE_DEBUG_PREFIX
966 #define FAILURE_DEBUG_PREFIX "CCWA"
parse(const std::string_view str)967 AtResponsePtr AtResponse::CCWA::parse(const std::string_view str) {
968     CCWA ccwa;
969     int mode;
970 
971     Parser parser(str);
972     if (parser(&mode).skip(',')(&ccwa.serviceClass).fullMatch()) {
973         ccwa.enable = (mode == 1);
974         return make(std::move(ccwa));
975     } else {
976         return FAILURE_V(makeParseErrorFor<CCWA>(),
977                          "Can't parse '%*.*s'",
978                          int(str.size()), int(str.size()), str.data());
979     }
980 }
981 
982 #undef FAILURE_DEBUG_PREFIX
983 #define FAILURE_DEBUG_PREFIX "CUSATD"
parse(const std::string_view str)984 AtResponsePtr AtResponse::CUSATD::parse(const std::string_view str) {
985     CUSATD cusatd;
986 
987     Parser parser(str);
988     if (parser(&cusatd.a).skip(',').skip(' ')(&cusatd.a).fullMatch()) {
989         return make(std::move(cusatd));
990     } else {
991         return FAILURE_V(makeParseErrorFor<CUSATD>(),
992                          "Can't parse '%*.*s'",
993                          int(str.size()), int(str.size()), str.data());
994     }
995 }
996 
997 #undef FAILURE_DEBUG_PREFIX
998 #define FAILURE_DEBUG_PREFIX "CUSATP"
parse(const std::string_view str)999 AtResponsePtr AtResponse::CUSATP::parse(const std::string_view str) {
1000     CUSATP cusatp = {
1001         .cmd = toString(str),
1002     };
1003 
1004     return make(std::move(cusatp));
1005 }
1006 
1007 #undef FAILURE_DEBUG_PREFIX
1008 #define FAILURE_DEBUG_PREFIX "CUSATE"
parse(const std::string_view str)1009 AtResponsePtr AtResponse::CUSATE::parse(const std::string_view str) {
1010     CUSATE cusate = {
1011         .response = toString(str),
1012     };
1013 
1014     return make(std::move(cusate));
1015 }
1016 
1017 #undef FAILURE_DEBUG_PREFIX
1018 #define FAILURE_DEBUG_PREFIX "CUSATT"
parse(const std::string_view str)1019 AtResponsePtr AtResponse::CUSATT::parse(const std::string_view str) {
1020     CUSATT cusatt;
1021 
1022     Parser parser(str);
1023     if (parser(&cusatt.value).fullMatch()) {
1024         return make(std::move(cusatt));
1025     } else {
1026         return FAILURE_V(makeParseErrorFor<CUSATT>(),
1027                          "Can't parse '%*.*s'",
1028                          int(str.size()), int(str.size()), str.data());
1029     }
1030 }
1031 
1032 #undef FAILURE_DEBUG_PREFIX
1033 #define FAILURE_DEBUG_PREFIX "CUSATEND"
parse(const std::string_view)1034 AtResponsePtr AtResponse::CUSATEND::parse(const std::string_view) {
1035     return make(CUSATEND());
1036 }
1037 
1038 #undef FAILURE_DEBUG_PREFIX
1039 #define FAILURE_DEBUG_PREFIX "CLCK"
parse(const std::string_view str)1040 AtResponsePtr AtResponse::CLCK::parse(const std::string_view str) {
1041     CLCK clck;
1042 
1043     switch (str.front()) {
1044     case '0': clck.locked = false; break;
1045     case '1': clck.locked = true; break;
1046     default:
1047         return FAILURE_V(makeParseErrorFor<CLCK>(),
1048                          "Can't parse '%*.*s'",
1049                          int(str.size()), int(str.size()), str.data());
1050     }
1051 
1052     return make(std::move(clck));
1053 }
1054 
1055 #undef FAILURE_DEBUG_PREFIX
1056 #define FAILURE_DEBUG_PREFIX "CSIM"
parse(const std::string_view str)1057 AtResponsePtr AtResponse::CSIM::parse(const std::string_view str) {
1058     Parser parser(str);
1059     int len;
1060 
1061     if (parser(&len).skip(',').matchSoFar()) {
1062         const std::string_view response = parser.remaining();
1063 
1064         if (len == response.size()) {
1065             CSIM csim = {
1066                 .response = toString(response),
1067             };
1068 
1069             return make(std::move(csim));
1070         }
1071     }
1072 
1073     return FAILURE_V(makeParseErrorFor<CSIM>(),
1074                      "Can't parse '%*.*s'",
1075                      int(str.size()), int(str.size()), str.data());
1076 }
1077 
1078 #undef FAILURE_DEBUG_PREFIX
1079 #define FAILURE_DEBUG_PREFIX "CGLA"
parse(const std::string_view str)1080 AtResponsePtr AtResponse::CGLA::parse(const std::string_view str) {
1081     Parser parser(str);
1082     int len;
1083 
1084     if (parser(&len).skip(',').matchSoFar()) {
1085         const std::string_view response = parser.remaining();
1086 
1087         if (len == response.size()) {
1088             CGLA cgla = {
1089                 .response = toString(response),
1090             };
1091 
1092             return make(std::move(cgla));
1093         }
1094     }
1095 
1096     return FAILURE_V(makeParseErrorFor<CGLA>(),
1097                      "Can't parse '%*.*s'",
1098                      int(str.size()), int(str.size()), str.data());
1099 }
1100 
1101 #undef FAILURE_DEBUG_PREFIX
1102 #define FAILURE_DEBUG_PREFIX "CCHC"
parse(const std::string_view)1103 AtResponsePtr AtResponse::CCHC::parse(const std::string_view) {
1104     return make(CCHC());
1105 }
1106 
1107 #undef FAILURE_DEBUG_PREFIX
1108 #define FAILURE_DEBUG_PREFIX "CLIP"
parse(const std::string_view str)1109 AtResponsePtr AtResponse::CLIP::parse(const std::string_view str) {
1110     int enable;
1111     int status;
1112 
1113     Parser parser(str);
1114     if (parser(&enable).skip(',')(&status).fullMatch()) {
1115         CLIP clip;
1116         clip.enable = enable != 0;
1117         clip.status = static_cast<voice::ClipStatus>(status);
1118 
1119         return make(std::move(clip));
1120     } else {
1121         return FAILURE_V(makeParseErrorFor<CLIP>(),
1122                          "Can't parse '%*.*s'",
1123                          int(str.size()), int(str.size()), str.data());
1124     }
1125 }
1126 
1127 #undef FAILURE_DEBUG_PREFIX
1128 #define FAILURE_DEBUG_PREFIX "CLIR"
parse(const std::string_view str)1129 AtResponsePtr AtResponse::CLIR::parse(const std::string_view str) {
1130     CLIR clir;
1131     Parser parser(str);
1132     if (parser(&clir.n).skip(',')(&clir.m).fullMatch()) {
1133         return make(std::move(clir));
1134     } else {
1135         return FAILURE_V(makeParseErrorFor<CLIR>(),
1136                          "Can't parse '%*.*s'",
1137                          int(str.size()), int(str.size()), str.data());
1138     }
1139 }
1140 
1141 #undef FAILURE_DEBUG_PREFIX
1142 #define FAILURE_DEBUG_PREFIX "CMUT"
parse(const std::string_view str)1143 AtResponsePtr AtResponse::CMUT::parse(const std::string_view str) {
1144     int on;
1145     Parser parser(str);
1146     if (parser(&on).fullMatch()) {
1147         CMUT cmut;
1148         cmut.on = (on != 0);
1149         return make(std::move(cmut));
1150     } else {
1151         return FAILURE_V(makeParseErrorFor<CMUT>(),
1152                          "Can't parse '%*.*s'",
1153                          int(str.size()), int(str.size()), str.data());
1154     }
1155 }
1156 
1157 #undef FAILURE_DEBUG_PREFIX
1158 #define FAILURE_DEBUG_PREFIX "WSOS"
parse(const std::string_view str)1159 AtResponsePtr AtResponse::WSOS::parse(const std::string_view str) {
1160     int isEmergencyMode;
1161     Parser parser(str);
1162     if (parser(&isEmergencyMode).fullMatch()) {
1163         WSOS wsos;
1164         wsos.isEmergencyMode = (isEmergencyMode != 0);
1165         return make(std::move(wsos));
1166     } else {
1167         return FAILURE_V(makeParseErrorFor<WSOS>(),
1168                          "Can't parse '%*.*s'",
1169                          int(str.size()), int(str.size()), str.data());
1170     }
1171 }
1172 
1173 #undef FAILURE_DEBUG_PREFIX
1174 #define FAILURE_DEBUG_PREFIX "CSCA"
parse(const std::string_view str)1175 AtResponsePtr AtResponse::CSCA::parse(const std::string_view str) {
1176     CSCA csca;
1177 
1178     Parser parser(str);
1179     if (!parser(&csca.sca, ',')(&csca.tosca).fullMatch()) {
1180         return FAILURE_V(makeParseErrorFor<CSCA>(),
1181                          "Can't parse '%*.*s'",
1182                          int(str.size()), int(str.size()), str.data());
1183     }
1184 
1185     return make(std::move(csca));
1186 }
1187 
1188 #undef FAILURE_DEBUG_PREFIX
1189 #define FAILURE_DEBUG_PREFIX "CSCB"
parse(const std::string_view str)1190 AtResponsePtr AtResponse::CSCB::parse(const std::string_view str) {
1191     CSCB cscb;
1192     std::string_view serviceId;
1193     std::string_view codeScheme;
1194 
1195     Parser parser(str);
1196     if (!parser(&cscb.mode).skip(',')
1197                .skip('"')(&serviceId, '"').skip(',')
1198                .skip('"')(&codeScheme, '"').fullMatch()) {
1199 fail:   return FAILURE_V(makeParseErrorFor<CSCB>(),
1200                          "Can't parse '%*.*s'",
1201                          int(str.size()), int(str.size()), str.data());
1202     }
1203 
1204     auto maybeIds = parseIds(serviceId);
1205     if (!maybeIds) {
1206         goto fail;
1207     }
1208     cscb.serviceId = std::move(maybeIds.value());
1209 
1210     maybeIds = parseIds(codeScheme);
1211     if (!maybeIds) {
1212         goto fail;
1213     }
1214     cscb.codeScheme = std::move(maybeIds.value());
1215 
1216     return make(std::move(cscb));
1217 }
1218 
1219 std::optional<std::vector<AtResponse::CSCB::Association>>
parseIds(const std::string_view str)1220 AtResponse::CSCB::parseIds(const std::string_view str) {
1221     std::vector<Association> ids;
1222     Parser parser(str);
1223     while (parser.hasMore()) {
1224         Association a;
1225         if (!parser(&a.from).matchSoFar()) {
1226             return std::nullopt;
1227         }
1228 
1229         if (parser.fullMatch()) {
1230             a.to = a.from;
1231             ids.push_back(a);
1232             break;
1233         }
1234 
1235         switch (parser.front()) {
1236         case '-':
1237             if (!parser.skip('-')(&a.to).matchSoFar()) {
1238                 return std::nullopt;
1239             }
1240             ids.push_back(a);
1241             if (parser.fullMatch()) {
1242                 break;
1243             } else if (parser.front() == ',') {
1244                 parser.skip(',');
1245             } else {
1246                 return std::nullopt;
1247             }
1248             break;
1249 
1250         case ',':
1251             parser.skip(',');
1252             break;
1253 
1254         default:
1255             return std::nullopt;
1256         }
1257     }
1258 
1259     return ids;
1260 }
1261 
1262 #undef FAILURE_DEBUG_PREFIX
1263 #define FAILURE_DEBUG_PREFIX "CMGS"
parse(const std::string_view str)1264 AtResponsePtr AtResponse::CMGS::parse(const std::string_view str) {
1265     CMGS cmgs;
1266 
1267     Parser parser(str);
1268     if (!parser(&cmgs.messageRef).fullMatch()) {
1269         return FAILURE_V(makeParseErrorFor<CMGS>(),
1270                          "Can't parse '%*.*s'",
1271                          int(str.size()), int(str.size()), str.data());
1272     }
1273 
1274     return make(std::move(cmgs));
1275 }
1276 
1277 #undef FAILURE_DEBUG_PREFIX
1278 #define FAILURE_DEBUG_PREFIX "CMGW"
parse(const std::string_view str)1279 AtResponsePtr AtResponse::CMGW::parse(const std::string_view str) {
1280     CMGW cmgw;
1281 
1282     Parser parser(str);
1283     if (!parser(&cmgw.messageRef).fullMatch()) {
1284         return FAILURE_V(makeParseErrorFor<CMGS>(),
1285                          "Can't parse '%*.*s'",
1286                          int(str.size()), int(str.size()), str.data());
1287     }
1288 
1289     return make(std::move(cmgw));
1290 }
1291 
1292 #undef FAILURE_DEBUG_PREFIX
1293 #define FAILURE_DEBUG_PREFIX "CMT"
parse(const std::string_view str)1294 std::pair<int, AtResponsePtr> AtResponse::CMT::parse(const std::string_view str) {
1295     CMT cmt;
1296     std::string strPdu;
1297 
1298     Parser parser(str);
1299     if (parser(&cmt.something).skip(kCR).matchSoFar()) {
1300         if (parser(&strPdu, kCR).matchSoFar()) {
1301             if (hex2bin(strPdu, &cmt.pdu)) {
1302                 return { parser.consumed(), make(std::move(cmt)) };
1303             }
1304         } else {
1305             return { 0, nullptr };
1306         }
1307     }
1308 
1309     auto err = std::make_pair(-1, makeParseErrorFor<CMT>());
1310     return FAILURE_V(err, "Can't parse '%*.*s'",
1311                      int(str.size()), int(str.size()), str.data());
1312 }
1313 
1314 #undef FAILURE_DEBUG_PREFIX
1315 #define FAILURE_DEBUG_PREFIX "CDS"
parse(const std::string_view str)1316 std::pair<int, AtResponsePtr> AtResponse::CDS::parse(const std::string_view str) {
1317     CDS cds;
1318     std::string strPdu;
1319 
1320     Parser parser(str);
1321     if (parser(&cds.pduSize).skip(kCR).matchSoFar()) {
1322         if (parser(&strPdu, kCR).matchSoFar()) {
1323             if (hex2bin(strPdu, &cds.pdu)) {
1324                 return { parser.consumed(), make(std::move(cds)) };
1325             }
1326         } else {
1327             return { 0, nullptr };
1328         }
1329     }
1330 
1331     auto err = std::make_pair(-1, makeParseErrorFor<CDS>());
1332     return FAILURE_V(err, "Can't parse '%*.*s'",
1333                      int(str.size()), int(str.size()), str.data());
1334 }
1335 
1336 #undef FAILURE_DEBUG_PREFIX
1337 #define FAILURE_DEBUG_PREFIX "CGDCONT"
1338 // +CGDCONT: <cid>,<pdp_type>,<APN>,<pdp_addr>,<d_comp>,<h_comp>\r
1339 // 1,"IPV6","fast.t-mobile.com",,0,0
parse(const std::string_view str)1340 AtResponsePtr AtResponse::CGDCONT::parse(const std::string_view str) {
1341     CGDCONT cgdcont;
1342 
1343     Parser parser(str);
1344     while (parser.hasMore()) {
1345         CGDCONT::PdpContext pdpContext;
1346 
1347         if (parser.skip("+CGDCONT:").skip(' ')(&pdpContext.index).skip(',')
1348                   .skip('"')(&pdpContext.type, '"').skip(',')
1349                   .skip('"')(&pdpContext.apn, '"').skip(',')
1350                   (&pdpContext.addr, ',')(&pdpContext.dComp)
1351                   .skip(',')(&pdpContext.hComp).skip(' ').matchSoFar()) {
1352             cgdcont.contexts.push_back(std::move(pdpContext));
1353         } else {
1354             return FAILURE_V(makeParseErrorFor<CGDCONT>(),
1355                              "Can't parse '%*.*s'",
1356                              int(str.size()), int(str.size()), str.data());
1357         }
1358     }
1359 
1360     return make(std::move(cgdcont));
1361 }
1362 
1363 #undef FAILURE_DEBUG_PREFIX
1364 #define FAILURE_DEBUG_PREFIX "CGCONTRDP"
1365 // 1,5,"epc.tmobile.com",10.0.2.15/24,10.0.2.2,10.0.2.3
1366 // 1,5,"epc.tmobile.com",10.0.2.15,10.0.2.2,10.0.2.3
parse(const std::string_view str)1367 AtResponsePtr AtResponse::CGCONTRDP::parse(const std::string_view str) {
1368     CGCONTRDP cgcontrdp;
1369     std::string_view unused;
1370     std::string_view localAddr;
1371 
1372     Parser parser(str);
1373     if (parser(&cgcontrdp.cid).skip(',')(&cgcontrdp.bearer).skip(',')
1374                .skip('"')(&cgcontrdp.apn, '"').skip(',')
1375                (&localAddr, ',')
1376                (&cgcontrdp.gwAddr, ',').matchSoFar()) {
1377         cgcontrdp.dns1 = parser.remainingAsString();
1378     } else {
1379         return FAILURE_V(makeParseErrorFor<CGCONTRDP>(),
1380                          "Can't parse '%*.*s'",
1381                          int(str.size()), int(str.size()), str.data());
1382     }
1383 
1384     Parser localAddrParser(localAddr);
1385     if (!localAddrParser(&cgcontrdp.localAddr, '/')
1386                         (&cgcontrdp.localAddrSize).fullMatch()) {
1387         cgcontrdp.localAddr = std::string(localAddr.data(), localAddr.size());
1388         cgcontrdp.localAddrSize = 0;
1389     }
1390 
1391     return make(std::move(cgcontrdp));
1392 }
1393 
1394 
1395 #undef FAILURE_DEBUG_PREFIX
1396 #define FAILURE_DEBUG_PREFIX "CGFPCCFG"
1397 // 1,5000,32,0,1
parse(const std::string_view str)1398 AtResponsePtr AtResponse::CGFPCCFG::parse(const std::string_view str) {
1399     CGFPCCFG cgfpccfg;
1400     int status;
1401     int mtech;
1402 
1403     Parser parser(str);
1404     if (!parser(&status).skip(',')
1405                (&cgfpccfg.bandwidth).skip(',')
1406                (&mtech).skip(',')
1407                (&cgfpccfg.freq).skip(',')
1408                (&cgfpccfg.contextId).fullMatch()) {
1409         return FAILURE_V(makeParseErrorFor<CGFPCCFG>(),
1410                          "Can't parse '%*.*s'",
1411                          int(str.size()), int(str.size()), str.data());
1412     }
1413 
1414     cgfpccfg.status = static_cast<network::CellConnectionStatus>(status);
1415     cgfpccfg.mtech = static_cast<ratUtils::ModemTechnology>(mtech);
1416 
1417     return make(std::move(cgfpccfg));
1418 }
1419 
1420 #undef FAILURE_DEBUG_PREFIX
1421 #define FAILURE_DEBUG_PREFIX "MBAU"
1422 // <STATUS>,<KC>,<SRES>
1423 // <STATUS>,<CK>,<IK>,<RES/AUTS>
parse(const std::string_view str)1424 AtResponsePtr AtResponse::MBAU::parse(const std::string_view str) {
1425     MBAU mbau;
1426 
1427     std::string_view kc;
1428     std::string_view sres;
1429     std::string_view ck;
1430     std::string_view ik;
1431     std::string_view resAuts;
1432 
1433     Parser parser(str);
1434     switch (std::count(str.begin(), str.end(), ',')) {
1435     default:
1436 failed:
1437         return FAILURE_V(makeParseErrorFor<MBAU>(),
1438                          "Can't parse '%*.*s'",
1439                          int(str.size()), int(str.size()), str.data());
1440 
1441     case 0:
1442         if (!parser(&mbau.status).fullMatch()) {
1443             goto failed;
1444         }
1445         break;
1446 
1447     case 2:
1448         if (parser(&mbau.status).skip(',')(&kc, ',').matchSoFar()) {
1449             sres = parser.remaining();
1450         } else {
1451             goto failed;
1452         }
1453         break;
1454 
1455     case 3:
1456         if (parser(&mbau.status).skip(',')(&ck, ',')(&ik, ',').matchSoFar()) {
1457             resAuts = parser.remaining();
1458         } else {
1459             goto failed;
1460         }
1461         break;
1462     }
1463 
1464     if (!hex2bin(kc, &mbau.kc) || !hex2bin(sres, &mbau.sres) || !hex2bin(ck, &mbau.ck) ||
1465             !hex2bin(ik, &mbau.ik) || !hex2bin(resAuts, &mbau.resAuts)) {
1466         goto failed;
1467     }
1468 
1469     return make(std::move(mbau));
1470 }
1471 
1472 #undef FAILURE_DEBUG_PREFIX
1473 #define FAILURE_DEBUG_PREFIX "CTZV"
1474 // 24/11/05:17:01:32-32:0:America!Los_Angeles
parse(const std::string_view str)1475 AtResponsePtr AtResponse::CTZV::parse(const std::string_view str) {
1476     int yy, month, day, hh, mm, ss, tzOffset15m;
1477     char tzSign, daylight;
1478 
1479     Parser parser(str);
1480     parser.skip(' ')(&yy).skip('/')(&month).skip('/')(&day).skip(':')
1481           (&hh).skip(':')(&mm).skip(':')(&ss)
1482           (&tzSign)(&tzOffset15m).skip(':')(&daylight).skip(':');
1483 
1484     if (!parser.matchSoFar()) {
1485         return FAILURE_V(makeParseErrorFor<CTZV>(),
1486                          "Can't parse: '%*.*s'",
1487                          int(str.size()), int(str.size()), str.data());
1488     }
1489 
1490     switch (tzSign) {
1491     case '+': break;
1492     case '-': tzOffset15m = -tzOffset15m; break;
1493     default:
1494         return FAILURE_V(makeParseErrorFor<CTZV>(),
1495                          "Unexpected timezone offset sign: '%*.*s'",
1496                          int(str.size()), int(str.size()), str.data());
1497     }
1498 
1499     CTZV ctzv = {
1500         .tzName = toString(parser.remaining()),
1501         .year = uint16_t(yy + 2000),
1502         .month = uint8_t(month),
1503         .day = uint8_t(day),
1504         .hour = uint8_t(hh),
1505         .isDaylightSaving = uint8_t(daylight != '0'),
1506         .minute = uint8_t(mm),
1507         .second = uint8_t(ss),
1508         .tzOffset15m = int8_t(tzOffset15m),
1509     };
1510 
1511     return make(std::move(ctzv));
1512 }
1513 
nitzString() const1514 std::string AtResponse::CTZV::nitzString() const {
1515     return std::format("{:02d}/{:02d}/{:02d}:{:02d}:{:02d}:{:02d}{:+d}:{:d}:{:s}",
1516                        year % 100, month, day, hour, minute, second,
1517                        tzOffset15m, isDaylightSaving, tzName.c_str());
1518 }
1519 
what() const1520 std::string_view AtResponse::what() const {
1521     return visitR<std::string_view>(CmdIdVisitor());
1522 }
1523 
unexpected(const char * klass,const char * request,const std::source_location location) const1524 void AtResponse::unexpected(const char* klass, const char* request,
1525                             const std::source_location location) const {
1526     const std::string_view r = what();
1527     const int rl = r.size();
1528 
1529     LOG_ALWAYS_FATAL("Unexpected response: '%*.*s' in %s:%s at %s:%d in %s", rl, rl, r.data(),
1530                      klass, request, location.function_name(), location.line(),
1531                      location.file_name());
1532 }
1533 
1534 }  // namespace implementation
1535 }  // namespace radio
1536 }  // namespace hardware
1537 }  // namespace android
1538 }  // namespace aidl
1539