Skip to content

Commit 0635ce3

Browse files
committed
modules: app: Merge with trigger module to simplify application
The app and trigger modules are merged to simplify the application logic. It's now all in the app module. This also allows for the environmental module to have only one state and hence no need for state machine, as triggers will not be sent if time is not available. Signed-off-by: Jan Tore Guggedal <jantore.guggedal@nordicsemi.no>
1 parent 3e2bc09 commit 0635ce3

17 files changed

+346
-404
lines changed

app/CMakeLists.txt

-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ project("Asset Tracker Template")
1313
add_subdirectory(src/common)
1414

1515
# Include mandatory module source folders
16-
add_subdirectory(src/modules/trigger)
1716
add_subdirectory(src/modules/battery)
1817
add_subdirectory(src/modules/network)
1918
add_subdirectory(src/modules/transport)

app/Kconfig

-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ config APP_PAYLOAD_CHANNEL_BUFFER_MAX_SIZE
1313
Maximum size of the buffer sent over the payload channel.
1414
Contains encoded CBOR data sampled and encoded in the various modules.
1515

16-
rsource "src/modules/trigger/Kconfig.trigger"
1716
rsource "src/modules/battery/Kconfig.battery"
1817
rsource "src/modules/network/Kconfig.network"
1918
rsource "src/modules/transport/Kconfig.transport"

app/prj.conf

-1
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,6 @@ CONFIG_APP_FOTA_LOG_LEVEL_DBG=y
221221
CONFIG_APP_BATTERY_LOG_LEVEL_DBG=y
222222
CONFIG_APP_LOCATION_LOG_LEVEL_DBG=y
223223
CONFIG_APP_TRANSPORT_LOG_LEVEL_DBG=y
224-
CONFIG_APP_TRIGGER_LOG_LEVEL_DBG=y
225224
CONFIG_APP_NETWORK_LOG_LEVEL_DBG=y
226225
CONFIG_APP_LED_LOG_LEVEL_DBG=y
227226
CONFIG_APP_ENVIRONMENTAL_LOG_LEVEL_DBG=y

