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
+ /* 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
+
17
254
static void date_time_handler (const struct date_time_evt * evt ) {
18
255
if (evt -> type != DATE_TIME_NOT_OBTAINED ) {
19
256
int err ;
@@ -27,10 +264,73 @@ static void date_time_handler(const struct date_time_evt *evt) {
27
264
}
28
265
}
29
266
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
+
30
329
static int app_init (void )
31
330
{
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 );
34
334
35
335
return 0 ;
36
336
}
0 commit comments