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