44 */
55
66#include <zephyr/kernel.h>
7- #include <zephyr/sys/atomic.h>
87
98#include <app_event_manager.h>
109#include "motion_event.h"
1110#include <caf/events/power_event.h>
1211#include "hid_event.h"
1312
1413#include <zephyr/shell/shell.h>
15- #include <zephyr/shell/shell_rtt.h>
1614
1715#define MODULE motion
1816#include <caf/events/module_state_event.h>
@@ -22,10 +20,12 @@ LOG_MODULE_REGISTER(MODULE, CONFIG_DESKTOP_MOTION_LOG_LEVEL);
2220
2321#define SCALE CONFIG_DESKTOP_MOTION_SIMULATED_SCALE_FACTOR
2422
25- enum {
23+ enum state {
24+ STATE_DISCONNECTED ,
2625 STATE_IDLE ,
2726 STATE_FETCHING ,
2827 STATE_SUSPENDED ,
28+ STATE_SUSPENDED_DISCONNECTED ,
2929};
3030
3131struct vertex {
@@ -50,19 +50,13 @@ const static int edge_time = CONFIG_DESKTOP_MOTION_SIMULATED_EDGE_TIME;
5050
5151static int x_cur ;
5252static 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 );
5558
5659
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-
6660static void motion_event_send (int16_t dx , int16_t dy )
6761{
6862 struct motion_event * event = new_motion_event ();
@@ -82,21 +76,37 @@ static uint64_t get_timestamp(void)
8276 }
8377}
8478
85- static void generate_motion_event ( void )
79+ static void generate_new_position ( int * x_new , int * y_new )
8680{
8781 BUILD_ASSERT ((edge_time & (edge_time - 1 )) == 0 ,
8882 "Edge time must be power of 2" );
8983
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 );
9388
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 ];
9691
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 );
100110
101111 motion_event_send (x_new - x_cur , y_new - y_cur );
102112
@@ -122,26 +132,43 @@ static bool app_event_handler(const struct app_event_header *aeh)
122132 peer_count -- ;
123133 }
124134
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 ;
131155 }
132156 }
133157 }
158+
134159 return false;
135160 }
136161
137162 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 );
140164
141165 if ((event -> report_id == REPORT_ID_MOUSE ) ||
142166 (event -> report_id == REPORT_ID_BOOT_MOUSE )) {
143- if (atomic_get ( & state ) == STATE_FETCHING ) {
167+ if (state == STATE_FETCHING ) {
144168 generate_motion_event ();
169+ if (!generating_motion ) {
170+ state = STATE_IDLE ;
171+ }
145172 }
146173 }
147174
@@ -152,7 +179,10 @@ static bool app_event_handler(const struct app_event_header *aeh)
152179 struct module_state_event * event = cast_module_state_event (aeh );
153180
154181 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+
156186 LOG_INF ("Simulated motion: ready" );
157187 }
158188
@@ -161,14 +191,26 @@ static bool app_event_handler(const struct app_event_header *aeh)
161191
162192 if (IS_ENABLED (CONFIG_DESKTOP_MOTION_PM_EVENTS ) &&
163193 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+ }
165199
166200 return false;
167201 }
168202
169203 if (IS_ENABLED (CONFIG_DESKTOP_MOTION_PM_EVENTS ) &&
170204 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+ }
172214
173215 return false;
174216 }
@@ -192,26 +234,33 @@ APP_EVENT_SUBSCRIBE(MODULE, hid_report_subscription_event);
192234
193235static int start_motion (const struct shell * shell , size_t argc , char * * argv )
194236{
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+ }
202247 }
203- shell_print (shell , "Started generating simulated motion" );
248+
249+ k_sched_unlock ();
204250
205251 return 0 ;
206252}
207253
208254static int stop_motion (const struct shell * shell , size_t argc , char * * argv )
209255{
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" );
213261 }
214- shell_print (shell , "Stopped generating simulated motion" );
262+
263+ k_sched_unlock ();
215264
216265 return 0 ;
217266}
@@ -222,7 +271,6 @@ SHELL_STATIC_SUBCMD_SET_CREATE(sub_motion_sim,
222271 SHELL_SUBCMD_SET_END
223272);
224273
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 );
227275
228276#endif /* CONFIG_SHELL */
0 commit comments