4040#include "../../shared-module/_pixelbuf/PixelBuf.h"
4141#include "shared-bindings/digitalio/DigitalInOut.h"
4242
43- extern const pixelbuf_byteorder_obj_t byteorder_BGR ;
44- extern const mp_obj_type_t pixelbuf_byteorder_type ;
4543extern const int32_t colorwheel (float pos );
4644
45+ int parse_byteorder_string (const char * byteorder , pixelbuf_byteorder_details_t details ) {
46+ details .bpp = strlen (byteorder );
47+ char * dotstar = strchr (byteorder , 'D' );
48+ char * r = strchr (byteorder , 'R' );
49+ char * g = strchr (byteorder , 'G' );
50+ char * b = strchr (byteorder , 'B' );
51+ char * w = strchr (byteorder , 'W' );
52+ int num_chars = (dotstar ? 1 : 0 ) + (w ? 1 : 0 ) + (r ? 1 : 0 ) + (g ? 1 : 0 ) + (b ? 1 : 0 );
53+ if (num_chars < details .bpp )
54+ mp_raise_ValueError (translate ("Unexpected character in byteorder" ));
55+ if (!(r && b && g ))
56+ mp_raise_ValueError (translate ("Incomplete byteorder string" ));
57+ details .is_dotstar = dotstar ? true : false;
58+ details .has_white = w ? true : false;
59+ details .byteorder .r = byteorder - r ;
60+ details .byteorder .g = byteorder - g ;
61+ details .byteorder .b = byteorder - b ;
62+ if (w )
63+ details .byteorder .w = byteorder - w ;
64+ // The dotstar brightness byte is always first (as it goes with the pixel start bits)
65+ // if 'D' is found at the end, adjust byte position
66+ // if 'D' is elsewhere, error out
67+ if (dotstar ) {
68+ size_t dotstar_pos = dotstar - byteorder ;
69+ if (dotstar_pos == 4 ) {
70+ details .byteorder .b += 1 ;
71+ details .byteorder .g += 1 ;
72+ details .byteorder .r += 1 ;
73+ } else if (dotstar_pos != 0 ) {
74+ mp_raise_ValueError (translate ("Dotstar position invalid" ));
75+ }
76+ }
77+ }
78+
4779//| .. currentmodule:: pixelbuf
4880//|
4981//| :class:`PixelBuf` -- A fast RGB[W] pixel buffer for LED and similar devices
5082//| ===========================================================================
5183//|
5284//| :class:`~_pixelbuf.PixelBuf` implements an RGB[W] bytearray abstraction.
5385//|
54- //| .. class:: PixelBuf(size, buf, byteorder=BGR, brightness=0, rawbuf=None, offset=0, dotstar=False , auto_write=False, write_function=None, write_args=None)
86+ //| .. class:: PixelBuf(size, buf, byteorder=" BGR" , brightness=0, rawbuf=None, offset=0, auto_write=False, write_function=None, write_args=None)
5587//|
5688//| Create a PixelBuf object of the specified size, byteorder, and bits per pixel.
5789//|
@@ -60,25 +92,23 @@ extern const int32_t colorwheel(float pos);
6092//|
6193//| When only given ``buf``, ``brightness`` applies to the next pixel assignment.
6294//|
63- //| When ``dotstar`` is True, and ``bpp`` is 4, the 4th value in a tuple/list
64- //| is the individual pixel brightness (0-1). Not compatible with RGBW Byteorders.
65- //| Compatible `ByteOrder` classes are bpp=3, or bpp=4 and has_luminosity=True (g LBGR).
95+ //| When ``D`` (dotstar mode) is present in the byteorder configuration, the
96+ //| 4th value in a tuple/list is the individual pixel brightness (0-1).
6697//|
6798//| :param ~int size: Number of pixelsx
68- //| :param ~bytearray buf: Bytearray to store pixel data in
69- //| :param ~_pixelbuf.ByteOrder byteorder: Byte order constant from `_pixelbuf`
99+ //| :param ~bytearray buf: Bytearray in which to store pixel data
100+ //| :param ~str byteorder: Byte order string (such as "BGR" or "BGRD")
70101//| :param ~float brightness: Brightness (0 to 1.0, default 1.0)
71- //| :param ~bytearray rawbuf: Bytearray to store raw pixel colors in
102+ //| :param ~bytearray rawbuf: Bytearray in which to store raw pixel data (before brightness adjustment)
72103//| :param ~int offset: Offset from start of buffer (default 0)
73- //| :param ~bool dotstar: Dotstar mode (default False)
74104//| :param ~bool auto_write: Whether to automatically write pixels (Default False)
75105//| :param ~callable write_function: (optional) Callable to use to send pixels
76106//| :param ~list write_args: (optional) Tuple or list of args to pass to ``write_function``. The
77107//| PixelBuf instance is appended after these args.
78108//|
79109STATIC mp_obj_t pixelbuf_pixelbuf_make_new (const mp_obj_type_t * type , size_t n_args , const mp_obj_t * pos_args , mp_map_t * kw_args ) {
80110 mp_arg_check_num (n_args , kw_args , 2 , MP_OBJ_FUN_ARGS_MAX , true);
81- enum { ARG_size , ARG_buf , ARG_byteorder , ARG_brightness , ARG_rawbuf , ARG_offset , ARG_dotstar ,
111+ enum { ARG_size , ARG_buf , ARG_byteorder , ARG_brightness , ARG_rawbuf , ARG_offset ,
82112 ARG_auto_write , ARG_write_function , ARG_write_args };
83113 static const mp_arg_t allowed_args [] = {
84114 { MP_QSTR_size , MP_ARG_REQUIRED | MP_ARG_INT },
@@ -87,23 +117,30 @@ STATIC mp_obj_t pixelbuf_pixelbuf_make_new(const mp_obj_type_t *type, size_t n_a
87117 { MP_QSTR_brightness , MP_ARG_OBJ , { .u_obj = mp_const_none } },
88118 { MP_QSTR_rawbuf , MP_ARG_OBJ , { .u_obj = mp_const_none } },
89119 { MP_QSTR_offset , MP_ARG_INT , { .u_int = 0 } },
90- { MP_QSTR_dotstar , MP_ARG_BOOL , { .u_bool = false } },
91120 { MP_QSTR_auto_write , MP_ARG_BOOL , {.u_bool = false} },
92121 { MP_QSTR_write_function , MP_ARG_OBJ , {.u_obj = mp_const_none } },
93122 { MP_QSTR_write_args , MP_ARG_OBJ , {.u_obj = mp_const_none } },
94123 };
95124 mp_arg_val_t args [MP_ARRAY_SIZE (allowed_args )];
96125 mp_arg_parse_all (n_args , pos_args , kw_args , MP_ARRAY_SIZE (allowed_args ), allowed_args , args );
97126
98- if (mp_obj_is_subclass_fast (args [ARG_byteorder ].u_obj , & pixelbuf_byteorder_type ))
99- mp_raise_TypeError_varg (translate ("byteorder is not an instance of ByteOrder (got a %s)" ), mp_obj_get_type_str ( args [ ARG_byteorder ]. u_obj ));
127+ if (! MP_OBJ_IS_STR (args [ARG_byteorder ].u_obj ))
128+ mp_raise_TypeError (translate ("byteorder is not a string" ));
100129
101- pixelbuf_byteorder_obj_t * byteorder = (args [ARG_byteorder ].u_obj == mp_const_none ) ? MP_OBJ_FROM_PTR (& byteorder_BGR ) : args [ARG_byteorder ].u_obj ;
130+ const char * byteorder_str = NULL ;
131+ pixelbuf_byteorder_details_t byteorder_details ;
132+ size_t bo_len ;
133+ if (args [ARG_byteorder ].u_obj == NULL )
134+ byteorder_str = "BGR" ;
135+ else
136+ byteorder_str = mp_obj_str_get_data (byteorder_str , bo_len );
102137
103- if (byteorder -> has_white && args [ARG_dotstar ].u_bool )
104- mp_raise_ValueError_varg (translate ("Can not use dotstar with %s" ), mp_obj_get_type_str (byteorder ));
138+ parse_byteorder_string (byteorder_str , byteorder_details );
105139
106- size_t effective_bpp = args [ARG_dotstar ].u_bool ? 4 : byteorder -> bpp ; // Always 4 for DotStar
140+ if (byteorder_details .has_white && byteorder_details .is_dotstar )
141+ mp_raise_ValueError (translate ("Can not use dotstar with a white byte" ));
142+
143+ size_t effective_bpp = byteorder_details .is_dotstar ? 4 : byteorder_details .bpp ; // Always 4 for DotStar
107144 size_t bytes = args [ARG_size ].u_int * effective_bpp ;
108145 size_t offset = args [ARG_offset ].u_int ;
109146 mp_buffer_info_t bufinfo , rawbufinfo ;
@@ -133,28 +170,16 @@ STATIC mp_obj_t pixelbuf_pixelbuf_make_new(const mp_obj_type_t *type, size_t n_a
133170 self -> base .type = & pixelbuf_pixelbuf_type ;
134171 self -> pixels = args [ARG_size ].u_int ;
135172 self -> bytes = bytes ;
136- self -> byteorder = * byteorder ; // Copied because we modify for dotstar
173+ self -> byteorder = byteorder_details ; // Copied because we modify for dotstar
137174 self -> bytearray = args [ARG_buf ].u_obj ;
138175 self -> two_buffers = two_buffers ;
139176 self -> rawbytearray = two_buffers ? args [ARG_rawbuf ].u_obj : NULL ;
140177 self -> offset = offset ;
141- self -> dotstar_mode = args [ARG_dotstar ].u_bool ;
142178 self -> buf = (uint8_t * )bufinfo .buf + offset ;
143179 self -> rawbuf = two_buffers ? (uint8_t * )rawbufinfo .buf + offset : NULL ;
144180 self -> pixel_step = effective_bpp ;
145181 self -> auto_write = args [ARG_auto_write ].u_bool ;
146182
147- if (self -> dotstar_mode ) {
148- // Ensure sane configuration
149- if (!self -> byteorder .has_luminosity ) {
150- self -> byteorder .has_luminosity = true;
151- self -> byteorder .byteorder .b += 1 ;
152- self -> byteorder .byteorder .g += 1 ;
153- self -> byteorder .byteorder .r += 1 ;
154- }
155- self -> byteorder .byteorder .w = 0 ;
156- }
157-
158183 // Show/auto-write callbacks
159184 self -> write_function = args [ARG_write_function ].u_obj ;
160185 mp_obj_t function_args = args [ARG_write_args ].u_obj ;
@@ -187,7 +212,7 @@ STATIC mp_obj_t pixelbuf_pixelbuf_make_new(const mp_obj_type_t *type, size_t n_a
187212 self -> brightness = 1 ;
188213 }
189214
190- if (self -> dotstar_mode ) {
215+ if (self -> byteorder . is_dotstar ) {
191216 // Initialize the buffer with the dotstar start bytes.
192217 // Header and end must be setup by caller
193218 for (uint i = 0 ; i < self -> pixels * 4 ; i += 4 ) {
@@ -266,7 +291,7 @@ void pixelbuf_recalculate_brightness(pixelbuf_pixelbuf_obj_t *self) {
266291 // Compensate for shifted buffer (bpp=3 dotstar)
267292 for (uint i = 0 ; i < self -> bytes ; i ++ ) {
268293 // Don't adjust per-pixel luminance bytes in dotstar mode
269- if (!self -> dotstar_mode || (i % 4 != 0 ))
294+ if (!self -> byteorder . is_dotstar || (i % 4 != 0 ))
270295 buf [i ] = rawbuf [i ] * self -> brightness ;
271296 }
272297}
@@ -321,7 +346,7 @@ const mp_obj_property_t pixelbuf_pixelbuf_buf_obj = {
321346
322347//| .. attribute:: byteorder
323348//|
324- //| `ByteOrder` class for the buffer (read-only)
349+ //| byteorder string for the buffer (read-only)
325350//|
326351STATIC mp_obj_t pixelbuf_pixelbuf_obj_get_byteorder (mp_obj_t self_in ) {
327352 mp_check_self (MP_OBJ_IS_TYPE (self_in , & pixelbuf_pixelbuf_type ));
@@ -397,7 +422,7 @@ STATIC mp_obj_t pixelbuf_pixelbuf_subscr(mp_obj_t self_in, mp_obj_t index_in, mp
397422
398423 if (value == MP_OBJ_SENTINEL ) { // Get
399424 size_t len = slice .stop - slice .start ;
400- return pixelbuf_get_pixel_array ((uint8_t * ) self -> buf + slice .start , len , & self -> byteorder , self -> pixel_step , self -> dotstar_mode );
425+ return pixelbuf_get_pixel_array ((uint8_t * ) self -> buf + slice .start , len , & self -> byteorder , self -> pixel_step , self -> byteorder . is_dotstar );
401426 } else { // Set
402427 #if MICROPY_PY_ARRAY_SLICE_ASSIGN
403428
@@ -426,7 +451,7 @@ STATIC mp_obj_t pixelbuf_pixelbuf_subscr(mp_obj_t self_in, mp_obj_t index_in, mp
426451 if (MP_OBJ_IS_TYPE (value , & mp_type_list ) || MP_OBJ_IS_TYPE (value , & mp_type_tuple ) || MP_OBJ_IS_INT (value )) {
427452 pixelbuf_set_pixel (self -> buf + (i * self -> pixel_step ),
428453 self -> two_buffers ? self -> rawbuf + (i * self -> pixel_step ) : NULL ,
429- self -> brightness , item , & self -> byteorder , self -> dotstar_mode );
454+ self -> brightness , item , & self -> byteorder , self -> byteorder . is_dotstar );
430455 }
431456 }
432457 if (self -> auto_write )
@@ -445,10 +470,10 @@ STATIC mp_obj_t pixelbuf_pixelbuf_subscr(mp_obj_t self_in, mp_obj_t index_in, mp
445470
446471 if (value == MP_OBJ_SENTINEL ) { // Get
447472 uint8_t * pixelstart = (uint8_t * )(self -> two_buffers ? self -> rawbuf : self -> buf ) + offset ;
448- return pixelbuf_get_pixel (pixelstart , & self -> byteorder , self -> dotstar_mode );
473+ return pixelbuf_get_pixel (pixelstart , & self -> byteorder , self -> byteorder . is_dotstar );
449474 } else { // Store
450475 pixelbuf_set_pixel (self -> buf + offset , self -> two_buffers ? self -> rawbuf + offset : NULL ,
451- self -> brightness , value , & self -> byteorder , self -> dotstar_mode );
476+ self -> brightness , value , & self -> byteorder , self -> byteorder . is_dotstar );
452477 if (self -> auto_write )
453478 call_write_function (self );
454479 return mp_const_none ;
0 commit comments