4
4
*/
5
5
6
6
#include <zephyr/kernel.h>
7
- #include <zephyr/sys/atomic.h>
8
7
9
8
#include <app_event_manager.h>
10
9
#include "motion_event.h"
11
10
#include <caf/events/power_event.h>
12
11
#include "hid_event.h"
13
12
14
13
#include <zephyr/shell/shell.h>
15
- #include <zephyr/shell/shell_rtt.h>
16
14
17
15
#define MODULE motion
18
16
#include <caf/events/module_state_event.h>
@@ -22,10 +20,12 @@ LOG_MODULE_REGISTER(MODULE, CONFIG_DESKTOP_MOTION_LOG_LEVEL);
22
20
23
21
#define SCALE CONFIG_DESKTOP_MOTION_SIMULATED_SCALE_FACTOR
24
22
25
- enum {
23
+ enum state {
24
+ STATE_DISCONNECTED ,
26
25
STATE_IDLE ,
27
26
STATE_FETCHING ,
28
27
STATE_SUSPENDED ,
28
+ STATE_SUSPENDED_DISCONNECTED ,
29
29
};
30
30
31
31
struct vertex {
@@ -50,19 +50,13 @@ const static int edge_time = CONFIG_DESKTOP_MOTION_SIMULATED_EDGE_TIME;
50
50
51
51
static int x_cur ;
52
52
static int y_cur ;
53
- static atomic_t state ;
54
- static atomic_t connected ;
53
+ static enum state state ;
54
+ /* If shell is enabled, wait for shell command to start generating motion.
55
+ * Otherwise, start generating motion right after boot.
56
+ */
57
+ static bool generating_motion = !IS_ENABLED (CONFIG_SHELL );
55
58
56
59
57
- static void set_default_state (void )
58
- {
59
- if (IS_ENABLED (CONFIG_SHELL )) {
60
- atomic_set (& state , STATE_IDLE );
61
- } else {
62
- atomic_set (& state , STATE_FETCHING );
63
- }
64
- }
65
-
66
60
static void motion_event_send (int16_t dx , int16_t dy )
67
61
{
68
62
struct motion_event * event = new_motion_event ();
@@ -82,21 +76,37 @@ static uint64_t get_timestamp(void)
82
76
}
83
77
}
84
78
85
- static void generate_motion_event ( void )
79
+ static void generate_new_position ( int * x_new , int * y_new )
86
80
{
87
81
BUILD_ASSERT ((edge_time & (edge_time - 1 )) == 0 ,
88
82
"Edge time must be power of 2" );
89
83
90
- uint64_t t = get_timestamp ();
91
- size_t v1_id = (t / edge_time ) % ARRAY_SIZE (coords );
92
- size_t v2_id = (v1_id + 1 ) % ARRAY_SIZE (coords );
84
+ if (generating_motion ) {
85
+ uint64_t t = get_timestamp ();
86
+ size_t v1_id = (t / edge_time ) % ARRAY_SIZE (coords );
87
+ size_t v2_id = (v1_id + 1 ) % ARRAY_SIZE (coords );
93
88
94
- const struct vertex * v1 = & coords [v1_id ];
95
- const struct vertex * v2 = & coords [v2_id ];
89
+ const struct vertex * v1 = & coords [v1_id ];
90
+ const struct vertex * v2 = & coords [v2_id ];
96
91
97
- int edge_pos = t % edge_time ;
98
- int x_new = v1 -> x + (v2 -> x - v1 -> x ) * edge_pos / edge_time ;
99
- int y_new = v1 -> y + (v2 -> y - v1 -> y ) * edge_pos / edge_time ;
92
+ int edge_pos = t % edge_time ;
93
+
94
+ * x_new = v1 -> x + (v2 -> x - v1 -> x ) * edge_pos / edge_time ;
95
+ * y_new = v1 -> y + (v2 -> y - v1 -> y ) * edge_pos / edge_time ;
96
+ } else {
97
+ * x_new = x_cur ;
98
+ * y_new = y_cur ;
99
+ }
100
+ }
101
+
102
+ static void generate_motion_event (void )
103
+ {
104
+ __ASSERT_NO_MSG (state == STATE_FETCHING );
105
+
106
+ int x_new ;
107
+ int y_new ;
108
+
109
+ generate_new_position (& x_new , & y_new );
100
110
101
111
motion_event_send (x_new - x_cur , y_new - y_cur );
102
112
@@ -122,26 +132,43 @@ static bool app_event_handler(const struct app_event_header *aeh)
122
132
peer_count -- ;
123
133
}
124
134
125
- bool new_state = (peer_count != 0 );
126
- bool old_state = atomic_set (& connected , new_state );
127
-
128
- if (old_state != new_state && new_state ) {
129
- if (atomic_get (& state ) == STATE_FETCHING ) {
130
- generate_motion_event ();
135
+ if ((peer_count == 1 ) && event -> enabled ) {
136
+ /* The first HID subscriber connected. */
137
+ if (state == STATE_DISCONNECTED ) {
138
+ state = generating_motion ?
139
+ STATE_FETCHING : STATE_IDLE ;
140
+
141
+ if (state == STATE_FETCHING ) {
142
+ generate_motion_event ();
143
+ }
144
+ } else {
145
+ __ASSERT_NO_MSG (state == STATE_SUSPENDED_DISCONNECTED );
146
+ state = STATE_SUSPENDED ;
147
+ }
148
+ } else if ((peer_count == 0 ) && !event -> enabled ) {
149
+ /* All of the HID subscribers disconnected. */
150
+ if ((state == STATE_FETCHING ) || (state == STATE_IDLE )) {
151
+ state = STATE_DISCONNECTED ;
152
+ } else {
153
+ __ASSERT_NO_MSG (state == STATE_SUSPENDED );
154
+ state = STATE_SUSPENDED_DISCONNECTED ;
131
155
}
132
156
}
133
157
}
158
+
134
159
return false;
135
160
}
136
161
137
162
if (is_hid_report_sent_event (aeh )) {
138
- const struct hid_report_sent_event * event =
139
- cast_hid_report_sent_event (aeh );
163
+ const struct hid_report_sent_event * event = cast_hid_report_sent_event (aeh );
140
164
141
165
if ((event -> report_id == REPORT_ID_MOUSE ) ||
142
166
(event -> report_id == REPORT_ID_BOOT_MOUSE )) {
143
- if (atomic_get ( & state ) == STATE_FETCHING ) {
167
+ if (state == STATE_FETCHING ) {
144
168
generate_motion_event ();
169
+ if (!generating_motion ) {
170
+ state = STATE_IDLE ;
171
+ }
145
172
}
146
173
}
147
174
@@ -152,7 +179,10 @@ static bool app_event_handler(const struct app_event_header *aeh)
152
179
struct module_state_event * event = cast_module_state_event (aeh );
153
180
154
181
if (check_state (event , MODULE_ID (main ), MODULE_STATE_READY )) {
155
- set_default_state ();
182
+ /* Ensure proper synchronization of the shell commands. */
183
+ BUILD_ASSERT (!IS_ENABLED (CONFIG_SHELL ) || !IS_ENABLED (CONFIG_SMP ));
184
+ __ASSERT_NO_MSG (!IS_ENABLED (CONFIG_SHELL ) || !k_is_preempt_thread ());
185
+
156
186
LOG_INF ("Simulated motion: ready" );
157
187
}
158
188
@@ -161,14 +191,26 @@ static bool app_event_handler(const struct app_event_header *aeh)
161
191
162
192
if (IS_ENABLED (CONFIG_DESKTOP_MOTION_PM_EVENTS ) &&
163
193
is_power_down_event (aeh )) {
164
- atomic_set (& state , STATE_SUSPENDED );
194
+ if (state == STATE_DISCONNECTED ) {
195
+ state = STATE_SUSPENDED_DISCONNECTED ;
196
+ } else if ((state == STATE_IDLE ) || (state == STATE_FETCHING )) {
197
+ state = STATE_SUSPENDED ;
198
+ }
165
199
166
200
return false;
167
201
}
168
202
169
203
if (IS_ENABLED (CONFIG_DESKTOP_MOTION_PM_EVENTS ) &&
170
204
is_wake_up_event (aeh )) {
171
- set_default_state ();
205
+ if (state == STATE_SUSPENDED_DISCONNECTED ) {
206
+ state = STATE_DISCONNECTED ;
207
+ } else if (state == STATE_SUSPENDED ) {
208
+ state = generating_motion ? STATE_FETCHING : STATE_IDLE ;
209
+
210
+ if (state == STATE_FETCHING ) {
211
+ generate_motion_event ();
212
+ }
213
+ }
172
214
173
215
return false;
174
216
}
@@ -192,26 +234,33 @@ APP_EVENT_SUBSCRIBE(MODULE, hid_report_subscription_event);
192
234
193
235
static int start_motion (const struct shell * shell , size_t argc , char * * argv )
194
236
{
195
- if (!atomic_cas (& state , STATE_IDLE , STATE_FETCHING )) {
196
- shell_print (shell , "Simulated motion inactive"
197
- " or already fetching" );
198
- return 0 ;
199
- }
200
- if (atomic_get (& connected )) {
201
- generate_motion_event ();
237
+ k_sched_lock ();
238
+
239
+ if (!generating_motion ) {
240
+ generating_motion = true;
241
+ shell_print (shell , "Started generating simulated motion" );
242
+
243
+ if (state == STATE_IDLE ) {
244
+ state = STATE_FETCHING ;
245
+ generate_motion_event ();
246
+ }
202
247
}
203
- shell_print (shell , "Started generating simulated motion" );
248
+
249
+ k_sched_unlock ();
204
250
205
251
return 0 ;
206
252
}
207
253
208
254
static int stop_motion (const struct shell * shell , size_t argc , char * * argv )
209
255
{
210
- if (!atomic_cas (& state , STATE_FETCHING , STATE_IDLE )) {
211
- shell_print (shell , "Simulated motion is not fetching" );
212
- return 0 ;
256
+ k_sched_lock ();
257
+
258
+ if (generating_motion ) {
259
+ generating_motion = false;
260
+ shell_print (shell , "Stopped generating simulated motion" );
213
261
}
214
- shell_print (shell , "Stopped generating simulated motion" );
262
+
263
+ k_sched_unlock ();
215
264
216
265
return 0 ;
217
266
}
@@ -222,7 +271,6 @@ SHELL_STATIC_SUBCMD_SET_CREATE(sub_motion_sim,
222
271
SHELL_SUBCMD_SET_END
223
272
);
224
273
225
- SHELL_CMD_REGISTER (motion_sim , & sub_motion_sim ,
226
- "Simulated motion commands" , NULL );
274
+ SHELL_CMD_REGISTER (motion_sim , & sub_motion_sim , "Simulated motion commands" , NULL );
227
275
228
276
#endif /* CONFIG_SHELL */
0 commit comments