Skip to content

Commit 861c33d

Browse files
tokangasrlubos
authored andcommitted
samples: cellular: modem_shell: Add support for environment evaluation
Added new shell command "link enveval" for performing environment evaluation. Environment evaluation is introduced in nRF91x1 modem firmware v2.0.3. Signed-off-by: Tommi Kangas <[email protected]>
1 parent a90d01c commit 861c33d

File tree

7 files changed

+312
-1
lines changed

7 files changed

+312
-1
lines changed

doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,10 @@ Cellular samples
373373

374374
* :ref:`modem_shell_application` sample:
375375

376-
* Added support for NTN NB-IoT to the ``link sysmode`` and ``link edrx`` commands.
376+
* Added:
377+
378+
* Support for environment evaluation using the ``link enveval`` command.
379+
* Support for NTN NB-IoT to the ``link sysmode`` and ``link edrx`` commands.
377380

378381
Cryptography samples
379382
--------------------

samples/cellular/modem_shell/README.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,14 @@ Examples
103103
link search --read
104104
link search --start
105105
106+
* Perform environment evaluation for PLMNs 24405, 24412 and 24491:
107+
108+
.. code-block:: console
109+
110+
link funmode --flightmode
111+
link funmode --rxonly
112+
link enveval --eval_type dynamic --plmns 24405,24412,24491
113+
106114
----
107115

108116
AT commands

samples/cellular/modem_shell/prj.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ CONFIG_LTE_LC_PSM_MODULE=y
119119
CONFIG_LTE_LC_RAI_MODULE=y
120120
CONFIG_LTE_LC_MODEM_SLEEP_MODULE=y
121121
CONFIG_LTE_LC_TAU_PRE_WARNING_MODULE=y
122+
CONFIG_LTE_LC_ENV_EVAL_MODULE=y
122123

123124
CONFIG_DATE_TIME=y
124125

