Skip to content

Commit e484e03

Browse files
committed
modules: cloud: Handle storage messages when cloud is paused
Storage messages need to be handled also when the cloud connection is paused. This is to avoid a batch session being open with no consumer, blocking opening and new session and sending data if the cloud comes back online before the session times out. Signed-off-by: Jan Tore Guggedal <[email protected]>
1 parent d883495 commit e484e03

File tree

2 files changed

+157
-8
lines changed

2 files changed

+157
-8
lines changed

app/src/modules/cloud/cloud.c

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,12 +1099,43 @@ static void state_connected_paused_entry(void *obj)
10991099
static enum smf_state_result state_connected_paused_run(void *obj)
11001100
{
11011101
struct cloud_state_object const *state_object = obj;
1102-
struct network_msg msg = MSG_TO_NETWORK_MSG(state_object->msg_buf);
11031102

1104-
if ((state_object->chan == &NETWORK_CHAN) && (msg.type == NETWORK_CONNECTED)) {
1105-
smf_set_state(SMF_CTX(state_object), &states[STATE_CONNECTED_READY]);
1103+
if (state_object->chan == &NETWORK_CHAN) {
1104+
struct network_msg msg = MSG_TO_NETWORK_MSG(state_object->msg_buf);
11061105

1107-
return SMF_EVENT_HANDLED;
1106+
if (msg.type == NETWORK_CONNECTED) {
1107+
smf_set_state(SMF_CTX(state_object), &states[STATE_CONNECTED_READY]);
1108+
1109+
return SMF_EVENT_HANDLED;
1110+
}
1111+
}
1112+
1113+
if (state_object->chan == &STORAGE_CHAN) {
1114+
const struct storage_msg *msg = MSG_TO_STORAGE_MSG(state_object->msg_buf);
1115+
1116+
switch (msg->type) {
1117+
case STORAGE_BATCH_AVAILABLE:
1118+
case STORAGE_BATCH_EMPTY:
1119+
LOG_WRN("Storage batch received, cloud is paused, closing session 0x%X",
1120+
msg->session_id);
1121+
1122+
handle_storage_batch_empty(msg);
1123+
1124+
return SMF_EVENT_HANDLED;
1125+
case STORAGE_BATCH_ERROR:
1126+
LOG_DBG("Storage batch error received while paused, closing session 0x%X",
1127+
msg->session_id);
1128+
1129+
handle_storage_batch_error(msg);
1130+
1131+
return SMF_EVENT_HANDLED;
1132+
case STORAGE_BATCH_BUSY:
1133+
handle_storage_batch_busy(msg);
1134+
1135+
return SMF_EVENT_HANDLED;
1136+
default:
1137+
break;
1138+
}
11081139
}
11091140

11101141
return SMF_EVENT_PROPAGATE;

tests/module/cloud/src/cloud_module_test.c

Lines changed: 122 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,9 @@ static K_SEM_DEFINE(cloud_disconnected, 0, 1);
143143
static K_SEM_DEFINE(cloud_connected, 0, 1);
144144
static K_SEM_DEFINE(data_sent, 0, 1);
145145
static K_SEM_DEFINE(cloud_module_response_recv_sem, 0, 1);
146+
static K_SEM_DEFINE(storage_batch_closed, 0, 1);
146147
static struct cloud_msg last_shadow_response;
148+
static struct storage_msg last_storage_msg;
147149

148150
static nrf_provisioning_event_cb_t handler;
149151

@@ -248,12 +250,13 @@ static void setup_cloud_and_passthrough(void)
248250
};
249251

250252
/* Connect to cloud */
251-
zbus_chan_pub(&NETWORK_CHAN, &network_msg, K_NO_WAIT);
253+
err = zbus_chan_pub(&NETWORK_CHAN, &network_msg, K_SECONDS(1));
254+
TEST_ASSERT_EQUAL(0, err);
252255
err = k_sem_take(&cloud_connected, K_SECONDS(WAIT_TIMEOUT));
253256
TEST_ASSERT_EQUAL(0, err);
254257

255258
/* Enable passthrough mode */
256-
err = zbus_chan_pub(&STORAGE_CHAN, &passthrough_msg, K_NO_WAIT);
259+
err = zbus_chan_pub(&STORAGE_CHAN, &passthrough_msg, K_SECONDS(1));
257260
TEST_ASSERT_EQUAL(0, err);
258261
k_sleep(K_MSEC(PROCESSING_DELAY_MS));
259262
}
@@ -281,8 +284,13 @@ static void cloud_chan_cb(const struct zbus_channel *chan)
281284
status == CLOUD_SHADOW_RESPONSE_DELTA) {
282285
memcpy(&last_shadow_response, cloud_msg, sizeof(struct cloud_msg));
283286
k_sem_give(&cloud_module_response_recv_sem);
287+
}
288+
} else if (chan == &STORAGE_CHAN) {
289+
const struct storage_msg *storage_msg = zbus_chan_const_msg(chan);
284290

285-
printk("cloud_chan_cb: received cloud message of type %d\n", status);
291+
if (storage_msg->type == STORAGE_BATCH_CLOSE) {
292+
memcpy(&last_storage_msg, storage_msg, sizeof(struct storage_msg));
293+
k_sem_give(&storage_batch_closed);
286294
}
287295
}
288296
}
@@ -328,7 +336,7 @@ static void publish_and_assert(const struct zbus_channel *chan, const void *msg)
328336
{
329337
int err;
330338

331-
err = zbus_chan_pub(chan, msg, K_NO_WAIT);
339+
err = zbus_chan_pub(chan, msg, K_SECONDS(1));
332340
TEST_ASSERT_EQUAL(0, err);
333341
}
334342

