Skip to content

Commit 8a7b9c8

Browse files
committed
main: Rework sub states in STATE_TRIGGERING
The sub states in STATE_TRIGGERING have been updated to allow for a dedicated wait state, and to make it easier to have accurate intervals between samples. Tests are updated, and we now also test that the correct interval is maintained over time. Signed-off-by: Jan Tore Guggedal <jantore.guggedal@nordicsemi.no>
1 parent 98fe5af commit 8a7b9c8

File tree

7 files changed

+191
-88
lines changed

7 files changed

+191
-88
lines changed

app/src/cbor/cbor_helper.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
int get_update_interval_from_cbor_response(const uint8_t *cbor,
1010
size_t len,
11-
uint64_t *interval_sec)
11+
uint32_t *interval_sec)
1212
{
1313
struct config_object object = { 0 };
1414
size_t not_used;

app/src/cbor/cbor_helper.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,4 @@
2020
*/
2121
int get_update_interval_from_cbor_response(const uint8_t *cbor,
2222
size_t len,
23-
uint64_t *interval_sec);
23+
uint32_t *interval_sec);

app/src/cbor/device_shadow.cddl

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
config-object = {
22
"config": {
3-
"update_interval": uint .size 8
3+
"update_interval": uint .size 4
44
}
55
}

app/src/main.c

+71-47
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,12 @@ static void running_run(void *o);
7777
static void triggering_entry(void *o);
7878
static void triggering_run(void *o);
7979

80-
static void requesting_location_entry(void *o);
81-
static void requesting_location_run(void *o);
80+
static void sample_data_entry(void *o);
81+
static void sample_data_run(void *o);
8282

83-
static void requesting_sensors_and_polling_entry(void *o);
84-
static void requesting_sensors_and_polling_run(void *o);
85-
static void requesting_sensors_and_polling_exit(void *o);
83+
static void wait_for_trigger_entry(void *o);
84+
static void wait_for_trigger_run(void *o);
85+
static void wait_for_trigger_exit(void *o);
8686

8787
static void idle_entry(void *o);
8888
static void idle_run(void *o);
@@ -110,10 +110,13 @@ enum state {
110110
STATE_IDLE,
111111
/* Triggers are periodically sent at a configured interval */
112112
STATE_TRIGGERING,
113-
/* Requesting location from the location module */
114-
STATE_REQUESTING_LOCATION,
115-
/* Requesting sensor values and polling for downlink data */
116-
STATE_REQUESTING_SENSORS_AND_POLLING,
113+
/* Requesting data samples from relevant modules.
114+
* Location data is requested first, upon state entry.
115+
* After location data is received, the other modules are polled.
116+
*/
117+
STATE_SAMPLE_DATA,
118+
/* Wait for timer or button press to trigger the next sample */
119+
STATE_WAIT_FOR_TRIGGER,
117120
/* Ongoing FOTA process, triggers are blocked */
118121
STATE_FOTA,
119122
/* FOTA image is being downloaded */
@@ -144,10 +147,15 @@ struct main_state {
144147
uint8_t msg_buf[MAX_MSG_SIZE];
145148

146149
/* Trigger interval */
147-
uint64_t interval_sec;
150+
uint32_t interval_sec;
148151

149152
/* Cloud connection status */
150153
bool connected;
154+
155+
/* Start time of the most recent sampling. This is used to calculate the correct
156+
* time when scheduling the next sampling trigger.
157+
*/
158+
uint32_t sample_start_time;
151159
};
152160

153161
/* Construct state table */
@@ -171,19 +179,19 @@ static const struct smf_state states[] = {
171179
triggering_run,
172180
NULL,
173181
&states[STATE_RUNNING],
174-
&states[STATE_REQUESTING_LOCATION]
182+
&states[STATE_SAMPLE_DATA]
175183
),
176-
[STATE_REQUESTING_LOCATION] = SMF_CREATE_STATE(
177-
requesting_location_entry,
178-
requesting_location_run,
184+
[STATE_SAMPLE_DATA] = SMF_CREATE_STATE(
185+
sample_data_entry,
186+
sample_data_run,
179187
NULL,
180188
&states[STATE_TRIGGERING],
181189
NULL
182190
),
183-
[STATE_REQUESTING_SENSORS_AND_POLLING] = SMF_CREATE_STATE(
184-
requesting_sensors_and_polling_entry,
185-
requesting_sensors_and_polling_run,
186-
requesting_sensors_and_polling_exit,
191+
[STATE_WAIT_FOR_TRIGGER] = SMF_CREATE_STATE(
192+
wait_for_trigger_entry,
193+
wait_for_trigger_run,
194+
wait_for_trigger_exit,
187195
&states[STATE_TRIGGERING],
188196
NULL
189197
),
@@ -293,18 +301,6 @@ static void sensor_and_poll_triggers_send(void)
293301
SEND_FATAL_ERROR();
294302
return;
295303
}
296-
297-
/* Send trigger for shadow polling */
298-
struct cloud_msg cloud_msg = {
299-
.type = CLOUD_POLL_SHADOW
300-
};
301-
302-
err = zbus_chan_pub(&CLOUD_CHAN, &cloud_msg, K_SECONDS(1));
303-
if (err) {
304-
LOG_ERR("zbus_chan_pub shadow trigger, error: %d", err);
305-
SEND_FATAL_ERROR();
306-
return;
307-
}
308304
}
309305

310306
/* Delayable work used to send messages on the TIMER_CHAN */
@@ -464,7 +460,7 @@ static void triggering_run(void *o)
464460
return;
465461
}
466462

