Skip to content

Commit

Permalink
lib: lte_link_control: Skip parsing of unexpected %NCELLMEAS notif
Browse files Browse the repository at this point in the history
Added check to skip %NCELLMEAS notification parsing when neighbor
cell measurement has not been requested by calling
lte_lc_neighbor_cell_measurement(). If the neighbor cell measurement
is triggered by sending the AT%NCELLMEAS AT command to the modem,
LTE LC does not know how the received notification should be parsed,
sometimes leading to a parsing error.

Signed-off-by: Tommi Kangas <tommi.kangas@nordicsemi.no>
  • Loading branch information
tokangas committed Jan 7, 2025
1 parent 9abba20 commit 415ce2e
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 2 deletions.
34 changes: 33 additions & 1 deletion lib/lte_link_control/modules/ncellmeas.c
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,16 @@ static void at_handler_ncellmeas(const char *response)
goto exit;
}

if (k_sem_count_get(&ncellmeas_idle_sem) > 0) {
/* No need to parse the notification because neighbor cell measurement
* has not been requested.
*/
LOG_DBG("%%NCELLMEAS notification not parsed because "
"lte_lc_neighbor_cell_measurement() not called");

goto exit;
}

if (ncellmeas_params.search_type > LTE_LC_NEIGHBOR_SEARCH_TYPE_EXTENDED_COMPLETE) {
at_handler_ncellmeas_gci(response);
goto exit;
Expand Down Expand Up @@ -783,6 +793,24 @@ int ncellmeas_start(struct lte_lc_ncellmeas_params *params)
return err;
}

static void ncellmeas_cancel_timeout_work_fn(struct k_work *work)
{
struct lte_lc_evt evt = {0};

if (k_sem_count_get(&ncellmeas_idle_sem) == 0) {
LOG_DBG("No %%NCELLMEAS notification received after AT%%NCELLMEASSTOP, "
"sending empty results");

evt.type = LTE_LC_EVT_NEIGHBOR_CELL_MEAS;
evt.cells_info.current_cell.id = LTE_LC_CELL_EUTRAN_ID_INVALID;
event_handler_list_dispatch(&evt);

k_sem_give(&ncellmeas_idle_sem);
}
}

K_WORK_DELAYABLE_DEFINE(ncellmeas_cancel_timeout_work, ncellmeas_cancel_timeout_work_fn);

int ncellmeas_cancel(void)
{
LOG_DBG("Cancelling");
Expand All @@ -793,7 +821,11 @@ int ncellmeas_cancel(void)
err = -EFAULT;
}

k_sem_give(&ncellmeas_idle_sem);
/* Transition to idle happens when %NCELLMEAS notification is received. However, if modem
* had not yet started the measurement, no notification is sent and we need a timeout to
* handle it.
*/
k_work_schedule(&ncellmeas_cancel_timeout_work, K_SECONDS(1));

return err;
}
4 changes: 3 additions & 1 deletion tests/lib/location/src/location_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -1017,7 +1017,9 @@ void test_location_cellular_cancel_during_ncellmeas(void)

err = location_request_cancel();
TEST_ASSERT_EQUAL(0, err);
k_sleep(K_MSEC(1));

/* Need to wait a bit because no %NCELLMEAS notification is sent after AT%NCELLMEASSTOP. */
k_sleep(K_SECONDS(2));
}

/* Test cellular timeout during the 1st NCELLMEAS. */
Expand Down
91 changes: 91 additions & 0 deletions tests/lib/lte_lc_api/src/lte_lc_api_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -2384,6 +2384,18 @@ void test_lte_lc_neighbor_cell_measurement_fail(void)
TEST_ASSERT_EQUAL(-EFAULT, ret);
}

/* Test that no callbacks are triggered by an %NCELLMEAS notification when
* lte_lc_neighbor_cell_measurement() has not been called.
*/
void test_lte_lc_neighbor_cell_measurement_no_request(void)
{
strcpy(at_notif,
"%NCELLMEAS: 0,\"00112233\",\"98712\",\"0AB9\",4800,7,63,31,"
"456,4800,8,60,29,4,3500,9,99,18,5,5300,11\r\n");

at_monitor_dispatch(at_notif);
}