@@ -404,6 +412,7 @@ void setUp(void)
404412
k_sem_reset(&cloud_connected);
405413
k_sem_reset(&data_sent);
406414
k_sem_reset(&cloud_module_response_recv_sem);
415+
k_sem_reset(&storage_batch_closed);
407416

408417
/* Set default return values */
409418
nrf_cloud_coap_location_send_fake.return_val = 0;
@@ -1322,6 +1331,115 @@ void test_location_cloud_request_wifi_data_excessive_ap_count(void)
13221331

13231332
/* Verify that nrf_cloud_coap_location_get was NOT called due to validation failure. */
13241333
TEST_ASSERT_EQUAL(0, nrf_cloud_coap_location_get_fake.call_count);
1334+
1335+
/* 10 second sleep is needed to wait for the sleep in SEND_FATAL_ERROR to time out */
1336+
k_sleep(K_SECONDS(10));
1337+
}
1338+
1339+
/* Helper to get cloud into paused state (connected but network disconnected) */
1340+
static void setup_cloud_paused(void)
1341+
{
1342+
struct network_msg network_msg = {
1343+
.type = NETWORK_CONNECTED
1344+
};
1345+
1346+
/* Connect to cloud */
1347+
publish_and_assert(&NETWORK_CHAN, &network_msg);
1348+
wait_for_cloud_connected(K_SECONDS(WAIT_TIMEOUT));
1349+
wait_for_processing();
1350+
1351+
/* Disconnect network to enter paused state */
1352+
network_msg.type = NETWORK_DISCONNECTED;
1353+
1354+
publish_and_assert(&NETWORK_CHAN, &network_msg);
1355+
wait_for_cloud_disconnected(K_SECONDS(WAIT_TIMEOUT));
1356+
wait_for_processing();
1357+
}
1358+
1359+
/* Helper to wait for storage batch close message */
1360+
static void wait_for_storage_batch_close(k_timeout_t timeout)
1361+
{
1362+
int err;
1363+
1364+
err = k_sem_take(&storage_batch_closed, timeout);
1365+
TEST_ASSERT_EQUAL(0, err);
1366+
}
1367+
1368+
void test_storage_batch_available_when_paused_should_close_session(void)
1369+
{
1370+
struct storage_msg batch_available = {
1371+
.type = STORAGE_BATCH_AVAILABLE,
1372+
.data_len = 5,
1373+
.session_id = 0x12345678,
1374+
.more_data = false,
1375+
};
1376+
1377+
setup_cloud_paused();
1378+
1379+
publish_and_assert(&STORAGE_CHAN, &batch_available);
1380+
wait_for_processing();
1381+
1382+
wait_for_storage_batch_close(K_SECONDS(WAIT_TIMEOUT));
1383+
1384+
TEST_ASSERT_EQUAL(STORAGE_BATCH_CLOSE, last_storage_msg.type);
1385+
TEST_ASSERT_EQUAL(batch_available.session_id, last_storage_msg.session_id);
1386+
}
1387+
1388+
void test_storage_batch_empty_when_paused_should_close_session(void)
1389+
{
1390+
struct storage_msg batch_empty = {
1391+
.type = STORAGE_BATCH_EMPTY,
1392+
.session_id = 0x87654321,
1393+
};
1394+
1395+
setup_cloud_paused();
1396+
1397+
publish_and_assert(&STORAGE_CHAN, &batch_empty);
1398+
wait_for_processing();
1399+
1400+
wait_for_storage_batch_close(K_SECONDS(WAIT_TIMEOUT));
1401+
1402+
TEST_ASSERT_EQUAL(STORAGE_BATCH_CLOSE, last_storage_msg.type);
1403+
TEST_ASSERT_EQUAL(batch_empty.session_id, last_storage_msg.session_id);
1404+
}
1405+
1406+
void test_storage_batch_error_when_paused_should_close_session(void)
1407+
{
1408+
struct storage_msg batch_error = {
1409+
.type = STORAGE_BATCH_ERROR,
1410+
.session_id = 0xAABBCCDD,
1411+
};
1412+
1413+
setup_cloud_paused();
1414+
1415+
publish_and_assert(&STORAGE_CHAN, &batch_error);
1416+
wait_for_processing();
1417+
1418+
wait_for_storage_batch_close(K_SECONDS(WAIT_TIMEOUT));
1419+
1420+
TEST_ASSERT_EQUAL(STORAGE_BATCH_CLOSE, last_storage_msg.type);
1421+
TEST_ASSERT_EQUAL(batch_error.session_id, last_storage_msg.session_id);
1422+
}
1423+
1424+
void test_storage_batch_busy_when_paused_should_handle(void)
1425+
{
1426+
struct storage_msg batch_busy = {
1427+
.type = STORAGE_BATCH_BUSY,
1428+
.session_id = 0xDDCCBBAA,
1429+
};
1430+
1431+
setup_cloud_paused();
1432+
1433+
publish_and_assert(&STORAGE_CHAN, &batch_busy);
1434+
wait_for_processing();
1435+
1436+
/* BUSY message should be handled but not close the session
1437+
* Give some time to ensure no close message is sent.
1438+
*/
1439+
k_sleep(K_MSEC(PROCESSING_DELAY_MS));
1440+
1441+
/* Verify no close message was sent */
1442+
TEST_ASSERT_EQUAL(0, k_sem_count_get(&storage_batch_closed));
13251443
}
13261444

13271445
/* This is required to be added to each test. That is because unity's

0 commit comments

Comments
 (0)