Skip to content

Commit 7745f90

Browse files
committed
pybricks.hubs.PrimeHub: Use new awaitable for text animation.
Now that we can have protothreads as the iterable function, we can trivially do these in C instead of importing Python code from C. Now they can correctly be cancelled, too. A new text animation will take over and stop any ongoing ones.
1 parent 48b9904 commit 7745f90

File tree

3 files changed

+61
-50
lines changed

3 files changed

+61
-50
lines changed

bricks/primehub/manifest.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,3 @@
22
include("../_common/manifest.py")
33

44
freeze_as_mpy("../primehub/modules", "_imu_calibrate.py")
5-
freeze_as_mpy("../primehub/modules", "_light_matrix.py")

bricks/primehub/modules/_light_matrix.py

Lines changed: 0 additions & 9 deletions
This file was deleted.

pybricks/common/pb_type_lightmatrix.c

Lines changed: 61 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "py/objstr.h"
1313

1414
#include <pybricks/common.h>
15+
#include <pybricks/tools/pb_type_async.h>
1516
#include <pybricks/tools/pb_type_matrix.h>
1617
#include <pybricks/parameters.h>
1718

@@ -20,15 +21,22 @@
2021
#include <pybricks/util_mp/pb_kwarg_helper.h>
2122
#include <pybricks/util_mp/pb_type_enum.h>
2223

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;
2331

2432
// pybricks._common.LightMatrix class object
2533
typedef struct _common_LightMatrix_obj_t {
2634
mp_obj_base_t base;
2735
pbio_light_matrix_t *light_matrix;
2836
uint8_t *data;
2937
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;
3240
} common_LightMatrix_obj_t;
3341

3442
// 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
273281
}
274282
static MP_DEFINE_CONST_FUN_OBJ_KW(common_LightMatrix_pixel_obj, 1, common_LightMatrix_pixel);
275283

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) {
283285

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;
287300
}
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-
}
296301

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);
299308

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);
304316
}
305317
}
306318

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+
}
309321

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));
314329

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;
321331

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);
323344
}
324345
static MP_DEFINE_CONST_FUN_OBJ_KW(common_LightMatrix_text_obj, 1, common_LightMatrix_text);
325346

@@ -348,7 +369,7 @@ mp_obj_t pb_type_LightMatrix_obj_new(pbio_light_matrix_t *light_matrix) {
348369
common_LightMatrix_obj_t *self = mp_obj_malloc(common_LightMatrix_obj_t, &pb_type_LightMatrix);
349370
self->light_matrix = light_matrix;
350371
pbio_light_matrix_set_orientation(light_matrix, PBIO_GEOMETRY_SIDE_TOP);
351-
self->async_text_method = MP_OBJ_NULL;
372+
self->text_iter = NULL;
352373
return MP_OBJ_FROM_PTR(self);
353374
}
354375

0 commit comments

Comments
 (0)