1 //
2 // Copyright (C) 2020 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 #include "host/commands/modem_simulator/network_service.h"
17
18 #include <map>
19 #include <sstream>
20
21 #include "common/libs/utils/files.h"
22 #include "host/commands/modem_simulator/device_config.h"
23 #include "host/commands/modem_simulator/nvram_config.h"
24 #include "host/commands/modem_simulator/thread_looper.h"
25
26 namespace cuttlefish {
27
28 // string type; two byte location area code in hexadecimal format
29 static const std::string kAreaCode = "2142";
30 // string type; four byte GERAN/UTRAN cell ID in hexadecimal format
31 static const std::string kCellId = "0000B804";
32
33 // Check SignalStrength.java file for more details on how these map to
34 // signal strength bars
35 const std::pair<int, int> kGSMSignalStrength = std::make_pair(4, 30);
36 const std::pair<int, int> kCDMASignalStrength = std::make_pair(4, 120);
37 const std::pair<int, int> kEVDOSignalStrength = std::make_pair(4, 120);
38 const std::pair<int, int> kLTESignalStrength = std::make_pair(4, 30);
39 const std::pair<int, int> kWCDMASignalStrength = std::make_pair(4, 30);
40 const std::pair<int, int> kNRSignalStrength = std::make_pair(45, 135);
41
NetworkService(int32_t service_id,ChannelMonitor * channel_monitor,ThreadLooper * thread_looper)42 NetworkService::NetworkService(int32_t service_id,
43 ChannelMonitor* channel_monitor,
44 ThreadLooper* thread_looper)
45 : ModemService(service_id, this->InitializeCommandHandlers(),
46 channel_monitor, thread_looper) {
47 InitializeServiceState();
48 }
49
InitializeCommandHandlers()50 std::vector<CommandHandler> NetworkService::InitializeCommandHandlers() {
51 std::vector<CommandHandler> command_handlers = {
52 CommandHandler(
53 "+CFUN?",
54 [this](const Client& client) { this->HandleRadioPowerReq(client); }),
55 CommandHandler("+CFUN=",
56 [this](const Client& client, std::string& cmd) {
57 this->HandleRadioPower(client, cmd);
58 }),
59 CommandHandler(
60 "+CSQ",
61 [this](const Client& client) { this->HandleSignalStrength(client); }),
62 CommandHandler("+COPS?",
63 [this](const Client& client) {
64 this->HandleQueryNetworkSelectionMode(client);
65 }),
66 CommandHandler("+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS?",
67 [this](const Client& client) {
68 this->HandleRequestOperator(client);
69 }),
70 CommandHandler("+COPS=?",
71 [this](const Client& client) {
72 this->HandleQueryAvailableNetwork(client);
73 }),
74 CommandHandler("+COPS=",
75 [this](const Client& client, std::string& cmd) {
76 this->HandleSetNetworkSelectionMode(client, cmd);
77 }),
78 CommandHandler("+CREG",
79 [this](const Client& client, std::string& cmd) {
80 this->HandleVoiceNetworkRegistration(client, cmd);
81 }),
82 CommandHandler("+CGREG",
83 [this](const Client& client, std::string& cmd) {
84 this->HandleDataNetworkRegistration(client, cmd);
85 }),
86 CommandHandler("+CEREG",
87 [this](const Client& client, std::string& cmd) {
88 this->HandleDataNetworkRegistration(client, cmd);
89 }),
90 CommandHandler("+CTEC?",
91 [this](const Client& client) {
92 this->HandleGetPreferredNetworkType(client);
93 }),
94 CommandHandler("+CTEC=?",
95 [this](const Client& client) {
96 this->HandleQuerySupportedTechs(client);
97 }),
98 CommandHandler("+CTEC=",
99 [this](const Client& client, std::string& cmd) {
100 this->HandleSetPreferredNetworkType(client, cmd);
101 }),
102 CommandHandler("+REMOTECTEC",
103 [this](const Client& client, std::string& cmd) {
104 this->HandleReceiveRemoteCTEC(client, cmd);
105 }),
106 CommandHandler("+REMOTESIGNAL",
107 [this](const Client& client, std::string& cmd) {
108 this->HandleReceiveRemoteSignal(client, cmd);
109 }),
110 CommandHandler("+REMOTEREG",
111 [this](const Client& client, std::string& cmd) {
112 this->HandleReceiveRemoteVoiceDataReg(client, cmd);
113 }),
114 };
115 return (command_handlers);
116 }
117
InitializeServiceState()118 void NetworkService::InitializeServiceState() {
119 radio_state_ = RadioState::RADIO_STATE_OFF;
120
121 modem_radio_capability_ =
122 M_MODEM_TECH_GSM | M_MODEM_TECH_WCDMA | M_MODEM_TECH_LTE | M_MODEM_TECH_NR;
123
124 auto nvram_config = NvramConfig::Get();
125 auto instance = nvram_config->ForInstance(service_id_);
126
127 // Default to be ""
128 current_operator_numeric_ = instance.operator_numeric();
129 // Default to be OPER_SELECTION_AUTOMATIC
130 oper_selection_mode_ = (OperatorSelectionMode)instance.network_selection_mode();
131 // Default to be M_MODEM_TECH_LTE | M_MODEM_TECH_WCDMA | M_MODEM_TECH_GSM;
132 preferred_network_mode_ = instance.preferred_network_mode();
133 // Default to be M_MODEM_TECH_LTE
134 current_network_mode_ = (ModemTechnology)instance.modem_technoloy();
135
136 InitializeNetworkOperator();
137
138 first_signal_strength_request_ = true;
139 android_last_signal_time_ = 0;
140 }
141
InitializeNetworkOperator()142 void NetworkService::InitializeNetworkOperator() {
143 operator_list_.push_back(
144 {"311740", "Android Virtual Operator", "Android", NetworkOperator::OPER_STATE_AVAILABLE});
145 operator_list_.push_back(
146 {"310300", "Alternative Operator", "Alternative", NetworkOperator::OPER_STATE_AVAILABLE});
147 operator_list_.push_back(
148 {"310400", "Hermetic Network Operator", "Hermetic", NetworkOperator::OPER_STATE_FORBIDDEN});
149
150 if (oper_selection_mode_ == OperatorSelectionMode::OPER_SELECTION_AUTOMATIC) {
151 current_operator_numeric_ = operator_list_.begin()->numeric;
152 operator_list_.begin()->operator_state = NetworkOperator::OPER_STATE_CURRENT;
153 } else if (oper_selection_mode_ == OperatorSelectionMode::OPER_SELECTION_MANUAL_AUTOMATIC) {
154 auto iter = operator_list_.begin();
155 for (; iter != operator_list_.end(); ++iter) {
156 if (iter->numeric == current_operator_numeric_) {
157 break;
158 }
159 }
160 if (iter == operator_list_.end()) {
161 current_operator_numeric_ = operator_list_.begin()->numeric;
162 operator_list_.begin()->operator_state = NetworkOperator::OPER_STATE_CURRENT;
163 } else {
164 iter->operator_state = NetworkOperator::OPER_STATE_CURRENT;
165 }
166 }
167 }
168
InitializeSimOperator()169 void NetworkService::InitializeSimOperator() {
170 if (sim_service_ == nullptr) {
171 return;
172 }
173 auto sim_operator_numeric = sim_service_->GetSimOperator();
174 if (sim_operator_numeric == "") {
175 return;
176 }
177
178 // ensure the first element is sim_operator_numeric
179 for (auto iter = operator_list_.begin(); iter != operator_list_.end();
180 ++iter) {
181 if (iter->numeric == sim_operator_numeric) {
182 std::swap(*iter, *(operator_list_.begin()));
183 return;
184 }
185 }
186
187 {
188 const char *operator_numeric_xml = "etc/modem_simulator/files/numeric_operator.xml";
189 auto file = cuttlefish::modem::DeviceConfig::DefaultHostArtifactsPath(
190 operator_numeric_xml);
191 if (!cuttlefish::FileExists(file) || !cuttlefish::FileHasContent(file)) {
192 return;
193 }
194
195 XMLDocument doc;
196 auto err = doc.LoadFile(file.c_str());
197 if (err != tinyxml2::XML_SUCCESS) {
198 LOG(ERROR) << "unable to load XML file '" << file << " ', error " << err;
199 return;
200 }
201 XMLElement *resources = doc.RootElement();
202 if (resources == NULL) return;
203
204 XMLElement *stringArray = resources->FirstChildElement("string-array");
205 if (stringArray == NULL) return;
206
207 XMLElement *item = stringArray->FirstChildElement("item");
208 while (item) {
209 const XMLAttribute *attr_numeric = item->FindAttribute("numeric");
210 std::string numeric = attr_numeric ? attr_numeric->Value() : "";
211 if (numeric == sim_operator_numeric) {
212 break;
213 }
214 item = item->NextSiblingElement("item");
215 }
216 if (item) {
217 std::string names = item->GetText();
218 auto pos = names.find('=');
219 if (pos != std::string::npos) {
220 auto long_name = names.substr(0, pos);
221 auto short_name = names.substr(pos + 1);
222 NetworkOperator sim_operator(sim_operator_numeric, long_name,
223 short_name, NetworkOperator::OPER_STATE_AVAILABLE);
224 operator_list_.insert(operator_list_.begin(), sim_operator);
225 }
226 }
227 }
228 InitializeNetworkOperator();
229 }
230
SetupDependency(MiscService * misc,SimService * sim,DataService * data)231 void NetworkService::SetupDependency(MiscService* misc, SimService* sim,
232 DataService* data) {
233 misc_service_ = misc;
234 sim_service_ = sim;
235 data_service_ = data;
236 InitializeSimOperator();
237 }
238
OnSimStatusChanged(SimService::SimStatus sim_status)239 void NetworkService::OnSimStatusChanged(SimService::SimStatus sim_status) {
240 if (radio_state_ == RadioState::RADIO_STATE_OFF) {
241 return; // RegistrationState::NET_REGISTRATION_UNREGISTERED unchanged
242 }
243 if (sim_status == SimService::SIM_STATUS_READY) {
244 voice_registration_status_.registration_state = NET_REGISTRATION_HOME;
245 } else {
246 voice_registration_status_.registration_state = NET_REGISTRATION_EMERGENCY;
247 // 3GPP TS 24.008 [8] and 3GPP TS 24.301 [83] specify the condition
248 // when the MT is considered as attached for emergency bearer services.
249 // applicable only when <AcT> indicates 2,4,5,6
250 // Note: not saved to nvram config due to sim status may change after reboot
251 current_network_mode_ = M_MODEM_TECH_WCDMA;
252 }
253 thread_looper_->PostWithDelay(std::chrono::seconds(1),
254 makeSafeCallback(this, &NetworkService::UpdateRegisterState,
255 voice_registration_status_.registration_state));
256 }
257
258 /**
259 * AT+CFUN
260 * Set command selects the level of functionality <fun> in the MT. Level
261 * "full functionality" is where the highest level of power is drawn.
262 * "Minimum functionality" is where minimum power is drawn. Level of functionality
263 * between these may also be specified by manufacturers. When supported by
264 * manufacturers, MT resetting with <rst> parameter may be utilized
265 *
266 * Command Possible response(s)
267 * +CFUN=[<fun>[,<rst>]] +CME ERROR: <err>
268 * +CFUN? +CFUN: <fun>
269 * +CME ERROR: <err>
270 *
271 * <fun>: integer type
272 * 0 minimum functionality
273 * 1 full functionality. Enable (turn on) the transmit and receive RF circuits
274 * for all supported radio access technologies.
275 * 2 disable (turn off) MT transmit RF circuits only
276 * 3 disable (turn off) MT receive RF circuits only
277 * 4 disable (turn off) both MT transmit and receive RF circuits
278 * 5...127 reserved for manufacturers as intermediate states between full
279 * and minimum functionality
280 * 128 Full functionality with radio access support according to the setting of +CSRA.
281 * 129 Prepare for shutdown.
282 *
283 * see RIL_REQUEST_RADIO_POWER in RIL
284 */
HandleRadioPowerReq(const Client & client)285 void NetworkService::HandleRadioPowerReq(const Client& client) {
286 std::stringstream ss;
287 ss << "+CFUN: " << radio_state_;
288
289 std::vector<std::string> responses;
290 responses.push_back(ss.str());
291 responses.push_back("OK");
292
293 client.SendCommandResponse(responses);
294 }
295
HandleRadioPower(const Client & client,std::string & command)296 void NetworkService::HandleRadioPower(const Client& client, std::string& command) {
297 CommandParser cmd(command);
298 cmd.SkipPrefix();
299 int on = cmd.GetNextInt();
300 switch (on) {
301 case 0:
302 radio_state_ = RadioState::RADIO_STATE_OFF;
303 UpdateRegisterState(NET_REGISTRATION_UNREGISTERED);
304 break;
305 case 1:
306 radio_state_ = RadioState::RADIO_STATE_ON;
307 if (sim_service_ != nullptr) {
308 auto sim_status = sim_service_->GetSimStatus();
309 OnSimStatusChanged(sim_status);
310 }
311 break;
312 default:
313 client.SendCommandResponse(kCmeErrorOperationNotSupported);
314 return;
315 }
316 signal_strength_.Reset();
317
318 client.SendCommandResponse("OK");
319 }
320
WakeupFromSleep()321 bool NetworkService::WakeupFromSleep() {
322 // It has not called once yet
323 if (android_last_signal_time_ == 0) {
324 return false;
325 }
326 // Heuristics: if guest has not asked for signal strength
327 // for 2 minutes, we assume it is caused by host sleep
328 time_t now = time(0);
329 const bool wakeup_from_sleep = (now > android_last_signal_time_ + 120);
330 return wakeup_from_sleep;
331 }
332
SetSignalStrengthValue(int & value,const std::pair<int,int> & range,double percentd)333 void NetworkService::SetSignalStrengthValue(int& value,
334 const std::pair<int, int>& range,
335 double percentd) {
336 value = range.first + percentd * (range.second - range.first);
337 AdjustSignalStrengthValue(value, range);
338 }
339
AdjustSignalStrengthValue(int & value,const std::pair<int,int> & range)340 void NetworkService::AdjustSignalStrengthValue(int& value,
341 const std::pair<int, int>& range) {
342 if (value < range.first) {
343 value = range.first;
344 } else if (value > range.second) {
345 value = range.second;
346 }
347 }
348 /**
349 * AT+CSQ
350 * Execution command returns received signal strength indication <rssi>
351 * and channel bit error rate <ber> from the MT.
352 *
353 * command Possible response(s)
354 * AT+CSQ +CSQ: <rssi>,<ber>
355 * +CME ERROR: <err>
356 *
357 * <rssi>: integer type
358 * 0 ‑113 dBm or less
359 * 1 ‑111 dBm
360 * 2...30 ‑109... ‑53 dBm
361 * 31 ‑51 dBm or greater
362 * 99 not known or not detectable
363 * <ber>: integer type; channel bit error rate (in percent)
364 * 0...7 as RXQUAL values in the table in 3GPP TS 45.008 [20] subclause 8.2.4
365 * 99 not known or not detectable
366 *
367 * see RIL_REQUEST_SIGNAL_STRENGTH in RIL
368 */
HandleSignalStrength(const Client & client)369 void NetworkService::HandleSignalStrength(const Client& client) {
370 std::vector<std::string> responses;
371 std::stringstream ss;
372
373 if (WakeupFromSleep()) {
374 misc_service_->TimeUpdate();
375 } else if (first_signal_strength_request_) {
376 first_signal_strength_request_ = false;
377 misc_service_->TimeUpdate();
378 }
379
380 android_last_signal_time_ = time(0);
381
382 auto response = GetSignalStrength();
383
384 responses.push_back(response);
385 responses.push_back("OK");
386 client.SendCommandResponse(responses);
387 }
388
IsHasNetwork()389 bool NetworkService::IsHasNetwork() {
390 if (radio_state_ == RADIO_STATE_OFF ||
391 oper_selection_mode_ == OperatorSelectionMode::OPER_SELECTION_DEREGISTRATION) {
392 return false;
393 }
394 return true;
395 }
396
397 /**
398 * AT+COPS
399 * Set command forces an attempt to select and register to the
400 * GSM/UMTS/EPS/5GS network operator using the SIM/USIM card installed
401 * in the currently selected card slot.
402 *
403 * command Possible response(s)
404 * +COPS=[<mode>[,<format> +CME ERROR: <err>
405 * [,<oper>[,<AcT>]]]]
406 *
407 * +COPS? +COPS: <mode>[,<format>,<oper>[,<AcT>]]
408 * +CME ERROR: <err>
409 *
410 * +COPS=? +COPS: [list of supported (<stat>,
411 * long alphanumeric <oper>,
412 * short alphanumeric <oper>,
413 * numeric <oper>[,<AcT>])s]
414 * [,,(list of supported <mode>s),
415 * (list of supported <format>s)]
416 * +CME ERROR: <err>
417 *
418 * <mode>: integer type
419 * 0 automatic (<oper> field is ignored)
420 * 1 manual (<oper> field shall be present, and <AcT> optionally)
421 * 2 deregister from network
422 * 3 set only <format> (for read command +COPS?), do not attempt
423 * registration/deregistration (<oper> and <AcT> fields are ignored);
424 * this value is not applicable in read command response
425 * 4 manual/automatic (<oper> field shall be present); if manual selection fails, automatic mode (<mode>=0) is entered
426 * <format>: integer type
427 * 0 long format alphanumeric <oper>
428 * 1 short format alphanumeric <oper>
429 * 2 numeric <oper>
430 * <oper>: string type;
431 * <format> indicates if the format is alphanumeric or numeric;
432 * <stat>: integer type
433 * 0 unknown
434 * 1 available
435 * 2 current
436 * 3 forbidden
437 * <AcT>: integer type; access technology selected
438 * 0 GSM
439 * 1 GSM Compact
440 * 2 UTRAN
441 * 3 GSM w/EGPRS (see NOTE 1)
442 * 4 UTRAN w/HSDPA (see NOTE 2)
443 * 5 UTRAN w/HSUPA (see NOTE 2)
444 * 6 UTRAN w/HSDPA and HSUPA (see NOTE 2)
445 * 7 E-UTRAN
446 * 8 EC-GSM-IoT (A/Gb mode) (see NOTE 3)
447 * 9 E-UTRAN (NB-S1 mode) (see NOTE 4)
448 * 10 E-UTRA connected to a 5GCN (see NOTE 5)
449 * 11 NR connected to a 5GCN (see NOTE 5)
450 * 12 NG-RAN
451 * 13 E-UTRA-NR dual connectivity (see NOTE 6)
452 *
453 * see RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC or
454 * RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE or
455 * RIL_REQUEST_OPERATOR in RIL
456 */
HandleQueryNetworkSelectionMode(const Client & client)457 void NetworkService::HandleQueryNetworkSelectionMode(const Client& client) {
458 std::vector<std::string> responses;
459 std::stringstream ss;
460
461 if (!IsHasNetwork()) {
462 ss << "+COPS: 0,0,0";
463 } else {
464 auto iter = operator_list_.begin();
465 for (; iter != operator_list_.end(); ++iter) {
466 if (iter->numeric == current_operator_numeric_) {
467 break;
468 }
469 }
470 if (iter != operator_list_.end()) {
471 ss << "+COPS: " << oper_selection_mode_ << ",2," << iter->numeric;
472 } else {
473 ss << "+COPS: " << oper_selection_mode_ << ",0,0";
474 }
475 }
476 responses.push_back(ss.str());
477 responses.push_back("OK");
478 client.SendCommandResponse(responses);
479 }
480
481 /* AT+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS? */
HandleRequestOperator(const Client & client)482 void NetworkService::HandleRequestOperator(const Client& client) {
483 if (!IsHasNetwork()) {
484 client.SendCommandResponse(kCmeErrorOperationNotAllowed);
485 return;
486 }
487
488 auto iter = operator_list_.begin();
489 for (; iter != operator_list_.end(); ++iter) {
490 if (iter->numeric == current_operator_numeric_) {
491 break;
492 }
493 }
494 if (iter == operator_list_.end()) {
495 client.SendCommandResponse(kCmeErrorNoNetworkService);
496 return;
497 }
498
499 std::vector<std::string> responses;
500 std::vector<std::stringstream> ss;
501 ss.resize(3);
502
503 ss[0] << "+COPS: 0,0," << iter->long_name;
504 ss[1] << "+COPS: 0,1," << iter->short_name;
505 ss[2] << "+COPS: 0,2," << iter->numeric;
506
507 responses.push_back(ss[0].str());
508 responses.push_back(ss[1].str());
509 responses.push_back(ss[2].str());
510 responses.push_back("OK");
511
512 client.SendCommandResponse(responses);
513 }
514
515 /* AT+COPS=? */
HandleQueryAvailableNetwork(const Client & client)516 void NetworkService::HandleQueryAvailableNetwork(const Client& client) {
517 std::vector<std::string> responses;
518 std::stringstream ss;
519
520 for (auto iter = operator_list_.begin(); iter != operator_list_.end(); ++iter) {
521 ss.clear();
522 ss << "+COPS: (" << iter->operator_state << ","
523 << iter->long_name << ","
524 << iter->short_name << ","
525 << iter->numeric << "),";
526 responses.push_back(ss.str());
527 ss.str("");
528 }
529
530 responses.push_back("OK");
531 client.SendCommandResponse(responses);
532 }
533
534 /* AT+COPS=mode,format,operatorNumeric,act */
HandleSetNetworkSelectionMode(const Client & client,std::string & command)535 void NetworkService::HandleSetNetworkSelectionMode(const Client& client, std::string& command) {
536 std::vector<std::string> responses;
537 std::stringstream ss;
538
539 CommandParser cmd(command);
540 cmd.SkipPrefix();
541
542 int mode = (OperatorSelectionMode)cmd.GetNextInt();
543 cmd.SkipPrefix(); // Default to be numeric
544
545 auto& registration_state = voice_registration_status_.registration_state;
546
547 switch (mode) {
548 // <oper> field is ignored
549 case OperatorSelectionMode::OPER_SELECTION_AUTOMATIC: {
550 oper_selection_mode_ = OperatorSelectionMode::OPER_SELECTION_AUTOMATIC;
551
552 // The first operator stored in operator_list_ map default to be
553 // the automatic selected operator
554 auto iter = operator_list_.begin();
555 current_operator_numeric_ = iter->numeric;
556 iter->operator_state = NetworkOperator::OPER_STATE_CURRENT;
557
558 // Change operator state stored in the operator_list_ map
559 ++iter;
560 for (; iter != operator_list_.end(); ++iter) {
561 if (iter->operator_state == NetworkOperator::OPER_STATE_CURRENT) {
562 iter->operator_state = NetworkOperator::OPER_STATE_AVAILABLE;
563 break;
564 }
565 }
566
567 registration_state = NET_REGISTRATION_HOME;
568 client.SendCommandResponse("OK");
569 break;
570 }
571
572 // <oper> field shall be present, and <AcT> optionally
573 case OperatorSelectionMode::OPER_SELECTION_MANUAL: {
574 oper_selection_mode_ = OperatorSelectionMode::OPER_SELECTION_MANUAL;
575 current_operator_numeric_ = cmd.GetNextStr();
576 auto iter = operator_list_.begin();
577 for (; iter != operator_list_.end(); ++iter) {
578 if (iter->numeric == current_operator_numeric_) {
579 break;
580 }
581 }
582 // If the selected operator is not available, no other operator shall be
583 // selected (except <mode>=4).
584 if (iter == operator_list_.end()) {
585 registration_state = NET_REGISTRATION_UNKNOWN;
586 client.SendCommandResponse(kCmeErrorNoNetworkService);
587 break;
588 }
589
590 // Change operator state stored in the operator_list_ vector
591 iter->operator_state = NetworkOperator::OPER_STATE_CURRENT;
592 iter = operator_list_.begin();
593 for (; iter != operator_list_.end(); ++iter) {
594 if (iter->numeric != current_operator_numeric_ &&
595 iter->operator_state == NetworkOperator::OPER_STATE_CURRENT) {
596 iter->operator_state = NetworkOperator::OPER_STATE_AVAILABLE;
597 }
598 }
599
600 // If the selected access technology is not available, then the same operator
601 // shall be selected in other access technology
602 int act = cmd.GetNextInt();
603 if (act != -1) {
604 auto tech = getTechFromNetworkType((NetworkRegistrationStatus::AccessTechnoloy)act);
605 if (tech & modem_radio_capability_) {
606 current_network_mode_ = tech;
607 } // else: remain current network mode unchanged
608 } // else: remain act unchanged
609
610 if (iter->operator_state == NetworkOperator::OPER_STATE_FORBIDDEN) {
611 registration_state = NET_REGISTRATION_DENIED;
612 } else if (iter->operator_state == NetworkOperator::OPER_STATE_UNKNOWN) {
613 registration_state = NET_REGISTRATION_UNKNOWN;
614 } else {
615 registration_state = NET_REGISTRATION_HOME;
616 }
617 client.SendCommandResponse("OK");
618 break;
619 }
620
621 case OperatorSelectionMode::OPER_SELECTION_DEREGISTRATION: {
622 oper_selection_mode_ = OperatorSelectionMode::OPER_SELECTION_DEREGISTRATION;
623 registration_state = NET_REGISTRATION_UNREGISTERED;
624 client.SendCommandResponse("OK");
625 break;
626 }
627
628 // <oper> field shall be present
629 case OperatorSelectionMode::OPER_SELECTION_MANUAL_AUTOMATIC: {
630 oper_selection_mode_ = OperatorSelectionMode::OPER_SELECTION_MANUAL_AUTOMATIC;
631 auto operator_numeric = cmd.GetNextStr();
632 // If manual selection fails, automatic mode (<mode>=0) is entered
633 auto iter = operator_list_.begin();
634 for (; iter != operator_list_.end(); ++iter) {
635 if (iter->numeric == operator_numeric) {
636 break;
637 }
638 }
639 // If the selected operator is not available, no other operator shall be
640 // selected (except <mode>=4)
641 if (iter != operator_list_.end() ||
642 iter->operator_state == NetworkOperator::OPER_STATE_AVAILABLE) {
643 current_operator_numeric_ = iter->numeric;
644 }
645
646 // Change operator state stored in the operator_list_ vector
647 iter = operator_list_.begin();
648 for (; iter != operator_list_.end(); ++iter) {
649 if (iter->numeric == current_operator_numeric_) {
650 iter->operator_state = NetworkOperator::OPER_STATE_CURRENT;
651 } else if (iter->operator_state == NetworkOperator::OPER_STATE_CURRENT) {
652 iter->operator_state = NetworkOperator::OPER_STATE_AVAILABLE;
653 }
654 }
655
656 registration_state = NET_REGISTRATION_HOME;
657 client.SendCommandResponse("OK");
658 break;
659 }
660
661 default:
662 client.SendCommandResponse(kCmeErrorInCorrectParameters);
663 return;
664 }
665
666 // Save the value anyway, no matter the value changes or not
667 auto nvram_config = NvramConfig::Get();
668 auto instance = nvram_config->ForInstance(service_id_);
669 instance.set_network_selection_mode(oper_selection_mode_);
670 instance.set_operator_numeric(current_operator_numeric_);
671
672 NvramConfig::SaveToFile();
673
674 thread_looper_->PostWithDelay(std::chrono::seconds(1),
675 makeSafeCallback(this, &NetworkService::UpdateRegisterState, registration_state));
676 }
677
678 NetworkService::NetworkRegistrationStatus::AccessTechnoloy
getNetworkTypeFromTech(ModemTechnology modemTech)679 NetworkService::getNetworkTypeFromTech(ModemTechnology modemTech) {
680 switch (modemTech) {
681 case ModemTechnology::M_MODEM_TECH_GSM:
682 return NetworkRegistrationStatus::ACESS_TECH_EGPRS;
683 case ModemTechnology::M_MODEM_TECH_WCDMA:
684 return NetworkRegistrationStatus::ACESS_TECH_HSPA;
685 case ModemTechnology::M_MODEM_TECH_LTE:
686 return NetworkRegistrationStatus::ACESS_TECH_EUTRAN;
687 case ModemTechnology::M_MODEM_TECH_NR:
688 return NetworkRegistrationStatus::ACESS_TECH_NR;
689 default:
690 return NetworkRegistrationStatus::ACESS_TECH_EGPRS;
691 }
692 }
693
getTechFromNetworkType(NetworkRegistrationStatus::AccessTechnoloy act)694 NetworkService::ModemTechnology NetworkService::getTechFromNetworkType(
695 NetworkRegistrationStatus::AccessTechnoloy act) {
696 switch (act) {
697 case NetworkRegistrationStatus::ACESS_TECH_GSM:
698 case NetworkRegistrationStatus::ACESS_TECH_GSM_COMPACT:
699 case NetworkRegistrationStatus::ACESS_TECH_EGPRS:
700 case NetworkRegistrationStatus::ACESS_TECH_EC_GSM_IoT:
701 return ModemTechnology::M_MODEM_TECH_GSM;
702
703 case NetworkRegistrationStatus::ACESS_TECH_UTRAN:
704 case NetworkRegistrationStatus::ACESS_TECH_HSDPA:
705 case NetworkRegistrationStatus::ACESS_TECH_HSUPA:
706 case NetworkRegistrationStatus::ACESS_TECH_HSPA:
707 return ModemTechnology::M_MODEM_TECH_WCDMA;
708
709 case NetworkRegistrationStatus::ACESS_TECH_EUTRAN:
710 case NetworkRegistrationStatus::ACESS_TECH_E_UTRAN:
711 case NetworkRegistrationStatus::ACESS_TECH_E_UTRA:
712 return ModemTechnology::M_MODEM_TECH_LTE;
713
714 case NetworkRegistrationStatus::ACESS_TECH_NR:
715 case NetworkRegistrationStatus::ACESS_TECH_NG_RAN:
716 case NetworkRegistrationStatus::ACESS_TECH_E_UTRA_NR:
717 return ModemTechnology::M_MODEM_TECH_NR;
718
719 default:
720 return ModemTechnology::M_MODEM_TECH_GSM;
721 }
722 }
723
724 /**
725 * AT+CREG
726 * Set command controls the presentation of an unsolicited result code
727 * +CREG: <stat> when <n>=1 and there is a change in the MT’s circuit
728 * mode network registration status in GERAN/UTRAN/E-UTRAN, or unsolicited
729 * result code +CREG: <stat>[,[<lac>],[<ci>],[<AcT>]]
730 * when <n>=2 and there is a change of the network cell in GERAN/UTRAN/E-UTRAN. The
731 * parameters <AcT>, <lac> and <ci> are sent only if available.
732 * The value <n>=3 further extends the unsolicited result code with [,<cause_type>,
733 * <reject_cause>], when available, when the value of <stat> changes.
734 *
735 * command Possible response(s)
736 * +CREG=[<n>] +CME ERROR: <err>
737 *
738 * +CREG? +CREG: <n>,<stat>[,[<lac>],[<ci>],[<AcT>]
739 * [,<cause_type>,<reject_cause>]]
740 *
741 * <n>: integer type
742 * 0 disable network registration unsolicited result code
743 * 1 enable network registration unsolicited result code +CREG: <stat>
744 * 2 enable network registration and location information unsolicited
745 * result code +CREG: <stat>[,[<lac>],[<ci>],[<AcT>]]
746 * 3 enable network registration, location information and cause value
747 * information unsolicited result code +CREG: <stat>[,[<lac>],[<ci>],
748 * [<AcT>][,<cause_type>,<reject_cause>]]
749 *
750 * <stat>: integer type;
751 * 0 not registered, MT is not currently searching a new operator to register to
752 * 1 registered, home network
753 * 2 not registered, but MT is currently searching a new operator to register to
754 * 3 registration denied
755 * 4 unknown (e.g. out of GERAN/UTRAN/E-UTRAN coverage)
756 * 5 registered, roaming
757 *
758 * <lac>: string type; two byte location area code (when <AcT> indicates
759 * value 0 to 6), or tracking area code (when <AcT> indicates
760 * value 7). In hexadecimal format
761 * <ci>: string type; four byte GERAN/UTRAN/E-UTRAN cell ID in
762 * hexadecimal format
763 * <AcT>: refer line 190
764 *
765 * see RIL_REQUEST_VOICE_REGISTRATION_STATE or in RIL
766 */
HandleVoiceNetworkRegistration(const Client & client,std::string & command)767 void NetworkService::HandleVoiceNetworkRegistration(const Client& client,
768 std::string& command) {
769 std::vector<std::string> responses;
770 std::stringstream ss;
771
772 CommandParser cmd(command);
773 cmd.SkipPrefix();
774 if (*cmd == "AT+CREG?") {
775 ss << "+CREG: " << voice_registration_status_.unsol_mode << ","
776 << voice_registration_status_.registration_state;
777 if (voice_registration_status_.unsol_mode ==
778 NetworkRegistrationStatus::REGISTRATION_UNSOL_ENABLED_FULL &&
779 (voice_registration_status_.registration_state ==
780 NET_REGISTRATION_HOME ||
781 voice_registration_status_.registration_state ==
782 NET_REGISTRATION_ROAMING ||
783 voice_registration_status_.registration_state ==
784 NET_REGISTRATION_EMERGENCY)) {
785 ss << ",\"" << kAreaCode << "\"" << ",\"" << kCellId << "\","
786 << voice_registration_status_.network_type;
787 }
788
789 responses.push_back(ss.str());
790 } else {
791 int n = cmd.GetNextInt();
792 switch (n) {
793 case 0:
794 voice_registration_status_.unsol_mode =
795 NetworkRegistrationStatus::REGISTRATION_UNSOL_DISABLED;
796 break;
797 case 1:
798 voice_registration_status_.unsol_mode =
799 NetworkRegistrationStatus::REGISTRATION_UNSOL_ENABLED;
800 break;
801 case 2:
802 voice_registration_status_.unsol_mode =
803 NetworkRegistrationStatus::REGISTRATION_UNSOL_ENABLED_FULL;
804 break;
805 default:
806 client.SendCommandResponse(kCmeErrorInCorrectParameters);
807 return;
808 }
809 }
810 responses.push_back("OK");
811 client.SendCommandResponse(responses);
812 }
813
814 /**
815 * AT+CGREG
816 * The set command controls the presentation of an unsolicited result
817 * code +CGREG: <stat> when <n>=1 and there is a change in the MT's
818 * GPRS network registration status, or code +CGREG: <stat>[,<lac>,
819 * <ci>[,<AcT>]] when <n>=2 and there is a change of the network cell.
820 *
821 * command Possible response(s)
822 * +CGREG=[<n>] +CME ERROR: <err>
823 *
824 * +CGREG? when <n>=0, 1, 2 or 3 and command successful:
825 * +CGREG: <n>,<stat>[,[<lac>],[<ci>],[<AcT>],
826 * [<rac>][,<cause_type>,<reject_cause>]]
827 * when <n>=4 or 5 and command successful:
828 * +CGREG: <n>,<stat>[,[<lac>],[<ci>],[<AcT>],
829 * [<rac>][,[<cause_type>],[<reject_cause>][,
830 * [<Active-Time>],[<Periodic-RAU>],
831 * [<GPRS-READY-timer>]]]]
832 * [,<cause_type>,<reject_cause>]]
833 *
834 * note: see AT+CREG
835 *
836 * see RIL_REQUEST_DATA_REGISTRATION_STATE in RIL
837 */
HandleDataNetworkRegistration(const Client & client,std::string & command)838 void NetworkService::HandleDataNetworkRegistration(const Client& client,
839 std::string& command) {
840 std::vector<std::string> responses;
841 std::stringstream ss;
842 std::string prefix;
843
844 CommandParser cmd(command);
845 cmd.SkipPrefix();
846 if (command.find("CGREG") != std::string::npos) {
847 prefix = "+CGREG: ";
848 } else if (command.find("CEREG") != std::string::npos){
849 prefix = "+CEREG: ";
850 }
851
852 if (*cmd == "AT+CGREG?" || *cmd == "AT+CEREG?") {
853 ss << prefix << data_registration_status_.unsol_mode << ","
854 << data_registration_status_.registration_state;
855 if (voice_registration_status_.unsol_mode ==
856 NetworkRegistrationStatus::REGISTRATION_UNSOL_ENABLED_FULL &&
857 (voice_registration_status_.registration_state ==
858 NET_REGISTRATION_HOME ||
859 voice_registration_status_.registration_state ==
860 NET_REGISTRATION_ROAMING ||
861 voice_registration_status_.registration_state ==
862 NET_REGISTRATION_EMERGENCY)) {
863 data_registration_status_.network_type =
864 getNetworkTypeFromTech(current_network_mode_);
865 ss << ",\"" << kAreaCode << "\"" << ",\"" << kCellId << "\"" << ","
866 << data_registration_status_.network_type;
867 }
868 responses.push_back(ss.str());
869 } else {
870 int n = cmd.GetNextInt();
871 switch (n) {
872 case 0:
873 data_registration_status_.unsol_mode =
874 NetworkRegistrationStatus::REGISTRATION_UNSOL_DISABLED;
875 break;
876 case 1:
877 data_registration_status_.unsol_mode =
878 NetworkRegistrationStatus::REGISTRATION_UNSOL_ENABLED;
879 break;
880 case 2:
881 data_registration_status_.unsol_mode =
882 NetworkRegistrationStatus::REGISTRATION_UNSOL_ENABLED_FULL;
883 break;
884 default:
885 client.SendCommandResponse(kCmeErrorInCorrectParameters);
886 return;
887 }
888 }
889 responses.push_back("OK");
890 client.SendCommandResponse(responses);
891 }
892
893 /* AT+CTEC? */
HandleGetPreferredNetworkType(const Client & client)894 void NetworkService::HandleGetPreferredNetworkType(const Client& client) {
895 std::vector<std::string> responses;
896 std::stringstream ss;
897
898 ss << "+CTEC: " << current_network_mode_ << "," << std::hex << preferred_network_mode_;
899
900 responses.push_back(ss.str());
901 responses.push_back("OK");
902 client.SendCommandResponse(responses);
903 }
904
905 /* AT+CTEC=? */
HandleQuerySupportedTechs(const Client & client)906 void NetworkService::HandleQuerySupportedTechs(const Client& client) {
907 std::vector<std::string> responses;
908 std::stringstream ss;
909 ss << "+CTEC: 0,1,5,6"; // NR | LTE | WCDMA | GSM
910 responses.push_back(ss.str());
911 responses.push_back("OK");
912 client.SendCommandResponse(responses);
913 }
914
915 /**
916 * Preferred mode bitmask. This is actually 4 byte-sized bitmasks with different priority values,
917 * in which the byte number from LSB to MSB give the priority.
918 *
919 * |MSB| | |LSB
920 * value: |00 |00 |00 |00
921 * byte #: |3 |2 |1 |0
922 *
923 * Higher byte order give higher priority. Thus, a value of 0x0000000f represents
924 * a preferred mode of GSM, WCDMA, CDMA, and EvDo in which all are equally preferrable, whereas
925 * 0x00000201 represents a mode with GSM and WCDMA, in which WCDMA is preferred over GSM
926 */
getModemTechFromPrefer(int preferred_mask)927 int NetworkService::getModemTechFromPrefer(int preferred_mask) {
928 int i, j;
929
930 // Current implementation will only return the highest priority,
931 // lowest numbered technology that is set in the mask.
932 for (i = 3 ; i >= 0; i--) {
933 for (j = 7 ; j >= 0 ; j--) {
934 if (preferred_mask & (1 << (j + 8 * i)))
935 return 1 << j;
936 }
937 }
938 // This should never happen. Just to please the compiler.
939 return ModemTechnology::M_MODEM_TECH_GSM;
940 }
941
UpdateRegisterState(RegistrationState state)942 void NetworkService::UpdateRegisterState(RegistrationState state ) {
943 voice_registration_status_.registration_state = state;
944 data_registration_status_.registration_state = state;
945 voice_registration_status_.network_type =
946 (NetworkRegistrationStatus::AccessTechnoloy)getNetworkTypeFromTech(current_network_mode_);
947 data_registration_status_.network_type =
948 (NetworkRegistrationStatus::AccessTechnoloy)getNetworkTypeFromTech(current_network_mode_);
949
950 OnVoiceRegisterStateChanged();
951 OnDataRegisterStateChanged();
952 OnSignalStrengthChanged();
953
954 int cellBandwidthDownlink = 5000;
955 const int UNKNOWN = 0;
956 const int MMWAVE = 4;
957 int freq = UNKNOWN;
958 if (current_network_mode_ == M_MODEM_TECH_NR) {
959 freq = MMWAVE;
960 cellBandwidthDownlink = 50000;
961 }
962
963 data_service_->onUpdatePhysicalChannelconfigs(current_network_mode_, freq,
964 cellBandwidthDownlink);
965 }
966
967 /* AT+CTEC=current,preferred */
HandleSetPreferredNetworkType(const Client & client,std::string & command)968 void NetworkService::HandleSetPreferredNetworkType(const Client& client, std::string& command) {
969 std::vector<std::string> responses;
970 std::stringstream ss;
971 int preferred_mask_new;
972 CommandParser cmd(command);
973 cmd.SkipPrefix();
974
975 int current = cmd.GetNextInt();
976 std::string preferred(cmd.GetNextStr());
977 preferred_mask_new = std::stoi(preferred, nullptr, 16);
978 if (preferred_mask_new != preferred_network_mode_) {
979 current_network_mode_ = (ModemTechnology)getModemTechFromPrefer(preferred_mask_new);
980 preferred_network_mode_ = preferred_mask_new;
981 }
982
983 if (current != current_network_mode_) {
984 UpdateRegisterState(NET_REGISTRATION_UNREGISTERED);
985 signal_strength_.Reset();
986
987 ss << "+CTEC: "<< current_network_mode_;
988
989 thread_looper_->PostWithDelay(std::chrono::seconds(1),
990 makeSafeCallback(this, &NetworkService::UpdateRegisterState,
991 NET_REGISTRATION_HOME));
992 } else {
993 ss << "+CTEC: DONE";
994 }
995
996 auto nvram_config = NvramConfig::Get();
997 auto instance = nvram_config->ForInstance(service_id_);
998 instance.set_modem_technoloy(current_network_mode_);
999 instance.set_preferred_network_mode(preferred_network_mode_);
1000
1001 NvramConfig::SaveToFile();
1002
1003 responses.push_back(ss.str());
1004 responses.push_back("OK");
1005 client.SendCommandResponse(responses);
1006 }
1007
OnVoiceRegisterStateChanged()1008 void NetworkService::OnVoiceRegisterStateChanged() {
1009 std::stringstream ss;
1010
1011 switch (voice_registration_status_.unsol_mode) {
1012 case NetworkRegistrationStatus::REGISTRATION_UNSOL_ENABLED:
1013 ss << "+CREG: " << voice_registration_status_.registration_state;
1014 break;
1015 case NetworkRegistrationStatus::REGISTRATION_UNSOL_ENABLED_FULL:
1016 ss << "+CREG: " << voice_registration_status_.registration_state;
1017 if (voice_registration_status_.registration_state ==
1018 NET_REGISTRATION_HOME ||
1019 voice_registration_status_.registration_state ==
1020 NET_REGISTRATION_ROAMING) {
1021 ss << ",\""<< kAreaCode << "\",\"" << kCellId << "\","
1022 << voice_registration_status_.network_type;
1023 }
1024 break;
1025 default :
1026 return;
1027 }
1028 SendUnsolicitedCommand(ss.str());
1029 }
1030
OnDataRegisterStateChanged()1031 void NetworkService::OnDataRegisterStateChanged() {
1032 std::stringstream ss;
1033
1034 switch (data_registration_status_.unsol_mode) {
1035 case NetworkRegistrationStatus::REGISTRATION_UNSOL_ENABLED:
1036 ss << "+CGREG: " << data_registration_status_.registration_state;
1037 if (data_registration_status_.network_type ==
1038 NetworkRegistrationStatus::ACESS_TECH_EUTRAN) {
1039 ss << "\r+CEREG: " << data_registration_status_.registration_state;
1040 }
1041 break;
1042 case NetworkRegistrationStatus::REGISTRATION_UNSOL_ENABLED_FULL:
1043 ss << "+CGREG: " << data_registration_status_.registration_state;
1044 if (data_registration_status_.registration_state ==
1045 NET_REGISTRATION_HOME ||
1046 data_registration_status_.registration_state ==
1047 NET_REGISTRATION_ROAMING) {
1048 ss << ",\"" << kAreaCode << "\",\"" << kCellId << "\","
1049 << data_registration_status_.network_type;
1050 }
1051 if (data_registration_status_.network_type ==
1052 NetworkRegistrationStatus::ACESS_TECH_EUTRAN) {
1053 ss << "\r+CEREG: " << data_registration_status_.registration_state;
1054 if (data_registration_status_.registration_state ==
1055 NET_REGISTRATION_HOME ||
1056 data_registration_status_.registration_state ==
1057 NET_REGISTRATION_ROAMING) {
1058 ss << ",\"" << kAreaCode << "\",\"" << kCellId << "\","
1059 << data_registration_status_.network_type;
1060 }
1061 }
1062 break;
1063 default:
1064 return;
1065 }
1066 SendUnsolicitedCommand(ss.str());
1067 }
1068
GetSignalStrength()1069 std::string NetworkService::GetSignalStrength() {
1070 switch (current_network_mode_) {
1071 case M_MODEM_TECH_GSM:
1072 signal_strength_.gsm_rssi += (rand() % 3 - 1);
1073 AdjustSignalStrengthValue(signal_strength_.gsm_rssi, kGSMSignalStrength);
1074 break;
1075 case M_MODEM_TECH_CDMA:
1076 signal_strength_.cdma_dbm += (rand() % 3 - 1);
1077 AdjustSignalStrengthValue(signal_strength_.cdma_dbm, kCDMASignalStrength);
1078 break;
1079 case M_MODEM_TECH_EVDO:
1080 signal_strength_.evdo_dbm += (rand() % 3 - 1);
1081 AdjustSignalStrengthValue(signal_strength_.evdo_dbm, kEVDOSignalStrength);
1082 break;
1083 case M_MODEM_TECH_LTE:
1084 signal_strength_.lte_rssi += (rand() % 3 - 1);
1085 AdjustSignalStrengthValue(signal_strength_.lte_rssi, kLTESignalStrength);
1086 break;
1087 case M_MODEM_TECH_WCDMA:
1088 signal_strength_.wcdma_rssi += (rand() % 3 - 1);
1089 AdjustSignalStrengthValue(signal_strength_.wcdma_rssi, kWCDMASignalStrength);
1090 break;
1091 case M_MODEM_TECH_NR:
1092 signal_strength_.nr_ss_rsrp += (rand() % 3 - 1);
1093 AdjustSignalStrengthValue(signal_strength_.nr_ss_rsrp, kNRSignalStrength);
1094 break;
1095 default:
1096 break;
1097 }
1098
1099 std::stringstream ss;
1100 ss << "+CSQ: " << signal_strength_.gsm_rssi << ","
1101 << signal_strength_.gsm_ber << ","
1102 << signal_strength_.cdma_dbm << ","
1103 << signal_strength_.cdma_ecio << ","
1104 << signal_strength_.evdo_dbm << ","
1105 << signal_strength_.evdo_ecio << ","
1106 << signal_strength_.evdo_snr << ","
1107 << signal_strength_.lte_rssi << ","
1108 << signal_strength_.lte_rsrp << ","
1109 << signal_strength_.lte_rsrq << ","
1110 << signal_strength_.lte_rssnr << ","
1111 << signal_strength_.lte_cqi << ","
1112 << signal_strength_.lte_ta << ","
1113 << signal_strength_.tdscdma_rscp << ","
1114 << signal_strength_.wcdma_rssi << ","
1115 << signal_strength_.wcdma_ber << ","
1116 << signal_strength_.nr_ss_rsrp << ","
1117 << signal_strength_.nr_ss_rsrq << ","
1118 << signal_strength_.nr_ss_sinr << ","
1119 << signal_strength_.nr_csi_rsrp << ","
1120 << signal_strength_.nr_csi_rsrq << ","
1121 << signal_strength_.nr_csi_sinr;;
1122 return ss.str();
1123 }
1124
1125 /* AT+REMOTEREG: state*/
HandleReceiveRemoteVoiceDataReg(const Client & client,std::string & command)1126 void NetworkService::HandleReceiveRemoteVoiceDataReg(const Client& client,
1127 std::string& command) {
1128 (void)client;
1129 std::stringstream ss;
1130 std::string states = command.substr(std::string("AT+REMOTEREG:").size());
1131 int stated = std::stoi(states, nullptr, 10);
1132
1133 UpdateRegisterState(NET_REGISTRATION_UNREGISTERED);
1134 signal_strength_.Reset();
1135
1136 thread_looper_->PostWithDelay(
1137 std::chrono::seconds(1),
1138 makeSafeCallback(this, &NetworkService::UpdateRegisterState,
1139 (cuttlefish::NetworkService::RegistrationState)stated));
1140 }
1141
1142 /* AT+REMOTECTEC: ctec */
HandleReceiveRemoteCTEC(const Client & client,std::string & command)1143 void NetworkService::HandleReceiveRemoteCTEC(const Client& client,
1144 std::string& command) {
1145 (void)client;
1146 LOG(DEBUG) << "calling ctec from remote";
1147 std::stringstream ss;
1148 std::string types = command.substr(std::string("AT+REMOTECTEC: ").size());
1149 int preferred_mask_new = std::stoi(types, nullptr, 10);
1150
1151 if (preferred_mask_new != preferred_network_mode_) {
1152 preferred_network_mode_ = preferred_mask_new;
1153 }
1154 auto current_network_mode_new =
1155 (ModemTechnology)getModemTechFromPrefer(preferred_mask_new);
1156 if (current_network_mode_new != current_network_mode_) {
1157 current_network_mode_ = current_network_mode_new;
1158 auto saved_state = voice_registration_status_.registration_state;
1159 UpdateRegisterState(NET_REGISTRATION_UNREGISTERED);
1160 signal_strength_.Reset();
1161
1162 ss << "+CTEC: " << current_network_mode_;
1163
1164 thread_looper_->PostWithDelay(
1165 std::chrono::seconds(1),
1166 makeSafeCallback(this, &NetworkService::UpdateRegisterState,
1167 saved_state));
1168 }
1169 }
1170
1171 /* AT+REMOTESIGNAL: percent */
HandleReceiveRemoteSignal(const Client & client,std::string & command)1172 void NetworkService::HandleReceiveRemoteSignal(const Client& client,
1173 std::string& command) {
1174 (void)client;
1175 std::stringstream ss;
1176 std::string percents = command.substr(std::string("AT+REMOTESIGNAL:").size());
1177 double percentd = std::stoi(percents, nullptr, 10) / 100.0;
1178
1179 switch (current_network_mode_) {
1180 case M_MODEM_TECH_GSM:
1181 SetSignalStrengthValue(signal_strength_.gsm_rssi, kGSMSignalStrength,
1182 percentd);
1183 break;
1184 case M_MODEM_TECH_CDMA:
1185 SetSignalStrengthValue(signal_strength_.cdma_dbm, kCDMASignalStrength,
1186 percentd);
1187 break;
1188 case M_MODEM_TECH_EVDO:
1189 SetSignalStrengthValue(signal_strength_.evdo_dbm, kEVDOSignalStrength,
1190 percentd);
1191 break;
1192 case M_MODEM_TECH_LTE:
1193 SetSignalStrengthValue(signal_strength_.lte_rssi, kLTESignalStrength,
1194 percentd);
1195 break;
1196 case M_MODEM_TECH_WCDMA:
1197 SetSignalStrengthValue(signal_strength_.wcdma_rssi, kWCDMASignalStrength,
1198 percentd);
1199 break;
1200 case M_MODEM_TECH_NR:
1201 SetSignalStrengthValue(signal_strength_.nr_ss_rsrp, kNRSignalStrength,
1202 percentd);
1203 break;
1204 default:
1205 break;
1206 }
1207
1208 auto command2 = GetSignalStrength();
1209 SendUnsolicitedCommand(command2);
1210 }
1211
OnSignalStrengthChanged()1212 void NetworkService::OnSignalStrengthChanged() {
1213 auto command = GetSignalStrength();
1214 SendUnsolicitedCommand(command);
1215 }
1216
GetVoiceRegistrationState() const1217 NetworkService::RegistrationState NetworkService::GetVoiceRegistrationState() const {
1218 return voice_registration_status_.registration_state;
1219 }
1220 } // namespace cuttlefish
1221