8
8
#include <zephyr/logging/log.h>
9
9
#include <zephyr/zbus/zbus.h>
10
10
#include <date_time.h>
11
+ #include <zephyr/task_wdt/task_wdt.h>
12
+ #include <zephyr/smf.h>
11
13
14
+ #include "modules_common.h"
12
15
#include "message_channel.h"
13
16
14
17
/* Register log module */
15
18
LOG_MODULE_REGISTER (app , CONFIG_APP_LOG_LEVEL );
16
19
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
+ /* Cloud status */
105
+ enum cloud_msg_type status ;
106
+ } app_state ;
107
+
108
+ static void triggers_send (void )
109
+ {
110
+ int err ;
111
+ struct network_msg network_msg = {
112
+ .type = NETWORK_QUALITY_SAMPLE_REQUEST ,
113
+ };
114
+ struct battery_msg battery_msg = {
115
+ .type = BATTERY_PERCENTAGE_SAMPLE_REQUEST ,
116
+ };
117
+ enum trigger_type poll_trigger = TRIGGER_FOTA_POLL ;
118
+
119
+ err = zbus_chan_pub (& NETWORK_CHAN , & network_msg , K_SECONDS (1 ));
120
+ if (err ) {
121
+ LOG_ERR ("zbus_chan_pub, error: %d" , err );
122
+ SEND_FATAL_ERROR ();
123
+ return ;
124
+ }
125
+
126
+ err = zbus_chan_pub (& BATTERY_CHAN , & battery_msg , K_SECONDS (1 ));
127
+ if (err ) {
128
+ LOG_ERR ("zbus_chan_pub, error: %d" , err );
129
+ SEND_FATAL_ERROR ();
130
+ return ;
131
+ }
132
+
133
+ /* Send FOTA poll trigger */
134
+ err = zbus_chan_pub (& TRIGGER_CHAN , & poll_trigger , K_SECONDS (1 ));
135
+ if (err ) {
136
+ LOG_ERR ("zbus_chan_pub FOTA trigger, error: %d" , err );
137
+ SEND_FATAL_ERROR ();
138
+ return ;
139
+ }
140
+
141
+ /* Send trigger for shadow polling */
142
+ poll_trigger = TRIGGER_POLL_SHADOW ;
143
+
144
+ err = zbus_chan_pub (& TRIGGER_CHAN , & poll_trigger , K_SECONDS (1 ));
145
+ if (err ) {
146
+ LOG_ERR ("zbus_chan_pub shadow trigger, error: %d" , err );
147
+ SEND_FATAL_ERROR ();
148
+ return ;
149
+ }
150
+
151
+ /* Trigger location search and environmental data sample */
152
+ poll_trigger = TRIGGER_DATA_SAMPLE ;
153
+
154
+ err = zbus_chan_pub (& TRIGGER_CHAN , & poll_trigger , K_SECONDS (1 ));
155
+ if (err ) {
156
+ LOG_ERR ("zbus_chan_pub data sample trigger, error: %d" , err );
157
+ SEND_FATAL_ERROR ();
158
+ return ;
159
+ }
160
+ }
161
+
162
+ /* Zephyr State Machine framework handlers */
163
+
164
+ /* STATE_INIT */
165
+
166
+ static void init_entry (void * o )
167
+ {
168
+ ARG_UNUSED (o );
169
+
170
+ LOG_DBG ("%s" , __func__ );
171
+
172
+ /* Setup handler for date_time library */
173
+ date_time_register_handler (date_time_handler );
174
+ }
175
+
176
+ static void init_run (void * o )
177
+ {
178
+ struct state_object * user_object = o ;
179
+
180
+ LOG_DBG ("%s" , __func__ );
181
+
182
+ if (user_object -> chan == & TIME_CHAN ) {
183
+ LOG_DBG ("Time available, going into disconnected state" );
184
+ STATE_SET (app_state , STATE_DISCONNECTED );
185
+ return ;
186
+ }
187
+ }
188
+
189
+ /* STATE_DISCONNECTED */
190
+
191
+ static void disconnected_entry (void * o )
192
+ {
193
+ ARG_UNUSED (o );
194
+
195
+ LOG_DBG ("%s" , __func__ );
196
+
197
+ k_work_cancel_delayable (& trigger_work );
198
+ }
199
+
200
+ static void disconnected_run (void * o )
201
+ {
202
+ struct state_object * user_object = o ;
203
+
204
+ LOG_DBG ("%s" , __func__ );
205
+
206
+ if ((user_object -> chan == & CLOUD_CHAN ) &&
207
+ (user_object -> status == CLOUD_CONNECTED_READY_TO_SEND )) {
208
+ STATE_SET (app_state , STATE_CONNECTED );
209
+ return ;
210
+ }
211
+ }
212
+
213
+ /* STATE_CONNECTED */
214
+
215
+ static void connected_entry (void * o )
216
+ {
217
+ ARG_UNUSED (o );
218
+
219
+ LOG_DBG ("%s" , __func__ );
220
+
221
+ k_work_reschedule (& trigger_work , K_NO_WAIT );
222
+ }
223
+
224
+ static void connected_run (void * o )
225
+ {
226
+ struct state_object * user_object = o ;
227
+
228
+ LOG_DBG ("%s" , __func__ );
229
+
230
+ if ((user_object -> chan == & CLOUD_CHAN ) &&
231
+ ((user_object -> status == CLOUD_CONNECTED_PAUSED ) ||
232
+ (user_object -> status == CLOUD_DISCONNECTED ))) {
233
+ LOG_DBG ("Cloud disconnected/paused, going into disconnected state" );
234
+ STATE_SET (app_state , STATE_DISCONNECTED );
235
+ return ;
236
+ }
237
+
238
+ if (user_object -> chan == & BUTTON_CHAN ) {
239
+ LOG_DBG ("Button %d pressed!" , user_object -> button_number );
240
+ k_work_reschedule (& trigger_work , K_NO_WAIT );
241
+ return ;
242
+ }
243
+
244
+ if (user_object -> chan == & CONFIG_CHAN ) {
245
+ LOG_DBG ("Configuration update, new interval: %lld" , user_object -> interval_sec );
246
+ k_work_reschedule (& trigger_work , K_SECONDS (user_object -> interval_sec ));
247
+ return ;
248
+ }
249
+ }
250
+
17
251
static void date_time_handler (const struct date_time_evt * evt ) {
18
252
if (evt -> type != DATE_TIME_NOT_OBTAINED ) {
19
253
int err ;
@@ -27,10 +261,68 @@ static void date_time_handler(const struct date_time_evt *evt) {
27
261
}
28
262
}
29
263
264
+ /* Delayable work used to send triggers to the rest of the system */
265
+ static void trigger_work_fn (struct k_work * work )
266
+ {
267
+ ARG_UNUSED (work );
268
+
269
+ LOG_DBG ("Sending data sample trigger" );
270
+
271
+ triggers_send ();
272
+
273
+ k_work_reschedule (& trigger_work , K_SECONDS (app_state .interval_sec ));
274
+ }
275
+
276
+ /* Function called when there is a message received on a channel that the module listens to */
277
+ static void app_callback (const struct zbus_channel * chan )
278
+ {
279
+ int err ;
280
+
281
+ if ((chan != & CONFIG_CHAN ) &&
282
+ (chan != & CLOUD_CHAN ) &&
283
+ (chan != & BUTTON_CHAN )) {
284
+ LOG_ERR ("Unknown channel" );
285
+ return ;
286
+ }
287
+
288
+ LOG_DBG ("Received message on channel %s" , zbus_chan_name (chan ));
289
+
290
+ /* Update the state object with the channel that the message was received on */
291
+ app_state .chan = chan ;
292
+
293
+ /* Copy corresponding data to the state object depending on the incoming channel */
294
+ if (& CONFIG_CHAN == chan ) {
295
+ const struct configuration * config = zbus_chan_const_msg (chan );
296
+
297
+ if (config -> update_interval_present ) {
298
+ app_state .interval_sec = config -> update_interval ;
299
+ }
300
+ } else if (& CLOUD_CHAN == chan ) {
301
+ const enum cloud_msg_type * status = zbus_chan_const_msg (chan );
302
+
303
+ app_state .status = * status ;
304
+ } else if (& BUTTON_CHAN == chan ) {
305
+ const int * button_number = zbus_chan_const_msg (chan );
306
+
307
+ app_state .button_number = (uint8_t )* button_number ;
308
+ }
309
+
310
+ LOG_DBG ("Running SMF" );
311
+
312
+ /* State object updated, run SMF */
313
+ err = STATE_RUN (app_state );
314
+ if (err ) {
315
+ LOG_ERR ("smf_run_state, error: %d" , err );
316
+ SEND_FATAL_ERROR ();
317
+ return ;
318
+ }
319
+ }
320
+
30
321
static int app_init (void )
31
322
{
32
- /* Setup handler for date_time library */
33
- date_time_register_handler (date_time_handler );
323
+ app_state .interval_sec = CONFIG_APP_MODULE_TRIGGER_TIMEOUT_SECONDS ;
324
+
325
+ STATE_SET_INITIAL (app_state , STATE_INIT );
34
326
35
327
return 0 ;
36
328
}
0 commit comments