void test_lte_lc_neighbor_cell_measurement_normal(void)
{
int ret;
Expand Down Expand Up @@ -3366,11 +3378,90 @@ void test_lte_lc_neighbor_cell_measurement_gci_max_length(void)
void test_lte_lc_neighbor_cell_measurement_cancel(void)
{
int ret;
struct lte_lc_ncellmeas_params params = {
.search_type = LTE_LC_NEIGHBOR_SEARCH_TYPE_DEFAULT,
.gci_count = 0,
};
strcpy(at_notif,
"%NCELLMEAS:0,\"00112233\",\"98712\",\"0AB9\",4800,7,63,31,"
"456,4800,8,60,29,4,3500,9,99,18,5,5300,11\r\n");

lte_lc_callback_count_expected = 1;

test_event_data[0].type = LTE_LC_EVT_NEIGHBOR_CELL_MEAS;
test_event_data[0].cells_info.current_cell.mcc = 987;
test_event_data[0].cells_info.current_cell.mnc = 12;
test_event_data[0].cells_info.current_cell.id = 0x00112233;
test_event_data[0].cells_info.current_cell.tac = 0x0AB9;
test_event_data[0].cells_info.current_cell.earfcn = 7;
test_event_data[0].cells_info.current_cell.timing_advance = 4800;
test_event_data[0].cells_info.current_cell.timing_advance_meas_time = 11;
test_event_data[0].cells_info.current_cell.measurement_time = 4800;
test_event_data[0].cells_info.current_cell.phys_cell_id = 63;
test_event_data[0].cells_info.current_cell.rsrp = 31;
test_event_data[0].cells_info.current_cell.rsrq = 456;
test_event_data[0].cells_info.ncells_count = 2;
test_event_data[0].cells_info.gci_cells_count = 0;
test_neighbor_cells[0].earfcn = 8;
test_neighbor_cells[0].time_diff = 3500;
test_neighbor_cells[0].phys_cell_id = 60;
test_neighbor_cells[0].rsrp = 29;
test_neighbor_cells[0].rsrq = 4;
test_neighbor_cells[1].earfcn = 9;
test_neighbor_cells[1].time_diff = 5300;
test_neighbor_cells[1].phys_cell_id = 99;
test_neighbor_cells[1].rsrp = 18;
test_neighbor_cells[1].rsrq = 5;

__mock_nrf_modem_at_printf_ExpectAndReturn("AT%NCELLMEAS", EXIT_SUCCESS);

ret = lte_lc_neighbor_cell_measurement(&params);
TEST_ASSERT_EQUAL(EXIT_SUCCESS, ret);

__mock_nrf_modem_at_printf_ExpectAndReturn("AT%NCELLMEASSTOP", EXIT_SUCCESS);

ret = lte_lc_neighbor_cell_measurement_cancel();
TEST_ASSERT_EQUAL(EXIT_SUCCESS, ret);

at_monitor_dispatch(at_notif);
}

void test_lte_lc_neighbor_cell_measurement_cancel_no_notif(void)
{
int ret;
struct lte_lc_ncellmeas_params params = {
.search_type = LTE_LC_NEIGHBOR_SEARCH_TYPE_DEFAULT,
.gci_count = 0,
};

lte_lc_callback_count_expected = 1;

test_event_data[0].type = LTE_LC_EVT_NEIGHBOR_CELL_MEAS;
test_event_data[0].cells_info.current_cell.id = LTE_LC_CELL_EUTRAN_ID_INVALID;

__mock_nrf_modem_at_printf_ExpectAndReturn("AT%NCELLMEAS", EXIT_SUCCESS);

ret = lte_lc_neighbor_cell_measurement(&params);
TEST_ASSERT_EQUAL(EXIT_SUCCESS, ret);

__mock_nrf_modem_at_printf_ExpectAndReturn("AT%NCELLMEASSTOP", EXIT_SUCCESS);

ret = lte_lc_neighbor_cell_measurement_cancel();
TEST_ASSERT_EQUAL(EXIT_SUCCESS, ret);

/* After lte_lc_neighbor_cell_measurement_cancel(), new measurement can not be started
* before a %NCELLMEAS notification is received or a timeout happens.
*/
ret = lte_lc_neighbor_cell_measurement(&params);
TEST_ASSERT_EQUAL(-EINPROGRESS, ret);

k_sleep(K_MSEC(1));
}

void test_lte_lc_neighbor_cell_measurement_cancel_fail(void)
{
int ret;

__mock_nrf_modem_at_printf_ExpectAndReturn("AT%NCELLMEASSTOP", -NRF_ENOMEM);
ret = lte_lc_neighbor_cell_measurement_cancel();
TEST_ASSERT_EQUAL(-EFAULT, ret);
Expand Down

0 comments on commit 415ce2e

Please sign in to comment.