summaryrefslogtreecommitdiff
path: root/shared-module
diff options
context:
space:
mode:
Diffstat (limited to 'shared-module')
-rw-r--r--shared-module/_eve/__init__.c317
-rw-r--r--shared-module/_eve/__init__.h37
-rw-r--r--shared-module/_pixelbuf/PixelBuf.c308
-rw-r--r--shared-module/_pixelbuf/PixelBuf.h37
-rw-r--r--shared-module/_stage/__init__.c6
-rw-r--r--shared-module/_stage/__init__.h3
-rw-r--r--shared-module/audiocore/RawSample.c6
-rw-r--r--shared-module/audiocore/__init__.c92
-rw-r--r--shared-module/audiocore/__init__.h24
-rw-r--r--shared-module/audiomixer/Mixer.c385
-rw-r--r--shared-module/audiomixer/MixerVoice.c6
-rw-r--r--shared-module/audiomixer/MixerVoice.h2
-rw-r--r--shared-module/audiomp3/MP3Decoder.c352
-rw-r--r--shared-module/audiomp3/MP3Decoder.h72
-rw-r--r--shared-module/audiomp3/__init__.c0
-rw-r--r--shared-module/audiomp3/__init__.h30
-rw-r--r--shared-module/board/__init__.c24
-rw-r--r--shared-module/displayio/Display.c28
-rw-r--r--shared-module/displayio/EPaperDisplay.c10
-rw-r--r--shared-module/displayio/FourWire.c4
-rw-r--r--shared-module/displayio/__init__.c8
-rw-r--r--shared-module/displayio/display_core.c14
-rw-r--r--shared-module/displayio/display_core.h2
-rw-r--r--shared-module/network/__init__.c4
-rw-r--r--shared-module/storage/__init__.c4
-rw-r--r--shared-module/usb_hid/Device.c5
26 files changed, 1350 insertions, 430 deletions
diff --git a/shared-module/_eve/__init__.c b/shared-module/_eve/__init__.c
new file mode 100644
index 000000000..2c93eb69f
--- /dev/null
+++ b/shared-module/_eve/__init__.c
@@ -0,0 +1,317 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 James Bowman for Excamera Labs
+ *
+ * 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 <stddef.h>
+#include <stdint.h>
+#include "py/runtime.h"
+#include "shared-module/_eve/__init__.h"
+
+STATIC void write(common_hal__eve_t *eve, size_t len, void *buf) {
+ eve->dest[2] = mp_obj_new_bytearray_by_ref(len, buf);
+ mp_call_method_n_kw(1, 0, eve->dest);
+}
+
+void common_hal__eve_flush(common_hal__eve_t *eve) {
+ if (eve->n != 0) {
+ write(eve, eve->n, eve->buf);
+ eve->n = 0;
+ }
+}
+
+static void *append(common_hal__eve_t *eve, size_t m) {
+ if ((eve->n + m) > sizeof(eve->buf))
+ common_hal__eve_flush(eve);
+ uint8_t *r = eve->buf + eve->n;
+ eve->n += m;
+ return (void*)r;
+}
+
+void common_hal__eve_add(common_hal__eve_t *eve, size_t len, void *buf) {
+ if (len <= sizeof(eve->buf)) {
+ uint8_t *p = (uint8_t*)append(eve, len);
+ // memcpy(p, buffer_info.buf, buffer_info.len);
+ uint8_t *s = buf; for (size_t i = 0; i < len; i++) *p++ = *s++;
+ } else {
+ common_hal__eve_flush(eve);
+ write(eve, len, buf);
+ }
+}
+
+#define C4(eve, u) (*(uint32_t*)append((eve), sizeof(uint32_t)) = (u))
+
+void common_hal__eve_Vertex2f(common_hal__eve_t *eve, mp_float_t x, mp_float_t y) {
+ int16_t ix = (int)(eve->vscale * x);
+ int16_t iy = (int)(eve->vscale * y);
+ C4(eve, (1 << 30) | ((ix & 32767) << 15) | (iy & 32767));
+}
+
+void common_hal__eve_VertexFormat(common_hal__eve_t *eve, uint32_t frac)
+{
+ C4(eve, ((27 << 24) | ((frac & 7))));
+ eve->vscale = 1 << eve->vscale;
+}
+
+
+
+void common_hal__eve_AlphaFunc(common_hal__eve_t *eve, uint32_t func, uint32_t ref) {
+ C4(eve, ((9 << 24) | ((func & 7) << 8) | ((ref & 255))));
+}
+
+
+void common_hal__eve_Begin(common_hal__eve_t *eve, uint32_t prim) {
+ C4(eve, ((31 << 24) | ((prim & 15))));
+}
+
+
+void common_hal__eve_BitmapExtFormat(common_hal__eve_t *eve, uint32_t fmt) {
+ C4(eve, ((46 << 24) | (fmt & 65535)));
+}
+
+
+void common_hal__eve_BitmapHandle(common_hal__eve_t *eve, uint32_t handle) {
+ C4(eve, ((5 << 24) | ((handle & 31))));
+}
+
+
+void common_hal__eve_BitmapLayoutH(common_hal__eve_t *eve, uint32_t linestride, uint32_t height) {
+ C4(eve, ((40 << 24) | (((linestride) & 3) << 2) | (((height) & 3))));
+}
+
+
+void common_hal__eve_BitmapLayout(common_hal__eve_t *eve, uint32_t format, uint32_t linestride, uint32_t height) {
+ C4(eve, ((7 << 24) | ((format & 31) << 19) | ((linestride & 1023) << 9) | ((height & 511))));
+}
+
+
+void common_hal__eve_BitmapSizeH(common_hal__eve_t *eve, uint32_t width, uint32_t height) {
+ C4(eve, ((41 << 24) | (((width) & 3) << 2) | (((height) & 3))));
+}
+
+
+void common_hal__eve_BitmapSize(common_hal__eve_t *eve, uint32_t filter, uint32_t wrapx, uint32_t wrapy, uint32_t width, uint32_t height) {
+ C4(eve, ((8 << 24) | ((filter & 1) << 20) | ((wrapx & 1) << 19) | ((wrapy & 1) << 18) | ((width & 511) << 9) | ((height & 511))));
+}
+
+
+void common_hal__eve_BitmapSource(common_hal__eve_t *eve, uint32_t addr) {
+ C4(eve, ((1 << 24) | ((addr & 0xffffff))));
+}
+
+
+void common_hal__eve_BitmapSwizzle(common_hal__eve_t *eve, uint32_t r, uint32_t g, uint32_t b, uint32_t a) {
+ C4(eve, ((47 << 24) | ((r & 7) << 9) | ((g & 7) << 6) | ((b & 7) << 3) | ((a & 7))));
+}
+
+
+void common_hal__eve_BitmapTransformA(common_hal__eve_t *eve, uint32_t p, uint32_t v) {
+ C4(eve, ((21 << 24) | ((p & 1) << 17) | ((v & 131071))));
+}
+
+
+void common_hal__eve_BitmapTransformB(common_hal__eve_t *eve, uint32_t p, uint32_t v) {
+ C4(eve, ((22 << 24) | ((p & 1) << 17) | ((v & 131071))));
+}
+
+
+void common_hal__eve_BitmapTransformC(common_hal__eve_t *eve, uint32_t v) {
+ C4(eve, ((23 << 24) | ((v & 16777215))));
+}
+
+
+void common_hal__eve_BitmapTransformD(common_hal__eve_t *eve, uint32_t p, uint32_t v) {
+ C4(eve, ((24 << 24) | ((p & 1) << 17) | ((v & 131071))));
+}
+
+
+void common_hal__eve_BitmapTransformE(common_hal__eve_t *eve, uint32_t p, uint32_t v) {
+ C4(eve, ((25 << 24) | ((p & 1) << 17) | ((v & 131071))));
+}
+
+
+void common_hal__eve_BitmapTransformF(common_hal__eve_t *eve, uint32_t v) {
+ C4(eve, ((26 << 24) | ((v & 16777215))));
+}
+
+
+void common_hal__eve_BlendFunc(common_hal__eve_t *eve, uint32_t src, uint32_t dst) {
+ C4(eve, ((11 << 24) | ((src & 7) << 3) | ((dst & 7))));
+}
+
+
+void common_hal__eve_Call(common_hal__eve_t *eve, uint32_t dest) {
+ C4(eve, ((29 << 24) | ((dest & 65535))));
+}
+
+
+void common_hal__eve_Cell(common_hal__eve_t *eve, uint32_t cell) {
+ C4(eve, ((6 << 24) | ((cell & 127))));
+}
+
+
+void common_hal__eve_ClearColorA(common_hal__eve_t *eve, uint32_t alpha) {
+ C4(eve, ((15 << 24) | ((alpha & 255))));
+}
+
+
+void common_hal__eve_ClearColorRGB(common_hal__eve_t *eve, uint32_t red, uint32_t green, uint32_t blue) {
+ C4(eve, ((2 << 24) | ((red & 255) << 16) | ((green & 255) << 8) | ((blue & 255))));
+}
+
+
+void common_hal__eve_Clear(common_hal__eve_t *eve, uint32_t c, uint32_t s, uint32_t t) {
+ C4(eve, ((38 << 24) | ((c & 1) << 2) | ((s & 1) << 1) | ((t & 1))));
+}
+
+
+void common_hal__eve_ClearStencil(common_hal__eve_t *eve, uint32_t s) {
+ C4(eve, ((17 << 24) | ((s & 255))));
+}
+
+
+void common_hal__eve_ClearTag(common_hal__eve_t *eve, uint32_t s) {
+ C4(eve, ((18 << 24) | ((s & 255))));
+}
+
+
+void common_hal__eve_ColorA(common_hal__eve_t *eve, uint32_t alpha) {
+ C4(eve, ((16 << 24) | ((alpha & 255))));
+}
+
+
+void common_hal__eve_ColorMask(common_hal__eve_t *eve, uint32_t r, uint32_t g, uint32_t b, uint32_t a) {
+ C4(eve, ((32 << 24) | ((r & 1) << 3) | ((g & 1) << 2) | ((b & 1) << 1) | ((a & 1))));
+}
+
+
+void common_hal__eve_ColorRGB(common_hal__eve_t *eve, uint32_t red, uint32_t green, uint32_t blue) {
+ C4(eve, ((4 << 24) | ((red & 255) << 16) | ((green & 255) << 8) | ((blue & 255))));
+}
+
+
+void common_hal__eve_Display(common_hal__eve_t *eve) {
+ C4(eve, ((0 << 24)));
+}
+
+
+void common_hal__eve_End(common_hal__eve_t *eve) {
+ C4(eve, ((33 << 24)));
+}
+
+
+void common_hal__eve_Jump(common_hal__eve_t *eve, uint32_t dest) {
+ C4(eve, ((30 << 24) | ((dest & 65535))));
+}
+
+
+void common_hal__eve_LineWidth(common_hal__eve_t *eve, uint32_t width) {
+ C4(eve, ((14 << 24) | ((width & 4095))));
+}
+
+
+void common_hal__eve_Macro(common_hal__eve_t *eve, uint32_t m) {
+ C4(eve, ((37 << 24) | ((m & 1))));
+}
+
+
+void common_hal__eve_Nop(common_hal__eve_t *eve) {
+ C4(eve, ((45 << 24)));
+}
+
+
+void common_hal__eve_PaletteSource(common_hal__eve_t *eve, uint32_t addr) {
+ C4(eve, ((42 << 24) | (((addr) & 4194303))));
+}
+
+
+void common_hal__eve_PointSize(common_hal__eve_t *eve, uint32_t size) {
+ C4(eve, ((13 << 24) | ((size & 8191))));
+}
+
+
+void common_hal__eve_RestoreContext(common_hal__eve_t *eve) {
+ C4(eve, ((35 << 24)));
+}
+
+
+void common_hal__eve_Return(common_hal__eve_t *eve) {
+ C4(eve, ((36 << 24)));
+}
+
+
+void common_hal__eve_SaveContext(common_hal__eve_t *eve) {
+ C4(eve, ((34 << 24)));
+}
+
+
+void common_hal__eve_ScissorSize(common_hal__eve_t *eve, uint32_t width, uint32_t height) {
+ C4(eve, ((28 << 24) | ((width & 4095) << 12) | ((height & 4095))));
+}
+
+
+void common_hal__eve_ScissorXY(common_hal__eve_t *eve, uint32_t x, uint32_t y) {
+ C4(eve, ((27 << 24) | ((x & 2047) << 11) | ((y & 2047))));
+}
+
+
+void common_hal__eve_StencilFunc(common_hal__eve_t *eve, uint32_t func, uint32_t ref, uint32_t mask) {
+ C4(eve, ((10 << 24) | ((func & 7) << 16) | ((ref & 255) << 8) | ((mask & 255))));
+}
+
+
+void common_hal__eve_StencilMask(common_hal__eve_t *eve, uint32_t mask) {
+ C4(eve, ((19 << 24) | ((mask & 255))));
+}
+
+
+void common_hal__eve_StencilOp(common_hal__eve_t *eve, uint32_t sfail, uint32_t spass) {
+ C4(eve, ((12 << 24) | ((sfail & 7) << 3) | ((spass & 7))));
+}
+
+
+void common_hal__eve_TagMask(common_hal__eve_t *eve, uint32_t mask) {
+ C4(eve, ((20 << 24) | ((mask & 1))));
+}
+
+
+void common_hal__eve_Tag(common_hal__eve_t *eve, uint32_t s) {
+ C4(eve, ((3 << 24) | ((s & 255))));
+}
+
+
+void common_hal__eve_VertexTranslateX(common_hal__eve_t *eve, uint32_t x) {
+ C4(eve, ((43 << 24) | (((x) & 131071))));
+}
+
+
+void common_hal__eve_VertexTranslateY(common_hal__eve_t *eve, uint32_t y) {
+ C4(eve, ((44 << 24) | (((y) & 131071))));
+}
+
+
+void common_hal__eve_Vertex2ii(common_hal__eve_t *eve, uint32_t x, uint32_t y, uint32_t handle, uint32_t cell) {
+ C4(eve, ((2 << 30) | (((x) & 511) << 21) | (((y) & 511) << 12) | (((handle) & 31) << 7) | (((cell) & 127) << 0)));
+}
+
diff --git a/shared-module/_eve/__init__.h b/shared-module/_eve/__init__.h
new file mode 100644
index 000000000..5217d860a
--- /dev/null
+++ b/shared-module/_eve/__init__.h
@@ -0,0 +1,37 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 James Bowman for Excamera Labs
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_MODULE__EVE___INIT___H
+#define MICROPY_INCLUDED_SHARED_MODULE__EVE___INIT___H
+
+typedef struct _common_hal__eve_t {
+ mp_obj_t dest[3]; // Own 'write' method, plus argument
+ int vscale; // fixed-point scaling used for Vertex2f
+ size_t n; // Current size of command buffer
+ uint8_t buf[512]; // Command buffer
+} common_hal__eve_t;
+
+#endif // MICROPY_INCLUDED_SHARED_MODULE__EVE___INIT___H
diff --git a/shared-module/_pixelbuf/PixelBuf.c b/shared-module/_pixelbuf/PixelBuf.c
index d32697239..bad8539ea 100644
--- a/shared-module/_pixelbuf/PixelBuf.c
+++ b/shared-module/_pixelbuf/PixelBuf.c
@@ -26,95 +26,263 @@
#include "py/obj.h"
-#include "py/objarray.h"
+#include "py/objstr.h"
+#include "py/objtype.h"
#include "py/runtime.h"
-#include "PixelBuf.h"
+#include "shared-bindings/_pixelbuf/PixelBuf.h"
#include <string.h>
-void pixelbuf_set_pixel_int(uint8_t *buf, mp_int_t value, pixelbuf_byteorder_obj_t *byteorder) {
- buf[byteorder->byteorder.r] = value >> 16 & 0xff;
- buf[byteorder->byteorder.g] = (value >> 8) & 0xff;
- buf[byteorder->byteorder.b] = value & 0xff;
- if (byteorder->bpp == 4 && byteorder->has_white &&
- (buf[byteorder->byteorder.r] == buf[byteorder->byteorder.g] &&
- buf[byteorder->byteorder.r] == buf[byteorder->byteorder.b])) {
- buf[byteorder->byteorder.w] = buf[byteorder->byteorder.r];
- buf[byteorder->byteorder.r] = buf[byteorder->byteorder.g] = buf[byteorder->byteorder.b] = 0;
- }
-}
-
-void pixelbuf_set_pixel(uint8_t *buf, uint8_t *rawbuf, float brightness, mp_obj_t *item, pixelbuf_byteorder_obj_t *byteorder, bool dotstar) {
- if (MP_OBJ_IS_INT(item)) {
- uint8_t *target = rawbuf ? rawbuf : buf;
- pixelbuf_set_pixel_int(target, mp_obj_get_int_truncated(item), byteorder);
- if (dotstar) {
- buf[0] = DOTSTAR_LED_START_FULL_BRIGHT;
- if (rawbuf)
- rawbuf[0] = DOTSTAR_LED_START_FULL_BRIGHT;
- }
- if (rawbuf) {
- buf[byteorder->byteorder.r] = rawbuf[byteorder->byteorder.r] * brightness;
- buf[byteorder->byteorder.g] = rawbuf[byteorder->byteorder.g] * brightness;
- buf[byteorder->byteorder.b] = rawbuf[byteorder->byteorder.b] * brightness;
- } else {
- buf[byteorder->byteorder.r] *= brightness;
- buf[byteorder->byteorder.g] *= brightness;
- buf[byteorder->byteorder.b] *= brightness;
+// Helper to ensure we have the native super class instead of a subclass.
+static pixelbuf_pixelbuf_obj_t* native_pixelbuf(mp_obj_t pixelbuf_obj) {
+ mp_obj_t native_pixelbuf = mp_instance_cast_to_native_base(pixelbuf_obj, &pixelbuf_pixelbuf_type);
+ mp_obj_assert_native_inited(native_pixelbuf);
+ return MP_OBJ_TO_PTR(native_pixelbuf);
+}
+
+void common_hal__pixelbuf_pixelbuf_construct(pixelbuf_pixelbuf_obj_t *self, size_t n,
+ pixelbuf_byteorder_details_t* byteorder, mp_float_t brightness, bool auto_write,
+ uint8_t* header, size_t header_len, uint8_t* trailer, size_t trailer_len) {
+
+ self->pixel_count = n;
+ self->byteorder = *byteorder; // Copied because we modify for dotstar
+ self->bytes_per_pixel = byteorder->is_dotstar ? 4 : byteorder->bpp;
+ self->auto_write = false;
+
+ size_t pixel_len = self->pixel_count * self->bytes_per_pixel;
+ self->transmit_buffer_obj = mp_obj_new_bytes_of_zeros(header_len + pixel_len + trailer_len);
+ mp_obj_str_t *o = MP_OBJ_TO_PTR(self->transmit_buffer_obj);
+
+ // Abuse the bytes object a bit by mutating it's data by dropping the const. If the user's
+ // Python code holds onto it, they'll find out that it changes. At least this way it isn't
+ // mutable by the code itself.
+ uint8_t* transmit_buffer = (uint8_t*) o->data;
+ memcpy(transmit_buffer, header, header_len);
+ memcpy(transmit_buffer + header_len + pixel_len, trailer, trailer_len);
+ self->post_brightness_buffer = transmit_buffer + header_len;
+
+ if (self->byteorder.is_dotstar) {
+ // Initialize the buffer with the dotstar start bytes.
+ // Note: Header and end must be setup by caller
+ for (uint i = 0; i < self->pixel_count * 4; i += 4) {
+ self->post_brightness_buffer[i] = DOTSTAR_LED_START_FULL_BRIGHT;
+ }
+ }
+ // Call set_brightness so that it can allocate a second buffer if needed.
+ self->brightness = 1.0;
+ common_hal__pixelbuf_pixelbuf_set_brightness(MP_OBJ_FROM_PTR(self), brightness);
+
+ // Turn on auto_write. We don't want to do it with the above brightness call.
+ self->auto_write = auto_write;
+}
+
+size_t common_hal__pixelbuf_pixelbuf_get_len(mp_obj_t self_in) {
+ pixelbuf_pixelbuf_obj_t* self = native_pixelbuf(self_in);
+ return self->pixel_count;
+}
+
+uint8_t common_hal__pixelbuf_pixelbuf_get_bpp(mp_obj_t self_in) {
+ pixelbuf_pixelbuf_obj_t* self = native_pixelbuf(self_in);
+ return self->byteorder.bpp;
+}
+
+mp_obj_t common_hal__pixelbuf_pixelbuf_get_byteorder_string(mp_obj_t self_in) {
+ pixelbuf_pixelbuf_obj_t* self = native_pixelbuf(self_in);
+ return self->byteorder.order_string;
+}
+
+bool common_hal__pixelbuf_pixelbuf_get_auto_write(mp_obj_t self_in) {
+ pixelbuf_pixelbuf_obj_t* self = native_pixelbuf(self_in);
+ return self->auto_write;
+}
+
+void common_hal__pixelbuf_pixelbuf_set_auto_write(mp_obj_t self_in, bool auto_write) {
+ pixelbuf_pixelbuf_obj_t* self = native_pixelbuf(self_in);
+ self->auto_write = auto_write;
+}
+
+mp_float_t common_hal__pixelbuf_pixelbuf_get_brightness(mp_obj_t self_in) {
+ pixelbuf_pixelbuf_obj_t* self = native_pixelbuf(self_in);
+ return self->brightness;
+}
+
+void common_hal__pixelbuf_pixelbuf_set_brightness(mp_obj_t self_in, mp_float_t brightness) {
+ pixelbuf_pixelbuf_obj_t* self = native_pixelbuf(self_in);
+ // Skip out if the brightness is already set. The default of self->brightness is 1.0. So, this
+ // also prevents the pre_brightness_buffer allocation when brightness is set to 1.0 again.
+ mp_float_t change = brightness - self->brightness;
+ if (-0.001 < change && change < 0.001) {
+ return;
+ }
+ self->brightness = brightness;
+ size_t pixel_len = self->pixel_count * self->bytes_per_pixel;
+ if (self->pre_brightness_buffer == NULL) {
+ self->pre_brightness_buffer = m_malloc(pixel_len, false);
+ memcpy(self->pre_brightness_buffer, self->post_brightness_buffer, pixel_len);
+ }
+ for (size_t i = 0; i < pixel_len; i++) {
+ // Don't adjust per-pixel luminance bytes in dotstar mode
+ if (self->byteorder.is_dotstar && i % 4 == 0) {
+ continue;
+ }
+ self->post_brightness_buffer[i] = self->pre_brightness_buffer[i] * self->brightness;
+ }
+
+ if (self->auto_write) {
+ common_hal__pixelbuf_pixelbuf_show(self_in);
+ }
+}
+
+void _pixelbuf_parse_color(pixelbuf_pixelbuf_obj_t* self, mp_obj_t color, uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* w) {
+ pixelbuf_byteorder_details_t *byteorder = &self->byteorder;
+ // w is shared between white in NeoPixels and brightness in dotstars (so that DotStars can have
+ // per-pixel brightness). Set the defaults here in case it isn't set below.
+ if (byteorder->is_dotstar) {
+ *w = 255;
+ } else {
+ *w = 0;
+ }
+
+ if (MP_OBJ_IS_INT(color)) {
+ mp_int_t value = mp_obj_get_int_truncated(color);
+ *r = value >> 16 & 0xff;
+ *g = (value >> 8) & 0xff;
+ *b = value & 0xff;
+ // Int colors can't set white directly so convert to white when all components are equal.
+ if (!byteorder->is_dotstar && byteorder->bpp == 4 && byteorder->has_white && *r == *g && *r == *b) {
+ *w = *r;
+ *r = 0;
+ *g = 0;
+ *b = 0;
}
} else {
mp_obj_t *items;
size_t len;
- mp_obj_get_array(item, &len, &items);
- if (len != byteorder->bpp && !dotstar)
+ mp_obj_get_array(color, &len, &items);
+ if (len != byteorder->bpp && !byteorder->is_dotstar) {
mp_raise_ValueError_varg(translate("Expected tuple of length %d, got %d"), byteorder->bpp, len);
-
- buf[byteorder->byteorder.r] = mp_obj_get_int_truncated(items[PIXEL_R]) * brightness;
- buf[byteorder->byteorder.g] = mp_obj_get_int_truncated(items[PIXEL_G]) * brightness;
- buf[byteorder->byteorder.b] = mp_obj_get_int_truncated(items[PIXEL_B]) * brightness;
- if (rawbuf) {
- rawbuf[byteorder->byteorder.r] = mp_obj_get_int_truncated(items[PIXEL_R]);
- rawbuf[byteorder->byteorder.g] = mp_obj_get_int_truncated(items[PIXEL_G]);
- rawbuf[byteorder->byteorder.b] = mp_obj_get_int_truncated(items[PIXEL_B]);
}
+
+ *r = mp_obj_get_int_truncated(items[PIXEL_R]);
+ *g = mp_obj_get_int_truncated(items[PIXEL_G]);
+ *b = mp_obj_get_int_truncated(items[PIXEL_B]);
if (len > 3) {
- if (dotstar) {
- buf[byteorder->byteorder.w] = DOTSTAR_LED_START | DOTSTAR_BRIGHTNESS(mp_obj_get_float(items[PIXEL_W]));
- if (rawbuf)
- rawbuf[byteorder->byteorder.w] = buf[byteorder->byteorder.w];
+ if (mp_obj_is_float(items[PIXEL_W])) {
+ *w = 255 * mp_obj_get_float(items[PIXEL_W]);
} else {
- buf[byteorder->byteorder.w] = mp_obj_get_int_truncated(items[PIXEL_W]) * brightness;
- if (rawbuf)
- rawbuf[byteorder->byteorder.w] = mp_obj_get_int_truncated(items[PIXEL_W]);
+ *w = mp_obj_get_int_truncated(items[PIXEL_W]);
}
- } else if (dotstar) {
- buf[byteorder->byteorder.w] = DOTSTAR_LED_START_FULL_BRIGHT;
- if (rawbuf)
- rawbuf[byteorder->byteorder.w] = DOTSTAR_LED_START_FULL_BRIGHT;
}
}
}
-mp_obj_t *pixelbuf_get_pixel_array(uint8_t *buf, uint len, pixelbuf_byteorder_obj_t *byteorder, uint8_t step, bool dotstar) {
- mp_obj_t elems[len];
- for (uint i = 0; i < len; i++) {
- elems[i] = pixelbuf_get_pixel(buf + (i * step), byteorder, dotstar);
+void _pixelbuf_set_pixel_color(pixelbuf_pixelbuf_obj_t* self, size_t index, uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
+ // DotStars don't have white, instead they have 5 bit brightness so pack it into w. Shift right
+ // by three to leave the top five bits.
+ if (self->bytes_per_pixel == 4 && self->byteorder.is_dotstar) {
+ w = DOTSTAR_LED_START | w >> 3;
+ }
+ pixelbuf_rgbw_t *rgbw_order = &self->byteorder.byteorder;
+ size_t offset = index * self->bytes_per_pixel;
+ if (self->pre_brightness_buffer != NULL) {
+ uint8_t* pre_brightness_buffer = self->pre_brightness_buffer + offset;
+ if (self->bytes_per_pixel == 4) {
+ pre_brightness_buffer[rgbw_order->w] = w;
+ }
+
+ pre_brightness_buffer[rgbw_order->r] = r;
+ pre_brightness_buffer[rgbw_order->g] = g;
+ pre_brightness_buffer[rgbw_order->b] = b;
+ }
+
+ uint8_t* post_brightness_buffer = self->post_brightness_buffer + offset;
+ if (self->bytes_per_pixel == 4) {
+ // Only apply brightness if w is actually white (aka not DotStar.)
+ if (!self->byteorder.is_dotstar) {
+ w *= self->brightness;
+ }
+ post_brightness_buffer[rgbw_order->w] = w;
+ }
+ post_brightness_buffer[rgbw_order->r] = r * self->brightness;
+ post_brightness_buffer[rgbw_order->g] = g * self->brightness;
+ post_brightness_buffer[rgbw_order->b] = b * self->brightness;
+}
+
+void _pixelbuf_set_pixel(pixelbuf_pixelbuf_obj_t* self, size_t index, mp_obj_t value) {
+ uint8_t r;
+ uint8_t g;
+ uint8_t b;
+ uint8_t w;
+ _pixelbuf_parse_color(self, value, &r, &g, &b, &w);
+ _pixelbuf_set_pixel_color(self, index, r, g, b, w);
+}
+
+void common_hal__pixelbuf_pixelbuf_set_pixels(mp_obj_t self_in, size_t start, size_t stop, size_t step, mp_obj_t* values) {
+ pixelbuf_pixelbuf_obj_t* self = native_pixelbuf(self_in);
+ size_t source_i = 0;
+ for (size_t target_i = start; target_i < stop; target_i += step) {
+ _pixelbuf_set_pixel(self, target_i, values[source_i]);
+ source_i++;
+ }
+ if (self->auto_write) {
+ common_hal__pixelbuf_pixelbuf_show(self_in);
}
- return mp_obj_new_tuple(len, elems);
}
-mp_obj_t *pixelbuf_get_pixel(uint8_t *buf, pixelbuf_byteorder_obj_t *byteorder, bool dotstar) {
- mp_obj_t elems[byteorder->bpp];
-
- elems[0] = mp_obj_new_int(buf[byteorder->byteorder.r]);
- elems[1] = mp_obj_new_int(buf[byteorder->byteorder.g]);
- elems[2] = mp_obj_new_int(buf[byteorder->byteorder.b]);
- if (byteorder->bpp > 3)
- {
- if (dotstar)
- elems[3] = mp_obj_new_float(DOTSTAR_GET_BRIGHTNESS(buf[byteorder->byteorder.w]));
- else
- elems[3] = mp_obj_new_int(buf[byteorder->byteorder.w]);
+void common_hal__pixelbuf_pixelbuf_set_pixel(mp_obj_t self_in, size_t index, mp_obj_t value) {
+ pixelbuf_pixelbuf_obj_t* self = native_pixelbuf(self_in);
+ _pixelbuf_set_pixel(self, index, value);
+ if (self->auto_write) {
+ common_hal__pixelbuf_pixelbuf_show(self_in);
}
+}
- return mp_obj_new_tuple(byteorder->bpp, elems);
+mp_obj_t common_hal__pixelbuf_pixelbuf_get_pixel(mp_obj_t self_in, size_t index) {
+ pixelbuf_pixelbuf_obj_t* self = native_pixelbuf(self_in);
+ mp_obj_t elems[self->byteorder.bpp];
+ uint8_t* pixel_buffer = self->post_brightness_buffer;
+ if (self->pre_brightness_buffer != NULL) {
+ pixel_buffer = self->pre_brightness_buffer;
+ }
+
+ pixelbuf_rgbw_t *rgbw_order = &self->byteorder.byteorder;
+ elems[0] = MP_OBJ_NEW_SMALL_INT(pixel_buffer[rgbw_order->r]);
+ elems[1] = MP_OBJ_NEW_SMALL_INT(pixel_buffer[rgbw_order->g]);
+ elems[2] = MP_OBJ_NEW_SMALL_INT(pixel_buffer[rgbw_order->b]);
+ if (self->byteorder.bpp > 3) {
+ uint8_t w = pixel_buffer[rgbw_order->w];
+ if (self->byteorder.is_dotstar) {
+ elems[3] = mp_obj_new_float((w & 0b00011111) / 31.0);
+ } else {
+ elems[3] = MP_OBJ_NEW_SMALL_INT(w);
+ }
+ }
+
+ return mp_obj_new_tuple(self->byteorder.bpp, elems);
+}
+
+void common_hal__pixelbuf_pixelbuf_show(mp_obj_t self_in) {
+ pixelbuf_pixelbuf_obj_t* self = native_pixelbuf(self_in);
+ mp_obj_t dest[2 + 1];
+ mp_load_method(self_in, MP_QSTR__transmit, dest);
+
+ dest[2] = self->transmit_buffer_obj;
+
+ mp_call_method_n_kw(1, 0, dest);
+}
+
+void common_hal__pixelbuf_pixelbuf_fill(mp_obj_t self_in, mp_obj_t fill_color) {
+ pixelbuf_pixelbuf_obj_t* self = native_pixelbuf(self_in);
+
+ uint8_t r;
+ uint8_t g;
+ uint8_t b;
+ uint8_t w;
+ _pixelbuf_parse_color(self, fill_color, &r, &g, &b, &w);
+
+ for (size_t i = 0; i < self->pixel_count; i++) {
+ _pixelbuf_set_pixel_color(self, i, r, g, b, w);
+ }
+ if (self->auto_write) {
+ common_hal__pixelbuf_pixelbuf_show(self_in);
+ }
}
diff --git a/shared-module/_pixelbuf/PixelBuf.h b/shared-module/_pixelbuf/PixelBuf.h
index 9e115fe0c..a9fbed366 100644
--- a/shared-module/_pixelbuf/PixelBuf.h
+++ b/shared-module/_pixelbuf/PixelBuf.h
@@ -27,24 +27,45 @@
#include "py/obj.h"
#include "py/objarray.h"
-#include "../../shared-bindings/_pixelbuf/types.h"
#ifndef PIXELBUF_SHARED_MODULE_H
#define PIXELBUF_SHARED_MODULE_H
+typedef struct {
+ uint8_t r;
+ uint8_t g;
+ uint8_t b;
+ uint8_t w;
+} pixelbuf_rgbw_t;
+
+typedef struct {
+ uint8_t bpp;
+ pixelbuf_rgbw_t byteorder;
+ bool has_white;
+ bool is_dotstar;
+ mp_obj_t order_string;
+} pixelbuf_byteorder_details_t;
+
+typedef struct {
+ mp_obj_base_t base;
+ size_t pixel_count;
+ size_t bytes_per_pixel;
+ pixelbuf_byteorder_details_t byteorder;
+ mp_float_t brightness;
+ mp_obj_t transmit_buffer_obj;
+ // The post_brightness_buffer is offset into the buffer allocated in transmit_buffer_obj to
+ // account for any header.
+ uint8_t *post_brightness_buffer;
+ uint8_t *pre_brightness_buffer;
+ bool auto_write;
+} pixelbuf_pixelbuf_obj_t;
+
#define PIXEL_R 0
#define PIXEL_G 1
#define PIXEL_B 2
#define PIXEL_W 3
#define DOTSTAR_LED_START 0b11100000
-#define DOTSTAR_BRIGHTNESS(brightness) ((32 - (uint8_t)(32 - brightness * 31)) & 0b00011111)
-#define DOTSTAR_GET_BRIGHTNESS(value) ((value & 0b00011111) / 31.0)
#define DOTSTAR_LED_START_FULL_BRIGHT 0xFF
-void pixelbuf_set_pixel(uint8_t *buf, uint8_t *rawbuf, float brightness, mp_obj_t *item, pixelbuf_byteorder_obj_t *byteorder, bool dotstar);
-mp_obj_t *pixelbuf_get_pixel(uint8_t *buf, pixelbuf_byteorder_obj_t *byteorder, bool dotstar);
-mp_obj_t *pixelbuf_get_pixel_array(uint8_t *buf, uint len, pixelbuf_byteorder_obj_t *byteorder, uint8_t step, bool dotstar);
-void pixelbuf_set_pixel_int(uint8_t *buf, mp_int_t value, pixelbuf_byteorder_obj_t *byteorder);
-
#endif
diff --git a/shared-module/_stage/__init__.c b/shared-module/_stage/__init__.c
index d5da74272..0323c32cb 100644
--- a/shared-module/_stage/__init__.c
+++ b/shared-module/_stage/__init__.c
@@ -34,7 +34,8 @@
void render_stage(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1,
mp_obj_t *layers, size_t layers_size,
uint16_t *buffer, size_t buffer_size,
- displayio_display_obj_t *display, uint8_t scale) {
+ displayio_display_obj_t *display,
+ uint8_t scale, uint16_t background) {
displayio_area_t area;
@@ -68,6 +69,9 @@ void render_stage(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1,
break;
}
}
+ if (c == TRANSPARENT) {
+ c = background;
+ }
for (uint8_t xscale = 0; xscale < scale; ++xscale) {
buffer[index] = c;
index += 1;
diff --git a/shared-module/_stage/__init__.h b/shared-module/_stage/__init__.h
index 5af2124ae..7a1826200 100644
--- a/shared-module/_stage/__init__.h
+++ b/shared-module/_stage/__init__.h
@@ -37,6 +37,7 @@
void render_stage(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1,
mp_obj_t *layers, size_t layers_size,
uint16_t *buffer, size_t buffer_size,
- displayio_display_obj_t *display, uint8_t scale);
+ displayio_display_obj_t *display,
+ uint8_t scale, uint16_t background);
#endif // MICROPY_INCLUDED_SHARED_MODULE__STAGE
diff --git a/shared-module/audiocore/RawSample.c b/shared-module/audiocore/RawSample.c
index d6bf3a567..a69ddeb65 100644
--- a/shared-module/audiocore/RawSample.c
+++ b/shared-module/audiocore/RawSample.c
@@ -60,6 +60,12 @@ void common_hal_audioio_rawsample_set_sample_rate(audioio_rawsample_obj_t* self,
uint32_t sample_rate) {
self->sample_rate = sample_rate;
}
+uint8_t common_hal_audioio_rawsample_get_bits_per_sample(audioio_rawsample_obj_t* self) {
+ return self->bits_per_sample;
+}
+uint8_t common_hal_audioio_rawsample_get_channel_count(audioio_rawsample_obj_t* self) {
+ return self->channel_count;
+}
void audioio_rawsample_reset_buffer(audioio_rawsample_obj_t* self,
bool single_channel,
diff --git a/shared-module/audiocore/__init__.c b/shared-module/audiocore/__init__.c
index f9762676f..ac9d41b60 100644
--- a/shared-module/audiocore/__init__.c
+++ b/shared-module/audiocore/__init__.c
@@ -36,103 +36,37 @@
#include "shared-module/audiomixer/Mixer.h"
uint32_t audiosample_sample_rate(mp_obj_t sample_obj) {
- if (MP_OBJ_IS_TYPE(sample_obj, &audioio_rawsample_type)) {
- audioio_rawsample_obj_t* sample = MP_OBJ_TO_PTR(sample_obj);
- return sample->sample_rate;
- } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) {
- audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj);
- return file->sample_rate;
- #if CIRCUITPY_AUDIOMIXER
- } else if (MP_OBJ_IS_TYPE(sample_obj, &audiomixer_mixer_type)) {
- audiomixer_mixer_obj_t* mixer = MP_OBJ_TO_PTR(sample_obj);
- return mixer->sample_rate;
- #endif
- }
- return 16000;
+ const audiosample_p_t *proto = mp_proto_get_or_throw(MP_QSTR_protocol_audiosample, sample_obj);
+ return proto->sample_rate(MP_OBJ_TO_PTR(sample_obj));
}
uint8_t audiosample_bits_per_sample(mp_obj_t sample_obj) {
- if (MP_OBJ_IS_TYPE(sample_obj, &audioio_rawsample_type)) {
- audioio_rawsample_obj_t* sample = MP_OBJ_TO_PTR(sample_obj);
- return sample->bits_per_sample;
- } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) {
- audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj);
- return file->bits_per_sample;
- #if CIRCUITPY_AUDIOMIXER
- } else if (MP_OBJ_IS_TYPE(sample_obj, &audiomixer_mixer_type)) {
- audiomixer_mixer_obj_t* mixer = MP_OBJ_TO_PTR(sample_obj);
- return mixer->bits_per_sample;
- #endif
- }
- return 8;
+ const audiosample_p_t *proto = mp_proto_get_or_throw(MP_QSTR_protocol_audiosample, sample_obj);
+ return proto->bits_per_sample(MP_OBJ_TO_PTR(sample_obj));
}
uint8_t audiosample_channel_count(mp_obj_t sample_obj) {
- if (MP_OBJ_IS_TYPE(sample_obj, &audioio_rawsample_type)) {
- audioio_rawsample_obj_t* sample = MP_OBJ_TO_PTR(sample_obj);
- return sample->channel_count;
- } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) {
- audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj);
- return file->channel_count;
- #if CIRCUITPY_AUDIOMIXER
- } else if (MP_OBJ_IS_TYPE(sample_obj, &audiomixer_mixer_type)) {
- audiomixer_mixer_obj_t* mixer = MP_OBJ_TO_PTR(sample_obj);
- return mixer->channel_count;
- #endif
- }
- return 1;
+ const audiosample_p_t *proto = mp_proto_get_or_throw(MP_QSTR_protocol_audiosample, sample_obj);
+ return proto->channel_count(MP_OBJ_TO_PTR(sample_obj));
}
void audiosample_reset_buffer(mp_obj_t sample_obj, bool single_channel, uint8_t audio_channel) {
- if (MP_OBJ_IS_TYPE(sample_obj, &audioio_rawsample_type)) {
- audioio_rawsample_obj_t* sample = MP_OBJ_TO_PTR(sample_obj);
- audioio_rawsample_reset_buffer(sample, single_channel, audio_channel);
- } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) {
- audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj);
- audioio_wavefile_reset_buffer(file, single_channel, audio_channel);
- #if CIRCUITPY_AUDIOMIXER
- } else if (MP_OBJ_IS_TYPE(sample_obj, &audiomixer_mixer_type)) {
- audiomixer_mixer_obj_t* file = MP_OBJ_TO_PTR(sample_obj);
- audiomixer_mixer_reset_buffer(file, single_channel, audio_channel);
- #endif
- }
+ const audiosample_p_t *proto = mp_proto_get_or_throw(MP_QSTR_protocol_audiosample, sample_obj);
+ proto->reset_buffer(MP_OBJ_TO_PTR(sample_obj), single_channel, audio_channel);
}
audioio_get_buffer_result_t audiosample_get_buffer(mp_obj_t sample_obj,
bool single_channel,
uint8_t channel,
uint8_t** buffer, uint32_t* buffer_length) {
- if (MP_OBJ_IS_TYPE(sample_obj, &audioio_rawsample_type)) {
- audioio_rawsample_obj_t* sample = MP_OBJ_TO_PTR(sample_obj);
- return audioio_rawsample_get_buffer(sample, single_channel, channel, buffer, buffer_length);
- } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) {
- audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj);
- return audioio_wavefile_get_buffer(file, single_channel, channel, buffer, buffer_length);
- #if CIRCUITPY_AUDIOMIXER
- } else if (MP_OBJ_IS_TYPE(sample_obj, &audiomixer_mixer_type)) {
- audiomixer_mixer_obj_t* file = MP_OBJ_TO_PTR(sample_obj);
- return audiomixer_mixer_get_buffer(file, single_channel, channel, buffer, buffer_length);
- #endif
- }
- return GET_BUFFER_DONE;
+ const audiosample_p_t *proto = mp_proto_get_or_throw(MP_QSTR_protocol_audiosample, sample_obj);
+ return proto->get_buffer(MP_OBJ_TO_PTR(sample_obj), single_channel, channel, buffer, buffer_length);
}
void audiosample_get_buffer_structure(mp_obj_t sample_obj, bool single_channel,
bool* single_buffer, bool* samples_signed,
uint32_t* max_buffer_length, uint8_t* spacing) {
- if (MP_OBJ_IS_TYPE(sample_obj, &audioio_rawsample_type)) {
- audioio_rawsample_obj_t* sample = MP_OBJ_TO_PTR(sample_obj);
- audioio_rawsample_get_buffer_structure(sample, single_channel, single_buffer,
- samples_signed, max_buffer_length, spacing);
- } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) {
- audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj);
- audioio_wavefile_get_buffer_structure(file, single_channel, single_buffer, samples_signed,
- max_buffer_length, spacing);
- #if CIRCUITPY_AUDIOMIXER
- } else if (MP_OBJ_IS_TYPE(sample_obj, &audiomixer_mixer_type)) {
- audiomixer_mixer_obj_t* file = MP_OBJ_TO_PTR(sample_obj);
- audiomixer_mixer_get_buffer_structure(file, single_channel, single_buffer, samples_signed,
- max_buffer_length, spacing);
- #endif
- }
+ const audiosample_p_t *proto = mp_proto_get_or_throw(MP_QSTR_protocol_audiosample, sample_obj);
+ proto->get_buffer_structure(MP_OBJ_TO_PTR(sample_obj), single_channel, single_buffer,
+ samples_signed, max_buffer_length, spacing);
}
diff --git a/shared-module/audiocore/__init__.h b/shared-module/audiocore/__init__.h
index 7aa0c1824..7a56454b8 100644
--- a/shared-module/audiocore/__init__.h
+++ b/shared-module/audiocore/__init__.h
@@ -31,6 +31,7 @@
#include <stdint.h>
#include "py/obj.h"
+#include "py/proto.h"
typedef enum {
GET_BUFFER_DONE, // No more data to read
@@ -38,6 +39,29 @@ typedef enum {
GET_BUFFER_ERROR, // Error while reading data.
} audioio_get_buffer_result_t;
+typedef uint32_t (*audiosample_sample_rate_fun)(mp_obj_t);
+typedef uint8_t (*audiosample_bits_per_sample_fun)(mp_obj_t);
+typedef uint8_t (*audiosample_channel_count_fun)(mp_obj_t);
+typedef void (*audiosample_reset_buffer_fun)(mp_obj_t,
+ bool single_channel, uint8_t audio_channel);
+typedef audioio_get_buffer_result_t (*audiosample_get_buffer_fun)(mp_obj_t,
+ bool single_channel, uint8_t channel, uint8_t** buffer,
+ uint32_t* buffer_length);
+typedef void (*audiosample_get_buffer_structure_fun)(mp_obj_t,
+ bool single_channel, bool* single_buffer,
+ bool* samples_signed, uint32_t *max_buffer_length,
+ uint8_t* spacing);
+
+typedef struct _audiosample_p_t {
+ MP_PROTOCOL_HEAD // MP_QSTR_protocol_audiosample
+ audiosample_sample_rate_fun sample_rate;
+ audiosample_bits_per_sample_fun bits_per_sample;
+ audiosample_channel_count_fun channel_count;
+ audiosample_reset_buffer_fun reset_buffer;
+ audiosample_get_buffer_fun get_buffer;
+ audiosample_get_buffer_structure_fun get_buffer_structure;
+} audiosample_p_t;
+
uint32_t audiosample_sample_rate(mp_obj_t sample_obj);
uint8_t audiosample_bits_per_sample(mp_obj_t sample_obj);
uint8_t audiosample_channel_count(mp_obj_t sample_obj);
diff --git a/shared-module/audiomixer/Mixer.c b/shared-module/audiomixer/Mixer.c
index a52489f85..4a72dab28 100644
--- a/shared-module/audiomixer/Mixer.c
+++ b/shared-module/audiomixer/Mixer.c
@@ -76,6 +76,14 @@ uint32_t common_hal_audiomixer_mixer_get_sample_rate(audiomixer_mixer_obj_t* sel
return self->sample_rate;
}
+uint8_t common_hal_audiomixer_mixer_get_channel_count(audiomixer_mixer_obj_t* self) {
+ return self->channel_count;
+}
+
+uint8_t common_hal_audiomixer_mixer_get_bits_per_sample(audiomixer_mixer_obj_t* self) {
+ return self->bits_per_sample;
+}
+
bool common_hal_audiomixer_mixer_get_playing(audiomixer_mixer_obj_t* self) {
for (uint8_t v = 0; v < self->voice_count; v++) {
if (common_hal_audiomixer_mixervoice_get_playing(MP_OBJ_TO_PTR(self->voice[v]))) {
@@ -93,198 +101,141 @@ void audiomixer_mixer_reset_buffer(audiomixer_mixer_obj_t* self,
}
}
-uint32_t add8signed(uint32_t a, uint32_t b) {
- #if (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) //Cortex-M4 w/FPU
- return __SHADD8(a, b);
- #else
- uint32_t result = 0;
- for (int8_t i = 0; i < 4; i++) {
- int8_t ai = a >> (sizeof(int8_t) * 8 * i);
- int8_t bi = b >> (sizeof(int8_t) * 8 * i);
- int32_t intermediate = (int32_t) ai + bi / 2;
- if (intermediate > CHAR_MAX) {
- intermediate = CHAR_MAX;
- } else if (intermediate < CHAR_MIN) {
- intermediate = CHAR_MIN;
- }
- result |= ((uint32_t) intermediate & 0xff) << (sizeof(int8_t) * 8 * i);
- }
- return result;
- #endif
+__attribute__((always_inline))
+static inline uint32_t add16signed(uint32_t a, uint32_t b) {
+ return __QADD16(a, b);
}
-uint32_t add8unsigned(uint32_t a, uint32_t b) {
- #if (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) //Cortex-M4 w/FPU
- return __UHADD8(a, b);
- #else
- uint32_t result = 0;
- for (int8_t i = 0; i < 4; i++) {
- uint8_t ai = (a >> (sizeof(uint8_t) * 8 * i));
- uint8_t bi = (b >> (sizeof(uint8_t) * 8 * i));
- int32_t intermediate = (int32_t) (ai + bi) / 2;
- if (intermediate > UCHAR_MAX) {
- intermediate = UCHAR_MAX;
- }
- result |= ((uint32_t) intermediate & 0xff) << (sizeof(uint8_t) * 8 * i);
- }
- return result;
- #endif
+__attribute__((always_inline))
+static inline uint32_t mult16signed(uint32_t val, int32_t mul) {
+ mul <<= 16;
+ int32_t hi, lo;
+ enum { bits = 16 }; // saturate to 16 bits
+ enum { shift = 15 }; // shift is done automatically
+ asm volatile("smulwb %0, %1, %2" : "=r" (lo) : "r" (mul), "r" (val));
+ asm volatile("smulwt %0, %1, %2" : "=r" (hi) : "r" (mul), "r" (val));
+ asm volatile("ssat %0, %1, %2, asr %3" : "=r" (lo) : "I" (bits), "r" (lo), "I" (shift));
+ asm volatile("ssat %0, %1, %2, asr %3" : "=r" (hi) : "I" (bits), "r" (hi), "I" (shift));
+ asm volatile("pkhbt %0, %1, %2, lsl #16" : "=r" (val) : "r" (lo), "r" (hi)); // pack
+ return val;
}
-uint32_t add16signed(uint32_t a, uint32_t b) {
- #if (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) //Cortex-M4 w/FPU
- return __SHADD16(a, b);
- #else
- uint32_t result = 0;
- for (int8_t i = 0; i < 2; i++) {
- int16_t ai = a >> (sizeof(int16_t) * 8 * i);
- int16_t bi = b >> (sizeof(int16_t) * 8 * i);
- int32_t intermediate = (int32_t) ai + bi / 2;
- if (intermediate > SHRT_MAX) {
- intermediate = SHRT_MAX;
- } else if (intermediate < SHRT_MIN) {
- intermediate = SHRT_MIN;
- }
- result |= (((uint32_t) intermediate) & 0xffff) << (sizeof(int16_t) * 8 * i);
- }
- return result;
- #endif
+static inline uint32_t tounsigned8(uint32_t val) {
+ return __UADD8(val, 0x80808080);
}
-uint32_t add16unsigned(uint32_t a, uint32_t b) {
- #if (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) //Cortex-M4 w/FPU
- return __UHADD16(a, b);
- #else
- uint32_t result = 0;
- for (int8_t i = 0; i < 2; i++) {
- int16_t ai = (a >> (sizeof(uint16_t) * 8 * i)) - 0x8000;
- int16_t bi = (b >> (sizeof(uint16_t) * 8 * i)) - 0x8000;
- int32_t intermediate = (int32_t) ai + bi / 2;
- if (intermediate > USHRT_MAX) {
- intermediate = USHRT_MAX;
- }
- result |= ((uint32_t) intermediate & 0xffff) << (sizeof(int16_t) * 8 * i);
- }
- return result;
- #endif
+static inline uint32_t tounsigned16(uint32_t val) {
+ return __UADD16(val, 0x80008000);
}
-static inline uint32_t mult8unsigned(uint32_t val, int32_t mul) {
- // if mul == 0, no need in wasting cycles
- if (mul == 0) {
- return 0;
- }
- /* TODO: workout ARMv7 instructions
- #if (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) //Cortex-M4 w/FPU
- return val;
- #else*/
- uint32_t result = 0;
- float mod_mul = (float) mul / (float) ((1<<15)-1);
- for (int8_t i = 0; i < 4; i++) {
- uint8_t ai = val >> (sizeof(uint8_t) * 8 * i);
- int32_t intermediate = ai * mod_mul;
- if (intermediate > SHRT_MAX) {
- intermediate = SHRT_MAX;
- }
- result |= ((uint32_t) intermediate & 0xff) << (sizeof(uint8_t) * 8 * i);
- }
+static inline uint32_t tosigned16(uint32_t val) {
+ return __UADD16(val, 0x80008000);
+}
- return result;
- //#endif
+static inline uint32_t unpack8(uint16_t val) {
+ return ((val & 0xff00) << 16) | ((val & 0x00ff) << 8);
}
-static inline uint32_t mult8signed(uint32_t val, int32_t mul) {
- // if mul == 0, no need in wasting cycles
- if (mul == 0) {
- return 0;
- }
- /* TODO: workout ARMv7 instructions
- #if (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) //Cortex-M4 w/FPU
- return val;
- #else
- */
- uint32_t result = 0;
- float mod_mul = (float)mul / (float)((1<<15)-1);
- for (int8_t i = 0; i < 4; i++) {
- int16_t ai = val >> (sizeof(int8_t) * 8 * i);
- int32_t intermediate = ai * mod_mul;
- if (intermediate > CHAR_MAX) {
- intermediate = CHAR_MAX;
- } else if (intermediate < CHAR_MIN) {
- intermediate = CHAR_MIN;
- }
- result |= (((uint32_t) intermediate) & 0xff) << (sizeof(int16_t) * 8 * i);
- }
- return result;
- //#endif
+static inline uint32_t pack8(uint32_t val) {
+ return ((val & 0xff000000) >> 16) | ((val & 0xff00) >> 8);
}
-//TODO:
-static inline uint32_t mult16unsigned(uint32_t val, int32_t mul) {
- // if mul == 0, no need in wasting cycles
- if (mul == 0) {
- return 0;
- }
- /* TODO: the below ARMv7m instructions "work", but the amplitude is much higher/louder
- #if (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) //Cortex-M4 w/FPU
- // there is no unsigned equivalent to the 'SMULWx' ARMv7 Thumb function,
- // so we have to do it by hand.
- uint32_t lo = val & 0xffff;
- uint32_t hi = val >> 16;
- //mp_printf(&mp_plat_print, "pre-asm: (mul: %d)\n\tval: %x\tlo: %x\thi: %x\n", mul, val, lo, hi);
- uint32_t val_lo;
- asm volatile("mul %0, %1, %2" : "=r" (val_lo) : "r" (mul), "r" (lo));
- asm volatile("mla %0, %1, %2, %3" : "=r" (val) : "r" (mul), "r" (hi), "r" (val_lo));
- //mp_printf(&mp_plat_print, "post-asm:\n\tval: %x\tlo: %x\n\n", val, val_lo);
- return val;
- #else
- */
- uint32_t result = 0;
- float mod_mul = (float)mul / (float)((1<<15)-1);
- for (int8_t i = 0; i < 2; i++) {
- int16_t ai = (val >> (sizeof(uint16_t) * 8 * i)) - 0x8000;
- int32_t intermediate = ai * mod_mul;
- if (intermediate > SHRT_MAX) {
- intermediate = SHRT_MAX;
- } else if (intermediate < SHRT_MIN) {
- intermediate = SHRT_MIN;
+static void mix_down_one_voice(audiomixer_mixer_obj_t* self,
+ audiomixer_mixervoice_obj_t* voice, bool voices_active,
+ uint32_t* word_buffer, uint32_t length) {
+ bool voice_done = voice->sample == NULL;
+ while (!voice_done && length != 0) {
+ if (voice->buffer_length == 0) {
+ if (!voice->more_data) {
+ if (voice->loop) {
+ audiosample_reset_buffer(voice->sample, false, 0);
+ } else {
+ voice->sample = NULL;
+ voice_done = true;
+ break;
+ }
+ }
+ if (!voice_done) {
+ // Load another buffer
+ audioio_get_buffer_result_t result = audiosample_get_buffer(voice->sample, false, 0, (uint8_t**) &voice->remaining_buffer, &voice->buffer_length);
+ // Track length in terms of words.
+ voice->buffer_length /= sizeof(uint32_t);
+ voice->more_data = result == GET_BUFFER_MORE_DATA;
+ }
}
- result |= (((uint32_t) intermediate) + 0x8000) << (sizeof(int16_t) * 8 * i);
- }
- return result;
- //#endif
-}
-static inline uint32_t mult16signed(uint32_t val, int32_t mul) {
- // if mul == 0, no need in wasting cycles
- if (mul == 0) {
- return 0;
+ uint32_t n = MIN(voice->buffer_length, length);
+ uint32_t *src = voice->remaining_buffer;
+ uint16_t level = voice->level;
+
+ // First active voice gets copied over verbatim.
+ if (!voices_active) {
+ if (MP_LIKELY(self->bits_per_sample == 16)) {
+ if (MP_LIKELY(self->samples_signed)) {
+ for (uint32_t i = 0; i<n; i++) {
+ uint32_t v = src[i];
+ word_buffer[i] = mult16signed(v, level);
+ }
+ } else {
+ for (uint32_t i = 0; i<n; i++) {
+ uint32_t v = src[i];
+ v = tosigned16(v);
+ word_buffer[i] = mult16signed(v, level);
+ }
+ }
+ } else {
+ uint16_t *hword_buffer = (uint16_t*)word_buffer;
+ uint16_t *hsrc = (uint16_t*)src;
+ for (uint32_t i = 0; i<n*2; i++) {
+ uint32_t word = unpack8(hsrc[i]);
+ if (MP_LIKELY(!self->samples_signed)) {
+ word = tosigned16(word);
+ }
+ word = mult16signed(word, level);
+ hword_buffer[i] = pack8(word);
+ }
+ }
+ } else {
+ if (MP_LIKELY(self->bits_per_sample == 16)) {
+ if (MP_LIKELY(self->samples_signed)) {
+ for (uint32_t i = 0; i<n; i++) {
+ uint32_t word = src[i];
+ word_buffer[i] = add16signed(mult16signed(word, level), word_buffer[i]);
+ }
+ } else {
+ for (uint32_t i = 0; i<n; i++) {
+ uint32_t word = src[i];
+ word = tosigned16(word);
+ word_buffer[i] = add16signed(mult16signed(word, level), word_buffer[i]);
+ }
+ }
+ } else {
+ uint16_t *hword_buffer = (uint16_t*)word_buffer;
+ uint16_t *hsrc = (uint16_t*)src;
+ for (uint32_t i = 0; i<n*2; i++) {
+ uint32_t word = unpack8(hsrc[i]);
+ if (MP_LIKELY(!self->samples_signed)) {
+ word = tosigned16(word);
+ }
+ word = mult16signed(word, level);
+ word = add16signed(word, unpack8(hword_buffer[i]));
+ hword_buffer[i] = pack8(word);
+ }
+ }
+ }
+ length -= n;
+ word_buffer += n;
+ voice->remaining_buffer += n;
+ voice->buffer_length -= n;
}
- #if (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) //Cortex-M4 w/FPU
- int32_t hi, lo;
- enum { bits = 16 }; // saturate to 16 bits
- enum { shift = 0 }; // shift is done automatically
- asm volatile("smulwb %0, %1, %2" : "=r" (lo) : "r" (mul), "r" (val));
- asm volatile("smulwt %0, %1, %2" : "=r" (hi) : "r" (mul), "r" (val));
- asm volatile("ssat %0, %1, %2, asr %3" : "=r" (lo) : "I" (bits), "r" (lo), "I" (shift));
- asm volatile("ssat %0, %1, %2, asr %3" : "=r" (hi) : "I" (bits), "r" (hi), "I" (shift));
- asm volatile("pkhbt %0, %1, %2, lsl #16" : "=r" (val) : "r" (lo), "r" (hi)); // pack
- return val;
- #else
- uint32_t result = 0;
- float mod_mul = (float)mul / (float)((1<<15)-1);
- for (int8_t i = 0; i < 2; i++) {
- int16_t ai = val >> (sizeof(int16_t) * 8 * i);
- int32_t intermediate = ai * mod_mul;
- if (intermediate > SHRT_MAX) {
- intermediate = SHRT_MAX;
- } else if (intermediate < SHRT_MIN) {
- intermediate = SHRT_MIN;
+
+ if (length && !voices_active) {
+ uint32_t sample_value = self->bits_per_sample == 8
+ ? 0x80808080 : 0x80008000;
+ for (uint32_t i = 0; i<length; i++) {
+ word_buffer[i] = sample_value;
}
- result |= (((uint32_t) intermediate) & 0xffff) << (sizeof(int16_t) * 8 * i);
}
- return result;
- #endif
}
audioio_get_buffer_result_t audiomixer_mixer_get_buffer(audiomixer_mixer_obj_t* self,
@@ -314,87 +265,25 @@ audioio_get_buffer_result_t audiomixer_mixer_get_buffer(audiomixer_mixer_obj_t*
}
self->use_first_buffer = !self->use_first_buffer;
bool voices_active = false;
+ uint32_t length = self->len / sizeof(uint32_t);
+
for (int32_t v = 0; v < self->voice_count; v++) {
audiomixer_mixervoice_obj_t* voice = MP_OBJ_TO_PTR(self->voice[v]);
- uint32_t j = 0;
- bool voice_done = voice->sample == NULL;
- for (uint32_t i = 0; i < self->len / sizeof(uint32_t); i++) {
- if (!voice_done && j >= voice->buffer_length) {
- if (!voice->more_data) {
- if (voice->loop) {
- audiosample_reset_buffer(voice->sample, false, 0);
- } else {
- voice->sample = NULL;
- voice_done = true;
- }
- }
- if (!voice_done) {
- // Load another buffer
- audioio_get_buffer_result_t result = audiosample_get_buffer(voice->sample, false, 0, (uint8_t**) &voice->remaining_buffer, &voice->buffer_length);
- // Track length in terms of words.
- voice->buffer_length /= sizeof(uint32_t);
- voice->more_data = result == GET_BUFFER_MORE_DATA;
- j = 0;
- }
- }
- // First active voice gets copied over verbatim.
- uint32_t sample_value;
- if (voice_done) {
- // Exit early if another voice already set all samples once.
- if (voices_active) {
- continue;
- }
- sample_value = 0;
- if (!self->samples_signed) {
- if (self->bits_per_sample == 8) {
- sample_value = 0x7f7f7f7f;
- } else {
- sample_value = 0x7fff7fff;
- }
- }
- } else {
- sample_value = voice->remaining_buffer[j];
- }
+ mix_down_one_voice(self, voice, voices_active, word_buffer, length);
+ voices_active = true;
+ }
- // apply the mixer level
- if (!self->samples_signed) {
- if (self->bits_per_sample == 8) {
- sample_value = mult8unsigned(sample_value, voice->level);
- } else {
- sample_value = mult16unsigned(sample_value, voice->level);
- }
- } else {
- if (self->bits_per_sample == 8) {
- sample_value = mult8signed(sample_value, voice->level);
- } else {
- sample_value = mult16signed(sample_value, voice->level);
- }
+ if (!self->samples_signed) {
+ if (self->bits_per_sample == 16) {
+ for (uint32_t i = 0; i < length; i++) {
+ word_buffer[i] = tounsigned16(word_buffer[i]);
}
-
- if (!voices_active) {
- word_buffer[i] = sample_value;
- } else {
- if (self->bits_per_sample == 8) {
- if (self->samples_signed) {
- word_buffer[i] = add8signed(word_buffer[i], sample_value);
- } else {
- word_buffer[i] = add8unsigned(word_buffer[i], sample_value);
- }
- } else {
- if (self->samples_signed) {
- word_buffer[i] = add16signed(word_buffer[i], sample_value);
- } else {
- word_buffer[i] = add16unsigned(word_buffer[i], sample_value);
- }
- }
+ } else {
+ for (uint32_t i = 0; i < length; i++) {
+ word_buffer[i] = tounsigned8(word_buffer[i]);
}
- j++;
}
- voice->buffer_length -= j;
- voice->remaining_buffer += j;
-
- voices_active = true;
}
self->read_count += 1;
diff --git a/shared-module/audiomixer/MixerVoice.c b/shared-module/audiomixer/MixerVoice.c
index ff05dc93e..9be104afc 100644
--- a/shared-module/audiomixer/MixerVoice.c
+++ b/shared-module/audiomixer/MixerVoice.c
@@ -34,7 +34,7 @@
void common_hal_audiomixer_mixervoice_construct(audiomixer_mixervoice_obj_t *self) {
self->sample = NULL;
- self->level = ((1 << 15) - 1);
+ self->level = 1 << 15;
}
void common_hal_audiomixer_mixervoice_set_parent(audiomixer_mixervoice_obj_t* self, audiomixer_mixer_obj_t *parent) {
@@ -42,11 +42,11 @@ void common_hal_audiomixer_mixervoice_set_parent(audiomixer_mixervoice_obj_t* se
}
float common_hal_audiomixer_mixervoice_get_level(audiomixer_mixervoice_obj_t* self) {
- return ((float) self->level / ((1 << 15) - 1));
+ return ((float) self->level / (1 << 15));
}
void common_hal_audiomixer_mixervoice_set_level(audiomixer_mixervoice_obj_t* self, float level) {
- self->level = level * ((1 << 15)-1);
+ self->level = level * (1 << 15);
}
void common_hal_audiomixer_mixervoice_play(audiomixer_mixervoice_obj_t* self, mp_obj_t sample, bool loop) {
diff --git a/shared-module/audiomixer/MixerVoice.h b/shared-module/audiomixer/MixerVoice.h
index efac19156..a85316e3d 100644
--- a/shared-module/audiomixer/MixerVoice.h
+++ b/shared-module/audiomixer/MixerVoice.h
@@ -39,7 +39,7 @@ typedef struct {
bool more_data;
uint32_t* remaining_buffer;
uint32_t buffer_length;
- int16_t level;
+ uint16_t level;
} audiomixer_mixervoice_obj_t;
diff --git a/shared-module/audiomp3/MP3Decoder.c b/shared-module/audiomp3/MP3Decoder.c
new file mode 100644
index 000000000..30357c616
--- /dev/null
+++ b/shared-module/audiomp3/MP3Decoder.c
@@ -0,0 +1,352 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ * Copyright (c) 2019 Jeff Epler for Adafruit Industries
+ *
+ * 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 "shared-bindings/audiomp3/MP3Decoder.h"
+
+#include <stdint.h>
+#include <string.h>
+#include <math.h>
+
+#include "py/mperrno.h"
+#include "py/runtime.h"
+
+#include "shared-module/audiomp3/MP3Decoder.h"
+#include "supervisor/shared/translate.h"
+#include "lib/mp3/src/mp3common.h"
+
+#define MAX_BUFFER_LEN (MAX_NSAMP * MAX_NGRAN * MAX_NCHAN * sizeof(int16_t))
+
+/** Fill the input buffer if it is less than half full.
+ *
+ * Returns true if the input buffer contains any useful data,
+ * false otherwise. (The input buffer will be padded to the end with
+ * 0 bytes, which do not interfere with MP3 decoding)
+ *
+ * Raises OSError if f_read fails.
+ *
+ * Sets self->eof if any read of the file returns 0 bytes
+ */
+STATIC bool mp3file_update_inbuf(audiomp3_mp3file_obj_t* self) {
+ // If buffer is over half full, do nothing
+ if (self->inbuf_offset < self->inbuf_length/2) return true;
+
+ // If we didn't previously reach the end of file, we can try reading now
+ if (!self->eof) {
+
+ // Move the unconsumed portion of the buffer to the start
+ uint8_t *end_of_buffer = self->inbuf + self->inbuf_length;
+ uint8_t *new_end_of_data = self->inbuf + self->inbuf_length - self->inbuf_offset;
+ memmove(self->inbuf, self->inbuf + self->inbuf_offset,
+ self->inbuf_length - self->inbuf_offset);
+ self->inbuf_offset = 0;
+
+ UINT to_read = end_of_buffer - new_end_of_data;
+ UINT bytes_read = 0;
+ memset(new_end_of_data, 0, to_read);
+ if (f_read(&self->file->fp, new_end_of_data, to_read, &bytes_read) != FR_OK) {
+ self->eof = true;
+ mp_raise_OSError(MP_EIO);
+ }
+
+ if (bytes_read == 0) {
+ self->eof = true;
+ }
+
+ if (to_read != bytes_read) {
+ new_end_of_data += bytes_read;
+ memset(new_end_of_data, 0, end_of_buffer - new_end_of_data);
+ }
+
+ }
+
+ // Return true iff there are at least some useful bytes in the buffer
+ return self->inbuf_offset < self->inbuf_length;
+}
+
+#define READ_PTR(self) (self->inbuf + self->inbuf_offset)
+#define BYTES_LEFT(self) (self->inbuf_length - self->inbuf_offset)
+#define CONSUME(self, n) (self->inbuf_offset += n)
+
+// http://id3.org/d3v2.3.0
+// http://id3.org/id3v2.3.0
+STATIC void mp3file_skip_id3v2(audiomp3_mp3file_obj_t* self) {
+ mp3file_update_inbuf(self);
+ if (BYTES_LEFT(self) < 10) {
+ return;
+ }
+ uint8_t *data = READ_PTR(self);
+ if (!(
+ data[0] == 'I' &&
+ data[1] == 'D' &&
+ data[2] == '3' &&
+ data[3] != 0xff &&
+ data[4] != 0xff &&
+ (data[5] & 0x1f) == 0 &&
+ (data[6] & 0x80) == 0 &&
+ (data[7] & 0x80) == 0 &&
+ (data[8] & 0x80) == 0 &&
+ (data[9] & 0x80) == 0)) {
+ return;
+ }
+ uint32_t size = (data[6] << 21) | (data[7] << 14) | (data[8] << 7) | (data[9]);
+ size += 10; // size excludes the "header" (but not the "extended header")
+ // First, deduct from size whatever is left in buffer
+ uint32_t to_consume = MIN(size, BYTES_LEFT(self));
+ CONSUME(self, to_consume);
+ size -= to_consume;
+
+ // Next, seek in the file after the header
+ f_lseek(&self->file->fp, f_tell(&self->file->fp) + size);
+ return;
+}
+
+/* If a sync word can be found, advance to it and return true. Otherwise,
+ * return false.
+ */
+STATIC bool mp3file_find_sync_word(audiomp3_mp3file_obj_t* self) {
+ do {
+ mp3file_update_inbuf(self);
+ int offset = MP3FindSyncWord(READ_PTR(self), BYTES_LEFT(self));
+ if (offset >= 0) {
+ CONSUME(self, offset);
+ mp3file_update_inbuf(self);
+ return true;
+ }
+ CONSUME(self, MAX(0, BYTES_LEFT(self) - 16));
+ } while (!self->eof);
+ return false;
+}
+
+STATIC bool mp3file_get_next_frame_info(audiomp3_mp3file_obj_t* self, MP3FrameInfo* fi) {
+ int err;
+ do {
+ err = MP3GetNextFrameInfo(self->decoder, fi, READ_PTR(self));
+ if (err == ERR_MP3_NONE) {
+ break;
+ }
+ CONSUME(self, 1);
+ mp3file_find_sync_word(self);
+ } while (!self->eof);
+ return err == ERR_MP3_NONE;
+}
+
+void common_hal_audiomp3_mp3file_construct(audiomp3_mp3file_obj_t* self,
+ pyb_file_obj_t* file,
+ uint8_t *buffer,
+ size_t buffer_size) {
+ // XXX Adafruit_MP3 uses a 2kB input buffer and two 4kB output buffers.
+ // for a whopping total of 10kB buffers (+mp3 decoder state and frame buffer)
+ // At 44kHz, that's 23ms of output audio data.
+ //
+ // We will choose a slightly different allocation strategy for the output:
+ // Make sure the buffers are sized exactly to match (a multiple of) the
+ // frame size; this is typically 2304 * 2 bytes, so a little bit bigger
+ // than the two 4kB output buffers, except that the alignment allows to
+ // never allocate that extra frame buffer.
+
+ self->inbuf_length = 2048;
+ self->inbuf_offset = self->inbuf_length;
+ self->inbuf = m_malloc(self->inbuf_length, false);
+ if (self->inbuf == NULL) {
+ common_hal_audiomp3_mp3file_deinit(self);
+ mp_raise_msg(&mp_type_MemoryError,
+ translate("Couldn't allocate input buffer"));
+ }
+ self->decoder = MP3InitDecoder();
+ if (self->decoder == NULL) {
+ common_hal_audiomp3_mp3file_deinit(self);
+ mp_raise_msg(&mp_type_MemoryError,
+ translate("Couldn't allocate decoder"));
+ }
+
+ if ((intptr_t)buffer & 1) {
+ buffer += 1; buffer_size -= 1;
+ }
+ if (buffer_size >= 2 * MAX_BUFFER_LEN) {
+ self->buffers[0] = (int16_t*)(void*)buffer;
+ self->buffers[1] = (int16_t*)(void*)(buffer + MAX_BUFFER_LEN);
+ } else {
+ self->buffers[0] = m_malloc(MAX_BUFFER_LEN, false);
+ if (self->buffers[0] == NULL) {
+ common_hal_audiomp3_mp3file_deinit(self);
+ mp_raise_msg(&mp_type_MemoryError,
+ translate("Couldn't allocate first buffer"));
+ }
+
+ self->buffers[1] = m_malloc(MAX_BUFFER_LEN, false);
+ if (self->buffers[1] == NULL) {
+ common_hal_audiomp3_mp3file_deinit(self);
+ mp_raise_msg(&mp_type_MemoryError,
+ translate("Couldn't allocate second buffer"));
+ }
+ }
+
+ common_hal_audiomp3_mp3file_set_file(self, file);
+}
+
+void common_hal_audiomp3_mp3file_set_file(audiomp3_mp3file_obj_t* self, pyb_file_obj_t* file) {
+ self->file = file;
+ f_lseek(&self->file->fp, 0);
+ self->inbuf_offset = self->inbuf_length;
+ self->eof = 0;
+ self->other_channel = -1;
+ mp3file_update_inbuf(self);
+ mp3file_find_sync_word(self);
+ // It **SHOULD** not be necessary to do this; the buffer should be filled
+ // with fresh content before it is returned by get_buffer(). The fact that
+ // this is necessary to avoid a glitch at the start of playback of a second
+ // track using the same decoder object means there's still a bug in
+ // get_buffer() that I didn't understand.
+ memset(self->buffers[0], 0, MAX_BUFFER_LEN);
+ memset(self->buffers[1], 0, MAX_BUFFER_LEN);
+ MP3FrameInfo fi;
+ if(!mp3file_get_next_frame_info(self, &fi)) {
+ mp_raise_msg(&mp_type_RuntimeError,
+ translate("Failed to parse MP3 file"));
+ }
+
+ self->sample_rate = fi.samprate;
+ self->channel_count = fi.nChans;
+ self->frame_buffer_size = fi.outputSamps*sizeof(int16_t);
+ self->len = 2 * self->frame_buffer_size;
+}
+
+void common_hal_audiomp3_mp3file_deinit(audiomp3_mp3file_obj_t* self) {
+ MP3FreeDecoder(self->decoder);
+ self->decoder = NULL;
+ self->inbuf = NULL;
+ self->buffers[0] = NULL;
+ self->buffers[1] = NULL;
+ self->file = NULL;
+}
+
+bool common_hal_audiomp3_mp3file_deinited(audiomp3_mp3file_obj_t* self) {
+ return self->buffers[0] == NULL;
+}
+
+uint32_t common_hal_audiomp3_mp3file_get_sample_rate(audiomp3_mp3file_obj_t* self) {
+ return self->sample_rate;
+}
+
+void common_hal_audiomp3_mp3file_set_sample_rate(audiomp3_mp3file_obj_t* self,
+ uint32_t sample_rate) {
+ self->sample_rate = sample_rate;
+}
+
+uint8_t common_hal_audiomp3_mp3file_get_bits_per_sample(audiomp3_mp3file_obj_t* self) {
+ return 16;
+}
+
+uint8_t common_hal_audiomp3_mp3file_get_channel_count(audiomp3_mp3file_obj_t* self) {
+ return self->channel_count;
+}
+
+bool audiomp3_mp3file_samples_signed(audiomp3_mp3file_obj_t* self) {
+ return true;
+}
+
+void audiomp3_mp3file_reset_buffer(audiomp3_mp3file_obj_t* self,
+ bool single_channel,
+ uint8_t channel) {
+ if (single_channel && channel == 1) {
+ return;
+ }
+ // We don't reset the buffer index in case we're looping and we have an odd number of buffer
+ // loads
+ f_lseek(&self->file->fp, 0);
+ self->inbuf_offset = self->inbuf_length;
+ self->eof = 0;
+ self->other_channel = -1;
+ mp3file_update_inbuf(self);
+ mp3file_skip_id3v2(self);
+ mp3file_find_sync_word(self);
+}
+
+audioio_get_buffer_result_t audiomp3_mp3file_get_buffer(audiomp3_mp3file_obj_t* self,
+ bool single_channel,
+ uint8_t channel,
+ uint8_t** bufptr,
+ uint32_t* buffer_length) {
+ if (!self->inbuf) {
+ return GET_BUFFER_ERROR;
+ }
+ if (!single_channel) {
+ channel = 0;
+ }
+
+ *buffer_length = self->frame_buffer_size;
+
+ if (channel == self->other_channel) {
+ *bufptr = (uint8_t*)(self->buffers[self->other_buffer_index] + channel);
+ self->other_channel = -1;
+ return GET_BUFFER_MORE_DATA;
+ }
+
+
+ self->buffer_index = !self->buffer_index;
+ self->other_channel = 1-channel;
+ self->other_buffer_index = self->buffer_index;
+ int16_t *buffer = (int16_t *)(void *)self->buffers[self->buffer_index];
+ *bufptr = (uint8_t*)buffer;
+
+ mp3file_skip_id3v2(self);
+ if (!mp3file_find_sync_word(self)) {
+ return self->eof ? GET_BUFFER_DONE : GET_BUFFER_ERROR;
+ }
+ int bytes_left = BYTES_LEFT(self);
+ uint8_t *inbuf = READ_PTR(self);
+ int err = MP3Decode(self->decoder, &inbuf, &bytes_left, buffer, 0);
+ CONSUME(self, BYTES_LEFT(self) - bytes_left);
+ if (err) {
+ return GET_BUFFER_DONE;
+ }
+
+ return GET_BUFFER_MORE_DATA;
+}
+
+void audiomp3_mp3file_get_buffer_structure(audiomp3_mp3file_obj_t* self, bool single_channel,
+ bool* single_buffer, bool* samples_signed,
+ uint32_t* max_buffer_length, uint8_t* spacing) {
+ *single_buffer = false;
+ *samples_signed = true;
+ *max_buffer_length = self->frame_buffer_size;
+ if (single_channel) {
+ *spacing = self->channel_count;
+ } else {
+ *spacing = 1;
+ }
+}
+
+float common_hal_audiomp3_mp3file_get_rms_level(audiomp3_mp3file_obj_t* self) {
+ float sumsq = 0.f;
+ // Assumes no DC component to the audio. Is that a safe assumption?
+ int16_t *buffer = (int16_t *)(void *)self->buffers[self->buffer_index];
+ for(size_t i=0; i<self->frame_buffer_size / sizeof(int16_t); i++) {
+ sumsq += (float)buffer[i] * buffer[i];
+ }
+ return sqrtf(sumsq) / (self->frame_buffer_size / sizeof(int16_t));
+}
diff --git a/shared-module/audiomp3/MP3Decoder.h b/shared-module/audiomp3/MP3Decoder.h
new file mode 100644
index 000000000..9ee1d0949
--- /dev/null
+++ b/shared-module/audiomp3/MP3Decoder.h
@@ -0,0 +1,72 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft
+ * Copyright (c) 2019 Jeff Epler for Adafruit Industries
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_MP3FILE_H
+#define MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_MP3FILE_H
+
+#include "extmod/vfs_fat.h"
+#include "py/obj.h"
+
+#include "shared-module/audiocore/__init__.h"
+
+typedef struct {
+ mp_obj_base_t base;
+ struct _MP3DecInfo *decoder;
+ uint8_t* inbuf;
+ uint32_t inbuf_length;
+ uint32_t inbuf_offset;
+ int16_t* buffers[2];
+ uint32_t len;
+ uint32_t frame_buffer_size;
+
+ uint32_t sample_rate;
+ pyb_file_obj_t* file;
+
+ uint8_t buffer_index;
+ uint8_t channel_count;
+ bool eof;
+
+ int8_t other_channel;
+ int8_t other_buffer_index;
+} audiomp3_mp3file_obj_t;
+
+// These are not available from Python because it may be called in an interrupt.
+void audiomp3_mp3file_reset_buffer(audiomp3_mp3file_obj_t* self,
+ bool single_channel,
+ uint8_t channel);
+audioio_get_buffer_result_t audiomp3_mp3file_get_buffer(audiomp3_mp3file_obj_t* self,
+ bool single_channel,
+ uint8_t channel,
+ uint8_t** buffer,
+ uint32_t* buffer_length); // length in bytes
+void audiomp3_mp3file_get_buffer_structure(audiomp3_mp3file_obj_t* self, bool single_channel,
+ bool* single_buffer, bool* samples_signed,
+ uint32_t* max_buffer_length, uint8_t* spacing);
+
+float audiomp3_mp3file_get_rms_level(audiomp3_mp3file_obj_t* self);
+
+#endif // MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_MP3FILE_H
diff --git a/shared-module/audiomp3/__init__.c b/shared-module/audiomp3/__init__.c
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/shared-module/audiomp3/__init__.c
diff --git a/shared-module/audiomp3/__init__.h b/shared-module/audiomp3/__init__.h
new file mode 100644
index 000000000..e7b1f3aab
--- /dev/null
+++ b/shared-module/audiomp3/__init__.h
@@ -0,0 +1,30 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Jeff Epler for Adafruit Industries
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_MODULE_AUDIOMP3__INIT__H
+#define MICROPY_INCLUDED_SHARED_MODULE_AUDIOMP3__INIT__H
+
+#endif // MICROPY_INCLUDED_SHARED_MODULE_AUDIOMP3__INIT__H
diff --git a/shared-module/board/__init__.c b/shared-module/board/__init__.c
index dd07d7190..bbf177384 100644
--- a/shared-module/board/__init__.c
+++ b/shared-module/board/__init__.c
@@ -100,8 +100,30 @@ mp_obj_t common_hal_board_create_uart(void) {
const mcu_pin_obj_t* rx = MP_OBJ_TO_PTR(DEFAULT_UART_BUS_RX);
const mcu_pin_obj_t* tx = MP_OBJ_TO_PTR(DEFAULT_UART_BUS_TX);
+#ifdef DEFAULT_UART_BUS_RTS
+ const mcu_pin_obj_t* rts = MP_OBJ_TO_PTR(DEFAULT_UART_BUS_RTS);
+#else
+ const mcu_pin_obj_t* rts = mp_const_none;
+#endif
+#ifdef DEFAULT_UART_BUS_CTS
+ const mcu_pin_obj_t* cts = MP_OBJ_TO_PTR(DEFAULT_UART_BUS_CTS);
+#else
+ const mcu_pin_obj_t* cts = mp_const_none;
+#endif
+#ifdef DEFAULT_UART_IS_RS485
+ const mcu_pin_obj_t* rs485_dir = MP_OBJ_TO_PTR(DEFAULT_UART_BUS_RS485DIR);
+#ifdef DEFAULT_UART_RS485_INVERT
+ const bool rs485_invert = true;
+#else
+ const bool rs485_invert = false;
+#endif
+#else
+ const mcu_pin_obj_t* rs485_dir = mp_const_none;
+ const bool rs485_invert = false;
+#endif
- common_hal_busio_uart_construct(self, tx, rx, 9600, 8, PARITY_NONE, 1, 1000, 64);
+ common_hal_busio_uart_construct(self, tx, rx, rts, cts, rs485_dir, rs485_invert,
+ 9600, 8, PARITY_NONE, 1, 1.0f, 64);
MP_STATE_VM(shared_uart_bus) = MP_OBJ_FROM_PTR(self);
return MP_STATE_VM(shared_uart_bus);
}
diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c
index 862d2cf59..299c8ad35 100644
--- a/shared-module/displayio/Display.c
+++ b/shared-module/displayio/Display.c
@@ -35,6 +35,7 @@
#include "shared-module/displayio/__init__.h"
#include "shared-module/displayio/display_core.h"
#include "supervisor/shared/display.h"
+#include "supervisor/shared/tick.h"
#include "supervisor/usb.h"
#include <stdint.h>
@@ -307,13 +308,30 @@ STATIC void _refresh_display(displayio_display_obj_t* self) {
displayio_display_core_finish_refresh(&self->core);
}
+void common_hal_displayio_display_set_rotation(displayio_display_obj_t* self, int rotation){
+ bool transposed = (self->core.rotation == 90 || self->core.rotation == 270);
+ bool will_transposed = (rotation == 90 || rotation == 270);
+ if(transposed != will_transposed) {
+ int tmp = self->core.width;
+ self->core.width = self->core.height;
+ self->core.height = tmp;
+ }
+ displayio_display_core_set_rotation(&self->core, rotation);
+ supervisor_stop_terminal();
+ supervisor_start_terminal(self->core.width, self->core.height);
+ if (self->core.current_group != NULL) {
+ displayio_group_update_transform(self->core.current_group, &self->core.transform);
+ }
+}
+
uint16_t common_hal_displayio_display_get_rotation(displayio_display_obj_t* self){
return self->core.rotation;
}
+
bool common_hal_displayio_display_refresh(displayio_display_obj_t* self, uint32_t target_ms_per_frame, uint32_t maximum_ms_per_real_frame) {
if (!self->auto_refresh && !self->first_manual_refresh) {
- uint64_t current_time = ticks_ms;
+ uint64_t current_time = supervisor_ticks_ms64();
uint32_t current_ms_since_real_refresh = current_time - self->core.last_refresh;
// Test to see if the real frame time is below our minimum.
if (current_ms_since_real_refresh > maximum_ms_per_real_frame) {
@@ -327,7 +345,7 @@ bool common_hal_displayio_display_refresh(displayio_display_obj_t* self, uint32_
}
uint32_t remaining_time = target_ms_per_frame - (current_ms_since_real_refresh % target_ms_per_frame);
// We're ahead of the game so wait until we align with the frame rate.
- while (ticks_ms - self->last_refresh_call < remaining_time) {
+ while (supervisor_ticks_ms64() - self->last_refresh_call < remaining_time) {
RUN_BACKGROUND_TASKS;
}
}
@@ -350,20 +368,20 @@ STATIC void _update_backlight(displayio_display_obj_t* self) {
if (!self->auto_brightness || self->updating_backlight) {
return;
}
- if (ticks_ms - self->last_backlight_refresh < 100) {
+ if (supervisor_ticks_ms64() - self->last_backlight_refresh < 100) {
return;
}
// TODO(tannewt): Fade the backlight based on it's existing value and a target value. The target
// should account for ambient light when possible.
common_hal_displayio_display_set_brightness(self, 1.0);
- self->last_backlight_refresh = ticks_ms;
+ self->last_backlight_refresh = supervisor_ticks_ms64();
}
void displayio_display_background(displayio_display_obj_t* self) {
_update_backlight(self);
- if (self->auto_refresh && (ticks_ms - self->core.last_refresh) > self->native_ms_per_frame) {
+ if (self->auto_refresh && (supervisor_ticks_ms64() - self->core.last_refresh) > self->native_ms_per_frame) {
_refresh_display(self);
}
}
diff --git a/shared-module/displayio/EPaperDisplay.c b/shared-module/displayio/EPaperDisplay.c
index df1d5162b..91d4bb7f9 100644
--- a/shared-module/displayio/EPaperDisplay.c
+++ b/shared-module/displayio/EPaperDisplay.c
@@ -26,6 +26,7 @@
#include "shared-bindings/displayio/EPaperDisplay.h"
+#include "py/gc.h"
#include "py/runtime.h"
#include "shared-bindings/displayio/ColorConverter.h"
#include "shared-bindings/displayio/FourWire.h"
@@ -35,6 +36,7 @@
#include "shared-bindings/time/__init__.h"
#include "shared-module/displayio/__init__.h"
#include "supervisor/shared/display.h"
+#include "supervisor/shared/tick.h"
#include "supervisor/usb.h"
#include <stdint.h>
@@ -175,7 +177,7 @@ uint32_t common_hal_displayio_epaperdisplay_get_time_to_refresh(displayio_epaper
return 0;
}
// Refresh at seconds per frame rate.
- uint32_t elapsed_time = ticks_ms - self->core.last_refresh;
+ uint32_t elapsed_time = supervisor_ticks_ms64() - self->core.last_refresh;
if (elapsed_time > self->milliseconds_per_frame) {
return 0;
}
@@ -298,7 +300,7 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c
}
bool common_hal_displayio_epaperdisplay_refresh(displayio_epaperdisplay_obj_t* self) {
-
+
if (self->refreshing && self->busy.base.type == &digitalio_digitalinout_type) {
if (common_hal_digitalio_digitalinout_get_value(&self->busy) != self->busy_state) {
self->refreshing = false;
@@ -339,7 +341,7 @@ void displayio_epaperdisplay_background(displayio_epaperdisplay_obj_t* self) {
bool busy = common_hal_digitalio_digitalinout_get_value(&self->busy);
refresh_done = busy != self->busy_state;
} else {
- refresh_done = ticks_ms - self->core.last_refresh > self->refresh_time;
+ refresh_done = supervisor_ticks_ms64() - self->core.last_refresh > self->refresh_time;
}
if (refresh_done) {
self->refreshing = false;
@@ -365,6 +367,8 @@ void release_epaperdisplay(displayio_epaperdisplay_obj_t* self) {
void displayio_epaperdisplay_collect_ptrs(displayio_epaperdisplay_obj_t* self) {
displayio_display_core_collect_ptrs(&self->core);
+ gc_collect_ptr(self->start_sequence);
+ gc_collect_ptr(self->stop_sequence);
}
bool maybe_refresh_epaperdisplay(void) {
diff --git a/shared-module/displayio/FourWire.c b/shared-module/displayio/FourWire.c
index 92d4507dd..256c29642 100644
--- a/shared-module/displayio/FourWire.c
+++ b/shared-module/displayio/FourWire.c
@@ -49,8 +49,8 @@ void common_hal_displayio_fourwire_construct(displayio_fourwire_obj_t* self,
gc_never_free(self->bus);
self->frequency = baudrate;
- self->polarity = common_hal_busio_spi_get_polarity(spi);
- self->phase = common_hal_busio_spi_get_phase(spi);
+ self->polarity = 0;
+ self->phase = 0;
common_hal_digitalio_digitalinout_construct(&self->command, command);
common_hal_digitalio_digitalinout_switch_to_output(&self->command, true, DRIVE_MODE_PUSH_PULL);
diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c
index af22cb0df..efa61265e 100644
--- a/shared-module/displayio/__init__.c
+++ b/shared-module/displayio/__init__.c
@@ -16,6 +16,9 @@
#include "supervisor/shared/display.h"
#include "supervisor/memory.h"
+#include "supervisor/spi_flash_api.h"
+#include "py/mpconfig.h"
+
primary_display_t displays[CIRCUITPY_DISPLAY_LIMIT];
// Check for recursive calls to displayio_background.
@@ -100,6 +103,11 @@ void reset_displays(void) {
continue;
}
#endif
+ #ifdef BOARD_USE_INTERNAL_SPI
+ if (original_spi == (mp_obj_t)(&supervisor_flash_spi_bus)) {
+ continue;
+ }
+ #endif
memcpy(&fourwire->inline_bus, original_spi, sizeof(busio_spi_obj_t));
fourwire->bus = &fourwire->inline_bus;
// Check for other displays that use the same spi bus and swap them too.
diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c
index a73ea81d1..120b70f76 100644
--- a/shared-module/displayio/display_core.c
+++ b/shared-module/displayio/display_core.c
@@ -35,6 +35,7 @@
#include "shared-bindings/time/__init__.h"
#include "shared-module/displayio/__init__.h"
#include "supervisor/shared/display.h"
+#include "supervisor/shared/tick.h"
#include <stdint.h>
#include <string.h>
@@ -85,6 +86,15 @@ void displayio_display_core_construct(displayio_display_core_t* self,
self->height = height;
self->ram_width = ram_width;
self->ram_height = ram_height;
+
+ displayio_display_core_set_rotation(self, rotation);
+}
+
+void displayio_display_core_set_rotation( displayio_display_core_t* self,
+ int rotation) {
+ int height = self->height;
+ int width = self->width;
+
rotation = rotation % 360;
self->rotation = rotation;
self->transform.x = 0;
@@ -281,7 +291,7 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t* self,
}
void displayio_display_core_start_refresh(displayio_display_core_t* self) {
- self->last_refresh = ticks_ms;
+ self->last_refresh = supervisor_ticks_ms64();
}
void displayio_display_core_finish_refresh(displayio_display_core_t* self) {
@@ -289,7 +299,7 @@ void displayio_display_core_finish_refresh(displayio_display_core_t* self) {
displayio_group_finish_refresh(self->current_group);
}
self->full_refresh = false;
- self->last_refresh = ticks_ms;
+ self->last_refresh = supervisor_ticks_ms64();
}
void release_display_core(displayio_display_core_t* self) {
diff --git a/shared-module/displayio/display_core.h b/shared-module/displayio/display_core.h
index 3a69cd40a..1c3d0f09c 100644
--- a/shared-module/displayio/display_core.h
+++ b/shared-module/displayio/display_core.h
@@ -68,6 +68,8 @@ uint16_t displayio_display_core_get_height(displayio_display_core_t* self);
void displayio_display_core_set_dither(displayio_display_core_t* self, bool dither);
bool displayio_display_core_get_dither(displayio_display_core_t* self);
+void displayio_display_core_set_rotation(displayio_display_core_t* self, int rotation);
+
bool displayio_display_core_bus_free(displayio_display_core_t *self);
bool displayio_display_core_begin_transaction(displayio_display_core_t* self);
void displayio_display_core_end_transaction(displayio_display_core_t* self);
diff --git a/shared-module/network/__init__.c b/shared-module/network/__init__.c
index 96648b260..925e9a2a3 100644
--- a/shared-module/network/__init__.c
+++ b/shared-module/network/__init__.c
@@ -31,6 +31,8 @@
#include "py/mphal.h"
#include "py/mperrno.h"
+#include "supervisor/shared/tick.h"
+
#include "shared-bindings/random/__init__.h"
#include "shared-module/network/__init__.h"
@@ -53,7 +55,7 @@ void network_module_deinit(void) {
void network_module_background(void) {
static uint32_t next_tick = 0;
- uint32_t this_tick = ticks_ms;
+ uint32_t this_tick = supervisor_ticks_ms32();
if (this_tick < next_tick) return;
next_tick = this_tick + 1000;
diff --git a/shared-module/storage/__init__.c b/shared-module/storage/__init__.c
index 215e1356a..c3d4b50c8 100644
--- a/shared-module/storage/__init__.c
+++ b/shared-module/storage/__init__.c
@@ -149,9 +149,7 @@ void common_hal_storage_remount(const char *mount_path, bool readonly, bool disa
}
#ifdef USB_AVAILABLE
- // TODO(dhalbert): is this is a good enough check? It checks for
- // CDC enabled. There is no "MSC enabled" check.
- if (usb_enabled()) {
+ if (!usb_msc_ejected()) {
mp_raise_RuntimeError(translate("Cannot remount '/' when USB is active."));
}
#endif
diff --git a/shared-module/usb_hid/Device.c b/shared-module/usb_hid/Device.c
index bed7d163f..8744f2ed3 100644
--- a/shared-module/usb_hid/Device.c
+++ b/shared-module/usb_hid/Device.c
@@ -30,6 +30,7 @@
#include "shared-bindings/usb_hid/Device.h"
#include "shared-module/usb_hid/Device.h"
#include "supervisor/shared/translate.h"
+#include "supervisor/shared/tick.h"
#include "tusb.h"
uint8_t common_hal_usb_hid_device_get_usage_page(usb_hid_device_obj_t *self) {
@@ -46,8 +47,8 @@ void common_hal_usb_hid_device_send_report(usb_hid_device_obj_t *self, uint8_t*
}
// Wait until interface is ready, timeout = 2 seconds
- uint64_t end_ticks = ticks_ms + 2000;
- while ( (ticks_ms < end_ticks) && !tud_hid_ready() ) {
+ uint64_t end_ticks = supervisor_ticks_ms64() + 2000;
+ while ( (supervisor_ticks_ms64() < end_ticks) && !tud_hid_ready() ) {
RUN_BACKGROUND_TASKS;
}