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