467-
LOG_WRN("Received new interval: %lld seconds", state_object->interval_sec);
463+
LOG_WRN("Received new interval: %d seconds", state_object->interval_sec);
468464

469465
err = k_work_reschedule(&trigger_work,
470466
K_SECONDS(state_object->interval_sec));
@@ -476,17 +472,30 @@ static void triggering_run(void *o)
476472
}
477473
}
478474

479-
/* STATE_REQUESTING_LOCATION */
475+
/* STATE_SAMPLE_DATA */
480476

481-
static void requesting_location_entry(void *o)
477+
static void sample_data_entry(void *o)
482478
{
483479
int err;
484480
enum location_msg_type location_msg = LOCATION_SEARCH_TRIGGER;
481+
struct cloud_msg cloud_msg = {
482+
.type = CLOUD_POLL_SHADOW
483+
};
484+
struct main_state *state_object = (struct main_state *)o;
485485

486-
ARG_UNUSED(o);
487486

488487
LOG_DBG("%s", __func__);
489488

489+
/* Record the start time of sampling */
490+
state_object->sample_start_time = k_uptime_seconds();
491+
492+
err = zbus_chan_pub(&CLOUD_CHAN, &cloud_msg, K_SECONDS(1));
493+
if (err) {
494+
LOG_ERR("zbus_chan_pub shadow trigger, error: %d", err);
495+
SEND_FATAL_ERROR();
496+
return;
497+
}
498+
490499
err = zbus_chan_pub(&LOCATION_CHAN, &location_msg, K_SECONDS(1));
491500
if (err) {
492501
LOG_ERR("zbus_chan_pub data sample trigger, error: %d", err);
@@ -495,62 +504,77 @@ static void requesting_location_entry(void *o)
495504
}
496505
}
497506

498-
static void requesting_location_run(void *o)
507+
static void sample_data_run(void *o)
499508
{
500509
const struct main_state *state_object = (const struct main_state *)o;
501510

502511
if (state_object->chan == &LOCATION_CHAN) {
503512
enum location_msg_type msg = MSG_TO_LOCATION_TYPE(state_object->msg_buf);
504513

505514
if (msg == LOCATION_SEARCH_DONE) {
506-
smf_set_state(SMF_CTX(state_object),
507-
&states[STATE_REQUESTING_SENSORS_AND_POLLING]);
515+
sensor_and_poll_triggers_send();
516+
smf_set_state(SMF_CTX(state_object), &states[STATE_WAIT_FOR_TRIGGER]);
508517
return;
509518
}
510519
}
511520

521+
/* We are already sampling, ignore any new triggers */
512522
if (state_object->chan == &BUTTON_CHAN) {
513523
smf_set_handled(SMF_CTX(state_object));
514524
return;
515525
}
526+
527+
if (state_object->chan == &TIMER_CHAN) {
528+
smf_set_handled(SMF_CTX(state_object));
529+
return;
530+
}
516531
}
517532

