circuitpython/shared-bindings/usb_video/USBFramebuffer.c
2025-02-05 11:09:15 -08:00

147 lines
6 KiB
C

// This file is part of the CircuitPython project: https://circuitpython.org
//
// SPDX-FileCopyrightText: Copyright (c) 2024 Jeff Epler for Adafruit Industries
//
// SPDX-License-Identifier: MIT
#include "py/obj.h"
#include "py/objproperty.h"
#include "shared-bindings/usb_video/__init__.h"
#include "shared-bindings/usb_video/USBFramebuffer.h"
#include "shared-module/displayio/__init__.h"
#include "shared-module/framebufferio/FramebufferDisplay.h"
#include "shared-module/framebufferio/__init__.h"
#include "shared-module/usb_video/__init__.h"
#include "shared-module/usb_video/USBFramebuffer.h"
#include "shared-bindings/util.h"
static void check_for_deinit(usb_video_uvcframebuffer_obj_t *self) {
if (!shared_module_usb_video_uvcframebuffer_get_width(self)) {
raise_deinited_error();
}
}
//| class USBFramebuffer:
//| """Displays to a USB connected computer using the UVC protocol
//|
//| The data in the framebuffer is in RGB565_SWAPPED format.
//|
//| This object is most often used with `framebufferio.FramebufferDisplay`. However,
//| it also supports the ``WritableBuffer`` protocol and can be accessed
//| as an array of ``H`` (unsigned 16-bit values)."""
//|
//| def __init__(self) -> None:
//| """Returns the singleton framebuffer object, if USB video is enabled"""
//|
static mp_obj_t usb_video_uvcframebuffer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
static const mp_arg_t allowed_args[] = {};
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);
usb_video_uvcframebuffer_obj_t *self = &usb_video_uvcframebuffer_singleton_obj;
return self;
}
//| def refresh(self) -> None:
//| """Transmits the color data in the buffer to the pixels so that
//| they are shown."""
//| ...
//|
static mp_obj_t usb_video_uvcframebuffer_refresh(mp_obj_t self_in) {
usb_video_uvcframebuffer_obj_t *self = (usb_video_uvcframebuffer_obj_t *)self_in;
check_for_deinit(self);
shared_module_usb_video_uvcframebuffer_refresh(self);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(usb_video_uvcframebuffer_refresh_obj, usb_video_uvcframebuffer_refresh);
//| width: int
//| """The width of the display, in pixels"""
static mp_obj_t usb_video_uvcframebuffer_get_width(mp_obj_t self_in) {
usb_video_uvcframebuffer_obj_t *self = (usb_video_uvcframebuffer_obj_t *)self_in;
check_for_deinit(self);
return MP_OBJ_NEW_SMALL_INT(shared_module_usb_video_uvcframebuffer_get_width(self));
}
MP_DEFINE_CONST_FUN_OBJ_1(usb_video_uvcframebuffer_get_width_obj, usb_video_uvcframebuffer_get_width);
MP_PROPERTY_GETTER(usb_video_uvcframebuffer_width_obj,
(mp_obj_t)&usb_video_uvcframebuffer_get_width_obj);
//| height: int
//| """The height of the display, in pixels"""
//|
//|
static mp_obj_t usb_video_uvcframebuffer_get_height(mp_obj_t self_in) {
usb_video_uvcframebuffer_obj_t *self = (usb_video_uvcframebuffer_obj_t *)self_in;
check_for_deinit(self);
return MP_OBJ_NEW_SMALL_INT(shared_module_usb_video_uvcframebuffer_get_height(self));
}
MP_DEFINE_CONST_FUN_OBJ_1(usb_video_uvcframebuffer_get_height_obj, usb_video_uvcframebuffer_get_height);
MP_PROPERTY_GETTER(usb_video_uvcframebuffer_height_obj,
(mp_obj_t)&usb_video_uvcframebuffer_get_height_obj);
static const mp_rom_map_elem_t usb_video_uvcframebuffer_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_refresh), MP_ROM_PTR(&usb_video_uvcframebuffer_refresh_obj) },
{ MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&usb_video_uvcframebuffer_width_obj) },
{ MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&usb_video_uvcframebuffer_height_obj) },
};
static MP_DEFINE_CONST_DICT(usb_video_uvcframebuffer_locals_dict, usb_video_uvcframebuffer_locals_dict_table);
static void usb_video_uvcframebuffer_get_bufinfo(mp_obj_t self_in, mp_buffer_info_t *bufinfo) {
shared_module_usb_video_uvcframebuffer_get_bufinfo(self_in, bufinfo);
}
// These version exists so that the prototype matches the protocol,
// avoiding a type cast that can hide errors
static void usb_video_uvcframebuffer_swapbuffers(mp_obj_t self_in, uint8_t *dirty_row_bitmap) {
(void)dirty_row_bitmap;
shared_module_usb_video_uvcframebuffer_refresh(self_in);
}
static void usb_video_uvcframebuffer_deinit_proto(mp_obj_t self_in) {
/* NOTHING */
}
static int usb_video_uvcframebuffer_get_width_proto(mp_obj_t self_in) {
return shared_module_usb_video_uvcframebuffer_get_width(self_in);
}
static int usb_video_uvcframebuffer_get_height_proto(mp_obj_t self_in) {
return shared_module_usb_video_uvcframebuffer_get_height(self_in);
}
static int usb_video_uvcframebuffer_get_native_frames_per_second_proto(mp_obj_t self_in) {
return 10;
}
static bool usb_video_uvcframebuffer_get_reverse_pixels_in_word_proto(mp_obj_t self_in) {
return true;
}
static const framebuffer_p_t usb_video_uvcframebuffer_proto = {
MP_PROTO_IMPLEMENT(MP_QSTR_protocol_framebuffer)
.get_bufinfo = usb_video_uvcframebuffer_get_bufinfo,
.get_width = usb_video_uvcframebuffer_get_width_proto,
.get_height = usb_video_uvcframebuffer_get_height_proto,
.get_native_frames_per_second = usb_video_uvcframebuffer_get_native_frames_per_second_proto,
.swapbuffers = usb_video_uvcframebuffer_swapbuffers,
.deinit = usb_video_uvcframebuffer_deinit_proto,
.get_reverse_pixels_in_word = usb_video_uvcframebuffer_get_reverse_pixels_in_word_proto,
};
static mp_int_t usb_video_uvcframebuffer_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
shared_module_usb_video_uvcframebuffer_get_bufinfo(self_in, bufinfo);
bufinfo->typecode = 'H';
return 0;
}
MP_DEFINE_CONST_OBJ_TYPE(
usb_video_USBFramebuffer_type,
MP_QSTR_USBFramebuffer,
MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS,
locals_dict, &usb_video_uvcframebuffer_locals_dict,
make_new, usb_video_uvcframebuffer_make_new,
buffer, usb_video_uvcframebuffer_get_buffer,
protocol, &usb_video_uvcframebuffer_proto
);