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