518-
/* STATE_REQUESTING_SENSORS_AND_POLLING */
533+
/* STATE_WAIT_FOR_TRIGGER */
519534

520-
static void requesting_sensors_and_polling_entry(void *o)
535+
static void wait_for_trigger_entry(void *o)
521536
{
522537
int err;
523538
const struct main_state *state_object = (const struct main_state *)o;
539+
uint32_t time_elapsed = k_uptime_seconds() - state_object->sample_start_time;
540+
uint32_t time_remaining;
541+
542+
if (time_elapsed > state_object->interval_sec) {
543+
LOG_WRN("Sampling took longer than the interval, skipping next trigger");
544+
time_remaining = 0;
545+
} else {
546+
time_remaining = state_object->interval_sec - time_elapsed;
547+
}
524548

525549
LOG_DBG("%s", __func__);
526550

527-
sensor_and_poll_triggers_send();
551+
LOG_DBG("Next trigger in %d seconds", time_remaining);
528552

529-
LOG_DBG("Next trigger in %lld seconds", state_object->interval_sec);
530-
531-
err = k_work_reschedule(&trigger_work, K_SECONDS(state_object->interval_sec));
553+
(void)k_work_cancel_delayable(&trigger_work);
554+
err = k_work_reschedule(&trigger_work, K_SECONDS(time_remaining));
532555
if (err < 0) {
533556
LOG_ERR("k_work_reschedule, error: %d", err);
534557
SEND_FATAL_ERROR();
535558
}
536559
}
537560

538-
static void requesting_sensors_and_polling_run(void *o)
561+
static void wait_for_trigger_run(void *o)
539562
{
540563
const struct main_state *state_object = (const struct main_state *)o;
541564

542565
if (state_object->chan == &TIMER_CHAN) {
543-
smf_set_state(SMF_CTX(state_object), &states[STATE_REQUESTING_LOCATION]);
566+
LOG_DBG("Timer trigger received");
567+
smf_set_state(SMF_CTX(state_object), &states[STATE_SAMPLE_DATA]);
544568
return;
545569
}
546570

547571
if (state_object->chan == &BUTTON_CHAN) {
548-
smf_set_state(SMF_CTX(state_object), &states[STATE_REQUESTING_LOCATION]);
572+
smf_set_state(SMF_CTX(state_object), &states[STATE_SAMPLE_DATA]);
549573
return;
550574
}
551575
}
552576

