@@ -135,7 +135,7 @@ STATIC void preflight_pins_or_throw(uint8_t clock_pin, uint8_t *rgb_pins, uint8_
135135
136136//| :class:`~_protomatter.Protomatter` displays an in-memory framebuffer to an LED matrix.
137137//|
138- //| .. class:: Protomatter(width, bit_depth, rgb_pins, addr_pins, clock_pin, latch_pin, oe_pin , *, doublebuffer=True, framebuffer=None)
138+ //| .. class:: Protomatter(width, bit_depth, rgb_pins, addr_pins, clock_pin, latch_pin, output_enable_pin , *, doublebuffer=True, framebuffer=None)
139139//|
140140//| Create a Protomatter object with the given attributes. The height of
141141//| the display is determined by the number of rgb and address pins:
@@ -153,31 +153,39 @@ STATIC void preflight_pins_or_throw(uint8_t clock_pin, uint8_t *rgb_pins, uint8_
153153//| microcontroller board. For instance, the Feather M4 Express works
154154//| together with the RGB Matrix Feather.
155155//|
156- //| When specified as True, double buffering can reduce some flickering of
157- //| the matrix; however, this increases memory usage.
156+ //| The framebuffer is in "RGB565" format.
158157//|
159- //| The framebuffer is in "RGB565" format. If a framebuffer is not
160- //| passed in, one is allocated and initialized to all black. To update
161- //| the content, modify the framebuffer and call swapbuffers.
158+ //| "RGB565" means that it is organized as a series of 16-bit numbers
159+ //| where the highest 5 bits are interpreted as red, the next 6 as
160+ //| green, and the final 5 as blue. The object can be any buffer, but
161+ //| `array.array` and `ulab.array` objects are most often useful.
162+ //| To update the content, modify the framebuffer and call refresh.
163+ //|
164+ //| If a framebuffer is not passed in, one is allocated and initialized
165+ //| to all black. In any case, the framebuffer can be retrieved
166+ //| by passing the protomatter object to memoryview().
162167//|
163168//| If doublebuffer is False, some memory is saved, but the display may
164169//| flicker during updates.
165170//|
166171//| If a framebuffer is not passed in, one is allocated internally. To
167172//| retrieve it, pass the protomatter object to memoryview().
168173//|
174+ //| A Protomatter framebuffer is often used in conjunction with a
175+ //| `framebufferio.FramebufferDisplay`.
176+ //|
169177
170178STATIC mp_obj_t protomatter_protomatter_make_new (const mp_obj_type_t * type , size_t n_args , const mp_obj_t * pos_args , mp_map_t * kw_args ) {
171179 enum { ARG_width , ARG_bit_depth , ARG_rgb_list , ARG_addr_list ,
172- ARG_clock_pin , ARG_latch_pin , ARG_oe_pin , ARG_doublebuffer , ARG_framebuffer };
180+ ARG_clock_pin , ARG_latch_pin , ARG_output_enable_pin , ARG_doublebuffer , ARG_framebuffer };
173181 static const mp_arg_t allowed_args [] = {
174182 { MP_QSTR_width , MP_ARG_INT | MP_ARG_REQUIRED },
175183 { MP_QSTR_bit_depth , MP_ARG_INT | MP_ARG_REQUIRED },
176184 { MP_QSTR_rgb_pins , MP_ARG_OBJ | MP_ARG_REQUIRED },
177185 { MP_QSTR_addr_pins , MP_ARG_OBJ | MP_ARG_REQUIRED },
178186 { MP_QSTR_clock_pin , MP_ARG_OBJ | MP_ARG_REQUIRED },
179187 { MP_QSTR_latch_pin , MP_ARG_OBJ | MP_ARG_REQUIRED },
180- { MP_QSTR_oe_pin , MP_ARG_OBJ | MP_ARG_REQUIRED },
188+ { MP_QSTR_output_enable_pin , MP_ARG_OBJ | MP_ARG_REQUIRED },
181189 { MP_QSTR_doublebuffer , MP_ARG_BOOL , { .u_bool = true } },
182190 { MP_QSTR_framebuffer , MP_ARG_OBJ , { .u_obj = mp_const_none } },
183191 };
@@ -195,7 +203,7 @@ STATIC mp_obj_t protomatter_protomatter_make_new(const mp_obj_type_t *type, size
195203 uint8_t addr_pins [MP_ARRAY_SIZE (self -> addr_pins )];
196204 uint8_t clock_pin = validate_pin (args [ARG_clock_pin ].u_obj );
197205 uint8_t latch_pin = validate_pin (args [ARG_latch_pin ].u_obj );
198- uint8_t oe_pin = validate_pin (args [ARG_oe_pin ].u_obj );
206+ uint8_t output_enable_pin = validate_pin (args [ARG_output_enable_pin ].u_obj );
199207
200208 validate_pins (MP_QSTR_rgb_pins , rgb_pins , MP_ARRAY_SIZE (self -> rgb_pins ), args [ARG_rgb_list ].u_obj , & rgb_count );
201209 validate_pins (MP_QSTR_addr_pins , addr_pins , MP_ARRAY_SIZE (self -> addr_pins ), args [ARG_addr_list ].u_obj , & addr_count );
@@ -214,14 +222,14 @@ STATIC mp_obj_t protomatter_protomatter_make_new(const mp_obj_type_t *type, size
214222 args [ARG_bit_depth ].u_int ,
215223 rgb_count , rgb_pins ,
216224 addr_count , addr_pins ,
217- clock_pin , latch_pin , oe_pin ,
225+ clock_pin , latch_pin , output_enable_pin ,
218226 args [ARG_doublebuffer ].u_bool ,
219227 framebuffer , NULL );
220228
221229 claim_and_never_reset_pins (args [ARG_rgb_list ].u_obj );
222230 claim_and_never_reset_pins (args [ARG_addr_list ].u_obj );
223231 claim_and_never_reset_pin (args [ARG_clock_pin ].u_obj );
224- claim_and_never_reset_pin (args [ARG_oe_pin ].u_obj );
232+ claim_and_never_reset_pin (args [ARG_output_enable_pin ].u_obj );
225233 claim_and_never_reset_pin (args [ARG_latch_pin ].u_obj );
226234
227235 return MP_OBJ_FROM_PTR (self );
@@ -247,89 +255,91 @@ static void check_for_deinit(protomatter_protomatter_obj_t *self) {
247255 }
248256}
249257
250- //| .. attribute:: paused
258+ //| .. attribute:: brightness
251259//|
252- //| When paused, the matrix is not driven and all its LEDs are unlit.
260+ //| In the current implementation, 0.0 turns the display off entirely
261+ //| and any other value up to 1.0 turns the display on fully.
253262//|
254- STATIC mp_obj_t protomatter_protomatter_get_paused (mp_obj_t self_in ) {
263+ STATIC mp_obj_t protomatter_protomatter_get_brightness (mp_obj_t self_in ) {
255264 protomatter_protomatter_obj_t * self = (protomatter_protomatter_obj_t * )self_in ;
256265 check_for_deinit (self );
257- return mp_obj_new_bool (common_hal_protomatter_protomatter_get_paused (self ));
266+ return mp_obj_new_float (common_hal_protomatter_protomatter_get_paused (self )? 0.0f : 1.0f );
258267}
259- MP_DEFINE_CONST_FUN_OBJ_1 (protomatter_protomatter_get_paused_obj , protomatter_protomatter_get_paused );
268+ MP_DEFINE_CONST_FUN_OBJ_1 (protomatter_protomatter_get_brightness_obj , protomatter_protomatter_get_brightness );
260269
261- STATIC mp_obj_t protomatter_protomatter_set_paused (mp_obj_t self_in , mp_obj_t value_in ) {
270+ STATIC mp_obj_t protomatter_protomatter_set_brightness (mp_obj_t self_in , mp_obj_t value_in ) {
262271 protomatter_protomatter_obj_t * self = (protomatter_protomatter_obj_t * )self_in ;
263272 check_for_deinit (self );
264- bool paused = mp_obj_is_true (value_in );
265- common_hal_protomatter_protomatter_set_paused (self , paused );
273+ mp_float_t brightness = mp_obj_get_float (value_in );
274+ if (brightness < 0.0f || brightness > 1.0f ) {
275+ mp_raise_ValueError (translate ("Brightness must be 0-1.0" ));
276+ }
277+ common_hal_protomatter_protomatter_set_paused (self_in , brightness <= 0 );
266278
267279 return mp_const_none ;
268280}
269- MP_DEFINE_CONST_FUN_OBJ_2 (protomatter_protomatter_set_paused_obj , protomatter_protomatter_set_paused );
281+ MP_DEFINE_CONST_FUN_OBJ_2 (protomatter_protomatter_set_brightness_obj , protomatter_protomatter_set_brightness );
270282
271- const mp_obj_property_t protomatter_protomatter_paused_obj = {
283+ const mp_obj_property_t protomatter_protomatter_brightness_obj = {
272284 .base .type = & mp_type_property ,
273- .proxy = {(mp_obj_t )& protomatter_protomatter_get_paused_obj ,
274- (mp_obj_t )& protomatter_protomatter_set_paused_obj ,
285+ .proxy = {(mp_obj_t )& protomatter_protomatter_get_brightness_obj ,
286+ (mp_obj_t )& protomatter_protomatter_set_brightness_obj ,
275287 (mp_obj_t )& mp_const_none_obj },
276288};
277289
278- //| .. method:: swapbuffers()
279- //|
280- //| Transmits the color data in the buffer to the pixels so that they are shown.
290+ //| .. method:: refresh()
281291//|
282- //| The data in the buffer must be in "RGB565" format. This means
283- //| that it is organized as a series of 16-bit numbers where the highest 5
284- //| bits are interpreted as red, the next 6 as green, and the final 5 as
285- //| blue. The object can be any buffer, but `array.array` and `ulab.array`
286- //| objects are most often useful.
292+ //| Transmits the color data in the buffer to the pixels so that
293+ //| they are shown.
287294//|
288- STATIC mp_obj_t protomatter_protomatter_swapbuffers (mp_obj_t self_in ) {
295+ STATIC mp_obj_t protomatter_protomatter_refresh (mp_obj_t self_in ) {
289296 protomatter_protomatter_obj_t * self = (protomatter_protomatter_obj_t * )self_in ;
290297 check_for_deinit (self );
291-
292- _PM_convert_565 (& self -> core , self -> bufinfo .buf , self -> width );
293- _PM_swapbuffer_maybe (& self -> core );
298+ common_hal_protomatter_protomatter_refresh (self );
294299 return mp_const_none ;
295300}
296- MP_DEFINE_CONST_FUN_OBJ_1 (protomatter_protomatter_swapbuffers_obj , protomatter_protomatter_swapbuffers );
301+ MP_DEFINE_CONST_FUN_OBJ_1 (protomatter_protomatter_refresh_obj , protomatter_protomatter_refresh );
297302
298303STATIC const mp_rom_map_elem_t protomatter_protomatter_locals_dict_table [] = {
299304 { MP_ROM_QSTR (MP_QSTR_deinit ), MP_ROM_PTR (& protomatter_protomatter_deinit_obj ) },
300- { MP_ROM_QSTR (MP_QSTR_paused ), MP_ROM_PTR (& protomatter_protomatter_paused_obj ) },
301- { MP_ROM_QSTR (MP_QSTR_swapbuffers ), MP_ROM_PTR (& protomatter_protomatter_swapbuffers_obj ) },
305+ { MP_ROM_QSTR (MP_QSTR_brightness ), MP_ROM_PTR (& protomatter_protomatter_brightness_obj ) },
306+ { MP_ROM_QSTR (MP_QSTR_refresh ), MP_ROM_PTR (& protomatter_protomatter_refresh_obj ) },
302307};
303308STATIC MP_DEFINE_CONST_DICT (protomatter_protomatter_locals_dict , protomatter_protomatter_locals_dict_table );
304309
305310STATIC void protomatter_protomatter_get_bufinfo (mp_obj_t self_in , mp_buffer_info_t * bufinfo ) {
306311 protomatter_protomatter_obj_t * self = (protomatter_protomatter_obj_t * )self_in ;
307312 check_for_deinit (self );
308-
313+
309314 * bufinfo = self -> bufinfo ;
310315}
311316
312- // This version exists so that the return value of the function can be none, matching the protocol
313- STATIC void protomatter_protomatter_swapbuffers_void (mp_obj_t self_in ) {
314- protomatter_protomatter_swapbuffers (self_in );
317+ // These version exists so that the prototype matches the protocol,
318+ // avoiding a type cast that can hide errors
319+ STATIC void protomatter_protomatter_swapbuffers (mp_obj_t self_in ) {
320+ common_hal_protomatter_protomatter_refresh (self_in );
321+ }
322+
323+ STATIC void protomatter_protomatter_deinit_proto (mp_obj_t self_in ) {
324+ common_hal_protomatter_protomatter_deinit (self_in );
315325}
316326
317- // This version exists so that the return value of the function can be none, matching the protocol
318- STATIC void protomatter_protomatter_deinit_void (mp_obj_t self_in ) {
319- protomatter_protomatter_deinit (self_in );
327+ STATIC float protomatter_protomatter_get_brightness_proto (mp_obj_t self_in ) {
328+ return common_hal_protomatter_protomatter_get_paused (self_in ) ? 0.0f : 1.0f ;
320329}
321330
322- STATIC bool protomatter_protomatter_set_brightness (mp_obj_t self_in , mp_float_t value ) {
331+ STATIC bool protomatter_protomatter_set_brightness_proto (mp_obj_t self_in , mp_float_t value ) {
323332 common_hal_protomatter_protomatter_set_paused (self_in , value <= 0 );
324333 return true;
325334}
326335
327336STATIC const framebuffer_p_t protomatter_protomatter_proto = {
328337 MP_PROTO_IMPLEMENT (MP_QSTR_protocol_framebuffer )
329338 .get_bufinfo = protomatter_protomatter_get_bufinfo ,
330- .set_brightness = protomatter_protomatter_set_brightness ,
331- .swapbuffers = protomatter_protomatter_swapbuffers_void ,
332- .deinit = protomatter_protomatter_deinit_void ,
339+ .set_brightness = protomatter_protomatter_set_brightness_proto ,
340+ .get_brightness = protomatter_protomatter_get_brightness_proto ,
341+ .swapbuffers = protomatter_protomatter_swapbuffers ,
342+ .deinit = protomatter_protomatter_deinit_proto ,
333343};
334344
335345STATIC mp_int_t protomatter_protomatter_get_buffer (mp_obj_t self_in , mp_buffer_info_t * bufinfo , mp_uint_t flags ) {
0 commit comments