commit
db34db24ef
|
@ -1508,6 +1508,10 @@ msgstr ""
|
|||
msgid "MOSI pin init failed."
|
||||
msgstr ""
|
||||
|
||||
#: shared-bindings/is31fl3741/__init__.c
|
||||
msgid "Mapping must be a tuple"
|
||||
msgstr ""
|
||||
|
||||
#: shared-module/displayio/Shape.c
|
||||
#, c-format
|
||||
msgid "Maximum x value when mirrored is %d"
|
||||
|
|
|
@ -539,6 +539,7 @@ SRC_SHARED_MODULE_ALL = \
|
|||
ipaddress/IPv4Address.c \
|
||||
ipaddress/__init__.c \
|
||||
is31fl3741/IS31FL3741.c \
|
||||
is31fl3741/FrameBuffer.c \
|
||||
is31fl3741/__init__.c \
|
||||
keypad/__init__.c \
|
||||
keypad/Event.c \
|
||||
|
|
|
@ -0,0 +1,312 @@
|
|||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 Mark Komus
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "py/objproperty.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/objarray.h"
|
||||
|
||||
#include "shared-bindings/is31fl3741/IS31FL3741.h"
|
||||
#include "shared-bindings/is31fl3741/FrameBuffer.h"
|
||||
#include "shared-bindings/util.h"
|
||||
#include "shared-module/displayio/__init__.h"
|
||||
#include "shared-module/framebufferio/__init__.h"
|
||||
#include "shared-module/framebufferio/FramebufferDisplay.h"
|
||||
#include "shared-bindings/busio/I2C.h"
|
||||
|
||||
//| class IS31FL3741_FrameBuffer:
|
||||
//| """Creates an in-memory framebuffer for a IS31FL3741 device."""
|
||||
//|
|
||||
//| def __init__(self, is31: is31fl3741.IS31FL3741, width: int, height: int, mapping: Tuple[int, ...], *,
|
||||
//| framebuffer: Optional[WriteableBuffer] = None, scale: bool = False, gamma: bool = False) -> None:
|
||||
//| """Create a IS31FL3741_FrameBuffer object with the given attributes.
|
||||
//|
|
||||
//| The framebuffer is in "RGB888" format using 4 bytes per pixel.
|
||||
//| Bits 24-31 are ignored. The format is in RGB order.
|
||||
//|
|
||||
//| If a framebuffer is not passed in, one is allocated and initialized
|
||||
//| to all black. In any case, the framebuffer can be retrieved
|
||||
//| by passing the Is31fl3741 object to memoryview().
|
||||
//|
|
||||
//| A Is31fl3741 is often used in conjunction with a
|
||||
//| `framebufferio.FramebufferDisplay`.
|
||||
//|
|
||||
//| :param is31fl3741.IS31FL3741 is31: base IS31FL3741 instance to drive the framebuffer
|
||||
//| :param int width: width of the display
|
||||
//| :param int height: height of the display
|
||||
//| :param Tuple[int, ...] mapping: mapping of matrix locations to LEDs
|
||||
//| :param Optional[WriteableBuffer] framebuffer: Optional buffer to hold the display
|
||||
//| :param bool scale: if True display is scaled down by 3 when displayed
|
||||
//| :param bool gamma: if True apply gamma correction to all LEDs"""
|
||||
//| ...
|
||||
//|
|
||||
STATIC mp_obj_t is31fl3741_FrameBuffer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
||||
enum { ARG_is31, ARG_width, ARG_height, ARG_mapping, ARG_framebuffer, ARG_scale, ARG_gamma };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_is31, MP_ARG_OBJ | MP_ARG_REQUIRED },
|
||||
{ MP_QSTR_width, MP_ARG_INT | MP_ARG_REQUIRED },
|
||||
{ MP_QSTR_height, MP_ARG_INT | MP_ARG_REQUIRED },
|
||||
{ MP_QSTR_mapping, MP_ARG_OBJ | MP_ARG_REQUIRED },
|
||||
{ MP_QSTR_framebuffer, MP_ARG_OBJ | MP_ARG_KW_ONLY, { .u_obj = mp_const_none } },
|
||||
{ MP_QSTR_scale, MP_ARG_BOOL | MP_ARG_KW_ONLY, { .u_bool = false } },
|
||||
{ MP_QSTR_gamma, MP_ARG_BOOL | MP_ARG_KW_ONLY, { .u_bool = false } },
|
||||
};
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
is31fl3741_FrameBuffer_obj_t *self = &allocate_display_bus_or_raise()->is31fl3741;
|
||||
self->base.type = &is31fl3741_FrameBuffer_type;
|
||||
|
||||
if (args[ARG_width].u_int <= 0) {
|
||||
mp_raise_ValueError(translate("width must be greater than zero"));
|
||||
}
|
||||
|
||||
self->scale = args[ARG_scale].u_bool;
|
||||
if (self->scale) {
|
||||
if (((args[ARG_height].u_int % 3) != 0) || ((args[ARG_width].u_int % 3) != 0)) {
|
||||
mp_raise_ValueError(translate("Scale dimensions must divide by 3"));
|
||||
}
|
||||
|
||||
self->scale_width = args[ARG_width].u_int / 3;
|
||||
self->scale_height = args[ARG_height].u_int / 3;
|
||||
} else {
|
||||
self->scale_width = args[ARG_width].u_int;
|
||||
self->scale_height = args[ARG_height].u_int;
|
||||
}
|
||||
|
||||
self->auto_gamma = args[ARG_gamma].u_bool;
|
||||
|
||||
mp_obj_t framebuffer = args[ARG_framebuffer].u_obj;
|
||||
if (framebuffer == mp_const_none) {
|
||||
int width = args[ARG_width].u_int;
|
||||
int height = args[ARG_height].u_int;
|
||||
int bufsize = 4 * width * height;
|
||||
framebuffer = mp_obj_new_bytearray_of_zeros(bufsize);
|
||||
}
|
||||
|
||||
common_hal_is31fl3741_FrameBuffer_construct(self,
|
||||
args[ARG_width].u_int,
|
||||
args[ARG_height].u_int,
|
||||
framebuffer,
|
||||
args[ARG_is31].u_obj,
|
||||
args[ARG_mapping].u_obj
|
||||
);
|
||||
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
||||
//| def deinit(self) -> None:
|
||||
//| """Free the resources associated with this
|
||||
//| IS31FL3741 instance. After deinitialization, no further operations
|
||||
//| may be performed."""
|
||||
//| ...
|
||||
//|
|
||||
STATIC mp_obj_t is31fl3741_FrameBuffer_deinit(mp_obj_t self_in) {
|
||||
is31fl3741_FrameBuffer_obj_t *self = (is31fl3741_FrameBuffer_obj_t *)self_in;
|
||||
common_hal_is31fl3741_FrameBuffer_deinit(self);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_FrameBuffer_deinit_obj, is31fl3741_FrameBuffer_deinit);
|
||||
|
||||
static void check_for_deinit(is31fl3741_FrameBuffer_obj_t *self) {
|
||||
if (self->framebuffer == NULL) {
|
||||
raise_deinited_error();
|
||||
}
|
||||
}
|
||||
|
||||
//| brightness: float
|
||||
//| """In the current implementation, 0.0 turns the display off entirely
|
||||
//| and any other value up to 1.0 turns the display on fully."""
|
||||
//|
|
||||
STATIC mp_obj_t is31fl3741_FrameBuffer_get_brightness(mp_obj_t self_in) {
|
||||
is31fl3741_FrameBuffer_obj_t *self = (is31fl3741_FrameBuffer_obj_t *)self_in;
|
||||
check_for_deinit(self);
|
||||
uint8_t current = common_hal_is31fl3741_get_current(self->is31fl3741);
|
||||
|
||||
float brightness = (float)current / (float)0xFF;
|
||||
return mp_obj_new_float(brightness);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_FrameBuffer_get_brightness_obj, is31fl3741_FrameBuffer_get_brightness);
|
||||
|
||||
STATIC mp_obj_t is31fl3741_FrameBuffer_set_brightness(mp_obj_t self_in, mp_obj_t value_in) {
|
||||
is31fl3741_FrameBuffer_obj_t *self = (is31fl3741_FrameBuffer_obj_t *)self_in;
|
||||
check_for_deinit(self);
|
||||
mp_float_t brightness = mp_obj_get_float(value_in);
|
||||
if (brightness < 0.0f || brightness > 1.0f) {
|
||||
mp_raise_ValueError(translate("Brightness must be 0-1.0"));
|
||||
}
|
||||
|
||||
uint8_t current = (uint8_t)(brightness * 0xFF);
|
||||
common_hal_is31fl3741_set_current(self->is31fl3741, current);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(is31fl3741_FrameBuffer_set_brightness_obj, is31fl3741_FrameBuffer_set_brightness);
|
||||
|
||||
const mp_obj_property_t is31fl3741_FrameBuffer_brightness_obj = {
|
||||
.base.type = &mp_type_property,
|
||||
.proxy = {(mp_obj_t)&is31fl3741_FrameBuffer_get_brightness_obj,
|
||||
(mp_obj_t)&is31fl3741_FrameBuffer_set_brightness_obj,
|
||||
MP_ROM_NONE},
|
||||
};
|
||||
|
||||
//| def refresh(self) -> None:
|
||||
//| """Transmits the color data in the buffer to the pixels so that
|
||||
//| they are shown."""
|
||||
//| ...
|
||||
//|
|
||||
STATIC mp_obj_t is31fl3741_FrameBuffer_refresh(mp_obj_t self_in) {
|
||||
is31fl3741_FrameBuffer_obj_t *self = (is31fl3741_FrameBuffer_obj_t *)self_in;
|
||||
check_for_deinit(self);
|
||||
common_hal_is31fl3741_FrameBuffer_refresh(self, 0);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_FrameBuffer_refresh_obj, is31fl3741_FrameBuffer_refresh);
|
||||
|
||||
//| width: int
|
||||
//| """The width of the display, in pixels"""
|
||||
//|
|
||||
STATIC mp_obj_t is31fl3741_FrameBuffer_get_width(mp_obj_t self_in) {
|
||||
is31fl3741_FrameBuffer_obj_t *self = (is31fl3741_FrameBuffer_obj_t *)self_in;
|
||||
check_for_deinit(self);
|
||||
return MP_OBJ_NEW_SMALL_INT(common_hal_is31fl3741_FrameBuffer_get_width(self));
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_FrameBuffer_get_width_obj, is31fl3741_FrameBuffer_get_width);
|
||||
const mp_obj_property_t is31fl3741_FrameBuffer_width_obj = {
|
||||
.base.type = &mp_type_property,
|
||||
.proxy = {(mp_obj_t)&is31fl3741_FrameBuffer_get_width_obj,
|
||||
MP_ROM_NONE,
|
||||
MP_ROM_NONE},
|
||||
};
|
||||
|
||||
//| height: int
|
||||
//| """The height of the display, in pixels"""
|
||||
//|
|
||||
STATIC mp_obj_t is31fl3741_FrameBuffer_get_height(mp_obj_t self_in) {
|
||||
is31fl3741_FrameBuffer_obj_t *self = (is31fl3741_FrameBuffer_obj_t *)self_in;
|
||||
check_for_deinit(self);
|
||||
return MP_OBJ_NEW_SMALL_INT(common_hal_is31fl3741_FrameBuffer_get_height(self));
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_FrameBuffer_get_height_obj, is31fl3741_FrameBuffer_get_height);
|
||||
const mp_obj_property_t is31fl3741_FrameBuffer_height_obj = {
|
||||
.base.type = &mp_type_property,
|
||||
.proxy = {(mp_obj_t)&is31fl3741_FrameBuffer_get_height_obj,
|
||||
MP_ROM_NONE,
|
||||
MP_ROM_NONE},
|
||||
};
|
||||
|
||||
STATIC const mp_rom_map_elem_t is31fl3741_FrameBuffer_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&is31fl3741_FrameBuffer_deinit_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_brightness), MP_ROM_PTR(&is31fl3741_FrameBuffer_brightness_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_refresh), MP_ROM_PTR(&is31fl3741_FrameBuffer_refresh_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&is31fl3741_FrameBuffer_width_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&is31fl3741_FrameBuffer_height_obj) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(is31fl3741_FrameBuffer_locals_dict, is31fl3741_FrameBuffer_locals_dict_table);
|
||||
|
||||
STATIC void is31fl3741_FrameBuffer_get_bufinfo(mp_obj_t self_in, mp_buffer_info_t *bufinfo) {
|
||||
is31fl3741_FrameBuffer_obj_t *self = (is31fl3741_FrameBuffer_obj_t *)self_in;
|
||||
check_for_deinit(self);
|
||||
|
||||
*bufinfo = self->bufinfo;
|
||||
}
|
||||
|
||||
STATIC void is31fl3741_FrameBuffer_swapbuffers(mp_obj_t self_in, uint8_t *dirty_row_bitmap) {
|
||||
common_hal_is31fl3741_FrameBuffer_refresh(self_in, dirty_row_bitmap);
|
||||
}
|
||||
|
||||
STATIC void is31fl3741_FrameBuffer_deinit_proto(mp_obj_t self_in) {
|
||||
common_hal_is31fl3741_FrameBuffer_deinit(self_in);
|
||||
}
|
||||
|
||||
STATIC float is31fl3741_FrameBuffer_get_brightness_proto(mp_obj_t self_in) {
|
||||
return common_hal_is31fl3741_FrameBuffer_get_paused(self_in) ? 0.0f : 1.0f;
|
||||
}
|
||||
|
||||
STATIC bool is31fl3741_FrameBuffer_set_brightness_proto(mp_obj_t self_in, mp_float_t value) {
|
||||
common_hal_is31fl3741_FrameBuffer_set_paused(self_in, value <= 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
STATIC int is31fl3741_FrameBuffer_get_width_proto(mp_obj_t self_in) {
|
||||
return common_hal_is31fl3741_FrameBuffer_get_width(self_in);
|
||||
}
|
||||
|
||||
STATIC int is31fl3741_FrameBuffer_get_height_proto(mp_obj_t self_in) {
|
||||
return common_hal_is31fl3741_FrameBuffer_get_height(self_in);
|
||||
}
|
||||
|
||||
STATIC int is31fl3741_FrameBuffer_get_color_depth_proto(mp_obj_t self_in) {
|
||||
// The way displayio works depth is used to calculate bytes
|
||||
// We use an uint32_t for color already so setting to 24 causes
|
||||
// more changes required
|
||||
return 32;
|
||||
}
|
||||
|
||||
STATIC int is31fl3741_FrameBuffer_get_bytes_per_cell_proto(mp_obj_t self_in) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
STATIC int is31fl3741_FrameBuffer_get_native_frames_per_second_proto(mp_obj_t self_in) {
|
||||
return 60; // This was just chosen may vary based on LEDs used?
|
||||
}
|
||||
|
||||
STATIC const framebuffer_p_t is31fl3741_FrameBuffer_proto = {
|
||||
MP_PROTO_IMPLEMENT(MP_QSTR_protocol_framebuffer)
|
||||
.get_bufinfo = is31fl3741_FrameBuffer_get_bufinfo,
|
||||
.set_brightness = is31fl3741_FrameBuffer_set_brightness_proto,
|
||||
.get_brightness = is31fl3741_FrameBuffer_get_brightness_proto,
|
||||
.get_width = is31fl3741_FrameBuffer_get_width_proto,
|
||||
.get_height = is31fl3741_FrameBuffer_get_height_proto,
|
||||
.get_color_depth = is31fl3741_FrameBuffer_get_color_depth_proto,
|
||||
.get_bytes_per_cell = is31fl3741_FrameBuffer_get_bytes_per_cell_proto,
|
||||
.get_native_frames_per_second = is31fl3741_FrameBuffer_get_native_frames_per_second_proto,
|
||||
.swapbuffers = is31fl3741_FrameBuffer_swapbuffers,
|
||||
.deinit = is31fl3741_FrameBuffer_deinit_proto,
|
||||
};
|
||||
|
||||
STATIC mp_int_t is31fl3741_FrameBuffer_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
|
||||
is31fl3741_FrameBuffer_obj_t *self = (is31fl3741_FrameBuffer_obj_t *)self_in;
|
||||
// a readonly framebuffer would be unusual but not impossible
|
||||
if ((flags & MP_BUFFER_WRITE) && !(self->bufinfo.typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW)) {
|
||||
return 1;
|
||||
}
|
||||
*bufinfo = self->bufinfo;
|
||||
bufinfo->typecode = 'H';
|
||||
return 0;
|
||||
}
|
||||
|
||||
const mp_obj_type_t is31fl3741_FrameBuffer_type = {
|
||||
{ &mp_type_type },
|
||||
.flags = MP_TYPE_FLAG_EXTENDED,
|
||||
.name = MP_QSTR_is31fl3741,
|
||||
.locals_dict = (mp_obj_dict_t *)&is31fl3741_FrameBuffer_locals_dict,
|
||||
.make_new = is31fl3741_FrameBuffer_make_new,
|
||||
MP_TYPE_EXTENDED_FIELDS(
|
||||
.buffer_p = { .get_buffer = is31fl3741_FrameBuffer_get_buffer, },
|
||||
.protocol = &is31fl3741_FrameBuffer_proto,
|
||||
),
|
||||
};
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 Mark Komus
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "shared-module/is31fl3741/FrameBuffer.h"
|
||||
#include "shared-module/is31fl3741/IS31FL3741.h"
|
||||
|
||||
extern const mp_obj_type_t is31fl3741_FrameBuffer_type;
|
||||
|
||||
void common_hal_is31fl3741_FrameBuffer_construct(is31fl3741_FrameBuffer_obj_t *self, int width, int height, mp_obj_t framebuffer, is31fl3741_IS31FL3741_obj_t *is31, mp_obj_t mapping);
|
||||
|
||||
void common_hal_is31fl3741_FrameBuffer_deinit(is31fl3741_FrameBuffer_obj_t *);
|
||||
|
||||
int common_hal_is31fl3741_FrameBuffer_get_width(is31fl3741_FrameBuffer_obj_t *self);
|
||||
int common_hal_is31fl3741_FrameBuffer_get_height(is31fl3741_FrameBuffer_obj_t *self);
|
||||
|
||||
void common_hal_is31fl3741_FrameBuffer_set_global_current(is31fl3741_FrameBuffer_obj_t *self, uint8_t current);
|
||||
uint8_t common_hal_is31fl3741_FrameBuffer_get_global_current(is31fl3741_FrameBuffer_obj_t *self);
|
||||
|
||||
void common_hal_is31fl3741_FrameBuffer_set_paused(is31fl3741_FrameBuffer_obj_t *self, bool paused);
|
||||
bool common_hal_is31fl3741_FrameBuffer_get_paused(is31fl3741_FrameBuffer_obj_t *self);
|
||||
void common_hal_is31fl3741_FrameBuffer_refresh(is31fl3741_FrameBuffer_obj_t *self, uint8_t *dirtyrows);
|
||||
|
||||
void common_hal_is31fl3741_FrameBuffer_reconstruct(is31fl3741_FrameBuffer_obj_t *self, mp_obj_t framebuffer);
|
||||
|
||||
void is31fl3741_FrameBuffer_collect_ptrs(is31fl3741_FrameBuffer_obj_t *self);
|
|
@ -32,82 +32,38 @@
|
|||
#include "shared-bindings/is31fl3741/IS31FL3741.h"
|
||||
#include "shared-bindings/util.h"
|
||||
#include "shared-module/displayio/__init__.h"
|
||||
#include "shared-module/framebufferio/__init__.h"
|
||||
#include "shared-module/framebufferio/FramebufferDisplay.h"
|
||||
#include "shared-bindings/busio/I2C.h"
|
||||
|
||||
//| class IS31FL3741:
|
||||
//| """Displays an in-memory framebuffer to a IS31FL3741 drive display."""
|
||||
//| """Driver for an IS31FL3741 device."""
|
||||
//|
|
||||
|
||||
//| def __init__(self, *, width: int) -> None:
|
||||
//| def __init__(self, i2c: busio.I2C, *, addr: int = 0x30) -> None:
|
||||
//| """Create a IS31FL3741 object with the given attributes.
|
||||
//|
|
||||
//| The framebuffer is in "RGB888" format using 4 bytes per pixel.
|
||||
//| Bits 24-31 are ignored. The format is in RGB order.
|
||||
//| Designed to work low level or passed to and object such as
|
||||
//| :class:`~is31fl3741.IS31FL3741_FrameBuffer`.
|
||||
//|
|
||||
//| If a framebuffer is not passed in, one is allocated and initialized
|
||||
//| to all black. In any case, the framebuffer can be retrieved
|
||||
//| by passing the Is31fl3741 object to memoryview().
|
||||
//| :param ~busio.I2C i2c: I2C bus the IS31FL3741 is on
|
||||
//| :param int addr: device address"""
|
||||
//| ...
|
||||
//|
|
||||
//| A Is31fl3741 is often used in conjunction with a
|
||||
//| `framebufferio.FramebufferDisplay`."""
|
||||
//|
|
||||
|
||||
STATIC mp_obj_t is31fl3741_IS31FL3741_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
||||
enum { ARG_width, ARG_height, ARG_i2c, ARG_addr, ARG_framebuffer, ARG_mapping, ARG_scale, ARG_gamma };
|
||||
enum { ARG_i2c, ARG_addr };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_width, MP_ARG_INT | MP_ARG_REQUIRED | MP_ARG_KW_ONLY },
|
||||
{ MP_QSTR_height, MP_ARG_INT | MP_ARG_REQUIRED | MP_ARG_KW_ONLY },
|
||||
{ MP_QSTR_i2c, MP_ARG_OBJ | MP_ARG_REQUIRED | MP_ARG_KW_ONLY },
|
||||
{ MP_QSTR_i2c, MP_ARG_OBJ | MP_ARG_REQUIRED },
|
||||
{ MP_QSTR_addr, MP_ARG_INT | MP_ARG_KW_ONLY, { .u_int = 0x30 } },
|
||||
{ MP_QSTR_framebuffer, MP_ARG_OBJ | MP_ARG_KW_ONLY, { .u_obj = mp_const_none } },
|
||||
{ MP_QSTR_mapping, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED },
|
||||
{ MP_QSTR_scale, MP_ARG_BOOL | MP_ARG_KW_ONLY, { .u_bool = false } },
|
||||
{ MP_QSTR_gamma, MP_ARG_BOOL | MP_ARG_KW_ONLY, { .u_bool = false } },
|
||||
};
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
mp_obj_t i2c = mp_arg_validate_type(args[ARG_i2c].u_obj, &busio_i2c_type, MP_QSTR_i2c_bus);
|
||||
|
||||
is31fl3741_IS31FL3741_obj_t *self = &allocate_display_bus_or_raise()->is31fl3741;
|
||||
is31fl3741_IS31FL3741_obj_t *self = m_new_obj(is31fl3741_IS31FL3741_obj_t);
|
||||
self->base.type = &is31fl3741_IS31FL3741_type;
|
||||
|
||||
if (args[ARG_width].u_int <= 0) {
|
||||
mp_raise_ValueError(translate("width must be greater than zero"));
|
||||
}
|
||||
|
||||
self->scale = args[ARG_scale].u_bool;
|
||||
if (self->scale) {
|
||||
if (((args[ARG_height].u_int % 3) != 0) || ((args[ARG_width].u_int % 3) != 0)) {
|
||||
mp_raise_ValueError(translate("Scale dimensions must divide by 3"));
|
||||
}
|
||||
|
||||
self->scale_width = args[ARG_width].u_int / 3;
|
||||
self->scale_height = args[ARG_height].u_int / 3;
|
||||
} else {
|
||||
self->scale_width = args[ARG_width].u_int;
|
||||
self->scale_height = args[ARG_height].u_int;
|
||||
}
|
||||
|
||||
self->auto_gamma = args[ARG_gamma].u_bool;
|
||||
|
||||
mp_obj_t framebuffer = args[ARG_framebuffer].u_obj;
|
||||
if (framebuffer == mp_const_none) {
|
||||
int width = args[ARG_width].u_int;
|
||||
int height = args[ARG_height].u_int;
|
||||
int bufsize = 4 * width * height;
|
||||
framebuffer = mp_obj_new_bytearray_of_zeros(bufsize);
|
||||
}
|
||||
|
||||
common_hal_is31fl3741_IS31FL3741_construct(self,
|
||||
args[ARG_width].u_int,
|
||||
args[ARG_height].u_int,
|
||||
framebuffer,
|
||||
MP_OBJ_TO_PTR(i2c),
|
||||
args[ARG_addr].u_int,
|
||||
args[ARG_mapping].u_obj
|
||||
args[ARG_addr].u_int
|
||||
);
|
||||
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
|
@ -124,185 +80,101 @@ STATIC mp_obj_t is31fl3741_IS31FL3741_deinit(mp_obj_t self_in) {
|
|||
common_hal_is31fl3741_IS31FL3741_deinit(self);
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_IS31FL3741_deinit_obj, is31fl3741_IS31FL3741_deinit);
|
||||
|
||||
static void check_for_deinit(is31fl3741_IS31FL3741_obj_t *self) {
|
||||
if (self->framebuffer == NULL) {
|
||||
raise_deinited_error();
|
||||
}
|
||||
}
|
||||
|
||||
//| brightness: float
|
||||
//| """In the current implementation, 0.0 turns the display off entirely
|
||||
//| and any other value up to 1.0 turns the display on fully."""
|
||||
//| def reset(self) -> None:
|
||||
//| """Resets the IS31FL3741 chip."""
|
||||
//| ...
|
||||
//|
|
||||
STATIC mp_obj_t is31fl3741_IS31FL3741_get_brightness(mp_obj_t self_in) {
|
||||
is31fl3741_IS31FL3741_obj_t *self = (is31fl3741_IS31FL3741_obj_t *)self_in;
|
||||
check_for_deinit(self);
|
||||
uint8_t current = common_hal_is31fl3741_IS31FL3741_get_global_current(self);
|
||||
|
||||
float brightness = (float)current / (float)0xFF;
|
||||
return mp_obj_new_float(brightness);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_IS31FL3741_get_brightness_obj, is31fl3741_IS31FL3741_get_brightness);
|
||||
|
||||
STATIC mp_obj_t is31fl3741_IS31FL3741_set_brightness(mp_obj_t self_in, mp_obj_t value_in) {
|
||||
is31fl3741_IS31FL3741_obj_t *self = (is31fl3741_IS31FL3741_obj_t *)self_in;
|
||||
check_for_deinit(self);
|
||||
mp_float_t brightness = mp_obj_get_float(value_in);
|
||||
if (brightness < 0.0f || brightness > 1.0f) {
|
||||
mp_raise_ValueError(translate("Brightness must be 0-1.0"));
|
||||
}
|
||||
|
||||
uint8_t current = (uint8_t)(brightness * 0xFF);
|
||||
common_hal_is31fl3741_IS31FL3741_set_global_current(self, current);
|
||||
|
||||
STATIC mp_obj_t is31fl3741_IS31FL3741_reset(mp_obj_t self_in) {
|
||||
is31fl3741_IS31FL3741_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
common_hal_is31fl3741_send_reset(self);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(is31fl3741_IS31FL3741_set_brightness_obj, is31fl3741_IS31FL3741_set_brightness);
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_IS31FL3741_reset_obj, is31fl3741_IS31FL3741_reset);
|
||||
|
||||
const mp_obj_property_t is31fl3741_IS31FL3741_brightness_obj = {
|
||||
.base.type = &mp_type_property,
|
||||
.proxy = {(mp_obj_t)&is31fl3741_IS31FL3741_get_brightness_obj,
|
||||
(mp_obj_t)&is31fl3741_IS31FL3741_set_brightness_obj,
|
||||
MP_ROM_NONE},
|
||||
};
|
||||
|
||||
//| def refresh(self) -> None:
|
||||
//| """Transmits the color data in the buffer to the pixels so that
|
||||
//| they are shown."""
|
||||
//| ...
|
||||
//| def enable(self) -> None:
|
||||
//| """Enables the IS31FL3741 chip."""
|
||||
//| ...
|
||||
//|
|
||||
STATIC mp_obj_t is31fl3741_IS31FL3741_refresh(mp_obj_t self_in) {
|
||||
is31fl3741_IS31FL3741_obj_t *self = (is31fl3741_IS31FL3741_obj_t *)self_in;
|
||||
check_for_deinit(self);
|
||||
common_hal_is31fl3741_IS31FL3741_refresh(self, 0);
|
||||
STATIC mp_obj_t is31fl3741_IS31FL3741_enable(mp_obj_t self_in) {
|
||||
is31fl3741_IS31FL3741_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
common_hal_is31fl3741_send_enable(self);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_IS31FL3741_refresh_obj, is31fl3741_IS31FL3741_refresh);
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_IS31FL3741_enable_obj, is31fl3741_IS31FL3741_enable);
|
||||
|
||||
//| width: int
|
||||
//| """The width of the display, in pixels"""
|
||||
//| def set_global_current(self, current: int) -> None:
|
||||
//| """Sets the global current of the IS31FL3741 chip.
|
||||
//|
|
||||
STATIC mp_obj_t is31fl3741_IS31FL3741_get_width(mp_obj_t self_in) {
|
||||
is31fl3741_IS31FL3741_obj_t *self = (is31fl3741_IS31FL3741_obj_t *)self_in;
|
||||
check_for_deinit(self);
|
||||
return MP_OBJ_NEW_SMALL_INT(common_hal_is31fl3741_IS31FL3741_get_width(self));
|
||||
//| :param int current: global current value 0x00 to 0xFF"""
|
||||
//| ...
|
||||
//|
|
||||
STATIC mp_obj_t is31fl3741_IS31FL3741_set_global_current(mp_obj_t self_in, mp_obj_t value) {
|
||||
is31fl3741_IS31FL3741_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_int_t current = mp_obj_get_int(value);
|
||||
common_hal_is31fl3741_set_current(self, current);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_IS31FL3741_get_width_obj, is31fl3741_IS31FL3741_get_width);
|
||||
const mp_obj_property_t is31fl3741_IS31FL3741_width_obj = {
|
||||
.base.type = &mp_type_property,
|
||||
.proxy = {(mp_obj_t)&is31fl3741_IS31FL3741_get_width_obj,
|
||||
MP_ROM_NONE,
|
||||
MP_ROM_NONE},
|
||||
};
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(is31fl3741_IS31FL3741_set_global_current_obj, is31fl3741_IS31FL3741_set_global_current);
|
||||
|
||||
//| height: int
|
||||
//| """The height of the display, in pixels"""
|
||||
//| def set_led(self, led: int, value: int, page: int) -> None:
|
||||
//| """Resets the IS31FL3741 chip.
|
||||
//|
|
||||
STATIC mp_obj_t is31fl3741_IS31FL3741_get_height(mp_obj_t self_in) {
|
||||
is31fl3741_IS31FL3741_obj_t *self = (is31fl3741_IS31FL3741_obj_t *)self_in;
|
||||
check_for_deinit(self);
|
||||
return MP_OBJ_NEW_SMALL_INT(common_hal_is31fl3741_IS31FL3741_get_height(self));
|
||||
//| :param int led: which LED to set
|
||||
//| :param int value: value to set the LED to 0x00 to 0xFF
|
||||
//| :param int page: page to write to 0 or 2. If the LED is a >= 180
|
||||
//| the routine will automatically write to page 1 or 3 (instead
|
||||
//| of 0 or 2)"""
|
||||
//| ...
|
||||
//|
|
||||
STATIC mp_obj_t is31fl3741_IS31FL3741_set_led(size_t n_args, const mp_obj_t *args) {
|
||||
is31fl3741_IS31FL3741_obj_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||
mp_int_t led = mp_obj_get_int(args[1]);
|
||||
mp_int_t value = mp_obj_get_int(args[2]);
|
||||
mp_int_t page = mp_obj_get_int(args[3]);
|
||||
common_hal_is31fl3741_set_led(self, led, value, page);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_IS31FL3741_get_height_obj, is31fl3741_IS31FL3741_get_height);
|
||||
const mp_obj_property_t is31fl3741_IS31FL3741_height_obj = {
|
||||
.base.type = &mp_type_property,
|
||||
.proxy = {(mp_obj_t)&is31fl3741_IS31FL3741_get_height_obj,
|
||||
MP_ROM_NONE,
|
||||
MP_ROM_NONE},
|
||||
};
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(is31fl3741_IS31FL3741_set_led_obj, 4, 4, is31fl3741_IS31FL3741_set_led);
|
||||
|
||||
//| def write(mapping: Tuple[int, ...], buf: ReadableBuffer) -> None:
|
||||
//| """Write buf out on the I2C bus to the IS31FL3741.
|
||||
//|
|
||||
//| :param ~Tuple[int, ...] mapping: map the pixels in the buffer to the order addressed by the driver chip
|
||||
//| :param ~_typing.ReadableBuffer buf: The bytes to clock out. No assumption is made about color order"""
|
||||
//| ...
|
||||
STATIC mp_obj_t is31fl3741_IS31FL3741_write(mp_obj_t self_in, mp_obj_t mapping, mp_obj_t buffer) {
|
||||
is31fl3741_IS31FL3741_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
if (!mp_obj_is_tuple_compatible(mapping)) {
|
||||
mp_raise_ValueError(translate("Mapping must be a tuple"));
|
||||
}
|
||||
|
||||
mp_obj_t *map_items;
|
||||
size_t map_len;
|
||||
mp_obj_tuple_get(mapping, &map_len, &map_items);
|
||||
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_READ);
|
||||
|
||||
common_hal_is31fl3741_write(self, map_items, (uint8_t *)bufinfo.buf, bufinfo.len);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_3(is31fl3741_IS31FL3741_write_obj, is31fl3741_IS31FL3741_write);
|
||||
|
||||
STATIC const mp_rom_map_elem_t is31fl3741_IS31FL3741_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&is31fl3741_IS31FL3741_deinit_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_brightness), MP_ROM_PTR(&is31fl3741_IS31FL3741_brightness_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_refresh), MP_ROM_PTR(&is31fl3741_IS31FL3741_refresh_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&is31fl3741_IS31FL3741_width_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&is31fl3741_IS31FL3741_height_obj) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&is31fl3741_IS31FL3741_write_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_reset), (mp_obj_t)&is31fl3741_IS31FL3741_reset_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_enable), (mp_obj_t)&is31fl3741_IS31FL3741_enable_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_set_global_current), (mp_obj_t)&is31fl3741_IS31FL3741_set_global_current_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_set_led), (mp_obj_t)&is31fl3741_IS31FL3741_set_led_obj },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(is31fl3741_IS31FL3741_locals_dict, is31fl3741_IS31FL3741_locals_dict_table);
|
||||
|
||||
STATIC void is31fl3741_IS31FL3741_get_bufinfo(mp_obj_t self_in, mp_buffer_info_t *bufinfo) {
|
||||
is31fl3741_IS31FL3741_obj_t *self = (is31fl3741_IS31FL3741_obj_t *)self_in;
|
||||
check_for_deinit(self);
|
||||
|
||||
*bufinfo = self->bufinfo;
|
||||
}
|
||||
|
||||
STATIC void is31fl3741_IS31FL3741_swapbuffers(mp_obj_t self_in, uint8_t *dirty_row_bitmap) {
|
||||
common_hal_is31fl3741_IS31FL3741_refresh(self_in, dirty_row_bitmap);
|
||||
}
|
||||
|
||||
STATIC void is31fl3741_IS31FL3741_deinit_proto(mp_obj_t self_in) {
|
||||
common_hal_is31fl3741_IS31FL3741_deinit(self_in);
|
||||
}
|
||||
|
||||
STATIC float is31fl3741_IS31FL3741_get_brightness_proto(mp_obj_t self_in) {
|
||||
return common_hal_is31fl3741_IS31FL3741_get_paused(self_in) ? 0.0f : 1.0f;
|
||||
}
|
||||
|
||||
STATIC bool is31fl3741_IS31FL3741_set_brightness_proto(mp_obj_t self_in, mp_float_t value) {
|
||||
common_hal_is31fl3741_IS31FL3741_set_paused(self_in, value <= 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
STATIC int is31fl3741_IS31FL3741_get_width_proto(mp_obj_t self_in) {
|
||||
return common_hal_is31fl3741_IS31FL3741_get_width(self_in);
|
||||
}
|
||||
|
||||
STATIC int is31fl3741_IS31FL3741_get_height_proto(mp_obj_t self_in) {
|
||||
return common_hal_is31fl3741_IS31FL3741_get_height(self_in);
|
||||
}
|
||||
|
||||
STATIC int is31fl3741_IS31FL3741_get_color_depth_proto(mp_obj_t self_in) {
|
||||
// The way displayio works depth is used to calculate bytes
|
||||
// We use an uint32_t for color already so setting to 24 causes
|
||||
// more changes required
|
||||
return 32;
|
||||
}
|
||||
|
||||
STATIC int is31fl3741_IS31FL3741_get_bytes_per_cell_proto(mp_obj_t self_in) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
STATIC int is31fl3741_IS31FL3741_get_native_frames_per_second_proto(mp_obj_t self_in) {
|
||||
return 60; // This was just chosen may vary based on LEDs used?
|
||||
}
|
||||
|
||||
STATIC const framebuffer_p_t is31fl3741_IS31FL3741_proto = {
|
||||
MP_PROTO_IMPLEMENT(MP_QSTR_protocol_framebuffer)
|
||||
.get_bufinfo = is31fl3741_IS31FL3741_get_bufinfo,
|
||||
.set_brightness = is31fl3741_IS31FL3741_set_brightness_proto,
|
||||
.get_brightness = is31fl3741_IS31FL3741_get_brightness_proto,
|
||||
.get_width = is31fl3741_IS31FL3741_get_width_proto,
|
||||
.get_height = is31fl3741_IS31FL3741_get_height_proto,
|
||||
.get_color_depth = is31fl3741_IS31FL3741_get_color_depth_proto,
|
||||
.get_bytes_per_cell = is31fl3741_IS31FL3741_get_bytes_per_cell_proto,
|
||||
.get_native_frames_per_second = is31fl3741_IS31FL3741_get_native_frames_per_second_proto,
|
||||
.swapbuffers = is31fl3741_IS31FL3741_swapbuffers,
|
||||
.deinit = is31fl3741_IS31FL3741_deinit_proto,
|
||||
};
|
||||
|
||||
STATIC mp_int_t is31fl3741_IS31FL3741_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
|
||||
is31fl3741_IS31FL3741_obj_t *self = (is31fl3741_IS31FL3741_obj_t *)self_in;
|
||||
// a readonly framebuffer would be unusual but not impossible
|
||||
if ((flags & MP_BUFFER_WRITE) && !(self->bufinfo.typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW)) {
|
||||
return 1;
|
||||
}
|
||||
*bufinfo = self->bufinfo;
|
||||
bufinfo->typecode = 'H';
|
||||
return 0;
|
||||
}
|
||||
|
||||
const mp_obj_type_t is31fl3741_IS31FL3741_type = {
|
||||
{ &mp_type_type },
|
||||
.flags = MP_TYPE_FLAG_EXTENDED,
|
||||
.name = MP_QSTR_is31fl3741,
|
||||
.locals_dict = (mp_obj_dict_t *)&is31fl3741_IS31FL3741_locals_dict,
|
||||
.make_new = is31fl3741_IS31FL3741_make_new,
|
||||
MP_TYPE_EXTENDED_FIELDS(
|
||||
.buffer_p = { .get_buffer = is31fl3741_IS31FL3741_get_buffer, },
|
||||
.protocol = &is31fl3741_IS31FL3741_proto,
|
||||
),
|
||||
};
|
||||
|
|
|
@ -30,32 +30,20 @@
|
|||
|
||||
extern const mp_obj_type_t is31fl3741_IS31FL3741_type;
|
||||
|
||||
void common_hal_is31fl3741_IS31FL3741_construct(is31fl3741_IS31FL3741_obj_t *self, int width, int height, mp_obj_t framebuffer, busio_i2c_obj_t *i2c, uint8_t addr, mp_obj_t mapping);
|
||||
void common_hal_is31fl3741_IS31FL3741_construct(is31fl3741_IS31FL3741_obj_t *self, busio_i2c_obj_t *i2c, uint8_t addr);
|
||||
|
||||
void common_hal_is31fl3741_IS31FL3741_deinit(is31fl3741_IS31FL3741_obj_t *);
|
||||
|
||||
int common_hal_is31fl3741_IS31FL3741_get_width(is31fl3741_IS31FL3741_obj_t *self);
|
||||
int common_hal_is31fl3741_IS31FL3741_get_height(is31fl3741_IS31FL3741_obj_t *self);
|
||||
void common_hal_is31fl3741_write(is31fl3741_IS31FL3741_obj_t *is31, const mp_obj_t *mapping, const uint8_t *pixels, size_t numBytes);
|
||||
|
||||
void common_hal_displayio_is31fl3741_begin_transaction(is31fl3741_IS31FL3741_obj_t *self);
|
||||
void common_hal_displayio_is31fl3741_end_transaction(is31fl3741_IS31FL3741_obj_t *self);
|
||||
void common_hal_is31fl3741_begin_transaction(is31fl3741_IS31FL3741_obj_t *self);
|
||||
void common_hal_is31fl3741_end_transaction(is31fl3741_IS31FL3741_obj_t *self);
|
||||
|
||||
void common_hal_is31fl3741_IS31FL3741_set_global_current(is31fl3741_IS31FL3741_obj_t *self, uint8_t current);
|
||||
uint8_t common_hal_is31fl3741_IS31FL3741_get_global_current(is31fl3741_IS31FL3741_obj_t *self);
|
||||
|
||||
void common_hal_is31fl3741_IS31FL3741_set_paused(is31fl3741_IS31FL3741_obj_t *self, bool paused);
|
||||
bool common_hal_is31fl3741_IS31FL3741_get_paused(is31fl3741_IS31FL3741_obj_t *self);
|
||||
void common_hal_is31fl3741_IS31FL3741_refresh(is31fl3741_IS31FL3741_obj_t *self, uint8_t *dirtyrows);
|
||||
|
||||
void common_hal_is31fl3741_IS31FL3741_reconstruct(is31fl3741_IS31FL3741_obj_t *self, mp_obj_t framebuffer);
|
||||
|
||||
void is31fl3741_IS31FL3741_collect_ptrs(is31fl3741_IS31FL3741_obj_t *self);
|
||||
|
||||
void is31fl3741_send_unlock(busio_i2c_obj_t *i2c, uint8_t addr);
|
||||
void is31fl3741_set_page(busio_i2c_obj_t *i2c, uint8_t addr, uint8_t p);
|
||||
void is31fl3741_send_enable(busio_i2c_obj_t *i2c, uint8_t addr);
|
||||
void is31fl3741_send_reset(busio_i2c_obj_t *i2c, uint8_t addr);
|
||||
void is31fl3741_set_current(busio_i2c_obj_t *i2c, uint8_t addr, uint8_t current);
|
||||
uint8_t is31fl3741_get_current(busio_i2c_obj_t *i2c, uint8_t addr);
|
||||
void is31fl3741_set_led(busio_i2c_obj_t *i2c, uint8_t addr, uint16_t led, uint8_t level, uint8_t page);
|
||||
void is31fl3741_draw_pixel(busio_i2c_obj_t *i2c, uint8_t addr, int16_t x, int16_t y, uint32_t color, uint16_t *mapping);
|
||||
void common_hal_is31fl3741_send_unlock(is31fl3741_IS31FL3741_obj_t *self);
|
||||
void common_hal_is31fl3741_set_page(is31fl3741_IS31FL3741_obj_t *self, uint8_t p);
|
||||
void common_hal_is31fl3741_send_enable(is31fl3741_IS31FL3741_obj_t *self);
|
||||
void common_hal_is31fl3741_send_reset(is31fl3741_IS31FL3741_obj_t *self);
|
||||
void common_hal_is31fl3741_set_current(is31fl3741_IS31FL3741_obj_t *self, uint8_t current);
|
||||
uint8_t common_hal_is31fl3741_get_current(is31fl3741_IS31FL3741_obj_t *self);
|
||||
void common_hal_is31fl3741_set_led(is31fl3741_IS31FL3741_obj_t *self, uint16_t led, uint8_t level, uint8_t page);
|
||||
void common_hal_is31fl3741_draw_pixel(is31fl3741_IS31FL3741_obj_t *self, int16_t x, int16_t y, uint32_t color, uint16_t *mapping);
|
||||
|
|
|
@ -25,15 +25,19 @@
|
|||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
#include "shared-bindings/busio/I2C.h"
|
||||
#include "shared-bindings/is31fl3741/IS31FL3741.h"
|
||||
#include "shared-bindings/is31fl3741/FrameBuffer.h"
|
||||
|
||||
STATIC const mp_rom_map_elem_t is31fl3741_module_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_is31fl3741) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_IS31FL3741), MP_ROM_PTR(&is31fl3741_IS31FL3741_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_IS31FL3741_FrameBuffer), MP_ROM_PTR(&is31fl3741_FrameBuffer_type) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(is31fl3741_module_globals, is31fl3741_module_globals_table);
|
||||
|
|
|
@ -142,8 +142,8 @@ void common_hal_displayio_release_displays(void) {
|
|||
common_hal_rgbmatrix_rgbmatrix_deinit(&displays[i].rgbmatrix);
|
||||
#endif
|
||||
#if CIRCUITPY_IS31FL3741
|
||||
} else if (bus_type == &is31fl3741_IS31FL3741_type) {
|
||||
common_hal_is31fl3741_IS31FL3741_deinit(&displays[i].is31fl3741);
|
||||
} else if (bus_type == &is31fl3741_FrameBuffer_type) {
|
||||
common_hal_is31fl3741_FrameBuffer_deinit(&displays[i].is31fl3741);
|
||||
#endif
|
||||
#if CIRCUITPY_SHARPDISPLAY
|
||||
} else if (displays[i].bus_base.type == &sharpdisplay_framebuffer_type) {
|
||||
|
@ -224,34 +224,33 @@ void reset_displays(void) {
|
|||
}
|
||||
#endif
|
||||
#if CIRCUITPY_IS31FL3741
|
||||
} else if (displays[i].is31fl3741.base.type == &is31fl3741_IS31FL3741_type) {
|
||||
is31fl3741_IS31FL3741_obj_t *is31 = &displays[i].is31fl3741;
|
||||
if (((uint32_t)is31->i2c) < ((uint32_t)&displays) ||
|
||||
((uint32_t)is31->i2c) > ((uint32_t)&displays + CIRCUITPY_DISPLAY_LIMIT)) {
|
||||
busio_i2c_obj_t *original_i2c = is31->i2c;
|
||||
} else if (displays[i].is31fl3741.base.type == &is31fl3741_FrameBuffer_type) {
|
||||
is31fl3741_FrameBuffer_obj_t *is31fb = &displays[i].is31fl3741;
|
||||
|
||||
if (((uint32_t)is31fb->is31fl3741->i2c) < ((uint32_t)&displays) ||
|
||||
((uint32_t)is31fb->is31fl3741->i2c) > ((uint32_t)&displays + CIRCUITPY_DISPLAY_LIMIT)) {
|
||||
#if CIRCUITPY_BOARD_I2C
|
||||
// We don't need to move original_i2c if it is the board.I2C object because it is
|
||||
// statically allocated already. (Doing so would also make it impossible to reference in
|
||||
// a subsequent VM run.)
|
||||
if (common_hal_board_is_i2c(original_i2c)) {
|
||||
if (common_hal_board_is_i2c(is31fb->is31fl3741->i2c)) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
memcpy(&is31->inline_i2c, original_i2c, sizeof(busio_i2c_obj_t));
|
||||
is31->i2c = &is31->inline_i2c;
|
||||
// Check for other displays that use the same i2c bus and swap them too.
|
||||
/*for (uint8_t j = i + 1; j < CIRCUITPY_DISPLAY_LIMIT; j++) {
|
||||
if (displays[i].i2cdisplay_bus.base.type == &displayio_i2cdisplay_type &&
|
||||
displays[i].i2cdisplay_bus.bus == original_i2c) {
|
||||
displays[i].i2cdisplay_bus.bus = &i2c->inline_bus;
|
||||
}
|
||||
}*/
|
||||
|
||||
is31fl3741_IS31FL3741_obj_t *original_is31 = is31fb->is31fl3741;
|
||||
memcpy(&is31fb->inline_is31fl3741, original_is31, sizeof(is31fl3741_IS31FL3741_obj_t));
|
||||
is31fb->is31fl3741 = &is31fb->inline_is31fl3741;
|
||||
|
||||
busio_i2c_obj_t *original_i2c = is31fb->is31fl3741->i2c;
|
||||
memcpy(&is31fb->is31fl3741->inline_i2c, original_i2c, sizeof(busio_i2c_obj_t));
|
||||
is31fb->is31fl3741->i2c = &is31fb->is31fl3741->inline_i2c;
|
||||
}
|
||||
|
||||
if (!any_display_uses_this_framebuffer(&is31->base)) {
|
||||
common_hal_is31fl3741_IS31FL3741_deinit(is31);
|
||||
if (!any_display_uses_this_framebuffer(&is31fb->base)) {
|
||||
common_hal_is31fl3741_FrameBuffer_deinit(is31fb);
|
||||
} else {
|
||||
common_hal_is31fl3741_IS31FL3741_set_paused(is31, true);
|
||||
common_hal_is31fl3741_FrameBuffer_set_paused(is31fb, true);
|
||||
}
|
||||
#endif
|
||||
#if CIRCUITPY_SHARPDISPLAY
|
||||
|
@ -298,8 +297,8 @@ void displayio_gc_collect(void) {
|
|||
}
|
||||
#endif
|
||||
#if CIRCUITPY_IS31FL3741
|
||||
if (displays[i].is31fl3741.base.type == &is31fl3741_IS31FL3741_type) {
|
||||
is31fl3741_IS31FL3741_collect_ptrs(&displays[i].is31fl3741);
|
||||
if (displays[i].is31fl3741.base.type == &is31fl3741_FrameBuffer_type) {
|
||||
is31fl3741_FrameBuffer_collect_ptrs(&displays[i].is31fl3741);
|
||||
}
|
||||
#endif
|
||||
#if CIRCUITPY_SHARPDISPLAY
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
#include "shared-bindings/rgbmatrix/RGBMatrix.h"
|
||||
#endif
|
||||
#if CIRCUITPY_IS31FL3741
|
||||
#include "shared-bindings/is31fl3741/IS31FL3741.h"
|
||||
#include "shared-bindings/is31fl3741/FrameBuffer.h"
|
||||
#endif
|
||||
#if CIRCUITPY_SHARPDISPLAY
|
||||
#include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h"
|
||||
|
@ -63,7 +63,7 @@ typedef struct {
|
|||
rgbmatrix_rgbmatrix_obj_t rgbmatrix;
|
||||
#endif
|
||||
#if CIRCUITPY_IS31FL3741
|
||||
is31fl3741_IS31FL3741_obj_t is31fl3741;
|
||||
is31fl3741_FrameBuffer_obj_t is31fl3741;
|
||||
#endif
|
||||
#if CIRCUITPY_SHARPDISPLAY
|
||||
sharpdisplay_framebuffer_obj_t sharpdisplay;
|
||||
|
|
|
@ -0,0 +1,227 @@
|
|||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 Mark Komus
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "py/gc.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/objarray.h"
|
||||
#include "py/objproperty.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
#include "shared-module/is31fl3741/allocator.h"
|
||||
#include "shared-bindings/is31fl3741/IS31FL3741.h"
|
||||
#include "shared-bindings/is31fl3741/FrameBuffer.h"
|
||||
#include "shared-bindings/util.h"
|
||||
#include "shared-module/framebufferio/FramebufferDisplay.h"
|
||||
#include "shared-bindings/busio/I2C.h"
|
||||
|
||||
void common_hal_is31fl3741_FrameBuffer_construct(is31fl3741_FrameBuffer_obj_t *self, int width, int height, mp_obj_t framebuffer, is31fl3741_IS31FL3741_obj_t *is31, mp_obj_t mapping) {
|
||||
self->width = width;
|
||||
self->height = height;
|
||||
|
||||
self->bufsize = sizeof(uint32_t) * width * height;
|
||||
|
||||
self->is31fl3741 = is31;
|
||||
|
||||
common_hal_busio_i2c_never_reset(self->is31fl3741->i2c);
|
||||
// Our object is statically allocated off the heap so make sure the bus object lives to the end
|
||||
// of the heap as well.
|
||||
gc_never_free(self->is31fl3741->i2c);
|
||||
gc_never_free(self->is31fl3741);
|
||||
|
||||
mp_obj_t *items;
|
||||
size_t len;
|
||||
mp_obj_tuple_get(mapping, &len, &items);
|
||||
|
||||
if (len != (size_t)(self->scale_width * self->scale_height * 3)) {
|
||||
mp_raise_ValueError(translate("LED mappings must match display size"));
|
||||
}
|
||||
|
||||
self->mapping = common_hal_is31fl3741_allocator_impl(sizeof(uint16_t) * len);
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
mp_int_t value = mp_obj_get_int(items[i]);
|
||||
// We only store up to 16 bits
|
||||
if (value > 0xFFFF) {
|
||||
value = 0xFFFF;
|
||||
}
|
||||
self->mapping[i] = (uint16_t)value;
|
||||
}
|
||||
|
||||
common_hal_is31fl3741_FrameBuffer_reconstruct(self, framebuffer);
|
||||
}
|
||||
|
||||
void common_hal_is31fl3741_FrameBuffer_reconstruct(is31fl3741_FrameBuffer_obj_t *self, mp_obj_t framebuffer) {
|
||||
self->paused = 1;
|
||||
|
||||
if (framebuffer) {
|
||||
self->framebuffer = framebuffer;
|
||||
mp_get_buffer_raise(self->framebuffer, &self->bufinfo, MP_BUFFER_READ);
|
||||
if (mp_get_buffer(self->framebuffer, &self->bufinfo, MP_BUFFER_RW)) {
|
||||
self->bufinfo.typecode = 'H' | MP_OBJ_ARRAY_TYPECODE_FLAG_RW;
|
||||
} else {
|
||||
self->bufinfo.typecode = 'H';
|
||||
}
|
||||
|
||||
// verify that the matrix is big enough
|
||||
mp_get_index(mp_obj_get_type(self->framebuffer), self->bufinfo.len, MP_OBJ_NEW_SMALL_INT(self->bufsize - 1), false);
|
||||
} else {
|
||||
common_hal_is31fl3741_free_impl(self->bufinfo.buf);
|
||||
|
||||
self->framebuffer = NULL;
|
||||
self->bufinfo.buf = common_hal_is31fl3741_allocator_impl(self->bufsize);
|
||||
self->bufinfo.len = self->bufsize;
|
||||
self->bufinfo.typecode = 'H' | MP_OBJ_ARRAY_TYPECODE_FLAG_RW;
|
||||
}
|
||||
|
||||
common_hal_is31fl3741_begin_transaction(self->is31fl3741);
|
||||
common_hal_is31fl3741_send_reset(self->is31fl3741);
|
||||
common_hal_is31fl3741_set_current(self->is31fl3741, 0xFE);
|
||||
|
||||
// set scale (brightness) to max for all LEDs
|
||||
for (int i = 0; i < 351; i++) {
|
||||
common_hal_is31fl3741_set_led(self->is31fl3741, i, 0xFF, 2);
|
||||
}
|
||||
|
||||
common_hal_is31fl3741_send_enable(self->is31fl3741);
|
||||
common_hal_is31fl3741_end_transaction(self->is31fl3741);
|
||||
|
||||
self->paused = 0;
|
||||
}
|
||||
|
||||
void common_hal_is31fl3741_FrameBuffer_deinit(is31fl3741_FrameBuffer_obj_t *self) {
|
||||
common_hal_is31fl3741_end_transaction(self->is31fl3741); // in case we still had a lock
|
||||
|
||||
common_hal_is31fl3741_IS31FL3741_deinit(self->is31fl3741);
|
||||
|
||||
if (self->mapping != 0) {
|
||||
common_hal_is31fl3741_free_impl(self->mapping);
|
||||
self->mapping = 0;
|
||||
}
|
||||
|
||||
self->base.type = NULL;
|
||||
|
||||
// If a framebuffer was passed in to the constructor, NULL the reference
|
||||
// here so that it will become GC'able
|
||||
self->framebuffer = NULL;
|
||||
}
|
||||
|
||||
void common_hal_is31fl3741_FrameBuffer_set_paused(is31fl3741_FrameBuffer_obj_t *self, bool paused) {
|
||||
self->paused = paused;
|
||||
}
|
||||
|
||||
bool common_hal_is31fl3741_FrameBuffer_get_paused(is31fl3741_FrameBuffer_obj_t *self) {
|
||||
return self->paused;
|
||||
}
|
||||
|
||||
void common_hal_is31fl3741_FrameBuffer_refresh(is31fl3741_FrameBuffer_obj_t *self, uint8_t *dirtyrows) {
|
||||
if (!self->paused) {
|
||||
common_hal_is31fl3741_begin_transaction(self->is31fl3741);
|
||||
|
||||
uint8_t dirty_row_flags = 0xFF; // only supports 8 rows gotta fix
|
||||
|
||||
if (self->scale) {
|
||||
// Based on the Arduino IS31FL3741 driver code
|
||||
// dirtyrows flag current not implemented for scaled displays
|
||||
uint32_t *buffer = self->bufinfo.buf;
|
||||
|
||||
for (int x = 0; x < self->scale_width; x++) {
|
||||
uint32_t *ptr = &buffer[x * 3]; // Entry along top scan line w/x offset
|
||||
for (int y = 0; y < self->scale_height; y++) {
|
||||
uint16_t rsum = 0, gsum = 0, bsum = 0;
|
||||
// Inner x/y loops are row-major on purpose (less pointer math)
|
||||
for (uint8_t yy = 0; yy < 3; yy++) {
|
||||
for (uint8_t xx = 0; xx < 3; xx++) {
|
||||
uint32_t rgb = ptr[xx];
|
||||
rsum += rgb >> 16 & 0xFF;
|
||||
gsum += (rgb >> 8) & 0xFF;
|
||||
bsum += rgb & 0xFF;
|
||||
}
|
||||
ptr += self->width; // Advance one scan line
|
||||
}
|
||||
rsum = rsum / 9;
|
||||
gsum = gsum / 9;
|
||||
bsum = bsum / 9;
|
||||
uint32_t color = 0;
|
||||
if (self->auto_gamma) {
|
||||
color = (IS31GammaTable[rsum] << 16) +
|
||||
(IS31GammaTable[gsum] << 8) +
|
||||
IS31GammaTable[bsum];
|
||||
} else {
|
||||
color = (rsum << 16) + (gsum << 8) + bsum;
|
||||
}
|
||||
common_hal_is31fl3741_draw_pixel(self->is31fl3741, x, y, color, self->mapping);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
uint32_t *buffer = self->bufinfo.buf;
|
||||
for (int y = 0; y < self->height; y++) {
|
||||
if ((dirtyrows != 0) && ((y % 8) == 0)) {
|
||||
dirty_row_flags = *dirtyrows++;
|
||||
}
|
||||
|
||||
if ((dirty_row_flags >> (y % 8)) & 0x1) {
|
||||
uint32_t color = 0;
|
||||
if (self->auto_gamma) {
|
||||
color = IS31GammaTable[((*buffer) >> 16 & 0xFF)] +
|
||||
IS31GammaTable[((*buffer) >> 8 & 0xFF)] +
|
||||
IS31GammaTable[((*buffer) & 0xFF)];
|
||||
} else {
|
||||
color = *buffer;
|
||||
}
|
||||
|
||||
for (int x = 0; x < self->width; x++) {
|
||||
common_hal_is31fl3741_draw_pixel(self->is31fl3741, x, y, color, self->mapping);
|
||||
buffer++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
common_hal_is31fl3741_end_transaction(self->is31fl3741);
|
||||
}
|
||||
}
|
||||
|
||||
int common_hal_is31fl3741_FrameBuffer_get_width(is31fl3741_FrameBuffer_obj_t *self) {
|
||||
return self->width;
|
||||
}
|
||||
|
||||
int common_hal_is31fl3741_FrameBuffer_get_height(is31fl3741_FrameBuffer_obj_t *self) {
|
||||
return self->height;
|
||||
}
|
||||
|
||||
void *common_hal_is31fl3741_allocator_impl(size_t sz) {
|
||||
supervisor_allocation *allocation = allocate_memory(align32_size(sz), false, true);
|
||||
return allocation ? allocation->ptr : NULL;
|
||||
}
|
||||
|
||||
void common_hal_is31fl3741_free_impl(void *ptr_in) {
|
||||
free_memory(allocation_from_ptr(ptr_in));
|
||||
}
|
||||
|
||||
void is31fl3741_FrameBuffer_collect_ptrs(is31fl3741_FrameBuffer_obj_t *self) {
|
||||
gc_collect_ptr(self->framebuffer);
|
||||
gc_collect_ptr(self->mapping);
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 Mark Komus
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "lib/protomatter/src/core.h"
|
||||
#include "shared-module/is31fl3741/IS31FL3741.h"
|
||||
|
||||
extern const mp_obj_type_t is31fl3741_FrameBuffer_type;
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
is31fl3741_IS31FL3741_obj_t *is31fl3741;
|
||||
is31fl3741_IS31FL3741_obj_t inline_is31fl3741;
|
||||
mp_obj_t framebuffer;
|
||||
mp_buffer_info_t bufinfo;
|
||||
uint16_t bufsize, width, height, scale_width, scale_height;
|
||||
uint16_t *mapping;
|
||||
uint8_t bit_depth;
|
||||
bool paused;
|
||||
bool scale;
|
||||
bool auto_gamma;
|
||||
} is31fl3741_FrameBuffer_obj_t;
|
|
@ -32,20 +32,11 @@
|
|||
#include "py/objproperty.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
#include "shared-module/is31fl3741/allocator.h"
|
||||
#include "shared-bindings/is31fl3741/IS31FL3741.h"
|
||||
#include "shared-bindings/microcontroller/Pin.h"
|
||||
#include "shared-bindings/microcontroller/__init__.h"
|
||||
#include "shared-bindings/util.h"
|
||||
#include "shared-module/framebufferio/FramebufferDisplay.h"
|
||||
#include "shared-bindings/busio/I2C.h"
|
||||
|
||||
void common_hal_is31fl3741_IS31FL3741_construct(is31fl3741_IS31FL3741_obj_t *self, int width, int height, mp_obj_t framebuffer, busio_i2c_obj_t *i2c, uint8_t addr, mp_obj_t mapping) {
|
||||
self->width = width;
|
||||
self->height = height;
|
||||
|
||||
self->bufsize = sizeof(uint32_t) * width * height;
|
||||
|
||||
void common_hal_is31fl3741_IS31FL3741_construct(is31fl3741_IS31FL3741_obj_t *self, busio_i2c_obj_t *i2c, uint8_t addr) {
|
||||
// Probe the bus to see if a device acknowledges the given address.
|
||||
if (!common_hal_busio_i2c_probe(i2c, addr)) {
|
||||
self->base.type = &mp_type_NoneType;
|
||||
|
@ -54,192 +45,35 @@ void common_hal_is31fl3741_IS31FL3741_construct(is31fl3741_IS31FL3741_obj_t *sel
|
|||
|
||||
self->i2c = i2c;
|
||||
self->device_address = addr;
|
||||
common_hal_busio_i2c_never_reset(self->i2c);
|
||||
// Our object is statically allocated off the heap so make sure the bus object lives to the end
|
||||
// of the heap as well.
|
||||
gc_never_free(self->i2c);
|
||||
|
||||
mp_obj_t *items;
|
||||
size_t len;
|
||||
mp_obj_list_get(mapping, &len, &items);
|
||||
|
||||
if (len != (size_t)(self->scale_width * self->scale_height * 3)) {
|
||||
mp_raise_ValueError(translate("LED mappings must match display size"));
|
||||
}
|
||||
|
||||
self->mapping = common_hal_is31fl3741_allocator_impl(sizeof(uint16_t) * len);
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
mp_int_t value = mp_obj_get_int(items[i]);
|
||||
// We only store up to 16 bits
|
||||
if (value > 0xFFFF) {
|
||||
value = 0xFFFF;
|
||||
}
|
||||
self->mapping[i] = (uint16_t)value;
|
||||
}
|
||||
|
||||
common_hal_is31fl3741_IS31FL3741_reconstruct(self, framebuffer);
|
||||
}
|
||||
|
||||
void common_hal_is31fl3741_IS31FL3741_reconstruct(is31fl3741_IS31FL3741_obj_t *self, mp_obj_t framebuffer) {
|
||||
self->paused = 1;
|
||||
|
||||
if (framebuffer) {
|
||||
self->framebuffer = framebuffer;
|
||||
mp_get_buffer_raise(self->framebuffer, &self->bufinfo, MP_BUFFER_READ);
|
||||
if (mp_get_buffer(self->framebuffer, &self->bufinfo, MP_BUFFER_RW)) {
|
||||
self->bufinfo.typecode = 'H' | MP_OBJ_ARRAY_TYPECODE_FLAG_RW;
|
||||
} else {
|
||||
self->bufinfo.typecode = 'H';
|
||||
}
|
||||
|
||||
// verify that the matrix is big enough
|
||||
mp_get_index(mp_obj_get_type(self->framebuffer), self->bufinfo.len, MP_OBJ_NEW_SMALL_INT(self->bufsize - 1), false);
|
||||
} else {
|
||||
common_hal_is31fl3741_free_impl(self->bufinfo.buf);
|
||||
|
||||
self->framebuffer = NULL;
|
||||
self->bufinfo.buf = common_hal_is31fl3741_allocator_impl(self->bufsize);
|
||||
self->bufinfo.len = self->bufsize;
|
||||
self->bufinfo.typecode = 'H' | MP_OBJ_ARRAY_TYPECODE_FLAG_RW;
|
||||
}
|
||||
|
||||
common_hal_displayio_is31fl3741_begin_transaction(self);
|
||||
|
||||
uint8_t command = 0xFC; // device ID
|
||||
uint8_t data = 0;
|
||||
common_hal_busio_i2c_write_read(self->i2c, self->device_address, &command, 1, &data, 1);
|
||||
|
||||
is31fl3741_send_reset(self->i2c, self->device_address);
|
||||
is31fl3741_send_enable(self->i2c, self->device_address);
|
||||
is31fl3741_set_current(self->i2c, self->device_address, 0xFF);
|
||||
|
||||
// set scale (brightness) to max for all LEDs
|
||||
for (int i = 0; i < 351; i++) {
|
||||
is31fl3741_set_led(self->i2c, self->device_address, i, 0xFF, 2);
|
||||
}
|
||||
|
||||
common_hal_displayio_is31fl3741_end_transaction(self);
|
||||
|
||||
self->paused = 0;
|
||||
}
|
||||
|
||||
void common_hal_is31fl3741_IS31FL3741_deinit(is31fl3741_IS31FL3741_obj_t *self) {
|
||||
common_hal_displayio_is31fl3741_end_transaction(self); // in case we still had a lock
|
||||
common_hal_is31fl3741_end_transaction(self); // in case we still had a lock
|
||||
|
||||
if (self->i2c == &self->inline_i2c) {
|
||||
common_hal_busio_i2c_deinit(self->i2c);
|
||||
self->i2c = NULL;
|
||||
}
|
||||
|
||||
if (self->mapping != 0) {
|
||||
common_hal_is31fl3741_free_impl(self->mapping);
|
||||
self->mapping = 0;
|
||||
}
|
||||
|
||||
self->base.type = NULL;
|
||||
|
||||
// If a framebuffer was passed in to the constructor, NULL the reference
|
||||
// here so that it will become GC'able
|
||||
self->framebuffer = NULL;
|
||||
}
|
||||
|
||||
void common_hal_is31fl3741_IS31FL3741_set_paused(is31fl3741_IS31FL3741_obj_t *self, bool paused) {
|
||||
self->paused = paused;
|
||||
}
|
||||
void common_hal_is31fl3741_write(is31fl3741_IS31FL3741_obj_t *is31, const mp_obj_t *mapping, const uint8_t *pixels, size_t numBytes) {
|
||||
common_hal_is31fl3741_begin_transaction(is31);
|
||||
|
||||
bool common_hal_is31fl3741_IS31FL3741_get_paused(is31fl3741_IS31FL3741_obj_t *self) {
|
||||
return self->paused;
|
||||
}
|
||||
|
||||
void common_hal_is31fl3741_IS31FL3741_set_global_current(is31fl3741_IS31FL3741_obj_t *self, uint8_t current) {
|
||||
common_hal_displayio_is31fl3741_begin_transaction(self);
|
||||
is31fl3741_set_current(self->i2c, self->device_address, current);
|
||||
common_hal_displayio_is31fl3741_end_transaction(self);
|
||||
}
|
||||
|
||||
uint8_t common_hal_is31fl3741_IS31FL3741_get_global_current(is31fl3741_IS31FL3741_obj_t *self) {
|
||||
common_hal_displayio_is31fl3741_begin_transaction(self);
|
||||
uint8_t current = is31fl3741_get_current(self->i2c, self->device_address);
|
||||
common_hal_displayio_is31fl3741_end_transaction(self);
|
||||
return current;
|
||||
}
|
||||
|
||||
void common_hal_is31fl3741_IS31FL3741_refresh(is31fl3741_IS31FL3741_obj_t *self, uint8_t *dirtyrows) {
|
||||
common_hal_displayio_is31fl3741_begin_transaction(self);
|
||||
if (!self->paused) {
|
||||
uint8_t dirty_row_flags = 0xFF; // only supports 8 rows gotta fix
|
||||
|
||||
if (self->scale) {
|
||||
// Based on the Arduino IS31FL3741 driver code
|
||||
// dirtyrows flag current not implemented for scaled displays
|
||||
uint32_t *buffer = self->bufinfo.buf;
|
||||
|
||||
for (int x = 0; x < self->scale_width; x++) {
|
||||
uint32_t *ptr = &buffer[x * 3]; // Entry along top scan line w/x offset
|
||||
for (int y = 0; y < self->scale_height; y++) {
|
||||
uint16_t rsum = 0, gsum = 0, bsum = 0;
|
||||
// Inner x/y loops are row-major on purpose (less pointer math)
|
||||
for (uint8_t yy = 0; yy < 3; yy++) {
|
||||
for (uint8_t xx = 0; xx < 3; xx++) {
|
||||
uint32_t rgb = ptr[xx];
|
||||
rsum += rgb >> 16 & 0xFF;
|
||||
gsum += (rgb >> 8) & 0xFF;
|
||||
bsum += rgb & 0xFF;
|
||||
}
|
||||
ptr += self->width; // Advance one scan line
|
||||
}
|
||||
rsum = rsum / 9;
|
||||
gsum = gsum / 9;
|
||||
bsum = bsum / 9;
|
||||
uint32_t color = 0;
|
||||
if (self->auto_gamma) {
|
||||
color = (IS31GammaTable[rsum] << 16) +
|
||||
(IS31GammaTable[gsum] << 8) +
|
||||
IS31GammaTable[bsum];
|
||||
} else {
|
||||
color = (rsum << 16) + (gsum << 8) + bsum;
|
||||
}
|
||||
is31fl3741_draw_pixel(self->i2c, self->device_address, x, y, color, self->mapping);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
uint32_t *buffer = self->bufinfo.buf;
|
||||
for (int y = 0; y < self->height; y++) {
|
||||
if ((dirtyrows != 0) && ((y % 8) == 0)) {
|
||||
dirty_row_flags = *dirtyrows++;
|
||||
}
|
||||
|
||||
if ((dirty_row_flags >> (y % 8)) & 0x1) {
|
||||
uint32_t color = 0;
|
||||
if (self->auto_gamma) {
|
||||
color = IS31GammaTable[((*buffer) >> 16 & 0xFF)] +
|
||||
IS31GammaTable[((*buffer) >> 8 & 0xFF)] +
|
||||
IS31GammaTable[((*buffer) & 0xFF)];
|
||||
} else {
|
||||
color = *buffer;
|
||||
}
|
||||
|
||||
for (int x = 0; x < self->width; x++) {
|
||||
is31fl3741_draw_pixel(self->i2c, self->device_address, x, y, color, self->mapping);
|
||||
buffer++;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < numBytes; i += 3) {
|
||||
uint16_t ridx = mp_obj_get_int(mapping[i]);
|
||||
if (ridx != 65535) {
|
||||
common_hal_is31fl3741_set_led(is31, ridx, IS31GammaTable[pixels[i]], 0); // red
|
||||
common_hal_is31fl3741_set_led(is31, mp_obj_get_int(mapping[i + 1]), IS31GammaTable[pixels[i + 1]], 0); // green
|
||||
common_hal_is31fl3741_set_led(is31, mp_obj_get_int(mapping[i + 2]), IS31GammaTable[pixels[i + 2]], 0); // blue
|
||||
}
|
||||
}
|
||||
|
||||
common_hal_displayio_is31fl3741_end_transaction(self);
|
||||
common_hal_is31fl3741_end_transaction(is31);
|
||||
}
|
||||
|
||||
int common_hal_is31fl3741_IS31FL3741_get_width(is31fl3741_IS31FL3741_obj_t *self) {
|
||||
return self->width;
|
||||
}
|
||||
|
||||
int common_hal_is31fl3741_IS31FL3741_get_height(is31fl3741_IS31FL3741_obj_t *self) {
|
||||
return self->height;
|
||||
}
|
||||
|
||||
void common_hal_displayio_is31fl3741_begin_transaction(is31fl3741_IS31FL3741_obj_t *self) {
|
||||
void common_hal_is31fl3741_begin_transaction(is31fl3741_IS31FL3741_obj_t *self) {
|
||||
while (!common_hal_busio_i2c_try_lock(self->i2c)) {
|
||||
RUN_BACKGROUND_TASKS;
|
||||
if (mp_hal_is_interrupted()) {
|
||||
|
@ -248,92 +82,73 @@ void common_hal_displayio_is31fl3741_begin_transaction(is31fl3741_IS31FL3741_obj
|
|||
}
|
||||
}
|
||||
|
||||
void common_hal_displayio_is31fl3741_end_transaction(is31fl3741_IS31FL3741_obj_t *self) {
|
||||
void common_hal_is31fl3741_end_transaction(is31fl3741_IS31FL3741_obj_t *self) {
|
||||
common_hal_busio_i2c_unlock(self->i2c);
|
||||
}
|
||||
|
||||
void *common_hal_is31fl3741_allocator_impl(size_t sz) {
|
||||
supervisor_allocation *allocation = allocate_memory(align32_size(sz), false, true);
|
||||
return allocation ? allocation->ptr : NULL;
|
||||
}
|
||||
uint8_t is31fl3741_cur_page = 99; // set to invalid page to start
|
||||
|
||||
void common_hal_is31fl3741_free_impl(void *ptr_in) {
|
||||
free_memory(allocation_from_ptr(ptr_in));
|
||||
}
|
||||
|
||||
void is31fl3741_IS31FL3741_collect_ptrs(is31fl3741_IS31FL3741_obj_t *self) {
|
||||
gc_collect_ptr(self->framebuffer);
|
||||
gc_collect_ptr(self->mapping);
|
||||
}
|
||||
|
||||
// The following are routines to manipulate the IS31FL3741 chip
|
||||
// They are not meant to be called by user code but only used
|
||||
// internally.
|
||||
|
||||
uint8_t cur_page = 99; // set to invalid page to start
|
||||
|
||||
void is31fl3741_send_unlock(busio_i2c_obj_t *i2c, uint8_t addr) {
|
||||
void common_hal_is31fl3741_send_unlock(is31fl3741_IS31FL3741_obj_t *self) {
|
||||
uint8_t unlock[2] = { 0xFE, 0xC5 }; // unlock command
|
||||
common_hal_busio_i2c_write(i2c, addr, unlock, 2);
|
||||
common_hal_busio_i2c_write(self->i2c, self->device_address, unlock, 2);
|
||||
}
|
||||
|
||||
void is31fl3741_set_page(busio_i2c_obj_t *i2c, uint8_t addr, uint8_t p) {
|
||||
if (p == cur_page) {
|
||||
void common_hal_is31fl3741_set_page(is31fl3741_IS31FL3741_obj_t *self, uint8_t p) {
|
||||
if (p == is31fl3741_cur_page) {
|
||||
return;
|
||||
}
|
||||
|
||||
cur_page = p;
|
||||
is31fl3741_send_unlock(i2c, addr);
|
||||
is31fl3741_cur_page = p;
|
||||
common_hal_is31fl3741_send_unlock(self);
|
||||
|
||||
uint8_t page[2] = { 0xFD, 0x00 }; // page command
|
||||
page[1] = p;
|
||||
common_hal_busio_i2c_write(i2c, addr, page, 2);
|
||||
common_hal_busio_i2c_write(self->i2c, self->device_address, page, 2);
|
||||
}
|
||||
|
||||
void is31fl3741_send_enable(busio_i2c_obj_t *i2c, uint8_t addr) {
|
||||
is31fl3741_set_page(i2c, addr, 4);
|
||||
void common_hal_is31fl3741_send_enable(is31fl3741_IS31FL3741_obj_t *self) {
|
||||
common_hal_is31fl3741_set_page(self, 4);
|
||||
uint8_t enable[2] = { 0x00, 0x01 }; // enable command
|
||||
common_hal_busio_i2c_write(i2c, addr, enable, 2);
|
||||
common_hal_busio_i2c_write(self->i2c, self->device_address, enable, 2);
|
||||
}
|
||||
|
||||
void is31fl3741_send_reset(busio_i2c_obj_t *i2c, uint8_t addr) {
|
||||
is31fl3741_set_page(i2c, addr, 4);
|
||||
void common_hal_is31fl3741_send_reset(is31fl3741_IS31FL3741_obj_t *self) {
|
||||
common_hal_is31fl3741_set_page(self, 4);
|
||||
uint8_t rst[2] = { 0x3F, 0xAE }; // reset command
|
||||
common_hal_busio_i2c_write(i2c, addr, rst, 2);
|
||||
common_hal_busio_i2c_write(self->i2c, self->device_address, rst, 2);
|
||||
}
|
||||
|
||||
void is31fl3741_set_current(busio_i2c_obj_t *i2c, uint8_t addr, uint8_t current) {
|
||||
is31fl3741_set_page(i2c, addr, 4);
|
||||
void common_hal_is31fl3741_set_current(is31fl3741_IS31FL3741_obj_t *self, uint8_t current) {
|
||||
common_hal_is31fl3741_set_page(self, 4);
|
||||
uint8_t gcur[2] = { 0x01, 0x00 }; // global current command
|
||||
gcur[1] = current;
|
||||
common_hal_busio_i2c_write(i2c, addr, gcur, 2);
|
||||
common_hal_busio_i2c_write(self->i2c, self->device_address, gcur, 2);
|
||||
}
|
||||
|
||||
uint8_t is31fl3741_get_current(busio_i2c_obj_t *i2c, uint8_t addr) {
|
||||
is31fl3741_set_page(i2c, addr, 4);
|
||||
uint8_t common_hal_is31fl3741_get_current(is31fl3741_IS31FL3741_obj_t *self) {
|
||||
common_hal_is31fl3741_set_page(self, 4);
|
||||
uint8_t gcur = 0x01; // global current command
|
||||
uint8_t data = 0;
|
||||
common_hal_busio_i2c_write_read(i2c, addr, &gcur, 1, &data, 1);
|
||||
return data;
|
||||
common_hal_busio_i2c_write_read(self->i2c, self->device_address, &gcur, 1, &gcur, 1);
|
||||
return gcur;
|
||||
}
|
||||
|
||||
void is31fl3741_set_led(busio_i2c_obj_t *i2c, uint8_t addr, uint16_t led, uint8_t level, uint8_t page) {
|
||||
void common_hal_is31fl3741_set_led(is31fl3741_IS31FL3741_obj_t *self, uint16_t led, uint8_t level, uint8_t page) {
|
||||
uint8_t cmd[2] = { 0x00, 0x00 };
|
||||
|
||||
if (led < 180) {
|
||||
is31fl3741_set_page(i2c, addr, page);
|
||||
common_hal_is31fl3741_set_page(self, page);
|
||||
cmd[0] = (uint8_t)led;
|
||||
} else {
|
||||
is31fl3741_set_page(i2c, addr, page + 1);
|
||||
common_hal_is31fl3741_set_page(self, page + 1);
|
||||
cmd[0] = (uint8_t)(led - 180);
|
||||
}
|
||||
|
||||
cmd[1] = level;
|
||||
|
||||
common_hal_busio_i2c_write(i2c, addr, cmd, 2);
|
||||
common_hal_busio_i2c_write(self->i2c, self->device_address, cmd, 2);
|
||||
}
|
||||
|
||||
void is31fl3741_draw_pixel(busio_i2c_obj_t *i2c, uint8_t addr, int16_t x, int16_t y, uint32_t color, uint16_t *mapping) {
|
||||
void common_hal_is31fl3741_draw_pixel(is31fl3741_IS31FL3741_obj_t *self, int16_t x, int16_t y, uint32_t color, uint16_t *mapping) {
|
||||
uint8_t r = color >> 16 & 0xFF;
|
||||
uint8_t g = color >> 8 & 0xFF;
|
||||
uint8_t b = color & 0xFF;
|
||||
|
@ -343,8 +158,8 @@ void is31fl3741_draw_pixel(busio_i2c_obj_t *i2c, uint8_t addr, int16_t x, int16_
|
|||
if (ridx != 65535) {
|
||||
uint16_t gidx = mapping[x1 + 1];
|
||||
uint16_t bidx = mapping[x1 + 0];
|
||||
is31fl3741_set_led(i2c, addr, ridx, r, 0);
|
||||
is31fl3741_set_led(i2c, addr, gidx, g, 0);
|
||||
is31fl3741_set_led(i2c, addr, bidx, b, 0);
|
||||
common_hal_is31fl3741_set_led(self, ridx, r, 0);
|
||||
common_hal_is31fl3741_set_led(self, gidx, g, 0);
|
||||
common_hal_is31fl3741_set_led(self, bidx, b, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,17 +33,9 @@
|
|||
extern const mp_obj_type_t is31fl3741_is31fl3741_type;
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t framebuffer;
|
||||
mp_buffer_info_t bufinfo;
|
||||
uint16_t bufsize, width, height, scale_width, scale_height;
|
||||
busio_i2c_obj_t *i2c;
|
||||
busio_i2c_obj_t inline_i2c;
|
||||
uint8_t device_address;
|
||||
uint16_t *mapping;
|
||||
uint8_t bit_depth;
|
||||
bool paused;
|
||||
bool scale;
|
||||
bool auto_gamma;
|
||||
} is31fl3741_IS31FL3741_obj_t;
|
||||
|
||||
// Gamma correction table
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 Mark Komus
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
Loading…
Reference in New Issue