553-
static void requesting_sensors_and_polling_exit(void *o)
577+
static void wait_for_trigger_exit(void *o)
554578
{
555579
ARG_UNUSED(o);
556580

tests/module/main/src/checks.c

+43-7
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ ZBUS_CHAN_ADD_OBS(LOCATION_CHAN, location_subscriber, 0);
2020
ZBUS_CHAN_ADD_OBS(NETWORK_CHAN, network_subscriber, 0);
2121
ZBUS_CHAN_ADD_OBS(POWER_CHAN, power_subscriber, 0);
2222

23-
LOG_MODULE_REGISTER(trigger_module_checks, 4);
23+
LOG_MODULE_REGISTER(main_module_checks, 4);
2424

2525
void check_location_event(enum location_msg_type expected_location_type)
2626
{
@@ -31,7 +31,7 @@ void check_location_event(enum location_msg_type expected_location_type)
3131
/* Allow the test thread to sleep so that the DUT's thread is allowed to run. */
3232
k_sleep(K_MSEC(100));
3333

34-
err = zbus_sub_wait_msg(&location_subscriber, &chan, &location_msg_type, K_MSEC(1000));
34+
err = zbus_sub_wait_msg(&location_subscriber, &chan, &location_msg_type, K_MSEC(10000));
3535
if (err == -ENOMSG) {
3636
LOG_ERR("No location event received");
3737
TEST_FAIL();
@@ -60,7 +60,7 @@ void check_network_event(enum network_msg_type expected_network_type)
6060
/* Allow the test thread to sleep so that the DUT's thread is allowed to run. */
6161
k_sleep(K_MSEC(100));
6262

63-
err = zbus_sub_wait_msg(&network_subscriber, &chan, &network_msg, K_MSEC(1000));
63+
err = zbus_sub_wait_msg(&network_subscriber, &chan, &network_msg, K_MSEC(10000));
6464
if (err == -ENOMSG) {
6565
LOG_ERR("No network event received");
6666
TEST_FAIL();
@@ -89,7 +89,7 @@ void check_power_event(enum power_msg_type expected_power_type)
8989
/* Allow the test thread to sleep so that the DUT's thread is allowed to run. */
9090
k_sleep(K_MSEC(100));
9191

92-
err = zbus_sub_wait_msg(&power_subscriber, &chan, &power_msg, K_MSEC(1000));
92+
err = zbus_sub_wait_msg(&power_subscriber, &chan, &power_msg, K_MSEC(10000));
9393
if (err == -ENOMSG) {
9494
LOG_ERR("No power event received");
9595
TEST_FAIL();
@@ -116,7 +116,7 @@ static void check_no_location_events(void)
116116
const struct zbus_channel *chan;
117117
enum location_msg_type location_msg_type;
118118

119-
err = zbus_sub_wait_msg(&location_subscriber, &chan, &location_msg_type, K_MSEC(1000));
119+
err = zbus_sub_wait_msg(&location_subscriber, &chan, &location_msg_type, K_MSEC(10000));
120120
if (err == -ENOMSG) {
121121
return;
122122
} else if (err) {
@@ -136,7 +136,7 @@ static void check_no_network_events(void)
136136
const struct zbus_channel *chan;
137137
struct network_msg network_msg;
138138

139-
err = zbus_sub_wait_msg(&network_subscriber, &chan, &network_msg, K_MSEC(1000));
139+
err = zbus_sub_wait_msg(&network_subscriber, &chan, &network_msg, K_MSEC(10000));
140140
if (err == -ENOMSG) {
141141
return;
142142
} else if (err) {
@@ -156,7 +156,7 @@ static void check_no_power_events(void)
156156
const struct zbus_channel *chan;
157157
struct power_msg power_msg;
158158

159-
err = zbus_sub_wait_msg(&power_subscriber, &chan, &power_msg, K_MSEC(1000));
159+
err = zbus_sub_wait_msg(&power_subscriber, &chan, &power_msg, K_MSEC(10000));
160160
if (err == -ENOMSG) {
161161
return;
162162
} else if (err) {
@@ -243,3 +243,39 @@ void purge_all_events(void)
243243
purge_network_events();
244244
purge_power_events();
245245
}
246+
247+
int wait_for_location_event(enum location_msg_type expected_type, uint32_t timeout_sec)
248+
{
249+
int err;
250+
const struct zbus_channel *chan;
251+
enum location_msg_type location_msg_type;
252+
uint32_t start_time = k_uptime_seconds();
253+
uint32_t elapsed_time;
254+
255+
err = zbus_sub_wait_msg(&location_subscriber, &chan, &location_msg_type,
256+
K_SECONDS(timeout_sec));
257+
if (err == -ENOMSG) {
258+
return -ENOMSG;
259+
} else if (err) {
260+
LOG_ERR("zbus_sub_wait, error: %d", err);
261+
262+
return err;
263+
}
264+
265+
if (chan != &LOCATION_CHAN) {
266+
LOG_ERR("Received message from wrong channel, expected %s, got %s",
267+
zbus_chan_name(&LOCATION_CHAN), zbus_chan_name(chan));
268+
return -EINVAL;
269+
}
270+
271+
if (location_msg_type != expected_type) {
272+
LOG_ERR("Received unexpected location event: %d", location_msg_type);
273+
return -EINVAL;
274+
}
275+
276+
elapsed_time = k_uptime_seconds() - start_time;
277+
278+
LOG_DBG("Received expected location event: %d, wait: %d", location_msg_type, elapsed_time);
279+
280+
return elapsed_time;
281+
}

tests/module/main/src/checks.h

+7
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,10 @@ void purge_network_events(void);
2323
void purge_power_events(void);
2424

2525
void purge_all_events(void);
26+
27+
/* Wait for a location event of the expected type.
28+
*
29+
* Returns the time in seconds it took to receive the event if it is received within the timeout.
30+
* Otherwise, it returns a negative value.
31+
*/
32+
int wait_for_location_event(enum location_msg_type expected_type, uint32_t timeout_sec);

0 commit comments

Comments
 (0)