Skip to content

Commit 74058ed

Browse files
MarekPietakapi-no
authored andcommitted
applications: nrf_desktop: Cleanup motion simulated HW interface
Change aligns internal state handling with other motion HW interfaces. Generating motion is controlled through a separate boolean. The module sends an additional motion event when leaving the fetching state. Change also improves shell integration to prevent edge cases related to using preemptive execution context. Jira: NCSDK-35474 Signed-off-by: Marek Pieta <[email protected]>
1 parent af9ec17 commit 74058ed

File tree

1 file changed

+97
-49
lines changed

1 file changed

+97
-49
lines changed

applications/nrf_desktop/src/hw_interface/motion_simulated.c

Lines changed: 97 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,13 @@
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

3131
struct vertex {
@@ -50,19 +50,13 @@ const static int edge_time = CONFIG_DESKTOP_MOTION_SIMULATED_EDGE_TIME;
5050

5151
static int x_cur;
5252
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);
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-
6660
static 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

193235
static 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

208254
static 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

Comments
 (0)