Repository navigation
Expand file tree
/
Copy pathhost-control.patch
More file actions
284 lines (268 loc) · 10.5 KB
/
Copy pathhost-control.patch
File metadata and controls
284 lines (268 loc) · 10.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
Host control for the Modos Paper Dev Kit (Glider), on top of firmware 1.0.
Against: Modos-Labs/Glider @ ed94ef7fd95a42cfdcdaf5e5da1dcdd709122763
Exposes the OSD settings through `setcfg`, and adds an `act` command that posts
actions into the UI task's queue so they run through execute_button_action() --
the same function a physical button press reaches.
Apply with:
git checkout ed94ef7fd95a42cfdcdaf5e5da1dcdd709122763
patch -p1 < host-control.patch (or: git apply host-control.patch)
Then copy Makefile from this directory to fw/Makefile to build without
STM32CubeIDE. See the repo README.
diff --git a/fw/User/config.c b/fw/User/config.c
index a53b4ff..d4e9b1f 100644
--- a/fw/User/config.c
+++ b/fw/User/config.c
@@ -77,6 +77,12 @@ static void config_init_settings(void) {
config.osd_scale_2x = 0;
}
+// Restore the stock 1.0 user settings. Panel timing, VCOM and geometry are
+// deliberately left untouched.
+void config_reset_settings(void) {
+ config_init_settings();
+}
+
void config_init(void) {
// Set default values
config.size_x_mm = 270;
diff --git a/fw/User/config.h b/fw/User/config.h
index 9f99358..7370f48 100644
--- a/fw/User/config.h
+++ b/fw/User/config.h
@@ -123,6 +123,7 @@ extern config_t config;
void config_init(void);
void config_reset_button_actions(void);
+void config_reset_settings(void);
void config_validate_loaded(size_t loaded_size);
void config_load(void);
void config_save(void);
diff --git a/fw/User/shell/shell.c b/fw/User/shell/shell.c
index 9914a1d..d8e4fc8 100644
--- a/fw/User/shell/shell.c
+++ b/fw/User/shell/shell.c
@@ -73,6 +73,8 @@ SHELL_FUNC( shell_syslog );
SHELL_FUNC( shell_setcfg );
SHELL_FUNC( shell_setres );
SHELL_FUNC( shell_power );
+SHELL_FUNC( shell_act );
+SHELL_FUNC( shell_defaults );
#ifdef GLIDER_DIAGNOSTIC_SHELL
SHELL_FUNC( shell_mem );
SHELL_FUNC( shell_test );
@@ -91,6 +93,8 @@ SHELL_HELP( syslog );
SHELL_HELP( setcfg );
SHELL_HELP( setres );
SHELL_HELP( power );
+SHELL_HELP( act );
+SHELL_HELP( defaults );
#ifdef GLIDER_DIAGNOSTIC_SHELL
SHELL_HELP( mem );
SHELL_HELP( test );
@@ -112,6 +116,8 @@ const SHELL_COMMAND shell_commands[] =
{ "setcfg", shell_setcfg },
{ "setres", shell_setres },
{ "power", shell_power },
+ { "act", shell_act },
+ { "defaults", shell_defaults },
#ifdef GLIDER_DIAGNOSTIC_SHELL
{ "mem", shell_mem },
{ "test", shell_test },
diff --git a/fw/User/shell/shell_cmds.c b/fw/User/shell/shell_cmds.c
index 88a9a87..b3bbaec 100644
--- a/fw/User/shell/shell_cmds.c
+++ b/fw/User/shell/shell_cmds.c
@@ -894,7 +894,7 @@ const char shell_help_summary_setcfg[] = "Sets configuration. Remember to use sa
typedef struct {
const char *name;
void *pointer;
- enum {UINT8, UINT16, UINT32, FLOAT32, STRING} type;
+ enum {UINT8, UINT16, UINT32, INT32, FLOAT32, STRING} type;
} cfg_var_t;
cfg_var_t vars[] = {
@@ -923,7 +923,16 @@ cfg_var_t vars[] = {
{"tcon_hact", &(config.tcon_hact), UINT16},
{"mirror", &(config.mirror), UINT8},
{"input_sel", &(config.input_sel), UINT8},
- {"bitstream", &(config.bitstream), STRING}
+ {"bitstream", &(config.bitstream), STRING},
+ // Readable so a host can see what the buttons changed. Prefer the `act`
+ // command for writes, so changes run through the OSD's own code path.
+ {"update_mode", &(config.update_mode), INT32},
+ {"lightness", &(config.lightness), INT32},
+ {"contrast", &(config.contrast), INT32},
+ {"autoclear_mode", &(config.autoclear_mode), INT32},
+ {"autoclear_interval", &(config.autoclear_interval), INT32},
+ {"autoclear_threshold", &(config.autoclear_threshold), INT32},
+ {"osd_scale_2x", &(config.osd_scale_2x), INT32}
};
int num_vars = sizeof(vars) / sizeof(cfg_var_t);
@@ -937,6 +946,9 @@ static void setcfg_set_helper(shell_context_t *ctx, cfg_var_t *var, char *val) {
else if (var->type == UINT32) {
*(uint32_t *)(var->pointer) = strtol(val, NULL, 10);
}
+ else if (var->type == INT32) {
+ *(int32_t *)(var->pointer) = strtol(val, NULL, 10);
+ }
else if (var->type == FLOAT32) {
float parsed = 0.0f;
if (!numfmt_parse_float(val, &parsed)) {
@@ -965,6 +977,9 @@ static void setcfg_get_helper(shell_context_t *ctx, cfg_var_t *var) {
else if (var->type == UINT32) {
printf("%d\n", *(uint32_t *)(var->pointer));
}
+ else if (var->type == INT32) {
+ printf("%d\n", *(int32_t *)(var->pointer));
+ }
else if (var->type == FLOAT32) {
shell_print_fixed(ctx, *(float *)(var->pointer), 3);
printf("\n");
@@ -999,6 +1014,24 @@ void shell_setcfg(shell_context_t *ctx, int argc, char **argv) {
return;
}
setcfg_set_helper(ctx, var, argv[3]);
+ // Apply values that have a live effect straight away, so a host does
+ // not need to open the OSD or reboot. caster_set_tone() only rebuilds
+ // the tone LUT and writes it over SPI. Clamp to config.c's ranges.
+ if ((strcmp(argv[2], "lightness") == 0) ||
+ (strcmp(argv[2], "contrast") == 0)) {
+ if (config.lightness < -3) config.lightness = -3;
+ if (config.lightness > 3) config.lightness = 3;
+ if (config.contrast < -1) config.contrast = -1;
+ if (config.contrast > 6) config.contrast = 6;
+ caster_set_tone(config.lightness, config.contrast);
+ }
+ // update_mode: apply live too. The four OSD presets should be set with
+ // `act` (which also fixes up the UI's mode index); this path exists for
+ // the modes the OSD does not list, e.g. no-dither and error-diffusion.
+ else if (strcmp(argv[2], "update_mode") == 0) {
+ caster_setmode(0, 0, config.hact, config.vact,
+ (update_mode_t)config.update_mode);
+ }
}
else if (strcmp(argv[1], "get") == 0) {
if (argc < 4) {
@@ -1101,3 +1134,55 @@ void shell_damage(shell_context_t *ctx, int argc, char **argv) {
}
}
#endif
+
+
+// ---- act: run a UI action through the same path as a button press ----
+
+const char shell_help_act[] = "<action>\n";
+const char shell_help_summary_act[] = "Run a UI action (same path as the buttons).";
+
+static const struct { const char *name; int action; } act_names[] = {
+ {"next_mode", ACT_NEXT_MODE},
+ {"prev_mode", ACT_PREV_MODE},
+ {"browsing", ACT_MODE_BROWSING},
+ {"watching", ACT_MODE_WATCHING},
+ {"typing", ACT_MODE_TYPING},
+ {"reading", ACT_MODE_READING},
+ {"clear", ACT_CLEAR},
+ {"toggle_ac", ACT_TOGGLE_AC},
+ {"input_auto", ACT_INPUT_AUTO},
+ {"input_tmds", ACT_INPUT_TMDS},
+ {"input_dp", ACT_INPUT_DP},
+};
+
+void shell_act(shell_context_t *ctx, int argc, char **argv) {
+ unsigned i;
+ if (argc < 2) {
+ printf("Usage: %s", shell_help_act);
+ for (i = 0; i < sizeof(act_names) / sizeof(act_names[0]); i++)
+ printf(" %s\n", act_names[i].name);
+ return;
+ }
+ for (i = 0; i < sizeof(act_names) / sizeof(act_names[0]); i++) {
+ if (strcmp(argv[1], act_names[i].name) == 0) {
+ if (!ui_post_action(act_names[i].action))
+ printf("Queue full\n");
+ return;
+ }
+ }
+ printf("Unknown action\n");
+}
+
+// ---- defaults: restore stock 1.0 settings ----
+
+const char shell_help_defaults[] = "\n";
+const char shell_help_summary_defaults[] = "Reset settings to stock 1.0 defaults.";
+
+void shell_defaults(shell_context_t *ctx, int argc, char **argv) {
+ config_reset_settings();
+ config_save();
+ // Re-apply through the OSD path so the UI mode index, autoclear state and
+ // saved config all end up consistent with the reset values.
+ ui_post_action(ACT_MODE_BROWSING);
+ printf("Settings reset to defaults\n");
+}
diff --git a/fw/User/ui.c b/fw/User/ui.c
index e5600ed..cb4409e 100644
--- a/fw/User/ui.c
+++ b/fw/User/ui.c
@@ -31,6 +31,18 @@
#include "ui_menu.h"
static QueueHandle_t btn_queue;
+static QueueHandle_t act_queue;
+// Set only while running a host-posted action, so status popups are skipped.
+// Physical button presses never set it and still show their popup.
+static bool ui_suppress_popup = false;
+
+// Queue an action for the UI task. It is executed by execute_button_action(),
+// the identical path a physical button press takes.
+bool ui_post_action(int action) {
+ if (act_queue == NULL)
+ return false;
+ return xQueueSend(act_queue, &action, 0) == pdTRUE;
+}
typedef enum {
BTN1_SHORT_PRESSED,
@@ -89,6 +101,7 @@ static void apply_input_selection(bool *tmds_mode);
void ui_init(void) {
btn_queue = xQueueCreate(8, sizeof(btn_event_t));
+ act_queue = xQueueCreate(8, sizeof(int));
}
static void osd_set_pixel(int x, int y, bool p) {
@@ -216,6 +229,9 @@ static int mode_index_for(update_mode_t id) {
}
static void draw_status_popup(const osd_fonts_t *fonts, const char *title, const char *value) {
+ // Host-driven changes run silently: no toast, no extra e-ink refresh.
+ if (ui_suppress_popup)
+ return;
osd_clear(0xff);
char textbuf[80];
snprintf(textbuf, 80, "%s %s", title, value);
@@ -973,8 +989,22 @@ portTASK_FUNCTION(ui_task, pvParameters) {
// Key press logic
btn_event_t btn_event;
BaseType_t result = xQueueReceive(btn_queue, &btn_event, pdMS_TO_TICKS(200));
- if (result != pdTRUE)
+ if (result != pdTRUE) {
+ // No button this tick -- run any host-posted actions instead.
+ int posted_action;
+ while (xQueueReceive(act_queue, &posted_action, 0) == pdTRUE) {
+ TickType_t saved_timeout = osd_timeout;
+ ui_suppress_popup = true;
+ execute_button_action((button_action_t)posted_action,
+ &fonts, &menu, &menu_open, &autoclear, &osd_timeout,
+ &autoclear_timeout, &autoclear_damage_counter,
+ &autoclear_damage_last, &menu_render_state,
+ &autoclear_previous_mode, &tmds_mode);
+ ui_suppress_popup = false;
+ osd_timeout = saved_timeout;
+ }
continue;
+ }
if (menu_open) {
config_t previous_config = config;
diff --git a/fw/User/ui.h b/fw/User/ui.h
index 4771ee4..cbb64b6 100644
--- a/fw/User/ui.h
+++ b/fw/User/ui.h
@@ -23,5 +23,7 @@
#pragma once
void ui_init(void);
+// Post a button_action_t for the UI task to run, exactly as a button would.
+bool ui_post_action(int action);
portTASK_FUNCTION(ui_task, pvParameters);
portTASK_FUNCTION(key_scan_task, pvParameters);