app/src/common/message_channel.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ struct cloud_msg {
223223
#define MSG_TO_CLOUD_MSG(_msg) (*(const struct cloud_msg *)_msg)
224224

225225
enum trigger_type {
226-
TRIGGER_POLL = 0x1,
226+
TRIGGER_POLL_SHADOW = 0x1,
227227
TRIGGER_FOTA_POLL,
228228
TRIGGER_DATA_SAMPLE,
229229
};

app/src/modules/app/Kconfig.app

+7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@
55
#
66
menu "App"
77

8+
config APP_MODULE_TRIGGER_TIMEOUT_SECONDS
9+
int "Trigger timer timeout"
10+
default 600
11+
help
12+
Timeout for the trigger timer. On timeout, the module will send triggers for
13+
sensor sampling, location search and polling of shadow and FOTA status from cloud.
14+
815
config APP_MODULE_THREAD_STACK_SIZE
916
int "Thread stack size"
1017
default 3200

app/src/modules/app/app.c

+302-2
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,249 @@
88
#include <zephyr/logging/log.h>
99
#include <zephyr/zbus/zbus.h>
1010
#include <date_time.h>
11+
#include <zephyr/task_wdt/task_wdt.h>
12+
#include <zephyr/smf.h>
1113

14+
#include "modules_common.h"
1215
#include "message_channel.h"
1316

1417
/* Register log module */
1518
LOG_MODULE_REGISTER(app, CONFIG_APP_LOG_LEVEL);
1619

20+
/* Define a ZBUS listener for this module */
21+
static void app_callback(const struct zbus_channel *chan);
22+
ZBUS_LISTENER_DEFINE(app_listener, app_callback);
23+
24+
/* Observe channels */
25+
ZBUS_CHAN_ADD_OBS(CONFIG_CHAN, app_listener, 0);
26+
ZBUS_CHAN_ADD_OBS(CLOUD_CHAN, app_listener, 0);
27+
ZBUS_CHAN_ADD_OBS(BUTTON_CHAN, app_listener, 0);
28+
ZBUS_CHAN_ADD_OBS(TIME_CHAN, app_listener, 0);
29+
30+
/* Forward declarations */
31+
static void trigger_work_fn(struct k_work *work);
32+
static void date_time_handler(const struct date_time_evt *evt);
33+
static const struct smf_state states[];
34+
35+
/* Delayable work used to schedule triggers */
36+
static K_WORK_DELAYABLE_DEFINE(trigger_work, trigger_work_fn);
37+
38+
/* State machine definitions */
39+
static const struct smf_state states[];
40+
41+
/* Forward declarations of state handlers */
42+
static void init_entry(void *o);
43+
static void init_run(void *o);
44+
45+
static void connected_entry(void *o);
46+
static void connected_run(void *o);
47+
48+
static void disconnected_entry(void *o);
49+
static void disconnected_run(void *o);
50+
51+
/* Defining the hierarchical trigger module states:
52+
*
53+
* STATE_INIT: Initial state where the module waits for time to be available.
54+
* STATE_DISCONNECTED: Cloud connection is not established or paused
55+
* STATE_CONNECTED: Cloud connection is established and ready to send data
56+
*/
57+
enum state {
58+
STATE_INIT,
59+
STATE_CONNECTED,
60+
STATE_DISCONNECTED,
61+
};
62+
63+
/* Construct state table */
64+
static const struct smf_state states[] = {
65+
[STATE_INIT] = SMF_CREATE_STATE(
66+
init_entry,
67+
init_run,
68+
NULL,
69+
NULL,
70+
NULL
71+
),
72+
[STATE_CONNECTED] = SMF_CREATE_STATE(
73+
connected_entry,
74+
connected_run,
75+
NULL,
76+
NULL,
77+
NULL
78+
),
79+
[STATE_DISCONNECTED] = SMF_CREATE_STATE(
80+
disconnected_entry,
81+
disconnected_run,
82+
NULL,
83+
NULL,
84+
NULL
85+
)
86+
};
87+
88+
/* State ovject for the app module.
89+
* Used to transfer data between state changes.
90+
*/
91+
static struct state_object {
92+
/* This must be first */
93+
struct smf_ctx ctx;
94+
95+
/* Last channel type that a message was received on */
96+
const struct zbus_channel *chan;
97+
98+
/* Trigger interval */
99+
uint64_t interval_sec;
100+
101+
/* Button number */
102+
uint8_t button_number;
103+
104+
/* Time available */
105+
enum time_status time_status;
106+
107+
/* Cloud status */
108+
enum cloud_msg_type status;
109+
} app_state;
110+
111+
static void triggers_send(void)
112+
{
113+
int err;
114+
struct network_msg network_msg = {
115+
.type = NETWORK_QUALITY_SAMPLE_REQUEST,
116+
};
117+
struct battery_msg battery_msg = {
118+
.type = BATTERY_PERCENTAGE_SAMPLE_REQUEST,
119+
};
120+
enum trigger_type poll_trigger = TRIGGER_FOTA_POLL;
121+
122+
err = zbus_chan_pub(&NETWORK_CHAN, &network_msg, K_SECONDS(1));
123+
if (err) {
124+
LOG_ERR("zbus_chan_pub, error: %d", err);
125+
SEND_FATAL_ERROR();
126+
return;
127+
}
128+
129+
err = zbus_chan_pub(&BATTERY_CHAN, &battery_msg, K_SECONDS(1));
130+
if (err) {
131+
LOG_ERR("zbus_chan_pub, error: %d", err);
132+
SEND_FATAL_ERROR();
133+
return;
134+
}
135+
136+
/* Send FOTA poll trigger */
137+
err = zbus_chan_pub(&TRIGGER_CHAN, &poll_trigger, K_SECONDS(1));
138+
if (err) {
139+
LOG_ERR("zbus_chan_pub FOTA trigger, error: %d", err);
140+
SEND_FATAL_ERROR();
141+
return;
142+
}
143+
144+
/* Send trigger for shadow polling */
145+
poll_trigger = TRIGGER_POLL_SHADOW;
146+
147+
err = zbus_chan_pub(&TRIGGER_CHAN, &poll_trigger, K_SECONDS(1));
148+
if (err) {
149+
LOG_ERR("zbus_chan_pub shadow trigger, error: %d", err);
150+
SEND_FATAL_ERROR();
151+
return;
152+
}
153+
154+
/* Trigger location search and environmental data sample */
155+
poll_trigger = TRIGGER_DATA_SAMPLE;
156+
157+
err = zbus_chan_pub(&TRIGGER_CHAN, &poll_trigger, K_SECONDS(1));
158+
if (err) {
159+
LOG_ERR("zbus_chan_pub data sample trigger, error: %d", err);
160+
SEND_FATAL_ERROR();
161+
return;
162+
}
163+
}
164+
165+
/* Zephyr State Machine framework handlers */
166+
167+
/* STATE_INIT */
168+
169+
static void init_entry(void *o)
170+
{
171+
ARG_UNUSED(o);
172+
173+
LOG_DBG("%s", __func__);
174+
175+
/* Setup handler for date_time library */
176+
date_time_register_handler(date_time_handler);
177+
}
178+
179+
static void init_run(void *o)
180+
{
181+
struct state_object *user_object = o;
182+
183+
LOG_DBG("%s", __func__);
184+
185+
if ((user_object->chan == &TIME_CHAN) && (user_object->time_status == TIME_AVAILABLE)) {
186+
LOG_DBG("Time available, going into disconnected state");
187+
STATE_SET(app_state, STATE_DISCONNECTED);
188+
return;
189+
}
190+
}
191+
192+
/* STATE_DISCONNECTED */
193+
194+
static void disconnected_entry(void *o)
195+
{
196+
ARG_UNUSED(o);
197+
198+
LOG_DBG("%s", __func__);
199+
200+
k_work_cancel_delayable(&trigger_work);
201+
}
202+
203+
static void disconnected_run(void *o)
204+
{
205+
struct state_object *user_object = o;
206+
207+
LOG_DBG("%s", __func__);
208+
209+
if ((user_object->chan == &CLOUD_CHAN) &&
210+
(user_object->status == CLOUD_CONNECTED_READY_TO_SEND)) {
211+
STATE_SET(app_state, STATE_CONNECTED);
212+
return;
213+
}
214+
}
215+
216+
/* STATE_CONNECTED */
217+
218+
static void connected_entry(void *o)
219+
{
220+
ARG_UNUSED(o);
221+
222+
LOG_DBG("%s", __func__);
223+
224+
k_work_reschedule(&trigger_work, K_NO_WAIT);
225+
}
226+
227+
static void connected_run(void *o)
228+
{
229+
struct state_object *user_object = o;
230+
231+
LOG_DBG("%s", __func__);
232+
233+
if ((user_object->chan == &CLOUD_CHAN) &&
234+
((user_object->status == CLOUD_CONNECTED_PAUSED) ||
235+
(user_object->status == CLOUD_DISCONNECTED))) {
236+
LOG_DBG("Cloud disconnected/paused, going into disconnected state");
237+
STATE_SET(app_state, STATE_DISCONNECTED);
238+
return;
239+
}
240+
241+
if (user_object->chan == &BUTTON_CHAN) {
242+
LOG_DBG("Button %d pressed!", user_object->button_number);
243+
k_work_reschedule(&trigger_work, K_NO_WAIT);
244+
return;
245+
}
246+
247+
if (user_object->chan == &CONFIG_CHAN) {
248+
LOG_DBG("Configuration update, new interval: %lld", user_object->interval_sec);
249+
k_work_reschedule(&trigger_work, K_SECONDS(user_object->interval_sec));
250+
return;
251+
}
252+
}
253+
17254
static void date_time_handler(const struct date_time_evt *evt) {
18255
if (evt->type != DATE_TIME_NOT_OBTAINED) {
19256
int err;
@@ -27,10 +264,73 @@ static void date_time_handler(const struct date_time_evt *evt) {
27264
}
28265
}
29266

267+
/* Delayable work used to send triggers to the rest of the system */
268+
static void trigger_work_fn(struct k_work *work)
269+
{
270+
ARG_UNUSED(work);
271+
272+
LOG_DBG("Sending data sample trigger");
273+
274+
triggers_send();
275+
276+
k_work_reschedule(&trigger_work, K_SECONDS(app_state.interval_sec));
277+
}
278+
279+
/* Function called when there is a message received on a channel that the module listens to */
280+
static void app_callback(const struct zbus_channel *chan)
281+
{
282+
int err;
283+
284+
if ((chan != &CONFIG_CHAN) &&
285+
(chan != &CLOUD_CHAN) &&
286+
(chan != &BUTTON_CHAN) &&
287+
(chan != &TIME_CHAN)) {
288+
LOG_ERR("Unknown channel");
289+
return;
290+
}
291+
292+
LOG_DBG("Received message on channel %s", zbus_chan_name(chan));
293+
294+
/* Update the state object with the channel that the message was received on */
295+
app_state.chan = chan;
296+
297+
/* Copy corresponding data to the state object depending on the incoming channel */
298+
if (&CONFIG_CHAN == chan) {
299+
const struct configuration *config = zbus_chan_const_msg(chan);
300+
301+
if (config->update_interval_present) {
302+
app_state.interval_sec = config->update_interval;
303+
}
304+
} else if (&CLOUD_CHAN == chan) {
305+
const enum cloud_msg_type *status = zbus_chan_const_msg(chan);
306+
307+
app_state.status = *status;
308+
} else if (&BUTTON_CHAN == chan) {
309+
const int *button_number = zbus_chan_const_msg(chan);
310+
311+
app_state.button_number = (uint8_t)*button_number;
312+
} else if (&TIME_CHAN == chan) {
313+
const enum time_status *time_status = zbus_chan_const_msg(chan);
314+
315+
app_state.time_status = *time_status;
316+
}
317+
318+
LOG_DBG("Running SMF");
319+
320+
/* State object updated, run SMF */
321+
err = STATE_RUN(app_state);
322+
if (err) {
323+
LOG_ERR("smf_run_state, error: %d", err);
324+
SEND_FATAL_ERROR();
325+
return;
326+
}
327+
}
328+
30329
static int app_init(void)
31330
{
32-
/* Setup handler for date_time library */
33-
date_time_register_handler(date_time_handler);
331+
app_state.interval_sec = CONFIG_APP_MODULE_TRIGGER_TIMEOUT_SECONDS;
332+
333+
STATE_SET_INITIAL(app_state, STATE_INIT);
34334

35335
return 0;
36336
}

0 commit comments

Comments
 (0)