|
12 | 12 | #include "py/objstr.h" |
13 | 13 |
|
14 | 14 | #include <pybricks/common.h> |
| 15 | +#include <pybricks/tools/pb_type_async.h> |
15 | 16 | #include <pybricks/tools/pb_type_matrix.h> |
16 | 17 | #include <pybricks/parameters.h> |
17 | 18 |
|
|
20 | 21 | #include <pybricks/util_mp/pb_kwarg_helper.h> |
21 | 22 | #include <pybricks/util_mp/pb_type_enum.h> |
22 | 23 |
|
| 24 | +typedef struct { |
| 25 | + mp_obj_t string_obj; |
| 26 | + pbio_os_timer_t timer; |
| 27 | + uint32_t idx; |
| 28 | + uint32_t on_time; |
| 29 | + uint32_t off_time; |
| 30 | +} text_animation_state_t; |
23 | 31 |
|
24 | 32 | // pybricks._common.LightMatrix class object |
25 | 33 | typedef struct _common_LightMatrix_obj_t { |
26 | 34 | mp_obj_base_t base; |
27 | 35 | pbio_light_matrix_t *light_matrix; |
28 | 36 | uint8_t *data; |
29 | 37 | uint8_t frames; |
30 | | - // Frozen Python implementation of the async text() method. |
31 | | - mp_obj_t async_text_method; |
| 38 | + pb_type_async_t *text_iter; |
| 39 | + text_animation_state_t text; |
32 | 40 | } common_LightMatrix_obj_t; |
33 | 41 |
|
34 | 42 | // Renews memory for a given number of frames |
@@ -273,53 +281,66 @@ static mp_obj_t common_LightMatrix_pixel(size_t n_args, const mp_obj_t *pos_args |
273 | 281 | } |
274 | 282 | static MP_DEFINE_CONST_FUN_OBJ_KW(common_LightMatrix_pixel_obj, 1, common_LightMatrix_pixel); |
275 | 283 |
|
276 | | -// pybricks._common.LightMatrix.text |
277 | | -static mp_obj_t common_LightMatrix_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { |
278 | | - PB_PARSE_ARGS_METHOD(n_args, pos_args, kw_args, |
279 | | - common_LightMatrix_obj_t, self, |
280 | | - PB_ARG_REQUIRED(text), |
281 | | - PB_ARG_DEFAULT_INT(on, 500), |
282 | | - PB_ARG_DEFAULT_INT(off, 50)); |
| 284 | +static pbio_error_t pb_type_lightmatrix_text_iterate_once(pbio_os_state_t *state, mp_obj_t parent_obj) { |
283 | 285 |
|
284 | | - if (pb_module_tools_run_loop_is_active()) { |
285 | | - if (self->async_text_method == MP_OBJ_NULL) { |
286 | | - self->async_text_method = pb_function_import_helper(MP_QSTR__light_matrix, MP_QSTR_light_matrix_text_async); |
| 286 | + common_LightMatrix_obj_t *self = MP_OBJ_TO_PTR(parent_obj); |
| 287 | + text_animation_state_t *text = &self->text; |
| 288 | + pbio_error_t err; |
| 289 | + |
| 290 | + size_t len; |
| 291 | + const char *data = mp_obj_str_get_data(text->string_obj, &len); |
| 292 | + |
| 293 | + PBIO_OS_ASYNC_BEGIN(state); |
| 294 | + |
| 295 | + for (text->idx = 0; text->idx < len; text->idx++) { |
| 296 | + |
| 297 | + // Raise on invalid character. |
| 298 | + if (text->idx >= len || data[text->idx] < 32 || data[text->idx] > 126) { |
| 299 | + return PBIO_ERROR_INVALID_ARG; |
287 | 300 | } |
288 | | - mp_obj_t args[] = { |
289 | | - MP_OBJ_FROM_PTR(self), |
290 | | - text_in, |
291 | | - on_in, |
292 | | - off_in, |
293 | | - }; |
294 | | - return mp_call_function_n_kw(self->async_text_method, MP_ARRAY_SIZE(args), 0, args); |
295 | | - } |
296 | 301 |
|
297 | | - // Assert that the input is a single text |
298 | | - GET_STR_DATA_LEN(text_in, text, text_len); |
| 302 | + // On time. |
| 303 | + err = pbio_light_matrix_set_rows(self->light_matrix, pb_font_5x5[data[text->idx] - 32]); |
| 304 | + if (err != PBIO_SUCCESS) { |
| 305 | + return err; |
| 306 | + } |
| 307 | + PBIO_OS_AWAIT_MS(state, &text->timer, text->on_time); |
299 | 308 |
|
300 | | - // Make sure all characters are valid |
301 | | - for (size_t i = 0; i < text_len; i++) { |
302 | | - if (text[0] < 32 || text[0] > 126) { |
303 | | - pb_assert(PBIO_ERROR_INVALID_ARG); |
| 309 | + // Off time so we can see multiple of the same characters. |
| 310 | + if (text->off_time > 0 || text->idx == len - 1) { |
| 311 | + err = pbio_light_matrix_clear(self->light_matrix); |
| 312 | + if (err != PBIO_SUCCESS) { |
| 313 | + return err; |
| 314 | + } |
| 315 | + PBIO_OS_AWAIT_MS(state, &text->timer, text->off_time); |
304 | 316 | } |
305 | 317 | } |
306 | 318 |
|
307 | | - mp_int_t on = pb_obj_get_int(on_in); |
308 | | - mp_int_t off = pb_obj_get_int(off_in); |
| 319 | + PBIO_OS_ASYNC_END(PBIO_SUCCESS); |
| 320 | +} |
309 | 321 |
|
310 | | - // Display all characters one by one |
311 | | - for (size_t i = 0; i < text_len; i++) { |
312 | | - pb_assert(pbio_light_matrix_set_rows(self->light_matrix, pb_font_5x5[text[i] - 32])); |
313 | | - mp_hal_delay_ms(on); |
| 322 | +// pybricks._common.LightMatrix.text |
| 323 | +static mp_obj_t common_LightMatrix_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { |
| 324 | + PB_PARSE_ARGS_METHOD(n_args, pos_args, kw_args, |
| 325 | + common_LightMatrix_obj_t, self, |
| 326 | + PB_ARG_REQUIRED(text), |
| 327 | + PB_ARG_DEFAULT_INT(on, 500), |
| 328 | + PB_ARG_DEFAULT_INT(off, 50)); |
314 | 329 |
|
315 | | - // Some off time so we can see multiple of the same characters |
316 | | - if (off > 0 || i == text_len - 1) { |
317 | | - pb_assert(pbio_light_matrix_clear(self->light_matrix)); |
318 | | - mp_hal_delay_ms(off); |
319 | | - } |
320 | | - } |
| 330 | + text_animation_state_t *text = &self->text; |
321 | 331 |
|
322 | | - return mp_const_none; |
| 332 | + text->on_time = pb_obj_get_int(on_in); |
| 333 | + text->off_time = pb_obj_get_int(off_in); |
| 334 | + text->idx = 0; |
| 335 | + text->string_obj = text_in; |
| 336 | + |
| 337 | + pb_type_async_t config = { |
| 338 | + .parent_obj = MP_OBJ_FROM_PTR(self), |
| 339 | + .iter_once = pb_type_lightmatrix_text_iterate_once, |
| 340 | + }; |
| 341 | + // New operation always wins; ongoing animation is cancelled. |
| 342 | + pb_type_async_schedule_cancel(self->text_iter); |
| 343 | + return pb_type_async_wait_or_await(&config, &self->text_iter); |
323 | 344 | } |
324 | 345 | static MP_DEFINE_CONST_FUN_OBJ_KW(common_LightMatrix_text_obj, 1, common_LightMatrix_text); |
325 | 346 |
|
@@ -348,7 +369,7 @@ mp_obj_t pb_type_LightMatrix_obj_new(pbio_light_matrix_t *light_matrix) { |
348 | 369 | common_LightMatrix_obj_t *self = mp_obj_malloc(common_LightMatrix_obj_t, &pb_type_LightMatrix); |
349 | 370 | self->light_matrix = light_matrix; |
350 | 371 | pbio_light_matrix_set_orientation(light_matrix, PBIO_GEOMETRY_SIDE_TOP); |
351 | | - self->async_text_method = MP_OBJ_NULL; |
| 372 | + self->text_iter = NULL; |
352 | 373 | return MP_OBJ_FROM_PTR(self); |
353 | 374 | } |
354 | 375 |
|
|
0 commit comments