- Add reset for autoreload. De-request ticks.
- Separate state a little more in autoreload.c
- Rename some routines.
- Remove redundant settings of CIRCUITPY_AUTORELOAD_DELAY_MS.
This allows you to list and explore connected USB devices. It
only stubs out the methods to communicate to endpoints. That will
come in a follow up once TinyUSB has it. (It's in progress.)
Related to #5986
The ``reset`` and ``read`` pins should be optional, but the espressif
code had several places where it assumed they are not, and a bug that
caused a crash on ``release_displays`` if they were made optional.
The bug was caused by the fields for storing pin numbers being set
to ``NO_PIN``, which has value of -1, while the fields have type
``uint8_t``. That set the actual value to 255, and a subsequent
comparison to ``NO_PIN`` returned false.
Redundant import of analogio in example.
Confused MagTag user. MagTag does not come with analogio in uf2 and cannot play native WAV with buzzer hardware.
Initially enabled for samd51, this enables reading raw flux data as well
as DOS/MFM formatted media.
This is only the low-level code for reading & decoding flux pulses from a floppy drive.
high level details will live in a Python library.
adafruit-circuitpython-floppy will take care of details like stepping
from track to track, etc.
The port is free to return NULL for any/all of these, and the caller has
to check.
This will be used in the floppy code, because aside from getting the
registers, it looks like all is independent of MCU.
In my testing, there is no way to accurately know how far into a MP3 file
you're currently playing. You can use monotonic time, but that can have
drift versus the audio playback system, which may not be running at exactly
the expected sample rate.
To allow syncing animation with timestamps in a MP3 file, this presents a
new property, decoded_samples, that records the number of audio samples
sent out of the decoder. While this may not be a completely accurate time,
due to mixer delays, it's much better position that the monotonic clock
difference.
Implementation is keeping track of this value in the mp3file structure and
adding to it whenever data is sent out of the decoder. The property
implementation was a copy/paste from current properties in the audiomp3
files.
new utility function for all vectorio shape specializations for testing
whether a screen-space x,y point falls within a shape's x,y.
This respects the current orientation of the screen in the manner of
displayio and vectorio - so your x,y requests are in the same coordinate
domain as your x,y locations and your width/height etc. properties that
ou set on other shapes. I.e., if you're using this for touch points then
you will need to make sure the touch events are in the same x,y domain as
your display.
```
contains(2, 4) -> true
------------------
| |
| |
| -- |
| | \ |
| |. \ |
| | \ |
| |____\ |
| |
------------------
contains(5, 4) -> false
------------------
| |
| |
| -- |
| | \ |
| | \. |
| | \ |
| |____\ |
| |
------------------
```
This helps provide low overhead introspection of shape coverage on screen.
It's envisioned that this will be used for things like touch-and-drag
widget controls, touch "areas" and may help with random ornament placement
on toy Christmas trees.
These diagnostics occurred, but weren't treated as errors:
```
[WARN] Missing return type: alphablend on line 38
[WARN] Missing argument type: dest_bitmap on line 38
[WARN] Missing argument type: source_bitmap_1 on line 38
[WARN] Missing argument type: source_bitmap_2 on line 38
```
This object has a finalizer, so once it's no longer referenced, GC can
call that finalizer and then deallocate the storage.
In the case of a failure during construction (e.g., when checking
`validate_obj_is_free_pin_or_none`) this will happen on an incompletely
initialized structure. On samd, in particular, a newly allocated object
(with construct never called) appears to be valid, so GC collecting it
causes deinit() to do things, leading to a hard fault.
The double creation of the UART object was necessary specifically so that
the second allocation would fail. Probably there were other (single
call) ways to make it fail, but this was the easiest / the one discovered
in real life.
Closes: #5493
This targets the 64-bit CPU Raspberry Pis. The BCM2711 on the Pi 4
and the BCM2837 on the Pi 3 and Zero 2W. There are 64-bit fixes
outside of the ports directory for it.
There are a couple other cleanups that were incidental:
* Use const mcu_pin_obj_t instead of omitting the const. The structs
themselves are const because they are in ROM.
* Use PTR <-> OBJ conversions in more places. They were found when
mp_obj_t was set to an integer type rather than pointer.
* Optimize submodule checkout because the Pi submodules are heavy
and unnecessary for the vast majority of builds.
Fixes#4314
mp_obj_float_get gets the value of an object, which must be
exactly a float. mp_obj_get_float gets the float value of
an object of various types, including floats & ints.
This blends two "565"-format bitmaps, including byteswapped ones. All
the bitmaps have to have the same memory format.
The routine takes about 63ms on a Kaluga when operating on 320x240 bitmaps.
Of course, displaying the bitmap also takes time.
There's untested code for the L8 (8-bit greyscale) case. This can be
enabled once gifio is merged.
By having a pair of buffers, the capture hardware can fill one buffer while
Python code (including displayio, etc) operates on the other buffer. This
increases the responsiveness of camera-using code.
On the Kaluga it makes the following improvements:
* 320x240 viewfinder at 30fps instead of 15fps using directio
* 240x240 animated gif capture at 10fps instead of 7.5fps
As discussed at length on Discord, the "usual end user" code will look like
this:
camera = ...
with camera.continuous_capture(buffer1, buffer2) as capture:
for frame in capture:
# Do something with frame
However, rather than presenting a context manager, the core code consists of
three new functions to start & stop continuous capture, and to get the next
frame. The reason is twofold. First, it's simply easier to implement the
context manager object in pure Python. Second, for more advanced usage, the
context manager may be too limiting, and it's easier to iterate on the right
design in Python code. In particular, I noticed that adapting the
JPEG-capturing programs to use continuous capture mode needed a change in
program structure.
The camera app was structured as
```python
while True:
if shutter button was just pressed:
capture a jpeg frame
else:
update the viewfinder
```
However, "capture a jpeg frame" needs to (A) switch the camera settings and (B)
capture into a different, larger buffer then (C) return to the earlier
settings. This can't be done during continuous capture mode. So just
restructuring it as follows isn't going to work:
```python
with camera.continuous_capture(buffer1, buffer2) as capture:
for frame in capture:
if shutter button was just pressed:
capture a jpeg frame, without disturbing continuous capture mode
else:
update the viewfinder
```
The continuous mode is only implemented in the espressif port; others
will throw an exception if the associated methods are invoked. It's not
impossible to implement there, just not a priority, since these micros don't
have enough RAM for two framebuffer copies at any resonable sizes.
The capture code, including single-shot capture, now take mp_obj_t in the
common-hal layer, instead of a buffer & length. This was done for the
continuous capture mode because it has to identify & return to the user the
proper Python object representing the original buffer. In the Espressif port,
it was convenient to implement single capture in terms of a multi-capture,
which is why I changed the singleshot routine's signature too.
This involves:
* Adding a new "L8" colorspace for colorconverters
* factoring out displayio_colorconverter_convert_pixel
* Making a minimal "colorspace only" version of displayio for the
unix port (testing purposes)
* fixing an error message
I only tested writing B&W animated images, with the following script:
```python
import displayio
import gifio
with gifio.GifWriter("foo.gif", 64, 64, displayio.Colorspace.L8) as g:
for i in range(0, 256, 14):
data = bytes([i, 255-i] * 32 + [255-i, i] * 32) * 32
print("add_frame")
g.add_frame(data)
# expected to raise an error, buffer is not big enough
with gifio.GifWriter("/dev/null", 64, 64, displayio.Colorspace.L8) as g:
g.add_frame(bytes([3,3,3]))
```