samples/cellular/modem_shell/src/link/link.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,60 @@ void link_ind_handler(const struct lte_lc_evt *const evt)
270270
*/
271271
mosh_print("TAU pre warning: time %lld", evt->time);
272272
break;
273+
#if defined(CONFIG_LTE_LC_ENV_EVAL_MODULE)
274+
case LTE_LC_EVT_ENV_EVAL_RESULT: {
275+
struct mapping_tbl_item const enveval_status_strs[] = {
276+
{ 0, "successful" },
277+
{ 5, "failed, aborted because of higher priority operation" },
278+
{ 7, "failed, unspecified" },
279+
{ -1, NULL }
280+
};
281+
struct mapping_tbl_item const enveval_energy_est_strs[] = {
282+
{ LTE_LC_ENERGY_CONSUMPTION_EXCESSIVE,
283+
"bad conditions, excessive energy consumption" },
284+
{ LTE_LC_ENERGY_CONSUMPTION_INCREASED,
285+
"poor conditions, slightly increased energy consumption" },
286+
{ LTE_LC_ENERGY_CONSUMPTION_NORMAL,
287+
"normal conditions" },
288+
{ LTE_LC_ENERGY_CONSUMPTION_REDUCED,
289+
"good conditions, slightly reduced energy consumption" },
290+
{ LTE_LC_ENERGY_CONSUMPTION_EFFICIENT,
291+
"excellent conditions, energy efficient transmission" },
292+
{ -1, NULL }
293+
};
294+
const struct lte_lc_env_eval_result *result = &evt->env_eval_result;
295+
296+
mosh_print("Environment evaluation completed with status: %d (%s)",
297+
result->status,
298+
link_shell_map_to_string(enveval_status_strs, result->status, snum));
299+
mosh_print("Number of PLMN results: %u", result->result_count);
300+
301+
for (int i = 0; i < result->result_count; i++) {
302+
const struct lte_lc_conn_eval_params *plmn = &result->results[i];
303+
304+
mosh_print("PLMN %u:", i + 1);
305+
mosh_print(" MCC: %03d, MNC: %02d", plmn->mcc, plmn->mnc);
306+
mosh_print(" Energy estimate: %d (%s)",
307+
plmn->energy_estimate,
308+
link_shell_map_to_string(enveval_energy_est_strs,
309+
plmn->energy_estimate, snum));
310+
mosh_print(" Cell ID: %d", plmn->cell_id);
311+
/* rrc_state is ignored because it's always 0 */
312+
mosh_print(" RSRP: %d dBm, RSRQ: %.1f dB, SNR: %d dB",
313+
RSRP_IDX_TO_DBM(plmn->rsrp), (double)RSRQ_IDX_TO_DB(plmn->rsrq),
314+
SNR_IDX_TO_DB(plmn->snr));
315+
mosh_print(" EARFCN: %d, Band: %d",
316+
plmn->earfcn, plmn->band);
317+
mosh_print(" CE level: %d, TX power: %d dBm",
318+
plmn->ce_level, plmn->tx_power);
319+
/* tau_trig is ignored because it's always 1 */
320+
mosh_print(" TX rep: %d, RX rep: %d", plmn->tx_rep, plmn->rx_rep);
321+
mosh_print(" DL pathloss: %d, Phy cell ID: %d",
322+
plmn->dl_pathloss, plmn->phy_cid);
323+
}
324+
break;
325+
}
326+
#endif /* CONFIG_LTE_LC_ENV_EVAL_MODULE */
273327
case LTE_LC_EVT_NEIGHBOR_CELL_MEAS: {
274328
int i;
275329
struct lte_lc_cells_info cells = evt->cells_info;

samples/cellular/modem_shell/src/link/link_shell.c

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "link_shell_pdn.h"
2323
#include "link_settings.h"
2424
#include "net_utils.h"
25+
#include "str_utils.h"
2526

2627
#define LINK_SHELL_EDRX_VALUE_STR_LENGTH 4
2728
#define LINK_SHELL_EDRX_PTW_STR_LENGTH 4
@@ -31,6 +32,7 @@ enum link_shell_command {
3132
LINK_CMD_STATUS = 0,
3233
LINK_CMD_SETTINGS,
3334
LINK_CMD_CONEVAL,
35+
LINK_CMD_ENVEVAL,
3436
LINK_CMD_DEFCONT,
3537
LINK_CMD_DEFCONTAUTH,
3638
LINK_CMD_RSRP,
@@ -377,6 +379,28 @@ static const char link_modem_usage_str[] =
377379
"\n"
378380
"Several options can be given and they are run in the given order.";
379381

382+
#if defined(CONFIG_LTE_LC_ENV_EVAL_MODULE)
383+
static const char link_enveval_usage_str[] =
384+
"Usage: link enveval --eval_type <type> --plmns <plmn1>[,<plmn2>,...] | --cancel\n"
385+
"Options:\n"
386+
" --eval_type, [str] Evaluation type:\n"
387+
" 'dynamic', 'light' or 'full'\n"
388+
" --plmns, [str] Mobile Country Code and Mobile Network Code pairs\n"
389+
" --cancel, Cancel ongoing environment evaluation\n"
390+
" -h, --help, Shows this help information\n"
391+
"\n"
392+
"Evaluation types explained:\n"
393+
" Dynamic: PLMN search is stopped after light search if any of the\n"
394+
" PLMNs to evaluate were found. Search is continued over all\n"
395+
" frequency bands if light search did not find any results.\n"
396+
"\n"
397+
" Light: PLMN search is stopped after light search even if no PLMNs\n"
398+
" to evaluate were found.\n"
399+
"\n"
400+
" Full: PLMN search covers all channels in all supported frequency\n"
401+
" bands.\n";
402+
#endif /* CONFIG_LTE_LC_ENV_EVAL_MODULE */
403+
380404
/* The following do not have short options */
381405
enum {
382406
LINK_SHELL_OPT_MEM_SLOT_1 = 1001,
@@ -424,6 +448,8 @@ enum {
424448
LINK_SHELL_OPT_MODEM_INIT,
425449
LINK_SHELL_OPT_MODEM_SHUTDOWN,
426450
LINK_SHELL_OPT_MODEM_SHUTDOWN_CFUN0,
451+
LINK_SHELL_OPT_ENVEVAL_EVAL_TYPE,
452+
LINK_SHELL_OPT_ENVEVAL_PLMNS,
427453
};
428454

429455
/* Specifying the expected options (both long and short) */
@@ -502,6 +528,8 @@ static struct option long_options[] = {
502528
{ "init", no_argument, 0, LINK_SHELL_OPT_MODEM_INIT },
503529
{ "shutdown", no_argument, 0, LINK_SHELL_OPT_MODEM_SHUTDOWN },
504530
{ "shutdown_cfun0", no_argument, 0, LINK_SHELL_OPT_MODEM_SHUTDOWN_CFUN0 },
531+
{ "eval_type", required_argument, 0, LINK_SHELL_OPT_ENVEVAL_EVAL_TYPE },
532+
{ "plmns", required_argument, 0, LINK_SHELL_OPT_ENVEVAL_PLMNS },
505533
{ 0, 0, 0, 0 }
506534
};
507535

@@ -521,6 +549,11 @@ static void link_shell_print_usage(enum link_shell_command command)
521549
case LINK_CMD_DEFCONTAUTH:
522550
mosh_print_no_format(link_defcontauth_usage_str);
523551
break;
552+
#if defined(CONFIG_LTE_LC_ENV_EVAL_MODULE)
553+
case LINK_CMD_ENVEVAL:
554+
mosh_print_no_format(link_enveval_usage_str);
555+
break;
556+
#endif /* CONFIG_LTE_LC_ENV_EVAL_MODULE */
524557
case LINK_CMD_CONNECT:
525558
mosh_print_no_format(link_connect_usage_str);
526559
break;
@@ -649,6 +682,25 @@ static enum lte_lc_neighbor_search_type
649682
return search_type;
650683
}
651684

685+
#if defined(CONFIG_LTE_LC_ENV_EVAL_MODULE)
686+
#define MOSH_ENVEVAL_EVAL_TYPE_NONE 0xFF
687+
688+
static enum lte_lc_env_eval_type link_shell_string_to_env_eval_type(const char *eval_type_str)
689+
{
690+
enum lte_lc_env_eval_type eval_type = MOSH_ENVEVAL_EVAL_TYPE_NONE;
691+
692+
if (strcmp(eval_type_str, "dynamic") == 0) {
693+
eval_type = LTE_LC_ENV_EVAL_TYPE_DYNAMIC;
694+
} else if (strcmp(eval_type_str, "light") == 0) {
695+
eval_type = LTE_LC_ENV_EVAL_TYPE_LIGHT;
696+
} else if (strcmp(eval_type_str, "full") == 0) {
697+
eval_type = LTE_LC_ENV_EVAL_TYPE_FULL;
698+
}
699+
700+
return eval_type;
701+
}
702+
#endif /* CONFIG_LTE_LC_ENV_EVAL_MODULE */
703+
652704
int link_shell_get_and_print_current_system_modes(
653705
enum lte_lc_system_mode *sys_mode_current,
654706
enum lte_lc_system_mode_preference *sys_mode_preferred,
@@ -827,6 +879,170 @@ static int link_shell_coneval(const struct shell *shell, size_t argc, char **arg
827879
return 0;
828880
}
829881

882+
#if defined(CONFIG_LTE_LC_ENV_EVAL_MODULE)
883+
static int link_shell_string_to_env_eval_plmn_list(
884+
char *plmn_str,
885+
struct lte_lc_env_eval_plmn *plmn_list,
886+
uint8_t *plmn_count)
887+
{
888+
int ret = 0;
889+
size_t plmn_str_len;
890+
char *plmn_ptr;
891+
uint8_t count = 0;
892+
893+
__ASSERT_NO_MSG(plmn_str != NULL);
894+
__ASSERT_NO_MSG(plmn_list != NULL);
895+
__ASSERT_NO_MSG(plmn_count != NULL);
896+
897+
*plmn_count = 0;
898+
899+
plmn_str_len = strlen(plmn_str);
900+
plmn_ptr = plmn_str;
901+
902+
/* Replace commas with nul-terminators. */
903+
for (int i = 0; i < plmn_str_len; i++) {
904+
if (plmn_ptr[i] == ',') {
905+
plmn_ptr[i] = '\0';
906+
}
907+
}
908+
909+
while (plmn_ptr < (plmn_str + plmn_str_len)) {
910+
if (count >= CONFIG_LTE_LC_ENV_EVAL_MAX_PLMN_COUNT) {
911+
mosh_error("Number of PLMNs exceeds CONFIG_LTE_LC_ENV_EVAL_MAX_PLMN_COUNT"
912+
" (%d)",
913+
CONFIG_LTE_LC_ENV_EVAL_MAX_PLMN_COUNT);
914+
return -EINVAL;
915+
}
916+
917+
if (strlen(plmn_ptr) < 5) {
918+
mosh_error("Invalid PLMN: %s", plmn_ptr);
919+
return -EBADMSG;
920+
}
921+
922+
/* Read MNC and store as integer. The MNC starts as the fourth character
923+
* in the string, following three characters long MCC.
924+
*/
925+
ret = mosh_string_to_int(&plmn_ptr[3], 10, &plmn_list[count].mnc);
926+
if (ret) {
927+
return -EBADMSG;
928+
}
929+
930+
/* Nul-terminate MCC, read and store it. */
931+
plmn_ptr[3] = '\0';
932+
ret = mosh_string_to_int(&plmn_ptr[0], 10, &plmn_list[count].mcc);
933+
if (ret) {
934+
return -EBADMSG;
935+
}
936+
937+
if (plmn_list[count].mcc == 0 || plmn_list[count].mnc == 0) {
938+
mosh_error("Invalid PLMN: MCC: %03d, MNC: %02d",
939+
plmn_list[count].mcc, plmn_list[count].mnc);
940+
return -EBADMSG;
941+
}
942+
943+
count++;
944+
945+
/* Skip parsed PLMN, which is at least 5 digits. */
946+
plmn_ptr += 5;
947+
948+
if (*plmn_ptr != '\0') {
949+
/* Skip 6th digit.*/
950+
plmn_ptr++;
951+
}
952+
/* Skip nul-terminator. */
953+
plmn_ptr++;
954+
}
955+
956+
*plmn_count = count;
957+
958+
return ret;
959+
}
960+
961+
static int link_shell_enveval(const struct shell *shell, size_t argc, char **argv)
962+
{
963+
int ret;
964+
struct lte_lc_env_eval_plmn plmn_list[CONFIG_LTE_LC_ENV_EVAL_MAX_PLMN_COUNT] = {0};
965+
struct lte_lc_env_eval_params params = {
966+
.eval_type = MOSH_ENVEVAL_EVAL_TYPE_NONE,
967+
.plmn_list = plmn_list
968+
};
969+
bool cancel = false;
970+
971+
if (argc < 2) {
972+
goto show_usage;
973+
}
974+
975+
optreset = 1;
976+
optind = 1;
977+
int opt;
978+
979+
while ((opt = getopt_long(argc, argv, short_options, long_options, NULL)) != -1) {
980+
switch (opt) {
981+
case LINK_SHELL_OPT_ENVEVAL_EVAL_TYPE:
982+
params.eval_type = link_shell_string_to_env_eval_type(optarg);
983+
if (params.eval_type == MOSH_ENVEVAL_EVAL_TYPE_NONE) {
984+
mosh_error("Unknown evaluation type. See usage:");
985+
goto show_usage;
986+
}
987+
break;
988+
case LINK_SHELL_OPT_ENVEVAL_PLMNS:
989+
ret = link_shell_string_to_env_eval_plmn_list(
990+
optarg, params.plmn_list, &params.plmn_count);
991+
if (ret) {
992+
mosh_error("Invalid PLMN list. See usage:");
993+
goto show_usage;
994+
}
995+
break;
996+
case LINK_SHELL_OPT_STOP:
997+
cancel = true;
998+
break;
999+
1000+
case 'h':
1001+
goto show_usage;
1002+
case '?':
1003+
default:
1004+
mosh_error("Unknown option (%s). See usage:", argv[optind - 1]);
1005+
goto show_usage;
1006+
}
1007+
}
1008+
1009+
if (cancel) {
1010+
mosh_print("Cancelling environment evaluation...");
1011+
ret = lte_lc_env_eval_cancel();
1012+
if (ret) {
1013+
mosh_error("lte_lc_env_eval_cancel() returned %d", ret);
1014+
return -ENOEXEC;
1015+
}
1016+
return 0;
1017+
}
1018+
1019+
/* Validate that both eval_type and plmns were provided */
1020+
if (params.eval_type == MOSH_ENVEVAL_EVAL_TYPE_NONE) {
1021+
mosh_error("Evaluation type must be specified. See usage:");
1022+
goto show_usage;
1023+
}
1024+
1025+
if (params.plmn_count == 0) {
1026+
mosh_error("At least one PLMN must be specified. See usage:");
1027+
goto show_usage;
1028+
}
1029+
1030+
mosh_print("Starting environment evaluation for %zu PLMN(s)...", params.plmn_count);
1031+
1032+
ret = lte_lc_env_eval(&params);
1033+
if (ret) {
1034+
mosh_error("lte_lc_env_eval() returned %d", ret);
1035+
return -ENOEXEC;
1036+
}
1037+
1038+
return 0;
1039+
1040+
show_usage:
1041+
link_shell_print_usage(LINK_CMD_ENVEVAL);
1042+
return -EINVAL;
1043+
}
1044+
#endif /* CONFIG_LTE_LC_ENV_EVAL_MODULE */
1045+
8301046
static int link_shell_defcont(const struct shell *shell, size_t argc, char **argv)
8311047
{
8321048
int ret = 0;
@@ -2756,6 +2972,12 @@ SHELL_STATIC_SUBCMD_SET_CREATE(
27562972
edrx, NULL,
27572973
"Enable/disable eDRX with default or with custom parameters.",
27582974
link_shell_edrx, 0, 10),
2975+
#if defined(CONFIG_LTE_LC_ENV_EVAL_MODULE)
2976+
SHELL_CMD_ARG(
2977+
enveval, NULL,
2978+
"Perform environment evaluation for specified PLMNs.",
2979+
link_shell_enveval, 0, 20),
2980+
#endif /* CONFIG_LTE_LC_ENV_EVAL_MODULE */
27592981
SHELL_CMD_ARG(
27602982
funmode, NULL,
27612983
"Set/read functional modes of the modem.",

0 commit comments

Comments
 (0)