2 * uqmi -- tiny QMI support implementation
4 * Copyright (C) 2014-2015 Felix Fietkau <nbd@openwrt.org>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA.
23 #include "qmi-message.h"
26 #include <libubox/blobmsg.h>
28 /* According to libqmi, a value of -32768 in 5G
29 * indicates that the modem is not connected. */
30 #define _5GNR_NOT_CONNECTED_VALUE -32768
32 static struct qmi_nas_get_tx_rx_info_request tx_rx_req
;
33 static struct qmi_nas_set_system_selection_preference_request sel_req
;
40 print_earfcn_info(uint32_t earfcn
)
42 /* https://www.sqimway.com/lte_band.php */
50 { 0, 599, 1, 2100, "FDD" },
51 { 600, 1199, 2, 1800, "FDD" },
52 { 1200, 1949, 3, 1800, "FDD" },
53 { 1950, 2399, 4, 1700, "FDD" },
54 { 2400, 2649, 5, 850, "FDD" },
55 { 2650, 2749, 6, 800, "FDD" },
56 { 2750, 3449, 7, 2600, "FDD" },
57 { 3450, 3799, 8, 900, "FDD" },
58 { 3800, 4149, 9, 1800, "FDD" },
59 { 4150, 4749, 10, 1700, "FDD" },
60 { 4750, 4999, 11, 1500, "FDD" },
61 { 5000, 5179, 12, 700, "FDD" },
62 { 5180, 5279, 13, 700, "FDD" },
63 { 5280, 5379, 14, 700, "FDD" },
64 { 5730, 5849, 17, 700, "FDD" },
65 { 5850, 5999, 18, 850, "FDD" },
66 { 6000, 6149, 19, 850, "FDD" },
67 { 6150, 6449, 20, 800, "FDD" },
68 { 6450, 6599, 21, 1500, "FDD" },
69 { 6600, 7399, 22, 3500, "FDD" },
70 { 7500, 7699, 23, 2000, "FDD" },
71 { 7700, 8039, 24, 1600, "FDD" },
72 { 8040, 8689, 25, 1900, "FDD" },
73 { 8690, 9039, 26, 850, "FDD" },
74 { 9040, 9209, 27, 800, "FDD" },
75 { 9210, 9659, 28, 700, "FDD" },
76 { 9660, 9769, 29, 700, "SDL" },
77 { 9770, 9869, 30, 2300, "FDD" },
78 { 9870, 9919, 31, 450, "FDD" },
79 { 9920, 10359, 32, 1500, "SDL" },
80 { 36000, 36199, 33, 1900, "TDD" },
81 { 36200, 36349, 34, 2000, "TDD" },
82 { 36350, 36949, 35, 1900, "TDD" },
83 { 36950, 37549, 36, 1900, "TDD" },
84 { 37550, 37749, 37, 1900, "TDD" },
85 { 37750, 38249, 38, 2600, "TDD" },
86 { 38250, 38649, 39, 1900, "TDD" },
87 { 38650, 39649, 40, 2300, "TDD" },
88 { 39650, 41589, 41, 2500, "TDD" },
89 { 41590, 43589, 42, 3500, "TDD" },
90 { 43590, 45589, 43, 3700, "TDD" },
91 { 45590, 46589, 44, 700, "TDD" },
94 for (int i
= 0; i
< (sizeof(earfcn_ranges
) / sizeof(*earfcn_ranges
)); i
++) {
95 if (earfcn
<= earfcn_ranges
[i
].max
&& earfcn
>= earfcn_ranges
[i
].min
) {
96 blobmsg_add_u32(&status
, "band", earfcn_ranges
[i
].band
);
97 blobmsg_add_u32(&status
, "frequency", earfcn_ranges
[i
].freq
);
98 blobmsg_add_string(&status
, "duplex", earfcn_ranges
[i
].duplex
);
105 print_radio_interface(int8_t radio_interface
)
107 switch (radio_interface
) {
108 case QMI_NAS_RADIO_INTERFACE_NONE
:
110 case QMI_NAS_RADIO_INTERFACE_CDMA_1X
:
112 case QMI_NAS_RADIO_INTERFACE_CDMA_1XEVDO
:
113 return "cdma-1x_evdo";
114 case QMI_NAS_RADIO_INTERFACE_AMPS
:
116 case QMI_NAS_RADIO_INTERFACE_GSM
:
118 case QMI_NAS_RADIO_INTERFACE_UMTS
:
120 case QMI_NAS_RADIO_INTERFACE_LTE
:
122 case QMI_NAS_RADIO_INTERFACE_TD_SCDMA
:
124 case QMI_NAS_RADIO_INTERFACE_5GNR
:
131 #define cmd_nas_do_set_system_selection_cb no_cb
132 static enum qmi_cmd_result
133 cmd_nas_do_set_system_selection_prepare(struct qmi_dev
*qmi
, struct qmi_request
*req
, struct qmi_msg
*msg
, char *arg
)
135 qmi_set_nas_set_system_selection_preference_request(msg
, &sel_req
);
136 return QMI_CMD_REQUEST
;
139 static enum qmi_cmd_result
142 static bool use_sel_req
= false;
146 uqmi_add_command(NULL
, __UQMI_COMMAND_nas_do_set_system_selection
);
152 #define cmd_nas_set_network_modes_cb no_cb
153 static enum qmi_cmd_result
154 cmd_nas_set_network_modes_prepare(struct qmi_dev
*qmi
, struct qmi_request
*req
, struct qmi_msg
*msg
, char *arg
)
156 static const struct {
158 QmiNasRatModePreference val
;
160 { "cdma", QMI_NAS_RAT_MODE_PREFERENCE_CDMA_1X
| QMI_NAS_RAT_MODE_PREFERENCE_CDMA_1XEVDO
},
161 { "td-scdma", QMI_NAS_RAT_MODE_PREFERENCE_TD_SCDMA
},
162 { "gsm", QMI_NAS_RAT_MODE_PREFERENCE_GSM
},
163 { "umts", QMI_NAS_RAT_MODE_PREFERENCE_UMTS
},
164 { "lte", QMI_NAS_RAT_MODE_PREFERENCE_LTE
},
165 { "5gnr", QMI_NAS_RAT_MODE_PREFERENCE_5GNR
},
167 QmiNasRatModePreference val
= 0;
171 for (word
= strtok(arg
, ",");
173 word
= strtok(NULL
, ",")) {
176 for (i
= 0; i
< ARRAY_SIZE(modes
); i
++) {
177 if (strcmp(word
, modes
[i
].name
) != 0 &&
178 strcmp(word
, "all") != 0)
186 uqmi_add_error("Invalid network mode");
191 qmi_set(&sel_req
, mode_preference
, val
);
192 return do_sel_network();
195 #define cmd_nas_set_network_preference_cb no_cb
196 static enum qmi_cmd_result
197 cmd_nas_set_network_preference_prepare(struct qmi_dev
*qmi
, struct qmi_request
*req
, struct qmi_msg
*msg
, char *arg
)
199 QmiNasGsmWcdmaAcquisitionOrderPreference pref
= QMI_NAS_GSM_WCDMA_ACQUISITION_ORDER_PREFERENCE_AUTOMATIC
;
201 if (!strcmp(arg
, "gsm"))
202 pref
= QMI_NAS_GSM_WCDMA_ACQUISITION_ORDER_PREFERENCE_GSM
;
203 else if (!strcmp(arg
, "wcdma"))
204 pref
= QMI_NAS_GSM_WCDMA_ACQUISITION_ORDER_PREFERENCE_WCDMA
;
206 qmi_set(&sel_req
, gsm_wcdma_acquisition_order_preference
, pref
);
207 return do_sel_network();
210 #define cmd_nas_set_roaming_cb no_cb
211 static enum qmi_cmd_result
212 cmd_nas_set_roaming_prepare(struct qmi_dev
*qmi
, struct qmi_request
*req
, struct qmi_msg
*msg
, char *arg
)
214 QmiNasRoamingPreference pref
;
216 if (!strcmp(arg
, "any"))
217 pref
= QMI_NAS_ROAMING_PREFERENCE_ANY
;
218 else if (!strcmp(arg
, "only"))
219 pref
= QMI_NAS_ROAMING_PREFERENCE_NOT_OFF
;
220 else if (!strcmp(arg
, "off"))
221 pref
= QMI_NAS_ROAMING_PREFERENCE_OFF
;
223 return uqmi_add_error("Invalid argument");
225 qmi_set(&sel_req
, roaming_preference
, pref
);
226 return do_sel_network();
229 #define cmd_nas_set_mcc_cb no_cb
230 static enum qmi_cmd_result
231 cmd_nas_set_mcc_prepare(struct qmi_dev
*qmi
, struct qmi_request
*req
, struct qmi_msg
*msg
, char *arg
)
234 int value
= strtoul(arg
, &err
, 10);
236 uqmi_add_error("Invalid MCC value");
240 sel_req
.data
.network_selection_preference
.mcc
= value
;
241 plmn_code_flag
.mcc_is_set
= true;
245 #define cmd_nas_set_mnc_cb no_cb
246 static enum qmi_cmd_result
247 cmd_nas_set_mnc_prepare(struct qmi_dev
*qmi
, struct qmi_request
*req
, struct qmi_msg
*msg
, char *arg
)
250 int value
= strtoul(arg
, &err
, 10);
252 uqmi_add_error("Invalid MNC value");
256 sel_req
.data
.network_selection_preference
.mnc
= value
;
257 plmn_code_flag
.mnc_is_set
= true;
261 #define cmd_nas_set_plmn_cb no_cb
262 static enum qmi_cmd_result
263 cmd_nas_set_plmn_prepare(struct qmi_dev
*qmi
, struct qmi_request
*req
, struct qmi_msg
*msg
, char *arg
)
265 sel_req
.set
.network_selection_preference
= 1;
266 sel_req
.data
.network_selection_preference
.mode
= QMI_NAS_NETWORK_SELECTION_PREFERENCE_AUTOMATIC
;
268 if (!plmn_code_flag
.mcc_is_set
&& plmn_code_flag
.mnc_is_set
) {
269 uqmi_add_error("No MCC value");
273 if (plmn_code_flag
.mcc_is_set
&& sel_req
.data
.network_selection_preference
.mcc
) {
274 if (!plmn_code_flag
.mnc_is_set
) {
275 uqmi_add_error("No MNC value");
278 sel_req
.data
.network_selection_preference
.mode
= QMI_NAS_NETWORK_SELECTION_PREFERENCE_MANUAL
;
282 return do_sel_network();
285 #define cmd_nas_initiate_network_register_cb no_cb
286 static enum qmi_cmd_result
287 cmd_nas_initiate_network_register_prepare(struct qmi_dev
*qmi
, struct qmi_request
*req
, struct qmi_msg
*msg
, char *arg
)
289 static struct qmi_nas_initiate_network_register_request register_req
= {
290 QMI_INIT(action
, QMI_NAS_NETWORK_REGISTER_TYPE_AUTOMATIC
)
293 qmi_set_nas_initiate_network_register_request(msg
, ®ister_req
);
294 return QMI_CMD_REQUEST
;
298 cmd_nas_get_signal_info_cb(struct qmi_dev
*qmi
, struct qmi_request
*req
, struct qmi_msg
*msg
)
300 struct qmi_nas_get_signal_info_response res
;
302 bool is_5gnr_connected
= false;
303 bool is_5gnr_endc
= false;
305 qmi_parse_nas_get_signal_info_response(msg
, &res
);
307 /* If 5G NR EN-DC (dual connectivity) is enabled, the mobile device has two connections,
308 * one with the LTE base station, and one with the NR base station.
309 * Therefore an array of signals has to be reported in this case. */
310 is_5gnr_connected
= ((res
.set
._5g_signal_strength
&&
311 ((res
.data
._5g_signal_strength
.rsrp
!= _5GNR_NOT_CONNECTED_VALUE
) ||
312 (res
.data
._5g_signal_strength
.snr
!= _5GNR_NOT_CONNECTED_VALUE
))) ||
313 (res
.set
._5g_signal_strength_extended
&&
314 (res
.data
._5g_signal_strength_extended
!= _5GNR_NOT_CONNECTED_VALUE
)));
315 is_5gnr_endc
= (res
.set
.lte_signal_strength
&& is_5gnr_connected
);
318 a
= blobmsg_open_array(&status
, NULL
);
321 c
= blobmsg_open_table(&status
, NULL
);
322 if (res
.set
.cdma_signal_strength
) {
323 blobmsg_add_string(&status
, "type", "cdma");
324 blobmsg_add_u32(&status
, "rssi", (int32_t) res
.data
.cdma_signal_strength
.rssi
);
325 blobmsg_add_u32(&status
, "ecio", (int32_t) res
.data
.cdma_signal_strength
.ecio
);
328 if (res
.set
.hdr_signal_strength
) {
329 blobmsg_add_string(&status
, "type", "hdr");
330 blobmsg_add_u32(&status
, "rssi", (int32_t) res
.data
.hdr_signal_strength
.rssi
);
331 blobmsg_add_u32(&status
, "ecio", (int32_t) res
.data
.hdr_signal_strength
.ecio
);
332 blobmsg_add_u32(&status
, "io", res
.data
.hdr_signal_strength
.io
);
335 if (res
.set
.gsm_signal_strength
) {
336 blobmsg_add_string(&status
, "type", "gsm");
337 blobmsg_add_u32(&status
, "signal", (int32_t) res
.data
.gsm_signal_strength
);
340 if (res
.set
.wcdma_signal_strength
) {
341 blobmsg_add_string(&status
, "type", "wcdma");
342 blobmsg_add_u32(&status
, "rssi", (int32_t) res
.data
.wcdma_signal_strength
.rssi
);
343 blobmsg_add_u32(&status
, "ecio", (int32_t) res
.data
.wcdma_signal_strength
.ecio
);
346 if (res
.set
.lte_signal_strength
) {
347 blobmsg_add_string(&status
, "type", "lte");
348 blobmsg_add_u32(&status
, "rssi", (int32_t) res
.data
.lte_signal_strength
.rssi
);
349 blobmsg_add_u32(&status
, "rsrq", (int32_t) res
.data
.lte_signal_strength
.rsrq
);
350 blobmsg_add_u32(&status
, "rsrp", (int32_t) res
.data
.lte_signal_strength
.rsrp
);
351 blobmsg_add_double(&status
, "snr", (double) res
.data
.lte_signal_strength
.snr
*0.1);
354 if (res
.set
.tdma_signal_strength
) {
355 blobmsg_add_string(&status
, "type", "tdma");
356 blobmsg_add_u32(&status
, "signal", (int32_t) res
.data
.tdma_signal_strength
);
359 if (is_5gnr_connected
) {
361 blobmsg_close_table(&status
, c
);
362 c
= blobmsg_open_table(&status
, NULL
);
364 blobmsg_add_string(&status
, "type", "5gnr");
365 if (res
.set
._5g_signal_strength
) {
366 if (res
.data
._5g_signal_strength
.rsrp
!= _5GNR_NOT_CONNECTED_VALUE
)
367 blobmsg_add_u32(&status
, "rsrp", (int32_t) res
.data
._5g_signal_strength
.rsrp
);
368 if (res
.data
._5g_signal_strength
.snr
!= _5GNR_NOT_CONNECTED_VALUE
)
369 blobmsg_add_double(&status
, "snr", (double) res
.data
._5g_signal_strength
.snr
*0.1);
372 if (res
.set
._5g_signal_strength_extended
&&
373 (res
.data
._5g_signal_strength_extended
!= _5GNR_NOT_CONNECTED_VALUE
)) {
374 blobmsg_add_u32(&status
, "rsrq", (int32_t) res
.data
._5g_signal_strength_extended
);
378 blobmsg_close_table(&status
, c
);
381 blobmsg_close_array(&status
, a
);
386 print_system_info(uint8_t svc_status
, uint8_t tsvc_status
, bool preferred
, bool system_info
,
387 bool domain_valid
, uint8_t domain
,
388 bool service_cap_valid
, uint8_t service_cap
,
389 bool roaming_status_valid
, uint8_t roaming_status
,
390 bool forbidden_valid
, bool forbidden
,
391 bool network_id_valid
, char *mcc
, char *mnc
,
392 bool lac_valid
, uint16_t lac
)
394 static const char *map_service
[] = {
395 [QMI_NAS_SERVICE_STATUS_NONE
] = "none",
396 [QMI_NAS_SERVICE_STATUS_LIMITED
] = "limited",
397 [QMI_NAS_SERVICE_STATUS_AVAILABLE
] = "available",
398 [QMI_NAS_SERVICE_STATUS_LIMITED_REGIONAL
] = "limited regional",
399 [QMI_NAS_SERVICE_STATUS_POWER_SAVE
] = "power save",
402 static const char *map_roaming
[] = {
403 [QMI_NAS_ROAMING_STATUS_OFF
] = "off",
404 [QMI_NAS_ROAMING_STATUS_ON
] = "on",
405 [QMI_NAS_ROAMING_STATUS_BLINK
] = "blink",
406 [QMI_NAS_ROAMING_STATUS_OUT_OF_NEIGHBORHOOD
] = "out of neighborhood",
407 [QMI_NAS_ROAMING_STATUS_OUT_OF_BUILDING
] = "out of building",
408 [QMI_NAS_ROAMING_STATUS_PREFERRED_SYSTEM
] = "preferred system",
409 [QMI_NAS_ROAMING_STATUS_AVAILABLE_SYSTEM
] = "available system",
410 [QMI_NAS_ROAMING_STATUS_ALLIANCE_PARTNER
] = "alliance partner",
411 [QMI_NAS_ROAMING_STATUS_PREMIUM_PARTNER
] = "premium partner",
412 [QMI_NAS_ROAMING_STATUS_FULL_SERVICE
] = "full service",
413 [QMI_NAS_ROAMING_STATUS_PARTIAL_SERVICE
] = "partial service",
414 [QMI_NAS_ROAMING_STATUS_BANNER_ON
] = "banner on",
415 [QMI_NAS_ROAMING_STATUS_BANNER_OFF
] = "banner off",
418 static const char *map_network
[] = {
419 [QMI_NAS_NETWORK_SERVICE_DOMAIN_NONE
] = "none",
420 [QMI_NAS_NETWORK_SERVICE_DOMAIN_CS
] = "cs",
421 [QMI_NAS_NETWORK_SERVICE_DOMAIN_PS
] = "ps",
422 [QMI_NAS_NETWORK_SERVICE_DOMAIN_CS_PS
] = "cs-ps",
423 [QMI_NAS_NETWORK_SERVICE_DOMAIN_UNKNOWN
] = "unknown",
426 blobmsg_add_string(&status
, "service_status", map_service
[svc_status
]);
427 blobmsg_add_string(&status
, "true_service_status", map_service
[tsvc_status
]);
428 blobmsg_add_u8(&status
, "preferred_data_path", preferred
);
432 blobmsg_add_string(&status
, "domain", map_network
[domain
]);
433 if (service_cap_valid
)
434 blobmsg_add_string(&status
, "service", map_network
[service_cap
]);
435 if (roaming_status_valid
)
436 blobmsg_add_string(&status
, "roaming_status", map_roaming
[roaming_status
]);
438 blobmsg_add_u8(&status
, "forbidden", forbidden
);
439 if (network_id_valid
) {
440 blobmsg_add_string(&status
, "mcc", mcc
);
441 if ((uint8_t)mnc
[2] == 255)
443 blobmsg_add_string(&status
, "mnc", mnc
);
446 blobmsg_add_u32(&status
, "location_area_code", (int32_t) lac
);
451 cmd_nas_get_system_info_cb(struct qmi_dev
*qmi
, struct qmi_request
*req
, struct qmi_msg
*msg
)
453 static const char *cell_status
[] = {
454 [QMI_NAS_CELL_ACCESS_STATUS_NORMAL_ONLY
] = "normal",
455 [QMI_NAS_CELL_ACCESS_STATUS_EMERGENCY_ONLY
] = "emergency",
456 [QMI_NAS_CELL_ACCESS_STATUS_NO_CALLS
] = "no calls",
457 [QMI_NAS_CELL_ACCESS_STATUS_ALL_CALLS
] = "all calls",
458 [QMI_NAS_CELL_ACCESS_STATUS_UNKNOWN
] = "unknown",
461 struct qmi_nas_get_system_info_response res
;
464 qmi_parse_nas_get_system_info_response(msg
, &res
);
465 t
= blobmsg_open_table(&status
, NULL
);
466 if (res
.set
.gsm_service_status
) {
467 c
= blobmsg_open_table(&status
, "gsm");
468 print_system_info(res
.data
.gsm_service_status
.service_status
,
469 res
.data
.gsm_service_status
.true_service_status
,
470 res
.data
.gsm_service_status
.preferred_data_path
,
471 res
.set
.gsm_system_info_v2
,
472 res
.data
.gsm_system_info_v2
.domain_valid
,
473 res
.data
.gsm_system_info_v2
.domain
,
474 res
.data
.gsm_system_info_v2
.service_capability_valid
,
475 res
.data
.gsm_system_info_v2
.service_capability
,
476 res
.data
.gsm_system_info_v2
.roaming_status_valid
,
477 res
.data
.gsm_system_info_v2
.roaming_status
,
478 res
.data
.gsm_system_info_v2
.forbidden_valid
,
479 res
.data
.gsm_system_info_v2
.forbidden
,
480 res
.data
.gsm_system_info_v2
.network_id_valid
,
481 res
.data
.gsm_system_info_v2
.mcc
,
482 res
.data
.gsm_system_info_v2
.mnc
,
483 res
.data
.gsm_system_info_v2
.lac_valid
,
484 res
.data
.gsm_system_info_v2
.lac
);
485 if (res
.set
.gsm_system_info_v2
&& res
.data
.gsm_system_info_v2
.cid_valid
)
486 blobmsg_add_u32(&status
, "cell_id",
487 res
.data
.gsm_system_info_v2
.cid
);
488 if (res
.set
.additional_gsm_system_info
&&
489 res
.data
.additional_gsm_system_info
.geo_system_index
!= 0xFFFF)
490 blobmsg_add_u32(&status
, "geo_system_index",
491 res
.data
.additional_gsm_system_info
.geo_system_index
);
492 blobmsg_close_table(&status
, c
);
495 if (res
.set
.wcdma_service_status
) {
496 c
= blobmsg_open_table(&status
, "wcdma");
497 print_system_info(res
.data
.wcdma_service_status
.service_status
,
498 res
.data
.wcdma_service_status
.true_service_status
,
499 res
.data
.wcdma_service_status
.preferred_data_path
,
500 res
.set
.wcdma_system_info_v2
,
501 res
.data
.wcdma_system_info_v2
.domain_valid
,
502 res
.data
.wcdma_system_info_v2
.domain
,
503 res
.data
.wcdma_system_info_v2
.service_capability_valid
,
504 res
.data
.wcdma_system_info_v2
.service_capability
,
505 res
.data
.wcdma_system_info_v2
.roaming_status_valid
,
506 res
.data
.wcdma_system_info_v2
.roaming_status
,
507 res
.data
.wcdma_system_info_v2
.forbidden_valid
,
508 res
.data
.wcdma_system_info_v2
.forbidden
,
509 res
.data
.wcdma_system_info_v2
.network_id_valid
,
510 res
.data
.wcdma_system_info_v2
.mcc
,
511 res
.data
.wcdma_system_info_v2
.mnc
,
512 res
.data
.wcdma_system_info_v2
.lac_valid
,
513 res
.data
.wcdma_system_info_v2
.lac
);
514 if (res
.set
.wcdma_system_info_v2
&& res
.data
.wcdma_system_info_v2
.cid_valid
) {
515 blobmsg_add_u32(&status
, "rnc_id",res
.data
.wcdma_system_info_v2
.cid
/65536);
516 blobmsg_add_u32(&status
, "cell_id",res
.data
.wcdma_system_info_v2
.cid
%65536);
518 if (res
.set
.additional_wcdma_system_info
&&
519 res
.data
.additional_wcdma_system_info
.geo_system_index
!= 0xFFFF)
520 blobmsg_add_u32(&status
, "geo_system_index",
521 res
.data
.additional_wcdma_system_info
.geo_system_index
);
522 blobmsg_close_table(&status
, c
);
525 if (res
.set
.lte_service_status
) {
526 c
= blobmsg_open_table(&status
, "lte");
527 print_system_info(res
.data
.lte_service_status
.service_status
,
528 res
.data
.lte_service_status
.true_service_status
,
529 res
.data
.lte_service_status
.preferred_data_path
,
530 res
.set
.lte_system_info_v2
,
531 res
.data
.lte_system_info_v2
.domain_valid
,
532 res
.data
.lte_system_info_v2
.domain
,
533 res
.data
.lte_system_info_v2
.service_capability_valid
,
534 res
.data
.lte_system_info_v2
.service_capability
,
535 res
.data
.lte_system_info_v2
.roaming_status_valid
,
536 res
.data
.lte_system_info_v2
.roaming_status
,
537 res
.data
.lte_system_info_v2
.forbidden_valid
,
538 res
.data
.lte_system_info_v2
.forbidden
,
539 res
.data
.lte_system_info_v2
.network_id_valid
,
540 res
.data
.lte_system_info_v2
.mcc
,
541 res
.data
.lte_system_info_v2
.mnc
,
542 res
.data
.lte_system_info_v2
.lac_valid
,
543 res
.data
.lte_system_info_v2
.lac
);
544 if (res
.set
.lte_system_info_v2
&& res
.data
.lte_system_info_v2
.tac_valid
)
545 blobmsg_add_u32(&status
, "tracking_area_code",
546 res
.data
.lte_system_info_v2
.tac
);
547 if (res
.set
.lte_system_info_v2
&& res
.data
.lte_system_info_v2
.cid_valid
) {
548 blobmsg_add_u32(&status
, "enodeb_id",res
.data
.lte_system_info_v2
.cid
/256);
549 blobmsg_add_u32(&status
, "cell_id",res
.data
.lte_system_info_v2
.cid
%256);
551 if (res
.set
.additional_lte_system_info
&&
552 res
.data
.additional_lte_system_info
.geo_system_index
!= 0xFFFF)
553 blobmsg_add_u32(&status
, "geo_system_index",
554 res
.data
.additional_lte_system_info
.geo_system_index
);
555 if (res
.set
.lte_voice_support
)
556 blobmsg_add_u8(&status
, "voice_support", res
.data
.lte_voice_support
);
557 if (res
.set
.ims_voice_support
)
558 blobmsg_add_u8(&status
, "ims_voice_support", res
.data
.ims_voice_support
);
559 if (res
.set
.lte_cell_access_status
)
560 blobmsg_add_string(&status
, "cell_access_status",
561 cell_status
[res
.data
.lte_cell_access_status
]);
562 if (res
.set
.network_selection_registration_restriction
)
563 blobmsg_add_u32(&status
, "registration_restriction",
564 res
.data
.network_selection_registration_restriction
);
565 if (res
.set
.lte_registration_domain
)
566 blobmsg_add_u32(&status
, "registration_domain",
567 res
.data
.lte_registration_domain
);
568 if (res
.set
.eutra_with_nr5g_availability
)
569 blobmsg_add_u8(&status
, "5g_nsa_available",
570 res
.data
.eutra_with_nr5g_availability
);
571 if (res
.set
.dcnr_restriction_info
)
572 blobmsg_add_u8(&status
, "dcnr_restriction", res
.data
.dcnr_restriction_info
);
574 blobmsg_close_table(&status
, c
);
577 if (res
.set
.nr5g_service_status_info
) {
578 c
= blobmsg_open_table(&status
, "5gnr");
579 print_system_info(res
.data
.nr5g_service_status_info
.service_status
,
580 res
.data
.nr5g_service_status_info
.true_service_status
,
581 res
.data
.nr5g_service_status_info
.preferred_data_path
,
582 res
.set
.nr5g_system_info
,
583 res
.data
.nr5g_system_info
.domain_valid
,
584 res
.data
.nr5g_system_info
.domain
,
585 res
.data
.nr5g_system_info
.service_capability_valid
,
586 res
.data
.nr5g_system_info
.service_capability
,
587 res
.data
.nr5g_system_info
.roaming_status_valid
,
588 res
.data
.nr5g_system_info
.roaming_status
,
589 res
.data
.nr5g_system_info
.forbidden_valid
,
590 res
.data
.nr5g_system_info
.forbidden
,
591 res
.data
.nr5g_system_info
.network_id_valid
,
592 res
.data
.nr5g_system_info
.mcc
,
593 res
.data
.nr5g_system_info
.mnc
,
594 res
.data
.nr5g_system_info
.lac_valid
,
595 res
.data
.nr5g_system_info
.lac
);
596 if (res
.set
.nr5g_system_info
&& res
.data
.nr5g_system_info
.tac_valid
)
597 blobmsg_add_u32(&status
, "tracking_area_code",
598 res
.data
.nr5g_system_info
.tac
);
599 if (res
.set
.nr5g_system_info
&& res
.data
.nr5g_system_info
.cid_valid
) {
600 blobmsg_add_u32(&status
, "enodeb_id",res
.data
.nr5g_system_info
.cid
/256);
601 blobmsg_add_u32(&status
, "cell_id",res
.data
.nr5g_system_info
.cid
%256);
604 blobmsg_close_table(&status
, c
);
607 blobmsg_close_table(&status
, t
);
610 static enum qmi_cmd_result
611 cmd_nas_get_system_info_prepare(struct qmi_dev
*qmi
, struct qmi_request
*req
, struct qmi_msg
*msg
, char *arg
)
613 qmi_set_nas_get_system_info_request(msg
);
614 return QMI_CMD_REQUEST
;
618 print_channel_info(int32_t cell_id
, int32_t channel
, uint32_t bw
)
620 static const char *map_bandwidth
[] = {
621 [QMI_NAS_DL_BANDWIDTH_1_4
] = "1.4",
622 [QMI_NAS_DL_BANDWIDTH_3
] = "3",
623 [QMI_NAS_DL_BANDWIDTH_5
] = "5",
624 [QMI_NAS_DL_BANDWIDTH_10
] = "10",
625 [QMI_NAS_DL_BANDWIDTH_15
] = "15",
626 [QMI_NAS_DL_BANDWIDTH_20
] = "20",
627 [QMI_NAS_DL_BANDWIDTH_INVALID
] = "invalid",
628 [QMI_NAS_DL_BANDWIDTH_UNKNOWN
] = "unknown",
631 blobmsg_add_u32(&status
, "cell_id", cell_id
);
632 blobmsg_add_u32(&status
, "channel", channel
);
633 print_earfcn_info(channel
);
634 blobmsg_add_string(&status
, "bandwidth", map_bandwidth
[bw
]);
638 cmd_nas_get_lte_cphy_ca_info_cb(struct qmi_dev
*qmi
, struct qmi_request
*req
, struct qmi_msg
*msg
)
640 struct qmi_nas_get_lte_cphy_ca_info_response res
;
641 static const char *scell_state
[] = {
642 [QMI_NAS_SCELL_STATE_DECONFIGURED
] = "deconfigured",
643 [QMI_NAS_SCELL_STATE_DEACTIVATED
] = "deactivated",
644 [QMI_NAS_SCELL_STATE_ACTIVATED
] = "activated",
650 qmi_parse_nas_get_lte_cphy_ca_info_response(msg
, &res
);
651 t
= blobmsg_open_table(&status
, NULL
);
652 if (res
.set
.phy_ca_agg_pcell_info
) {
653 c
= blobmsg_open_table(&status
, "primary");
654 print_channel_info(res
.data
.phy_ca_agg_pcell_info
.physical_cell_id
,
655 res
.data
.phy_ca_agg_pcell_info
.rx_channel
,
656 res
.data
.phy_ca_agg_pcell_info
.dl_bandwidth
);
657 blobmsg_close_table(&status
, c
);
659 if (res
.set
.phy_ca_agg_scell_info
&& res
.data
.phy_ca_agg_secondary_cells_n
) {
660 for (i
= 0; i
< res
.data
.phy_ca_agg_secondary_cells_n
; i
++) {
661 if (res
.data
.phy_ca_agg_secondary_cells
[i
].rx_channel
== 0)
663 sprintf(idx_buf
, "secondary_%d",
664 res
.data
.phy_ca_agg_secondary_cells
[i
].cell_index
);
665 c
= blobmsg_open_table(&status
, idx_buf
);
666 print_channel_info(res
.data
.phy_ca_agg_secondary_cells
[i
].physical_cell_id
,
667 res
.data
.phy_ca_agg_secondary_cells
[i
].rx_channel
,
668 res
.data
.phy_ca_agg_secondary_cells
[i
].dl_bandwidth
);
669 blobmsg_add_string(&status
, "state",
670 scell_state
[res
.data
.phy_ca_agg_secondary_cells
[i
].state
]);
671 blobmsg_close_table(&status
, c
);
674 if (res
.set
.scell_index
)
675 sprintf(idx_buf
, "secondary_%d", res
.data
.scell_index
);
677 sprintf(idx_buf
, "secondary");
678 if (res
.set
.phy_ca_agg_scell_info
&& res
.data
.phy_ca_agg_scell_info
.rx_channel
!= 0) {
679 c
= blobmsg_open_table(&status
, idx_buf
);
680 print_channel_info(res
.data
.phy_ca_agg_scell_info
.physical_cell_id
,
681 res
.data
.phy_ca_agg_scell_info
.rx_channel
,
682 res
.data
.phy_ca_agg_scell_info
.dl_bandwidth
);
683 blobmsg_add_string(&status
, "state",
684 scell_state
[res
.data
.phy_ca_agg_scell_info
.state
]);
685 blobmsg_close_table(&status
, c
);
688 blobmsg_close_table(&status
, t
);
691 static enum qmi_cmd_result
692 cmd_nas_get_lte_cphy_ca_info_prepare(struct qmi_dev
*qmi
, struct qmi_request
*req
, struct qmi_msg
*msg
, char *arg
)
694 qmi_set_nas_get_lte_cphy_ca_info_request(msg
);
695 return QMI_CMD_REQUEST
;
699 print_chain_info(int8_t radio
, bool tuned
, int32_t rssi
, int32_t ecio
, int32_t rsrp
, int32_t rscp
, uint32_t phase
)
701 blobmsg_add_u8(&status
, "tuned", tuned
);
702 blobmsg_add_double(&status
, "rssi", (double) rssi
*0.1);
703 if (radio
== QMI_NAS_RADIO_INTERFACE_5GNR
) {
704 blobmsg_add_double(&status
, "rsrp", (double) rsrp
*-0.1);
706 else if (radio
== QMI_NAS_RADIO_INTERFACE_LTE
) {
707 blobmsg_add_double(&status
, "rsrq", (double) ecio
*-0.1);
708 blobmsg_add_double(&status
, "rsrp", (double) rsrp
*-0.1);
710 else if (radio
== QMI_NAS_RADIO_INTERFACE_UMTS
) {
711 blobmsg_add_double(&status
, "ecio", (double) ecio
*-0.1);
712 blobmsg_add_double(&status
, "rscp", (double) rscp
*-0.1);
714 if (phase
!= 0xFFFFFFFF)
715 blobmsg_add_double(&status
, "phase", (double) phase
*0.01);
719 cmd_nas_get_tx_rx_info_cb(struct qmi_dev
*qmi
, struct qmi_request
*req
, struct qmi_msg
*msg
)
721 struct qmi_nas_get_tx_rx_info_response res
;
724 qmi_parse_nas_get_tx_rx_info_response(msg
, &res
);
725 t
= blobmsg_open_table(&status
, NULL
);
726 if (res
.set
.rx_chain_0_info
) {
727 c
= blobmsg_open_table(&status
, "rx_chain_0");
728 print_chain_info(tx_rx_req
.data
.radio_interface
,
729 res
.data
.rx_chain_0_info
.is_radio_tuned
,
730 res
.data
.rx_chain_0_info
.rx_power
,
731 res
.data
.rx_chain_0_info
.ecio
,
732 res
.data
.rx_chain_0_info
.rsrp
,
733 res
.data
.rx_chain_0_info
.rscp
,
734 res
.data
.rx_chain_0_info
.phase
);
735 blobmsg_close_table(&status
, c
);
737 if (res
.set
.rx_chain_1_info
) {
738 c
= blobmsg_open_table(&status
, "rx_chain_1");
739 print_chain_info(tx_rx_req
.data
.radio_interface
,
740 res
.data
.rx_chain_1_info
.is_radio_tuned
,
741 res
.data
.rx_chain_1_info
.rx_power
,
742 res
.data
.rx_chain_1_info
.ecio
,
743 res
.data
.rx_chain_1_info
.rsrp
,
744 res
.data
.rx_chain_1_info
.rscp
,
745 res
.data
.rx_chain_1_info
.phase
);
746 blobmsg_close_table(&status
, c
);
748 if (res
.set
.rx_chain_2_info
) {
749 c
= blobmsg_open_table(&status
, "rx_chain_2");
750 print_chain_info(tx_rx_req
.data
.radio_interface
,
751 res
.data
.rx_chain_2_info
.is_radio_tuned
,
752 res
.data
.rx_chain_2_info
.rx_power
,
753 res
.data
.rx_chain_2_info
.ecio
,
754 res
.data
.rx_chain_2_info
.rsrp
,
755 res
.data
.rx_chain_2_info
.rscp
,
756 res
.data
.rx_chain_2_info
.phase
);
757 blobmsg_close_table(&status
, c
);
759 if (res
.set
.rx_chain_3_info
) {
760 c
= blobmsg_open_table(&status
, "rx_chain_3");
761 print_chain_info(tx_rx_req
.data
.radio_interface
,
762 res
.data
.rx_chain_3_info
.is_radio_tuned
,
763 res
.data
.rx_chain_3_info
.rx_power
,
764 res
.data
.rx_chain_3_info
.ecio
,
765 res
.data
.rx_chain_3_info
.rsrp
,
766 res
.data
.rx_chain_3_info
.rscp
,
767 res
.data
.rx_chain_3_info
.phase
);
768 blobmsg_close_table(&status
, c
);
770 if (res
.set
.tx_info
) {
771 c
= blobmsg_open_table(&status
, "tx");
772 blobmsg_add_u8(&status
, "traffic", res
.data
.tx_info
.is_in_traffic
);
773 if (res
.data
.tx_info
.is_in_traffic
)
774 blobmsg_add_double(&status
, "tx_power",
775 (double) res
.data
.tx_info
.tx_power
*0.1);
776 blobmsg_close_table(&status
, c
);
778 blobmsg_close_table(&status
, t
);
782 static enum qmi_cmd_result
783 cmd_nas_get_tx_rx_info_prepare(struct qmi_dev
*qmi
, struct qmi_request
*req
, struct qmi_msg
*msg
, char *arg
)
787 if (!strcmp(arg
, "5gnr"))
788 radio
= QMI_NAS_RADIO_INTERFACE_5GNR
;
789 else if (!strcmp(arg
, "lte"))
790 radio
= QMI_NAS_RADIO_INTERFACE_LTE
;
791 else if (!strcmp(arg
, "umts"))
792 radio
= QMI_NAS_RADIO_INTERFACE_UMTS
;
793 else if (!strcmp(arg
, "gsm"))
794 radio
= QMI_NAS_RADIO_INTERFACE_GSM
;
796 return uqmi_add_error("Invalid argument");
798 qmi_set(&tx_rx_req
, radio_interface
, radio
);
799 qmi_set_nas_get_tx_rx_info_request(msg
, &tx_rx_req
);
800 return QMI_CMD_REQUEST
;
804 print_lte_info(int32_t cell_id
, int16_t rsrp
, int16_t rsrq
, int16_t rssi
)
806 blobmsg_add_u32(&status
, "physical_cell_id", cell_id
);
807 blobmsg_add_double(&status
, "rsrq", ((double)rsrq
)/10);
808 blobmsg_add_double(&status
, "rsrp", ((double)rsrp
)/10);
809 blobmsg_add_double(&status
, "rssi", ((double)rssi
)/10);
813 print_sel_info(int32_t priority
, int32_t high
, int32_t low
)
815 blobmsg_add_u32(&status
, "cell_reselection_priority", priority
);
816 blobmsg_add_u32(&status
, "cell_reselection_low", low
);
817 blobmsg_add_u32(&status
, "cell_reselection_high", high
);
821 cmd_nas_get_cell_location_info_cb(struct qmi_dev
*qmi
, struct qmi_request
*req
, struct qmi_msg
*msg
)
823 struct qmi_nas_get_cell_location_info_response res
;
824 void *c
= NULL
, *t
, *cell
, *freq
;
827 qmi_parse_nas_get_cell_location_info_response(msg
, &res
);
828 t
= blobmsg_open_table(&status
, NULL
);
830 if (res
.set
.umts_info_v2
) {
831 c
= blobmsg_open_table(&status
, "umts_info");
832 blobmsg_add_u32(&status
, "location_area_code", res
.data
.umts_info_v2
.lac
);
833 blobmsg_add_u32(&status
, "cell_id", res
.data
.umts_info_v2
.cell_id
);
834 blobmsg_add_u32(&status
, "channel",
835 res
.data
.umts_info_v2
.utra_absolute_rf_channel_number
);
836 blobmsg_add_u32(&status
, "primary_scrambling_code",
837 res
.data
.umts_info_v2
.primary_scrambling_code
);
838 blobmsg_add_u32(&status
, "rscp", res
.data
.umts_info_v2
.rscp
);
839 blobmsg_add_u32(&status
, "ecio", res
.data
.umts_info_v2
.ecio
);
840 for (j
= 0; j
< res
.data
.umts_info_v2
.cell_n
; j
++) {
841 cell
= blobmsg_open_table(&status
, NULL
);
842 blobmsg_add_u32(&status
, "channel",
843 res
.data
.umts_info_v2
.cell
[j
].utra_absolute_rf_channel_number
);
844 blobmsg_add_u32(&status
, "primary_scrambling_code",
845 res
.data
.umts_info_v2
.cell
[j
].primary_scrambling_code
);
846 blobmsg_add_u32(&status
, "rscp", res
.data
.umts_info_v2
.cell
[j
].rscp
);
847 blobmsg_add_u32(&status
, "ecio", res
.data
.umts_info_v2
.cell
[j
].ecio
);
848 blobmsg_close_table(&status
, cell
);
850 for (j
= 0; j
< res
.data
.umts_info_v2
.neighboring_geran_n
; j
++) {
851 cell
= blobmsg_open_table(&status
, "neighboring_geran");
852 blobmsg_add_u32(&status
, "channel",
853 res
.data
.umts_info_v2
.neighboring_geran
[j
].geran_absolute_rf_channel_number
);
854 blobmsg_add_u8(&status
, "network_color_code",
855 res
.data
.umts_info_v2
.neighboring_geran
[j
].network_color_code
);
856 blobmsg_add_u8(&status
, "base_station_color_code",
857 res
.data
.umts_info_v2
.neighboring_geran
[j
].base_station_color_code
);
858 blobmsg_add_u32(&status
, "rssi",
859 res
.data
.umts_info_v2
.neighboring_geran
[j
].rssi
);
860 blobmsg_close_table(&status
, cell
);
862 blobmsg_close_table(&status
, c
);
864 if (res
.set
.intrafrequency_lte_info_v2
) {
865 c
= blobmsg_open_table(&status
, "intrafrequency_lte_info");
866 blobmsg_add_u32(&status
, "tracking_area_code",
867 res
.data
.intrafrequency_lte_info_v2
.tracking_area_code
);
868 blobmsg_add_u32(&status
, "enodeb_id",
869 res
.data
.intrafrequency_lte_info_v2
.global_cell_id
/256);
870 blobmsg_add_u32(&status
, "cell_id",
871 res
.data
.intrafrequency_lte_info_v2
.global_cell_id
%256);
872 blobmsg_add_u32(&status
, "channel",
873 res
.data
.intrafrequency_lte_info_v2
.eutra_absolute_rf_channel_number
);
874 print_earfcn_info(res
.data
.intrafrequency_lte_info_v2
.eutra_absolute_rf_channel_number
);
875 blobmsg_add_u32(&status
, "serving_cell_id",
876 res
.data
.intrafrequency_lte_info_v2
.serving_cell_id
);
877 if (res
.data
.intrafrequency_lte_info_v2
.ue_in_idle
) {
878 blobmsg_add_u32(&status
, "cell_reselection_priority",
879 res
.data
.intrafrequency_lte_info_v2
.cell_reselection_priority
);
880 blobmsg_add_u32(&status
, "s_non_intra_search_threshold",
881 res
.data
.intrafrequency_lte_info_v2
.s_non_intra_search_threshold
);
882 blobmsg_add_u32(&status
, "serving_cell_low_threshold",
883 res
.data
.intrafrequency_lte_info_v2
.serving_cell_low_threshold
);
884 blobmsg_add_u32(&status
, "s_intra_search_threshold",
885 res
.data
.intrafrequency_lte_info_v2
.s_intra_search_threshold
);
887 for (i
= 0; i
< res
.data
.intrafrequency_lte_info_v2
.cell_n
; i
++) {
888 cell
= blobmsg_open_table(&status
, NULL
);
889 print_lte_info(res
.data
.intrafrequency_lte_info_v2
.cell
[i
].physical_cell_id
,
890 res
.data
.intrafrequency_lte_info_v2
.cell
[i
].rsrq
,
891 res
.data
.intrafrequency_lte_info_v2
.cell
[i
].rsrp
,
892 res
.data
.intrafrequency_lte_info_v2
.cell
[i
].rssi
);
893 if (res
.data
.intrafrequency_lte_info_v2
.ue_in_idle
)
894 blobmsg_add_u32(&status
, "cell_selection_rx_level",
895 res
.data
.intrafrequency_lte_info_v2
.cell
[i
].cell_selection_rx_level
);
896 blobmsg_close_table(&status
, cell
);
898 blobmsg_close_table(&status
, c
);
900 if (res
.set
.interfrequency_lte_info
) {
901 if (res
.data
.interfrequency_lte_info
.frequency_n
> 0)
902 c
= blobmsg_open_table(&status
, "interfrequency_lte_info");
903 for (i
= 0; i
< res
.data
.interfrequency_lte_info
.frequency_n
; i
++) {
904 freq
= blobmsg_open_table(&status
, NULL
);
905 blobmsg_add_u32(&status
, "channel",
906 res
.data
.interfrequency_lte_info
.frequency
[i
].eutra_absolute_rf_channel_number
);
907 print_earfcn_info(res
.data
.interfrequency_lte_info
.frequency
[i
].eutra_absolute_rf_channel_number
);
908 if (res
.data
.interfrequency_lte_info
.ue_in_idle
) {
909 print_sel_info(res
.data
.interfrequency_lte_info
.frequency
[i
].cell_reselection_priority
,
910 res
.data
.interfrequency_lte_info
.frequency
[i
].cell_selection_rx_level_high_threshold
,
911 res
.data
.interfrequency_lte_info
.frequency
[i
].cell_selection_rx_level_low_threshold
);
913 for (j
= 0; j
< res
.data
.interfrequency_lte_info
.frequency
[i
].cell_n
; j
++) {
914 cell
= blobmsg_open_table(&status
, NULL
);
915 print_lte_info(res
.data
.interfrequency_lte_info
.frequency
[i
].cell
[j
].physical_cell_id
,
916 res
.data
.interfrequency_lte_info
.frequency
[i
].cell
[j
].rsrq
,
917 res
.data
.interfrequency_lte_info
.frequency
[i
].cell
[j
].rsrp
,
918 res
.data
.interfrequency_lte_info
.frequency
[i
].cell
[j
].rssi
);
919 if (res
.data
.interfrequency_lte_info
.ue_in_idle
)
920 blobmsg_add_u32(&status
, "cell_selection_rx_level",
921 res
.data
.interfrequency_lte_info
.frequency
[i
].cell
[j
].cell_selection_rx_level
);
922 blobmsg_close_table(&status
, cell
);
924 blobmsg_close_table(&status
, freq
);
926 if (res
.data
.interfrequency_lte_info
.frequency_n
> 0)
927 blobmsg_close_table(&status
, c
);
929 if (res
.set
.lte_info_neighboring_gsm
) {
930 if (res
.data
.lte_info_neighboring_gsm
.frequency_n
> 0)
931 c
= blobmsg_open_table(&status
, "lte_info_neighboring_gsm");
932 for (i
= 0; i
< res
.data
.lte_info_neighboring_gsm
.frequency_n
; i
++) {
933 freq
= blobmsg_open_table(&status
, NULL
);
934 blobmsg_add_u32(&status
, "ncc_permitted",
935 res
.data
.lte_info_neighboring_gsm
.frequency
[i
].ncc_permitted
);
936 if (res
.data
.lte_info_neighboring_gsm
.ue_in_idle
) {
937 print_sel_info(res
.data
.lte_info_neighboring_gsm
.frequency
[i
].cell_reselection_priority
,
938 res
.data
.lte_info_neighboring_gsm
.frequency
[i
].cell_reselection_high_threshold
,
939 res
.data
.lte_info_neighboring_gsm
.frequency
[i
].cell_reselection_low_threshold
);
941 for (j
= 0; j
< res
.data
.lte_info_neighboring_gsm
.frequency
[i
].cell_n
; j
++) {
942 cell
= blobmsg_open_table(&status
, NULL
);
943 blobmsg_add_u32(&status
, "channel",
944 res
.data
.lte_info_neighboring_gsm
.frequency
[i
].cell
[j
].geran_absolute_rf_channel_number
);
945 blobmsg_add_u32(&status
, "base_station_identity_code",
946 res
.data
.lte_info_neighboring_gsm
.frequency
[i
].cell
[j
].base_station_identity_code
);
947 blobmsg_add_double(&status
, "rssi",
948 ((double)res
.data
.lte_info_neighboring_gsm
.frequency
[i
].cell
[j
].rssi
)/10);
949 if (res
.data
.lte_info_neighboring_gsm
.ue_in_idle
)
950 blobmsg_add_u32(&status
, "cell_selection_rx_level",
951 res
.data
.lte_info_neighboring_gsm
.frequency
[i
].cell
[j
].cell_selection_rx_level
);
952 blobmsg_close_table(&status
, cell
);
954 blobmsg_close_table(&status
, freq
);
956 if (res
.data
.lte_info_neighboring_gsm
.frequency_n
> 0)
957 blobmsg_close_table(&status
, c
);
959 if (res
.set
.lte_info_neighboring_wcdma
) {
960 if (res
.data
.lte_info_neighboring_wcdma
.frequency_n
> 0)
961 c
= blobmsg_open_table(&status
, "lte_info_neighboring_wcdma");
962 for (i
= 0; i
< res
.data
.lte_info_neighboring_wcdma
.frequency_n
; i
++) {
963 freq
= blobmsg_open_table(&status
, NULL
);
964 blobmsg_add_u32(&status
, "channel",
965 res
.data
.lte_info_neighboring_wcdma
.frequency
[i
].utra_absolute_rf_channel_number
);
966 if (res
.data
.lte_info_neighboring_wcdma
.ue_in_idle
) {
967 print_sel_info(res
.data
.lte_info_neighboring_wcdma
.frequency
[i
].cell_reselection_priority
,
968 res
.data
.lte_info_neighboring_wcdma
.frequency
[i
].cell_reselection_high_threshold
,
969 res
.data
.lte_info_neighboring_wcdma
.frequency
[i
].cell_reselection_low_threshold
);
971 for (j
= 0; j
< res
.data
.lte_info_neighboring_wcdma
.frequency
[i
].cell_n
; j
++) {
972 cell
= blobmsg_open_table(&status
, NULL
);
973 blobmsg_add_u32(&status
, "primary_scrambling_code",
974 res
.data
.lte_info_neighboring_wcdma
.frequency
[i
].cell
[j
].primary_scrambling_code
);
975 blobmsg_add_double(&status
, "rscp",
976 ((double)res
.data
.lte_info_neighboring_wcdma
.frequency
[i
].cell
[j
].cpich_rscp
)/10);
977 blobmsg_add_double(&status
, "ecno",
978 ((double)res
.data
.lte_info_neighboring_wcdma
.frequency
[i
].cell
[j
].cpich_ecno
)/10);
979 if (res
.data
.lte_info_neighboring_wcdma
.ue_in_idle
)
980 blobmsg_add_u32(&status
, "cell_selection_rx_level",
981 res
.data
.lte_info_neighboring_wcdma
.frequency
[i
].cell
[j
].cell_selection_rx_level
);
982 blobmsg_close_table(&status
, cell
);
984 blobmsg_close_table(&status
, freq
);
986 if (res
.data
.lte_info_neighboring_wcdma
.frequency_n
> 0)
987 blobmsg_close_table(&status
, c
);
989 if (res
.set
.umts_info_neighboring_lte
) {
990 if (res
.data
.umts_info_neighboring_lte
.frequency_n
> 0)
991 c
= blobmsg_open_table(&status
, "umts_info_neighboring_lte");
992 for (i
= 0; i
< res
.data
.umts_info_neighboring_lte
.frequency_n
; i
++) {
993 freq
= blobmsg_open_table(&status
, NULL
);
994 blobmsg_add_u32(&status
, "channel",
995 res
.data
.umts_info_neighboring_lte
.frequency
[i
].eutra_absolute_rf_channel_number
);
996 print_earfcn_info(res
.data
.umts_info_neighboring_lte
.frequency
[i
].eutra_absolute_rf_channel_number
);
997 blobmsg_add_u32(&status
, "physical_cell_id",
998 res
.data
.umts_info_neighboring_lte
.frequency
[i
].physical_cell_id
);
999 blobmsg_add_double(&status
, "rsrp",
1000 (double) res
.data
.umts_info_neighboring_lte
.frequency
[i
].rsrp
);
1001 blobmsg_add_double(&status
, "rsrq",
1002 (double) res
.data
.umts_info_neighboring_lte
.frequency
[i
].rsrq
);
1003 blobmsg_add_u32(&status
, "cell_selection_rx_level",
1004 res
.data
.umts_info_neighboring_lte
.frequency
[i
].cell_selection_rx_level
);
1005 blobmsg_close_table(&status
, freq
);
1007 if (res
.data
.umts_info_neighboring_lte
.frequency_n
> 0)
1008 blobmsg_close_table(&status
, c
);
1010 if (res
.set
.nr5g_cell_information
) {
1011 c
= blobmsg_open_table(&status
, "nr5g_cell_information");
1012 blobmsg_add_u32(&status
, "enodeb_id",
1013 res
.data
.nr5g_cell_information
.global_cell_id
/256);
1014 blobmsg_add_u32(&status
, "cell_id",
1015 res
.data
.nr5g_cell_information
.global_cell_id
%256);
1016 blobmsg_add_u32(&status
, "physical_cell_id",
1017 res
.data
.nr5g_cell_information
.physical_cell_id
);
1018 blobmsg_add_double(&status
, "rsrq", ((double)res
.data
.nr5g_cell_information
.rsrq
)/10);
1019 blobmsg_add_double(&status
, "rsrp", ((double)res
.data
.nr5g_cell_information
.rsrp
)/10);
1020 blobmsg_add_double(&status
, "snr", ((double)res
.data
.nr5g_cell_information
.snr
)/10);
1021 blobmsg_close_table(&status
, c
);
1023 if (res
.set
.nr5g_arfcn
) {
1024 c
= blobmsg_open_table(&status
, "nr5g_arfcn");
1025 blobmsg_add_u32(&status
, "arfcn",
1026 res
.data
.nr5g_arfcn
);
1027 blobmsg_close_table(&status
, c
);
1029 blobmsg_close_table(&status
, t
);
1032 static enum qmi_cmd_result
1033 cmd_nas_get_cell_location_info_prepare(struct qmi_dev
*qmi
, struct qmi_request
*req
, struct qmi_msg
*msg
, char *arg
)
1035 qmi_set_nas_get_cell_location_info_request(msg
);
1036 return QMI_CMD_REQUEST
;
1039 static enum qmi_cmd_result
1040 cmd_nas_get_signal_info_prepare(struct qmi_dev
*qmi
, struct qmi_request
*req
, struct qmi_msg
*msg
, char *arg
)
1042 qmi_set_nas_get_signal_info_request(msg
);
1043 return QMI_CMD_REQUEST
;
1047 cmd_nas_get_serving_system_cb(struct qmi_dev
*qmi
, struct qmi_request
*req
, struct qmi_msg
*msg
)
1049 struct qmi_nas_get_serving_system_response res
;
1050 static const char *reg_states
[] = {
1051 [QMI_NAS_REGISTRATION_STATE_NOT_REGISTERED
] = "not_registered",
1052 [QMI_NAS_REGISTRATION_STATE_REGISTERED
] = "registered",
1053 [QMI_NAS_REGISTRATION_STATE_NOT_REGISTERED_SEARCHING
] = "searching",
1054 [QMI_NAS_REGISTRATION_STATE_REGISTRATION_DENIED
] = "registering_denied",
1055 [QMI_NAS_REGISTRATION_STATE_UNKNOWN
] = "unknown",
1059 qmi_parse_nas_get_serving_system_response(msg
, &res
);
1061 c
= blobmsg_open_table(&status
, NULL
);
1062 if (res
.set
.serving_system
) {
1063 int state
= res
.data
.serving_system
.registration_state
;
1065 if (state
> QMI_NAS_REGISTRATION_STATE_UNKNOWN
)
1066 state
= QMI_NAS_REGISTRATION_STATE_UNKNOWN
;
1068 blobmsg_add_string(&status
, "registration", reg_states
[state
]);
1070 if (res
.set
.current_plmn
) {
1071 blobmsg_add_u32(&status
, "plmn_mcc", res
.data
.current_plmn
.mcc
);
1072 blobmsg_add_u32(&status
, "plmn_mnc", res
.data
.current_plmn
.mnc
);
1073 if (res
.data
.current_plmn
.description
)
1074 blobmsg_add_string(&status
, "plmn_description", res
.data
.current_plmn
.description
);
1077 if (res
.set
.roaming_indicator
)
1078 blobmsg_add_u8(&status
, "roaming", !res
.data
.roaming_indicator
);
1080 blobmsg_close_table(&status
, c
);
1083 static enum qmi_cmd_result
1084 cmd_nas_get_serving_system_prepare(struct qmi_dev
*qmi
, struct qmi_request
*req
, struct qmi_msg
*msg
, char *arg
)
1086 qmi_set_nas_get_serving_system_request(msg
);
1087 return QMI_CMD_REQUEST
;
1091 cmd_nas_get_plmn_cb(struct qmi_dev
*qmi
, struct qmi_request
*req
, struct qmi_msg
*msg
)
1093 struct qmi_nas_get_system_selection_preference_response res
;
1094 static const char *modes
[] = {
1095 [QMI_NAS_NETWORK_SELECTION_PREFERENCE_AUTOMATIC
] = "automatic",
1096 [QMI_NAS_NETWORK_SELECTION_PREFERENCE_MANUAL
] = "manual",
1100 qmi_parse_nas_get_system_selection_preference_response(msg
, &res
);
1102 c
= blobmsg_open_table(&status
, NULL
);
1103 if (res
.set
.network_selection_preference
) {
1104 blobmsg_add_string(&status
, "mode", modes
[res
.data
.network_selection_preference
]);
1106 if (res
.set
.manual_network_selection
) {
1107 blobmsg_add_u32(&status
, "mcc", res
.data
.manual_network_selection
.mcc
);
1108 blobmsg_add_u32(&status
, "mnc", res
.data
.manual_network_selection
.mnc
);
1111 blobmsg_close_table(&status
, c
);
1114 static enum qmi_cmd_result
1115 cmd_nas_get_plmn_prepare(struct qmi_dev
*qmi
, struct qmi_request
*req
, struct qmi_msg
*msg
, char *arg
)
1117 qmi_set_nas_get_system_selection_preference_request(msg
);
1118 return QMI_CMD_REQUEST
;
1122 cmd_nas_network_scan_cb(struct qmi_dev
*qmi
, struct qmi_request
*req
, struct qmi_msg
*msg
)
1124 static struct qmi_nas_network_scan_response res
;
1125 const char *network_status
[] = {
1135 void *t
, *c
, *info
, *stat
;
1138 qmi_parse_nas_network_scan_response(msg
, &res
);
1140 t
= blobmsg_open_table(&status
, NULL
);
1142 c
= blobmsg_open_array(&status
, "network_info");
1143 for (i
= 0; i
< res
.data
.network_information_n
; i
++) {
1144 info
= blobmsg_open_table(&status
, NULL
);
1145 blobmsg_add_u32(&status
, "mcc", res
.data
.network_information
[i
].mcc
);
1146 blobmsg_add_u32(&status
, "mnc", res
.data
.network_information
[i
].mnc
);
1147 if (res
.data
.network_information
[i
].description
)
1148 blobmsg_add_string(&status
, "description", res
.data
.network_information
[i
].description
);
1149 stat
= blobmsg_open_array(&status
, "status");
1150 for (j
= 0; j
< ARRAY_SIZE(network_status
); j
++) {
1151 if (!(res
.data
.network_information
[i
].network_status
& (1 << j
)))
1154 blobmsg_add_string(&status
, NULL
, network_status
[j
]);
1156 blobmsg_close_array(&status
, stat
);
1157 blobmsg_close_table(&status
, info
);
1159 blobmsg_close_array(&status
, c
);
1161 c
= blobmsg_open_array(&status
, "radio_access_technology");
1162 for (i
= 0; i
< res
.data
.radio_access_technology_n
; i
++) {
1163 int8_t r_i
= res
.data
.radio_access_technology
[i
].radio_interface
;
1165 info
= blobmsg_open_table(&status
, NULL
);
1166 blobmsg_add_u32(&status
, "mcc", res
.data
.radio_access_technology
[i
].mcc
);
1167 blobmsg_add_u32(&status
, "mnc", res
.data
.radio_access_technology
[i
].mnc
);
1168 blobmsg_add_string(&status
, "radio", print_radio_interface(r_i
));
1169 blobmsg_close_table(&status
, info
);
1171 blobmsg_close_array(&status
, c
);
1173 blobmsg_close_table(&status
, t
);
1176 static enum qmi_cmd_result
1177 cmd_nas_network_scan_prepare(struct qmi_dev
*qmi
, struct qmi_request
*req
, struct qmi_msg
*msg
, char *arg
)
1179 struct qmi_nas_network_scan_request sreq
= {
1180 QMI_INIT(network_type
,
1181 QMI_NAS_NETWORK_SCAN_TYPE_GSM
|
1182 QMI_NAS_NETWORK_SCAN_TYPE_UMTS
|
1183 QMI_NAS_NETWORK_SCAN_TYPE_LTE
|
1184 QMI_NAS_NETWORK_SCAN_TYPE_TD_SCDMA
),
1187 qmi_set_nas_network_scan_request(msg
, &sreq
);
1188 return QMI_CMD_REQUEST
;