From 064c597b60d7394216d9c36080b7ee8ff089cb53 Mon Sep 17 00:00:00 2001 From: Kamil Tomaszewski Date: Wed, 2 Sep 2020 15:42:57 +0200 Subject: [PATCH 1/8] camera: Implement new library for camera --- py/circuitpy_defns.mk | 6 + py/circuitpy_mpconfig.h | 8 ++ py/circuitpy_mpconfig.mk | 3 + shared-bindings/camera/Camera.c | 178 +++++++++++++++++++++++++++++ shared-bindings/camera/Camera.h | 45 ++++++++ shared-bindings/camera/ImageSize.c | 163 ++++++++++++++++++++++++++ shared-bindings/camera/ImageSize.h | 59 ++++++++++ shared-bindings/camera/__init__.c | 50 ++++++++ 8 files changed, 512 insertions(+) create mode 100644 shared-bindings/camera/Camera.c create mode 100644 shared-bindings/camera/Camera.h create mode 100644 shared-bindings/camera/ImageSize.c create mode 100644 shared-bindings/camera/ImageSize.h create mode 100644 shared-bindings/camera/__init__.c diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 0e87287c13..f72c821e53 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -139,6 +139,9 @@ endif ifeq ($(CIRCUITPY_BUSIO),1) SRC_PATTERNS += busio/% bitbangio/OneWire.% endif +ifeq ($(CIRCUITPY_CAMERA),1) +SRC_PATTERNS += camera/% +endif ifeq ($(CIRCUITPY_COUNTIO),1) SRC_PATTERNS += countio/% endif @@ -310,6 +313,9 @@ SRC_COMMON_HAL_ALL = \ busio/SPI.c \ busio/UART.c \ busio/__init__.c \ + camera/__init__.c \ + camera/Camera.c \ + camera/ImageSize.c \ countio/Counter.c \ countio/__init__.c \ digitalio/DigitalInOut.c \ diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 0fafbe876d..4272de2ec7 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -329,6 +329,13 @@ extern const struct _mp_obj_module_t busio_module; #define BUSIO_MODULE #endif +#if CIRCUITPY_CAMERA +extern const struct _mp_obj_module_t camera_module; +#define CAMERA_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_camera), (mp_obj_t)&camera_module }, +#else +#define CAMERA_MODULE +#endif + #if CIRCUITPY_COUNTIO extern const struct _mp_obj_module_t countio_module; #define COUNTIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_countio), (mp_obj_t)&countio_module }, @@ -758,6 +765,7 @@ extern const struct _mp_obj_module_t wifi_module; BLEIO_MODULE \ BOARD_MODULE \ BUSIO_MODULE \ + CAMERA_MODULE \ COUNTIO_MODULE \ DIGITALIO_MODULE \ DISPLAYIO_MODULE \ diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index a2da9c42f5..54bdefc6dd 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -90,6 +90,9 @@ CFLAGS += -DCIRCUITPY_BOARD=$(CIRCUITPY_BOARD) CIRCUITPY_BUSIO ?= 1 CFLAGS += -DCIRCUITPY_BUSIO=$(CIRCUITPY_BUSIO) +CIRCUITPY_CAMERA ?= 0 +CFLAGS += -DCIRCUITPY_CAMERA=$(CIRCUITPY_CAMERA) + CIRCUITPY_DIGITALIO ?= 1 CFLAGS += -DCIRCUITPY_DIGITALIO=$(CIRCUITPY_DIGITALIO) diff --git a/shared-bindings/camera/Camera.c b/shared-bindings/camera/Camera.c new file mode 100644 index 0000000000..3855fed3c7 --- /dev/null +++ b/shared-bindings/camera/Camera.c @@ -0,0 +1,178 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright 2020 Sony Semiconductor Solutions Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/objproperty.h" +#include "py/runtime.h" + +#include "shared-bindings/camera/Camera.h" +#include "shared-bindings/util.h" + +//| class Camera: +//| """The class to control camera. +//| +//| Usage:: +//| +//| import board +//| import sdioio +//| import storage +//| import camera +//| +//| sd = sdioio.SDCard( +//| clock=board.SDIO_CLOCK, +//| command=board.SDIO_COMMAND, +//| data=board.SDIO_DATA, +//| frequency=25000000) +//| vfs = storage.VfsFat(sd) +//| storage.mount(vfs, '/sd') +//| +//| cam = camera.Camera(camera.ImageSize.IMAGE_SIZE_1920x1080) +//| +//| file = open("/sd/image.jpg","wb") +//| cam.take_picture() +//| file.write(cam.picture) +//| file.close()""" +//| + +//| def __init__(self, ): +//| """Initialize camera. +//| +//| :param camera.ImageSize size: image size""" +//| ... +//| +STATIC mp_obj_t camera_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + camera_obj_t *self = m_new_obj(camera_obj_t); + self->base.type = &camera_type; + enum { ARG_size }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_size, MP_ARG_REQUIRED | MP_ARG_OBJ }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + camera_imagesize_t size = camera_imagesize_obj_to_type(args[ARG_size].u_obj); + + common_hal_camera_construct(self, size); + return MP_OBJ_FROM_PTR(self); +} + +//| def deinit(self, ) -> Any: +//| """De-initialize camera.""" +//| ... +//| +STATIC mp_obj_t camera_obj_deinit(mp_obj_t self_in) { + camera_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_camera_deinit(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(camera_deinit_obj, camera_obj_deinit); + +STATIC void check_for_deinit(camera_obj_t *self) { + if (common_hal_camera_deinited(self)) { + raise_deinited_error(); + } +} + +//| def take_picture(self, ) -> Any: +//| """Take picture.""" +//| ... +//| +STATIC mp_obj_t camera_obj_take_picture(mp_obj_t self_in) { + camera_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + common_hal_camera_take_picture(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(camera_take_picture_obj, camera_obj_take_picture); + +//| picture: Any = ... +//| """Image buffer.""" +//| +STATIC mp_obj_t camera_obj_get_picture(mp_obj_t self_in) { + camera_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + uint8_t *buffer = common_hal_camera_get_picture_buffer(self); + size_t size = common_hal_camera_get_picture_size(self); + + return mp_obj_new_bytearray_by_ref(size, buffer); +} +MP_DEFINE_CONST_FUN_OBJ_1(camera_get_picture_obj, camera_obj_get_picture); + +const mp_obj_property_t camera_picture_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&camera_get_picture_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| size: Any = ... +//| """Image size.""" +//| +STATIC mp_obj_t camera_obj_get_size(mp_obj_t self_in) { + camera_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return camera_imagesize_type_to_obj(common_hal_camera_get_size(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(camera_get_size_obj, camera_obj_get_size); + +STATIC mp_obj_t camera_obj_set_size(mp_obj_t self_in, mp_obj_t value) { + camera_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + camera_imagesize_t size = camera_imagesize_obj_to_type(value); + if (size == IMAGESIZE_NONE) { + mp_raise_ValueError(translate("Invalid image size.")); + } + + common_hal_camera_set_size(self, size); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(camera_set_size_obj, camera_obj_set_size); + +const mp_obj_property_t camera_size_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&camera_get_size_obj, + (mp_obj_t)&camera_set_size_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +STATIC const mp_rom_map_elem_t camera_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&camera_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_take_picture), MP_ROM_PTR(&camera_take_picture_obj) }, + + { MP_ROM_QSTR(MP_QSTR_picture), MP_ROM_PTR(&camera_picture_obj) }, + { MP_ROM_QSTR(MP_QSTR_size), MP_ROM_PTR(&camera_size_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(camera_locals_dict, camera_locals_dict_table); + +const mp_obj_type_t camera_type = { + { &mp_type_type }, + .name = MP_QSTR_GNSS, + .make_new = camera_make_new, + .locals_dict = (mp_obj_dict_t*)&camera_locals_dict, +}; diff --git a/shared-bindings/camera/Camera.h b/shared-bindings/camera/Camera.h new file mode 100644 index 0000000000..e70d2493ec --- /dev/null +++ b/shared-bindings/camera/Camera.h @@ -0,0 +1,45 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright 2020 Sony Semiconductor Solutions Corporation + * + * 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_BINDINGS_CAMERA_CAMERA_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_CAMERA_CAMERA_H + +#include "common-hal/camera/Camera.h" +#include "shared-bindings/camera/ImageSize.h" + +extern const mp_obj_type_t camera_type; + +void common_hal_camera_construct(camera_obj_t *self, camera_imagesize_t size); +void common_hal_camera_deinit(camera_obj_t *self); +bool common_hal_camera_deinited(camera_obj_t *self); +void common_hal_camera_take_picture(camera_obj_t *self); + +uint8_t* common_hal_camera_get_picture_buffer(camera_obj_t *self); +size_t common_hal_camera_get_picture_size(camera_obj_t *self); +camera_imagesize_t common_hal_camera_get_size(camera_obj_t *self); +void common_hal_camera_set_size(camera_obj_t *self, camera_imagesize_t size); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_CAMERA_CAMERA_H diff --git a/shared-bindings/camera/ImageSize.c b/shared-bindings/camera/ImageSize.c new file mode 100644 index 0000000000..bfa01814d9 --- /dev/null +++ b/shared-bindings/camera/ImageSize.c @@ -0,0 +1,163 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright 2020 Sony Semiconductor Solutions Corporation + * + * 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/camera/ImageSize.h" + +//| class ImageSize: +//| """Image size""" +//| +//| def __init__(self) -> None: +//| """Enum-like class to define the image size.""" +//| +//| IMAGE_SIZE_320x240: ImageSize +//| """Image size 320x240.""" +//| +//| IMAGE_SIZE_640x480: ImageSize +//| """Image size 640x480.""" +//| +//| IMAGE_SIZE_1280x720: ImageSize +//| """Image size 1280x720.""" +//| +//| IMAGE_SIZE_1280x960: ImageSize +//| """Image size 1280x960.""" +//| +//| IMAGE_SIZE_1920x1080: ImageSize +//| """Image size 1920x1080.""" +//| +//| IMAGE_SIZE_2048x1536: ImageSize +//| """Image size 2048x1536.""" +//| +//| IMAGE_SIZE_2560x1920: ImageSize +//| """Image size 2560x1920.""" +//| +const mp_obj_type_t camera_imagesize_type; + +const camera_imagesize_obj_t camera_imagesize_320x240_obj = { + { &camera_imagesize_type }, +}; + +const camera_imagesize_obj_t camera_imagesize_640x320_obj = { + { &camera_imagesize_type }, +}; + +const camera_imagesize_obj_t camera_imagesize_1280x720_obj = { + { &camera_imagesize_type }, +}; + +const camera_imagesize_obj_t camera_imagesize_1280x960_obj = { + { &camera_imagesize_type }, +}; + +const camera_imagesize_obj_t camera_imagesize_1920x1080_obj = { + { &camera_imagesize_type }, +}; + +const camera_imagesize_obj_t camera_imagesize_2048x1536_obj = { + { &camera_imagesize_type }, +}; + +const camera_imagesize_obj_t camera_imagesize_2560x1920_obj = { + { &camera_imagesize_type }, +}; + +camera_imagesize_t camera_imagesize_obj_to_type(mp_obj_t obj) { + if (obj == MP_ROM_PTR(&camera_imagesize_320x240_obj)) { + return IMAGESIZE_320x240; + } else if (obj == MP_ROM_PTR(&camera_imagesize_640x320_obj)) { + return IMAGESIZE_640x320; + } else if (obj == MP_ROM_PTR(&camera_imagesize_1280x720_obj)) { + return IMAGESIZE_1280x720; + } else if (obj == MP_ROM_PTR(&camera_imagesize_1280x960_obj)) { + return IMAGESIZE_1280x960; + } else if (obj == MP_ROM_PTR(&camera_imagesize_1920x1080_obj)) { + return IMAGESIZE_1920x1080; + } else if (obj == MP_ROM_PTR(&camera_imagesize_2048x1536_obj)) { + return IMAGESIZE_2048x1536; + } else if (obj == MP_ROM_PTR(&camera_imagesize_2560x1920_obj)) { + return IMAGESIZE_2560x1920; + } + return IMAGESIZE_NONE; +} + +mp_obj_t camera_imagesize_type_to_obj(camera_imagesize_t size) { + switch (size) { + case IMAGESIZE_320x240: + return (mp_obj_t)MP_ROM_PTR(&camera_imagesize_320x240_obj); + case IMAGESIZE_640x320: + return (mp_obj_t)MP_ROM_PTR(&camera_imagesize_640x320_obj); + case IMAGESIZE_1280x720: + return (mp_obj_t)MP_ROM_PTR(&camera_imagesize_1280x720_obj); + case IMAGESIZE_1280x960: + return (mp_obj_t)MP_ROM_PTR(&camera_imagesize_1280x960_obj); + case IMAGESIZE_1920x1080: + return (mp_obj_t)MP_ROM_PTR(&camera_imagesize_1920x1080_obj); + case IMAGESIZE_2048x1536: + return (mp_obj_t)MP_ROM_PTR(&camera_imagesize_2048x1536_obj); + case IMAGESIZE_2560x1920: + return (mp_obj_t)MP_ROM_PTR(&camera_imagesize_2560x1920_obj); + case IMAGESIZE_NONE: + default: + return (mp_obj_t)MP_ROM_PTR(&mp_const_none_obj); + } +} + +STATIC const mp_rom_map_elem_t camera_imagesize_locals_dict_table[] = { + {MP_ROM_QSTR(MP_QSTR_IMAGE_SIZE_320x240), MP_ROM_PTR(&camera_imagesize_320x240_obj)}, + {MP_ROM_QSTR(MP_QSTR_IMAGE_SIZE_640x320), MP_ROM_PTR(&camera_imagesize_640x320_obj)}, + {MP_ROM_QSTR(MP_QSTR_IMAGE_SIZE_1280x720), MP_ROM_PTR(&camera_imagesize_1280x720_obj)}, + {MP_ROM_QSTR(MP_QSTR_IMAGE_SIZE_1280x960), MP_ROM_PTR(&camera_imagesize_1280x960_obj)}, + {MP_ROM_QSTR(MP_QSTR_IMAGE_SIZE_1920x1080), MP_ROM_PTR(&camera_imagesize_1920x1080_obj)}, + {MP_ROM_QSTR(MP_QSTR_IMAGE_SIZE_2048x1536), MP_ROM_PTR(&camera_imagesize_2048x1536_obj)}, + {MP_ROM_QSTR(MP_QSTR_IMAGE_SIZE_2560x1920), MP_ROM_PTR(&camera_imagesize_2560x1920_obj)}, +}; +STATIC MP_DEFINE_CONST_DICT(camera_imagesize_locals_dict, camera_imagesize_locals_dict_table); + +STATIC void camera_imagesize_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + qstr size = MP_QSTR_None; + if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&camera_imagesize_320x240_obj)) { + size = MP_QSTR_IMAGE_SIZE_320x240; + } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&camera_imagesize_640x320_obj)) { + size = MP_QSTR_IMAGE_SIZE_640x320; + } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&camera_imagesize_1280x720_obj)) { + size = MP_QSTR_IMAGE_SIZE_1280x720; + } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&camera_imagesize_1280x960_obj)) { + size = MP_QSTR_IMAGE_SIZE_1280x960; + } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&camera_imagesize_1920x1080_obj)) { + size = MP_QSTR_IMAGE_SIZE_1920x1080; + } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&camera_imagesize_2048x1536_obj)) { + size = MP_QSTR_IMAGE_SIZE_2048x1536; + } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&camera_imagesize_2560x1920_obj)) { + size = MP_QSTR_IMAGE_SIZE_2560x1920; + } + mp_printf(print, "%q.%q.%q", MP_QSTR_camera, MP_QSTR_ImageSize, size); +} + +const mp_obj_type_t camera_imagesize_type = { + { &mp_type_type }, + .name = MP_QSTR_ImageSize, + .print = camera_imagesize_print, + .locals_dict = (mp_obj_t)&camera_imagesize_locals_dict, +}; diff --git a/shared-bindings/camera/ImageSize.h b/shared-bindings/camera/ImageSize.h new file mode 100644 index 0000000000..3fe624e066 --- /dev/null +++ b/shared-bindings/camera/ImageSize.h @@ -0,0 +1,59 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright 2020 Sony Semiconductor Solutions Corporation + * + * 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_BINDINGS_CAMERA_IMAGESIZE_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_CAMERA_IMAGESIZE_H + +#include "py/obj.h" + +typedef enum { + IMAGESIZE_NONE, + IMAGESIZE_320x240, + IMAGESIZE_640x320, + IMAGESIZE_1280x720, + IMAGESIZE_1280x960, + IMAGESIZE_1920x1080, + IMAGESIZE_2048x1536, + IMAGESIZE_2560x1920, +} camera_imagesize_t; + +const mp_obj_type_t camera_imagesize_type; + +camera_imagesize_t camera_imagesize_obj_to_type(mp_obj_t obj); +mp_obj_t camera_imagesize_type_to_obj(camera_imagesize_t mode); + +typedef struct { + mp_obj_base_t base; +} camera_imagesize_obj_t; +extern const camera_imagesize_obj_t camera_imagesize_320x240_obj; +extern const camera_imagesize_obj_t camera_imagesize_640x320_obj; +extern const camera_imagesize_obj_t camera_imagesize_1280x720_obj; +extern const camera_imagesize_obj_t camera_imagesize_1280x960_obj; +extern const camera_imagesize_obj_t camera_imagesize_1920x1080_obj; +extern const camera_imagesize_obj_t camera_imagesize_2048x1536_obj; +extern const camera_imagesize_obj_t camera_imagesize_2560x1920_obj; + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_CAMERA_IMAGESIZE_H diff --git a/shared-bindings/camera/__init__.c b/shared-bindings/camera/__init__.c new file mode 100644 index 0000000000..3398d1ade6 --- /dev/null +++ b/shared-bindings/camera/__init__.c @@ -0,0 +1,50 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright 2020 Sony Semiconductor Solutions Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "shared-bindings/camera/Camera.h" +#include "shared-bindings/util.h" + +//| """Support for camera input +//| +//| The `camera` module contains classes to control the camera and take pictures.""" +//| +STATIC const mp_rom_map_elem_t camera_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_camera) }, + { MP_ROM_QSTR(MP_QSTR_Camera), MP_ROM_PTR(&camera_type) }, + + // Enum-like Classes. + { MP_ROM_QSTR(MP_QSTR_ImageSize), MP_ROM_PTR(&camera_imagesize_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(camera_module_globals, camera_module_globals_table); + +const mp_obj_module_t camera_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&camera_module_globals, +}; From 1fde8ef9bce14ceea241574f074ac446dca93055 Mon Sep 17 00:00:00 2001 From: Kamil Tomaszewski Date: Wed, 2 Sep 2020 15:43:37 +0200 Subject: [PATCH 2/8] spresense: Add support for camera --- ports/cxd56/Makefile | 2 +- ports/cxd56/common-hal/camera/Camera.c | 224 ++++++++++++++++++++++ ports/cxd56/common-hal/camera/Camera.h | 43 +++++ ports/cxd56/common-hal/camera/ImageSize.c | 0 ports/cxd56/common-hal/camera/__init__.c | 1 + ports/cxd56/mpconfigport.mk | 1 + 6 files changed, 270 insertions(+), 1 deletion(-) create mode 100644 ports/cxd56/common-hal/camera/Camera.c create mode 100644 ports/cxd56/common-hal/camera/Camera.h create mode 100644 ports/cxd56/common-hal/camera/ImageSize.c create mode 100644 ports/cxd56/common-hal/camera/__init__.c diff --git a/ports/cxd56/Makefile b/ports/cxd56/Makefile index bb3958af4f..7e145f5e2d 100644 --- a/ports/cxd56/Makefile +++ b/ports/cxd56/Makefile @@ -201,7 +201,7 @@ all: $(BUILD)/firmware.spk $(FIRMWARE): $(ECHO) "" $(ECHO) "Download the spresense binaries zip archive from:" - $(ECHO) "https://developer.sony.com/file/download/download-spresense-firmware-v1-4-000" + $(ECHO) "https://developer.sony.com/file/download/download-spresense-firmware-v2-0-000" $(ECHO) "Extract spresense binaries to $(FIRMWARE)" $(ECHO) "" $(ECHO) "run make flash-bootloader again to flash bootloader." diff --git a/ports/cxd56/common-hal/camera/Camera.c b/ports/cxd56/common-hal/camera/Camera.c new file mode 100644 index 0000000000..0c22525302 --- /dev/null +++ b/ports/cxd56/common-hal/camera/Camera.c @@ -0,0 +1,224 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright 2020 Sony Semiconductor Solutions Corporation + * + * 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 +#include + +#include +#include +#include + +#include "py/runtime.h" + +#include "shared-bindings/camera/Camera.h" + +#define JPG_COMPRESS_RATIO (9) +#define SPRESENSE_CAMIMAGE_MEM_ALIGN (32) + +typedef struct { + const char* devpath; + int fd; +} camera_dev_t; + +STATIC camera_dev_t camera_dev = {"/dev/video", -1}; + +static void camera_size_to_width_and_height(camera_imagesize_t size, uint16_t *width, uint16_t *height) { + switch (size) { + case IMAGESIZE_320x240: + *height = VIDEO_VSIZE_QVGA; + *width = VIDEO_HSIZE_QVGA; + break; + case IMAGESIZE_640x320: + *height = VIDEO_VSIZE_VGA; + *width = VIDEO_HSIZE_VGA; + break; + case IMAGESIZE_1280x720: + *height = VIDEO_VSIZE_HD; + *width = VIDEO_HSIZE_HD; + break; + case IMAGESIZE_1280x960: + *height = VIDEO_VSIZE_QUADVGA; + *width = VIDEO_HSIZE_QUADVGA; + break; + case IMAGESIZE_1920x1080: + *height = VIDEO_VSIZE_FULLHD; + *width = VIDEO_HSIZE_FULLHD; + break; + case IMAGESIZE_2048x1536: + *height = VIDEO_VSIZE_3M; + *width = VIDEO_HSIZE_3M; + break; + case IMAGESIZE_2560x1920: + *height = VIDEO_VSIZE_5M; + *width = VIDEO_HSIZE_5M; + break; + default: + mp_raise_ValueError(translate("Size not supported")); + break; + } +} + +static void camera_set_format(enum v4l2_buf_type type, uint32_t pixformat, uint16_t width, uint16_t height) { + v4l2_requestbuffers_t req = {0}; + + // Set Buffer Mode. + req.type = type; + req.memory = V4L2_MEMORY_USERPTR; + req.count = 1; + req.mode = V4L2_BUF_MODE_RING; + ioctl(camera_dev.fd, VIDIOC_REQBUFS, (unsigned long)&req); + v4l2_format_t fmt = {0}; + + // Set Format. + fmt.type = type; + fmt.fmt.pix.width = width; + fmt.fmt.pix.height = height; + fmt.fmt.pix.field = V4L2_FIELD_ANY; + fmt.fmt.pix.pixelformat = pixformat; + ioctl(camera_dev.fd, VIDIOC_S_FMT, (unsigned long)&fmt); +} + +static void camera_start_streaming(enum v4l2_buf_type type) { + ioctl(camera_dev.fd, VIDIOC_STREAMON, (unsigned long)&type); +} + +static void camera_start_preview() { + camera_set_format(V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_PIX_FMT_UYVY, VIDEO_HSIZE_QVGA, VIDEO_VSIZE_QVGA); + + v4l2_buffer_t buf; + + memset(&buf, 0, sizeof(v4l2_buffer_t)); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_USERPTR; + ioctl(camera_dev.fd, VIDIOC_QBUF, (unsigned long)&buf); + + camera_start_streaming(V4L2_BUF_TYPE_VIDEO_CAPTURE); +} + +void common_hal_camera_construct(camera_obj_t *self, camera_imagesize_t size) { + if (camera_dev.fd < 0) { + if (video_initialize(camera_dev.devpath) < 0) { + mp_raise_ValueError(translate("Could not initialize Camera")); + } + camera_dev.fd = open(camera_dev.devpath, 0); + if (camera_dev.fd < 0) { + mp_raise_ValueError(translate("Could not initialize Camera")); + } + } + + uint16_t width, height; + + camera_size_to_width_and_height(size, &width, &height); + + self->size = size; + + // In SPRESENSE SDK, JPEG compression quality=80 by default. + // In such setting, the maximum actual measured size of JPEG image + // is about width * height * 2 / 9. + self->buffer_size = (size_t)(width * height * 2 / JPG_COMPRESS_RATIO);; + self->buffer = m_malloc(self->buffer_size, true); + if (self->buffer == NULL) { + mp_raise_msg(&mp_type_MemoryError, translate("Couldn't allocate picture buffer")); + } + self->picture_buffer = self->buffer; + while ((uint32_t)self->picture_buffer % SPRESENSE_CAMIMAGE_MEM_ALIGN != 0) { + self->picture_buffer++; + } + + camera_start_preview(); + + camera_set_format(V4L2_BUF_TYPE_STILL_CAPTURE, V4L2_PIX_FMT_JPEG, width, height); + + camera_start_streaming(V4L2_BUF_TYPE_STILL_CAPTURE); + + sleep(1); +} + +void common_hal_camera_deinit(camera_obj_t *self) { + if (common_hal_camera_deinited(self)) { + return; + } + + video_uninitialize(); + + m_free(self->buffer); + + close(camera_dev.fd); + camera_dev.fd = -1; +} + +bool common_hal_camera_deinited(camera_obj_t *self) { + return camera_dev.fd < 0; +} + +void common_hal_camera_take_picture(camera_obj_t *self) { + v4l2_buffer_t buf; + + memset(&buf, 0, sizeof(v4l2_buffer_t)); + buf.type = V4L2_BUF_TYPE_STILL_CAPTURE; + buf.memory = V4L2_MEMORY_USERPTR; + buf.m.userptr = (unsigned long)self->picture_buffer; + buf.length = self->buffer_size - SPRESENSE_CAMIMAGE_MEM_ALIGN; + ioctl(camera_dev.fd, VIDIOC_QBUF, (unsigned long)&buf); + + ioctl(camera_dev.fd, VIDIOC_TAKEPICT_START, 0); + + ioctl(camera_dev.fd, VIDIOC_DQBUF, (unsigned long)&buf); + + ioctl(camera_dev.fd, VIDIOC_TAKEPICT_STOP, false); + + self->picture_size = (size_t)buf.bytesused; +} + +uint8_t *common_hal_camera_get_picture_buffer(camera_obj_t *self) { + return self->picture_buffer; +} + +size_t common_hal_camera_get_picture_size(camera_obj_t *self) { + return self->picture_size; +} + +camera_imagesize_t common_hal_camera_get_size(camera_obj_t *self) { + return self->size; +} + +void common_hal_camera_set_size(camera_obj_t *self, camera_imagesize_t size) { + uint16_t width, height; + + camera_size_to_width_and_height(size, &width, &height); + + self->buffer_size = (size_t)(width * height * 2 / JPG_COMPRESS_RATIO);; + self->buffer = m_realloc(self->buffer, self->buffer_size); + if (self->buffer == NULL) { + mp_raise_msg(&mp_type_MemoryError, translate("Couldn't allocate picture buffer")); + } + self->picture_buffer = self->buffer; + while ((uint32_t)self->picture_buffer % SPRESENSE_CAMIMAGE_MEM_ALIGN != 0) { + self->picture_buffer++; + } + + camera_set_format(V4L2_BUF_TYPE_STILL_CAPTURE, V4L2_PIX_FMT_JPEG, width, height); +} diff --git a/ports/cxd56/common-hal/camera/Camera.h b/ports/cxd56/common-hal/camera/Camera.h new file mode 100644 index 0000000000..1eb63ace11 --- /dev/null +++ b/ports/cxd56/common-hal/camera/Camera.h @@ -0,0 +1,43 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright 2020 Sony Semiconductor Solutions Corporation + * + * 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_CXD56_COMMON_HAL_CAMERA_CAMERA_H +#define MICROPY_INCLUDED_CXD56_COMMON_HAL_CAMERA_CAMERA_H + +#include "py/obj.h" + +#include "shared-bindings/camera/ImageSize.h" + +typedef struct { + mp_obj_base_t base; + uint8_t *buffer; + size_t buffer_size; + uint8_t *picture_buffer; + size_t picture_size; + camera_imagesize_t size; +} camera_obj_t; + +#endif // MICROPY_INCLUDED_CXD56_COMMON_HAL_CAMERA_CAMERA_H diff --git a/ports/cxd56/common-hal/camera/ImageSize.c b/ports/cxd56/common-hal/camera/ImageSize.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ports/cxd56/common-hal/camera/__init__.c b/ports/cxd56/common-hal/camera/__init__.c new file mode 100644 index 0000000000..bf38b5f2bd --- /dev/null +++ b/ports/cxd56/common-hal/camera/__init__.c @@ -0,0 +1 @@ +// No camera module functions. diff --git a/ports/cxd56/mpconfigport.mk b/ports/cxd56/mpconfigport.mk index 914e0b37d5..e1ffc79d08 100644 --- a/ports/cxd56/mpconfigport.mk +++ b/ports/cxd56/mpconfigport.mk @@ -11,6 +11,7 @@ MPY_TOOL_LONGINT_IMPL = -mlongint-impl=mpz CIRCUITPY_AUDIOBUSIO = 0 CIRCUITPY_AUDIOIO = 0 +CIRCUITPY_CAMERA = 1 CIRCUITPY_COUNTIO = 0 CIRCUITPY_DISPLAYIO = 0 CIRCUITPY_FREQUENCYIO = 0 From fbf4431aa0f40859d0686308bda226a4880449e8 Mon Sep 17 00:00:00 2001 From: Kamil Tomaszewski Date: Wed, 2 Sep 2020 15:44:51 +0200 Subject: [PATCH 3/8] locale: make translate --- locale/circuitpython.pot | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 038cdacfc6..7bf2f851da 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -615,6 +615,10 @@ msgstr "" msgid "Corrupt raw code" msgstr "" +#: ports/cxd56/common-hal/camera/Camera.c +msgid "Could not initialize Camera" +msgstr "" + #: ports/cxd56/common-hal/gnss/GNSS.c msgid "Could not initialize GNSS" msgstr "" @@ -672,6 +676,10 @@ msgstr "" msgid "Couldn't allocate input buffer" msgstr "" +#: ports/cxd56/common-hal/camera/Camera.c +msgid "Couldn't allocate picture buffer" +msgstr "" + #: shared-module/audiocore/WaveFile.c shared-module/audiomixer/Mixer.c #: shared-module/audiomp3/MP3Decoder.c msgid "Couldn't allocate second buffer" @@ -998,6 +1006,10 @@ msgstr "" msgid "Invalid frequency supplied" msgstr "" +#: shared-bindings/camera/Camera.c +msgid "Invalid image size." +msgstr "" + #: supervisor/shared/safe_mode.c msgid "Invalid memory access." msgstr "" @@ -1499,6 +1511,10 @@ msgstr "" msgid "Server side context cannot have hostname" msgstr "" +#: ports/cxd56/common-hal/camera/Camera.c +msgid "Size not supported" +msgstr "" + #: shared-bindings/nvm/ByteArray.c msgid "Slice and value different lengths." msgstr "" From 143a1ff94a5052465e3e65057b0ec4660120b2ed Mon Sep 17 00:00:00 2001 From: Kamil Tomaszewski Date: Fri, 11 Sep 2020 13:24:55 +0200 Subject: [PATCH 4/8] spresense: change the GC to do 32-byte blocks --- ports/cxd56/configs/circuitpython/defconfig | 1 - ports/cxd56/mpconfigport.h | 6 ++++-- ports/cxd56/spresense-exported-sdk | 2 +- ports/cxd56/supervisor/port.c | 12 ++++++++++-- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/ports/cxd56/configs/circuitpython/defconfig b/ports/cxd56/configs/circuitpython/defconfig index 268f7a68e9..a97f821dfa 100644 --- a/ports/cxd56/configs/circuitpython/defconfig +++ b/ports/cxd56/configs/circuitpython/defconfig @@ -165,7 +165,6 @@ CONFIG_USBDEV=y CONFIG_USBDEV_DMA=y CONFIG_USBDEV_DUALSPEED=y CONFIG_USEC_PER_TICK=1000 -CONFIG_USERMAIN_STACKSIZE=1064960 CONFIG_USER_ENTRYPOINT="spresense_main" CONFIG_VIDEO_ISX012=y CONFIG_VIDEO_STREAM=y diff --git a/ports/cxd56/mpconfigport.h b/ports/cxd56/mpconfigport.h index df87946b95..27c82337bc 100644 --- a/ports/cxd56/mpconfigport.h +++ b/ports/cxd56/mpconfigport.h @@ -27,13 +27,15 @@ #ifndef __INCLUDED_MPCONFIGPORT_H #define __INCLUDED_MPCONFIGPORT_H -#define MICROPY_PY_SYS_PLATFORM "CXD56" +#define MICROPY_PY_SYS_PLATFORM "CXD56" // 64kiB stack -#define CIRCUITPY_DEFAULT_STACK_SIZE 0x10000 +#define CIRCUITPY_DEFAULT_STACK_SIZE (0x10000) #include "py/circuitpy_mpconfig.h" +#define MICROPY_BYTES_PER_GC_BLOCK (32) + #define MICROPY_PORT_ROOT_POINTERS \ CIRCUITPY_COMMON_ROOT_POINTERS \ diff --git a/ports/cxd56/spresense-exported-sdk b/ports/cxd56/spresense-exported-sdk index c991d439fa..752c4cd56d 160000 --- a/ports/cxd56/spresense-exported-sdk +++ b/ports/cxd56/spresense-exported-sdk @@ -1 +1 @@ -Subproject commit c991d439fac9c23cfcac0da16fe8055f818d40a4 +Subproject commit 752c4cd56dd0a270a559c28272ceb61ddcb7806c diff --git a/ports/cxd56/supervisor/port.c b/ports/cxd56/supervisor/port.c index 7038ca4782..6a32dc0f9e 100644 --- a/ports/cxd56/supervisor/port.c +++ b/ports/cxd56/supervisor/port.c @@ -46,12 +46,20 @@ #include "common-hal/pwmio/PWMOut.h" #include "common-hal/busio/UART.h" +#define HEAP_SIZE (1000 * 1024) + +uint32_t* heap; +uint32_t heap_size; + safe_mode_t port_init(void) { boardctl(BOARDIOC_INIT, 0); // Wait until RTC is available while (g_rtc_enabled == false); + heap = memalign(32, HEAP_SIZE); + heap_size = HEAP_SIZE / sizeof(uint32_t); + if (board_requests_safe_mode()) { return USER_SAFE_MODE; } @@ -100,11 +108,11 @@ uint32_t *port_stack_get_top(void) { } uint32_t *port_heap_get_bottom(void) { - return port_stack_get_limit(); + return heap; } uint32_t *port_heap_get_top(void) { - return port_stack_get_top(); + return heap + heap_size; } extern uint32_t _ebss; From c2fc592c2ca7ec42374a50f9e33ac551bf846596 Mon Sep 17 00:00:00 2001 From: Kamil Tomaszewski Date: Fri, 11 Sep 2020 13:27:11 +0200 Subject: [PATCH 5/8] camera: Change API --- ports/cxd56/common-hal/camera/Camera.c | 144 +++++++--------- ports/cxd56/common-hal/camera/Camera.h | 9 +- ports/cxd56/common-hal/camera/ImageSize.c | 0 py/circuitpy_defns.mk | 2 +- shared-bindings/camera/Camera.c | 120 +++++++------ shared-bindings/camera/Camera.h | 14 +- shared-bindings/camera/ImageFormat.c | 93 ++++++++++ .../camera/{ImageSize.h => ImageFormat.h} | 36 ++-- shared-bindings/camera/ImageSize.c | 163 ------------------ shared-bindings/camera/__init__.c | 2 +- 10 files changed, 247 insertions(+), 336 deletions(-) delete mode 100644 ports/cxd56/common-hal/camera/ImageSize.c create mode 100644 shared-bindings/camera/ImageFormat.c rename shared-bindings/camera/{ImageSize.h => ImageFormat.h} (55%) delete mode 100644 shared-bindings/camera/ImageSize.c diff --git a/ports/cxd56/common-hal/camera/Camera.c b/ports/cxd56/common-hal/camera/Camera.c index 0c22525302..9376822c8a 100644 --- a/ports/cxd56/common-hal/camera/Camera.c +++ b/ports/cxd56/common-hal/camera/Camera.c @@ -35,9 +35,6 @@ #include "shared-bindings/camera/Camera.h" -#define JPG_COMPRESS_RATIO (9) -#define SPRESENSE_CAMIMAGE_MEM_ALIGN (32) - typedef struct { const char* devpath; int fd; @@ -45,39 +42,36 @@ typedef struct { STATIC camera_dev_t camera_dev = {"/dev/video", -1}; -static void camera_size_to_width_and_height(camera_imagesize_t size, uint16_t *width, uint16_t *height) { - switch (size) { - case IMAGESIZE_320x240: - *height = VIDEO_VSIZE_QVGA; - *width = VIDEO_HSIZE_QVGA; - break; - case IMAGESIZE_640x320: - *height = VIDEO_VSIZE_VGA; - *width = VIDEO_HSIZE_VGA; - break; - case IMAGESIZE_1280x720: - *height = VIDEO_VSIZE_HD; - *width = VIDEO_HSIZE_HD; - break; - case IMAGESIZE_1280x960: - *height = VIDEO_VSIZE_QUADVGA; - *width = VIDEO_HSIZE_QUADVGA; - break; - case IMAGESIZE_1920x1080: - *height = VIDEO_VSIZE_FULLHD; - *width = VIDEO_HSIZE_FULLHD; - break; - case IMAGESIZE_2048x1536: - *height = VIDEO_VSIZE_3M; - *width = VIDEO_HSIZE_3M; - break; - case IMAGESIZE_2560x1920: - *height = VIDEO_VSIZE_5M; - *width = VIDEO_HSIZE_5M; - break; - default: - mp_raise_ValueError(translate("Size not supported")); - break; +static bool camera_check_width_and_height(uint16_t width, uint16_t height) { + if ((width == VIDEO_HSIZE_QVGA && height == VIDEO_VSIZE_QVGA) || + (width == VIDEO_HSIZE_VGA && height == VIDEO_VSIZE_VGA) || + (width == VIDEO_HSIZE_HD && height == VIDEO_VSIZE_HD) || + (width == VIDEO_HSIZE_QUADVGA && height == VIDEO_VSIZE_QUADVGA) || + (width == VIDEO_HSIZE_FULLHD && height == VIDEO_VSIZE_FULLHD) || + (width == VIDEO_HSIZE_3M && height == VIDEO_VSIZE_3M) || + (width == VIDEO_HSIZE_5M && height == VIDEO_VSIZE_5M)) { + return true; + } else { + return false; + } +} + +static bool camera_check_buffer_length(uint16_t width, uint16_t height, camera_imageformat_t format, size_t length) { + if (format == IMAGEFORMAT_JPG) { + // In SPRESENSE SDK, JPEG compression quality=80 by default. + // In such setting, the maximum actual measured size of JPEG image + // is about width * height * 2 / 9. + return length >= (size_t)(width * height * 2 / 9) ? true : false; + } else { + return false; + } +} + +static bool camera_check_format(camera_imageformat_t format) { + if (format == IMAGEFORMAT_JPG) { + return true; + } else { + return false; } } @@ -118,7 +112,9 @@ static void camera_start_preview() { camera_start_streaming(V4L2_BUF_TYPE_VIDEO_CAPTURE); } -void common_hal_camera_construct(camera_obj_t *self, camera_imagesize_t size) { +extern uint32_t _ebss; +extern uint32_t _stext; +void common_hal_camera_construct(camera_obj_t *self, uint16_t width, uint16_t height) { if (camera_dev.fd < 0) { if (video_initialize(camera_dev.devpath) < 0) { mp_raise_ValueError(translate("Could not initialize Camera")); @@ -129,25 +125,13 @@ void common_hal_camera_construct(camera_obj_t *self, camera_imagesize_t size) { } } - uint16_t width, height; - - camera_size_to_width_and_height(size, &width, &height); - - self->size = size; - - // In SPRESENSE SDK, JPEG compression quality=80 by default. - // In such setting, the maximum actual measured size of JPEG image - // is about width * height * 2 / 9. - self->buffer_size = (size_t)(width * height * 2 / JPG_COMPRESS_RATIO);; - self->buffer = m_malloc(self->buffer_size, true); - if (self->buffer == NULL) { - mp_raise_msg(&mp_type_MemoryError, translate("Couldn't allocate picture buffer")); - } - self->picture_buffer = self->buffer; - while ((uint32_t)self->picture_buffer % SPRESENSE_CAMIMAGE_MEM_ALIGN != 0) { - self->picture_buffer++; + if (!camera_check_width_and_height(width, height)) { + mp_raise_ValueError(translate("Size not supported")); } + self->width = width; + self->height = height; + camera_start_preview(); camera_set_format(V4L2_BUF_TYPE_STILL_CAPTURE, V4L2_PIX_FMT_JPEG, width, height); @@ -164,8 +148,6 @@ void common_hal_camera_deinit(camera_obj_t *self) { video_uninitialize(); - m_free(self->buffer); - close(camera_dev.fd); camera_dev.fd = -1; } @@ -174,14 +156,26 @@ bool common_hal_camera_deinited(camera_obj_t *self) { return camera_dev.fd < 0; } -void common_hal_camera_take_picture(camera_obj_t *self) { +size_t common_hal_camera_take_picture(camera_obj_t *self, uint8_t *buffer, size_t len, camera_imageformat_t format) { + if (!camera_check_width_and_height(self->width, self->height)) { + mp_raise_ValueError(translate("Size not supported")); + } + if (!camera_check_buffer_length(self->width, self->height, format, len)) { + mp_raise_ValueError(translate("Buffer is too small")); + } + if (!camera_check_format(format)) { + mp_raise_ValueError(translate("Format not supported")); + } + + camera_set_format(V4L2_BUF_TYPE_STILL_CAPTURE, V4L2_PIX_FMT_JPEG, self->width, self->height); + v4l2_buffer_t buf; memset(&buf, 0, sizeof(v4l2_buffer_t)); buf.type = V4L2_BUF_TYPE_STILL_CAPTURE; buf.memory = V4L2_MEMORY_USERPTR; - buf.m.userptr = (unsigned long)self->picture_buffer; - buf.length = self->buffer_size - SPRESENSE_CAMIMAGE_MEM_ALIGN; + buf.m.userptr = (unsigned long)buffer; + buf.length = len; ioctl(camera_dev.fd, VIDIOC_QBUF, (unsigned long)&buf); ioctl(camera_dev.fd, VIDIOC_TAKEPICT_START, 0); @@ -190,35 +184,21 @@ void common_hal_camera_take_picture(camera_obj_t *self) { ioctl(camera_dev.fd, VIDIOC_TAKEPICT_STOP, false); - self->picture_size = (size_t)buf.bytesused; + return (size_t)buf.bytesused; } -uint8_t *common_hal_camera_get_picture_buffer(camera_obj_t *self) { - return self->picture_buffer; +uint16_t common_hal_camera_get_width(camera_obj_t *self) { + return self->width; } -size_t common_hal_camera_get_picture_size(camera_obj_t *self) { - return self->picture_size; +void common_hal_camera_set_width(camera_obj_t *self, uint16_t width) { + self->width = width; } -camera_imagesize_t common_hal_camera_get_size(camera_obj_t *self) { - return self->size; +uint16_t common_hal_camera_get_height(camera_obj_t *self) { + return self->height; } -void common_hal_camera_set_size(camera_obj_t *self, camera_imagesize_t size) { - uint16_t width, height; - - camera_size_to_width_and_height(size, &width, &height); - - self->buffer_size = (size_t)(width * height * 2 / JPG_COMPRESS_RATIO);; - self->buffer = m_realloc(self->buffer, self->buffer_size); - if (self->buffer == NULL) { - mp_raise_msg(&mp_type_MemoryError, translate("Couldn't allocate picture buffer")); - } - self->picture_buffer = self->buffer; - while ((uint32_t)self->picture_buffer % SPRESENSE_CAMIMAGE_MEM_ALIGN != 0) { - self->picture_buffer++; - } - - camera_set_format(V4L2_BUF_TYPE_STILL_CAPTURE, V4L2_PIX_FMT_JPEG, width, height); +void common_hal_camera_set_height(camera_obj_t *self, uint16_t height) { + self->height = height; } diff --git a/ports/cxd56/common-hal/camera/Camera.h b/ports/cxd56/common-hal/camera/Camera.h index 1eb63ace11..11fc102085 100644 --- a/ports/cxd56/common-hal/camera/Camera.h +++ b/ports/cxd56/common-hal/camera/Camera.h @@ -29,15 +29,10 @@ #include "py/obj.h" -#include "shared-bindings/camera/ImageSize.h" - typedef struct { mp_obj_base_t base; - uint8_t *buffer; - size_t buffer_size; - uint8_t *picture_buffer; - size_t picture_size; - camera_imagesize_t size; + uint16_t width; + uint16_t height; } camera_obj_t; #endif // MICROPY_INCLUDED_CXD56_COMMON_HAL_CAMERA_CAMERA_H diff --git a/ports/cxd56/common-hal/camera/ImageSize.c b/ports/cxd56/common-hal/camera/ImageSize.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index f72c821e53..6e98af8686 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -315,7 +315,6 @@ SRC_COMMON_HAL_ALL = \ busio/__init__.c \ camera/__init__.c \ camera/Camera.c \ - camera/ImageSize.c \ countio/Counter.c \ countio/__init__.c \ digitalio/DigitalInOut.c \ @@ -386,6 +385,7 @@ $(filter $(SRC_PATTERNS), \ _bleio/Attribute.c \ _bleio/ScanEntry.c \ _eve/__init__.c \ + camera/ImageFormat.c \ digitalio/Direction.c \ digitalio/DriveMode.c \ digitalio/Pull.c \ diff --git a/shared-bindings/camera/Camera.c b/shared-bindings/camera/Camera.c index 3855fed3c7..3b839d802f 100644 --- a/shared-bindings/camera/Camera.c +++ b/shared-bindings/camera/Camera.c @@ -48,37 +48,38 @@ //| vfs = storage.VfsFat(sd) //| storage.mount(vfs, '/sd') //| -//| cam = camera.Camera(camera.ImageSize.IMAGE_SIZE_1920x1080) +//| cam = camera.Camera(1920, 1080) //| +//| buffer = bytearray(512 * 1024) //| file = open("/sd/image.jpg","wb") -//| cam.take_picture() -//| file.write(cam.picture) +//| size = cam.take_picture() +//| file.write(buffer, size) //| file.close()""" //| -//| def __init__(self, ): +//| def __init__(self, width: int, height: int) -> None: //| """Initialize camera. //| -//| :param camera.ImageSize size: image size""" +//| :param int width: Width in pixels +//| :param int height: Height in pixels""" //| ... //| STATIC mp_obj_t camera_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { camera_obj_t *self = m_new_obj(camera_obj_t); self->base.type = &camera_type; - enum { ARG_size }; + enum { ARG_width, ARG_height }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_size, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - camera_imagesize_t size = camera_imagesize_obj_to_type(args[ARG_size].u_obj); - - common_hal_camera_construct(self, size); + common_hal_camera_construct(self, args[ARG_width].u_int, args[ARG_height].u_int); return MP_OBJ_FROM_PTR(self); } -//| def deinit(self, ) -> Any: +//| def deinit(self) -> None: //| """De-initialize camera.""" //| ... //| @@ -95,69 +96,84 @@ STATIC void check_for_deinit(camera_obj_t *self) { } } -//| def take_picture(self, ) -> Any: -//| """Take picture.""" +//| def take_picture(self, buf: WriteableBuffer, format: ImageFormat) -> int: +//| """Take picture and save to ``buf`` in the given ``format`` +//| +//| :return: the size of the picture taken +//| :rtype: int""" //| ... //| -STATIC mp_obj_t camera_obj_take_picture(mp_obj_t self_in) { +STATIC mp_obj_t camera_obj_take_picture(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_buffer, ARG_format }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_format, MP_ARG_REQUIRED | MP_ARG_OBJ }, + }; + camera_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(self); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_WRITE); + + camera_imageformat_t format = camera_imageformat_obj_to_type(args[ARG_format].u_obj); + + return MP_OBJ_NEW_SMALL_INT(common_hal_camera_take_picture(self, (uint8_t *)bufinfo.buf, bufinfo.len, format)); +} +MP_DEFINE_CONST_FUN_OBJ_KW(camera_take_picture_obj, 3, camera_obj_take_picture); + +//| width: int +//| """Image width in pixels.""" +//| +STATIC mp_obj_t camera_obj_get_width(mp_obj_t self_in) { + camera_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_camera_get_width(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(camera_get_width_obj, camera_obj_get_width); + +STATIC mp_obj_t camera_obj_set_width(mp_obj_t self_in, mp_obj_t value) { camera_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); - common_hal_camera_take_picture(self); + common_hal_camera_set_width(self, mp_obj_get_int(value)); + return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_1(camera_take_picture_obj, camera_obj_take_picture); +MP_DEFINE_CONST_FUN_OBJ_2(camera_set_width_obj, camera_obj_set_width); -//| picture: Any = ... -//| """Image buffer.""" -//| -STATIC mp_obj_t camera_obj_get_picture(mp_obj_t self_in) { - camera_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - - uint8_t *buffer = common_hal_camera_get_picture_buffer(self); - size_t size = common_hal_camera_get_picture_size(self); - - return mp_obj_new_bytearray_by_ref(size, buffer); -} -MP_DEFINE_CONST_FUN_OBJ_1(camera_get_picture_obj, camera_obj_get_picture); - -const mp_obj_property_t camera_picture_obj = { +const mp_obj_property_t camera_width_obj = { .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&camera_get_picture_obj, - (mp_obj_t)&mp_const_none_obj, + .proxy = {(mp_obj_t)&camera_get_width_obj, + (mp_obj_t)&camera_set_width_obj, (mp_obj_t)&mp_const_none_obj}, }; -//| size: Any = ... -//| """Image size.""" +//| height: int +//| """Image height in pixels.""" //| -STATIC mp_obj_t camera_obj_get_size(mp_obj_t self_in) { +STATIC mp_obj_t camera_obj_get_height(mp_obj_t self_in) { camera_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); - return camera_imagesize_type_to_obj(common_hal_camera_get_size(self)); + return MP_OBJ_NEW_SMALL_INT(common_hal_camera_get_height(self)); } -MP_DEFINE_CONST_FUN_OBJ_1(camera_get_size_obj, camera_obj_get_size); +MP_DEFINE_CONST_FUN_OBJ_1(camera_get_height_obj, camera_obj_get_height); -STATIC mp_obj_t camera_obj_set_size(mp_obj_t self_in, mp_obj_t value) { +STATIC mp_obj_t camera_obj_set_height(mp_obj_t self_in, mp_obj_t value) { camera_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); - camera_imagesize_t size = camera_imagesize_obj_to_type(value); - if (size == IMAGESIZE_NONE) { - mp_raise_ValueError(translate("Invalid image size.")); - } - - common_hal_camera_set_size(self, size); + common_hal_camera_set_height(self, mp_obj_get_int(value)); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_2(camera_set_size_obj, camera_obj_set_size); +MP_DEFINE_CONST_FUN_OBJ_2(camera_set_height_obj, camera_obj_set_height); -const mp_obj_property_t camera_size_obj = { +const mp_obj_property_t camera_height_obj = { .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&camera_get_size_obj, - (mp_obj_t)&camera_set_size_obj, + .proxy = {(mp_obj_t)&camera_get_height_obj, + (mp_obj_t)&camera_set_height_obj, (mp_obj_t)&mp_const_none_obj}, }; @@ -165,14 +181,14 @@ STATIC const mp_rom_map_elem_t camera_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&camera_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR_take_picture), MP_ROM_PTR(&camera_take_picture_obj) }, - { MP_ROM_QSTR(MP_QSTR_picture), MP_ROM_PTR(&camera_picture_obj) }, - { MP_ROM_QSTR(MP_QSTR_size), MP_ROM_PTR(&camera_size_obj) }, + { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&camera_width_obj) }, + { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&camera_height_obj) }, }; STATIC MP_DEFINE_CONST_DICT(camera_locals_dict, camera_locals_dict_table); const mp_obj_type_t camera_type = { { &mp_type_type }, - .name = MP_QSTR_GNSS, + .name = MP_QSTR_Camera, .make_new = camera_make_new, .locals_dict = (mp_obj_dict_t*)&camera_locals_dict, }; diff --git a/shared-bindings/camera/Camera.h b/shared-bindings/camera/Camera.h index e70d2493ec..7ef13cd07e 100644 --- a/shared-bindings/camera/Camera.h +++ b/shared-bindings/camera/Camera.h @@ -28,18 +28,18 @@ #define MICROPY_INCLUDED_SHARED_BINDINGS_CAMERA_CAMERA_H #include "common-hal/camera/Camera.h" -#include "shared-bindings/camera/ImageSize.h" +#include "shared-bindings/camera/ImageFormat.h" extern const mp_obj_type_t camera_type; -void common_hal_camera_construct(camera_obj_t *self, camera_imagesize_t size); +void common_hal_camera_construct(camera_obj_t *self, uint16_t width, uint16_t height); void common_hal_camera_deinit(camera_obj_t *self); bool common_hal_camera_deinited(camera_obj_t *self); -void common_hal_camera_take_picture(camera_obj_t *self); +size_t common_hal_camera_take_picture(camera_obj_t *self, uint8_t *buffer, size_t len, camera_imageformat_t format); -uint8_t* common_hal_camera_get_picture_buffer(camera_obj_t *self); -size_t common_hal_camera_get_picture_size(camera_obj_t *self); -camera_imagesize_t common_hal_camera_get_size(camera_obj_t *self); -void common_hal_camera_set_size(camera_obj_t *self, camera_imagesize_t size); +uint16_t common_hal_camera_get_width(camera_obj_t *self); +void common_hal_camera_set_width(camera_obj_t *self, uint16_t width); +uint16_t common_hal_camera_get_height(camera_obj_t *self); +void common_hal_camera_set_height(camera_obj_t *self, uint16_t height); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_CAMERA_CAMERA_H diff --git a/shared-bindings/camera/ImageFormat.c b/shared-bindings/camera/ImageFormat.c new file mode 100644 index 0000000000..d4bdddc562 --- /dev/null +++ b/shared-bindings/camera/ImageFormat.c @@ -0,0 +1,93 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright 2020 Sony Semiconductor Solutions Corporation + * + * 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/camera/ImageFormat.h" + +//| class ImageFormat: +//| """Image format""" +//| +//| def __init__(self) -> None: +//| """Enum-like class to define the image format.""" +//| +//| JPG: ImageFormat +//| """JPG format.""" +//| +//| RGB565: ImageFormat +//| """RGB565 format.""" +//| +const mp_obj_type_t camera_imageformat_type; + +const camera_imageformat_obj_t camera_imageformat_jpg_obj = { + { &camera_imageformat_type }, +}; + +const camera_imageformat_obj_t camera_imageformat_rgb565_obj = { + { &camera_imageformat_type }, +}; + +camera_imageformat_t camera_imageformat_obj_to_type(mp_obj_t obj) { + if (obj == MP_ROM_PTR(&camera_imageformat_jpg_obj)) { + return IMAGEFORMAT_JPG; + } else if (obj == MP_ROM_PTR(&camera_imageformat_rgb565_obj)) { + return IMAGEFORMAT_RGB565; + } + return IMAGEFORMAT_NONE; +} + +mp_obj_t camera_imageformat_type_to_obj(camera_imageformat_t format) { + switch (format) { + case IMAGEFORMAT_JPG: + return (mp_obj_t)MP_ROM_PTR(&camera_imageformat_jpg_obj); + case IMAGEFORMAT_RGB565: + return (mp_obj_t)MP_ROM_PTR(&camera_imageformat_rgb565_obj); + case IMAGEFORMAT_NONE: + default: + return (mp_obj_t)MP_ROM_PTR(&mp_const_none_obj); + } +} + +STATIC const mp_rom_map_elem_t camera_imageformat_locals_dict_table[] = { + {MP_ROM_QSTR(MP_QSTR_JPG), MP_ROM_PTR(&camera_imageformat_jpg_obj)}, + {MP_ROM_QSTR(MP_QSTR_RGB565), MP_ROM_PTR(&camera_imageformat_rgb565_obj)}, +}; +STATIC MP_DEFINE_CONST_DICT(camera_imageformat_locals_dict, camera_imageformat_locals_dict_table); + +STATIC void camera_imageformat_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + qstr format = MP_QSTR_None; + if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&camera_imageformat_jpg_obj)) { + format = MP_QSTR_JPG; + } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&camera_imageformat_rgb565_obj)) { + format = MP_QSTR_RGB565; + } + mp_printf(print, "%q.%q.%q", MP_QSTR_camera, MP_QSTR_ImageSize, format); +} + +const mp_obj_type_t camera_imageformat_type = { + { &mp_type_type }, + .name = MP_QSTR_ImageFormat, + .print = camera_imageformat_print, + .locals_dict = (mp_obj_t)&camera_imageformat_locals_dict, +}; diff --git a/shared-bindings/camera/ImageSize.h b/shared-bindings/camera/ImageFormat.h similarity index 55% rename from shared-bindings/camera/ImageSize.h rename to shared-bindings/camera/ImageFormat.h index 3fe624e066..8abc88438d 100644 --- a/shared-bindings/camera/ImageSize.h +++ b/shared-bindings/camera/ImageFormat.h @@ -24,36 +24,26 @@ * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_CAMERA_IMAGESIZE_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_CAMERA_IMAGESIZE_H +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_CAMERA_IMAGEFORMAT_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_CAMERA_IMAGEFORMAT_H #include "py/obj.h" typedef enum { - IMAGESIZE_NONE, - IMAGESIZE_320x240, - IMAGESIZE_640x320, - IMAGESIZE_1280x720, - IMAGESIZE_1280x960, - IMAGESIZE_1920x1080, - IMAGESIZE_2048x1536, - IMAGESIZE_2560x1920, -} camera_imagesize_t; + IMAGEFORMAT_NONE, + IMAGEFORMAT_JPG, + IMAGEFORMAT_RGB565, +} camera_imageformat_t; -const mp_obj_type_t camera_imagesize_type; +const mp_obj_type_t camera_imageformat_type; -camera_imagesize_t camera_imagesize_obj_to_type(mp_obj_t obj); -mp_obj_t camera_imagesize_type_to_obj(camera_imagesize_t mode); +camera_imageformat_t camera_imageformat_obj_to_type(mp_obj_t obj); +mp_obj_t camera_imageformat_type_to_obj(camera_imageformat_t mode); typedef struct { mp_obj_base_t base; -} camera_imagesize_obj_t; -extern const camera_imagesize_obj_t camera_imagesize_320x240_obj; -extern const camera_imagesize_obj_t camera_imagesize_640x320_obj; -extern const camera_imagesize_obj_t camera_imagesize_1280x720_obj; -extern const camera_imagesize_obj_t camera_imagesize_1280x960_obj; -extern const camera_imagesize_obj_t camera_imagesize_1920x1080_obj; -extern const camera_imagesize_obj_t camera_imagesize_2048x1536_obj; -extern const camera_imagesize_obj_t camera_imagesize_2560x1920_obj; +} camera_imageformat_obj_t; +extern const camera_imageformat_obj_t camera_imageformat_jpg_obj; +extern const camera_imageformat_obj_t camera_imageformat_rgb565_obj; -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_CAMERA_IMAGESIZE_H +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_CAMERA_IMAGEFORMAT_H diff --git a/shared-bindings/camera/ImageSize.c b/shared-bindings/camera/ImageSize.c deleted file mode 100644 index bfa01814d9..0000000000 --- a/shared-bindings/camera/ImageSize.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright 2020 Sony Semiconductor Solutions Corporation - * - * 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/camera/ImageSize.h" - -//| class ImageSize: -//| """Image size""" -//| -//| def __init__(self) -> None: -//| """Enum-like class to define the image size.""" -//| -//| IMAGE_SIZE_320x240: ImageSize -//| """Image size 320x240.""" -//| -//| IMAGE_SIZE_640x480: ImageSize -//| """Image size 640x480.""" -//| -//| IMAGE_SIZE_1280x720: ImageSize -//| """Image size 1280x720.""" -//| -//| IMAGE_SIZE_1280x960: ImageSize -//| """Image size 1280x960.""" -//| -//| IMAGE_SIZE_1920x1080: ImageSize -//| """Image size 1920x1080.""" -//| -//| IMAGE_SIZE_2048x1536: ImageSize -//| """Image size 2048x1536.""" -//| -//| IMAGE_SIZE_2560x1920: ImageSize -//| """Image size 2560x1920.""" -//| -const mp_obj_type_t camera_imagesize_type; - -const camera_imagesize_obj_t camera_imagesize_320x240_obj = { - { &camera_imagesize_type }, -}; - -const camera_imagesize_obj_t camera_imagesize_640x320_obj = { - { &camera_imagesize_type }, -}; - -const camera_imagesize_obj_t camera_imagesize_1280x720_obj = { - { &camera_imagesize_type }, -}; - -const camera_imagesize_obj_t camera_imagesize_1280x960_obj = { - { &camera_imagesize_type }, -}; - -const camera_imagesize_obj_t camera_imagesize_1920x1080_obj = { - { &camera_imagesize_type }, -}; - -const camera_imagesize_obj_t camera_imagesize_2048x1536_obj = { - { &camera_imagesize_type }, -}; - -const camera_imagesize_obj_t camera_imagesize_2560x1920_obj = { - { &camera_imagesize_type }, -}; - -camera_imagesize_t camera_imagesize_obj_to_type(mp_obj_t obj) { - if (obj == MP_ROM_PTR(&camera_imagesize_320x240_obj)) { - return IMAGESIZE_320x240; - } else if (obj == MP_ROM_PTR(&camera_imagesize_640x320_obj)) { - return IMAGESIZE_640x320; - } else if (obj == MP_ROM_PTR(&camera_imagesize_1280x720_obj)) { - return IMAGESIZE_1280x720; - } else if (obj == MP_ROM_PTR(&camera_imagesize_1280x960_obj)) { - return IMAGESIZE_1280x960; - } else if (obj == MP_ROM_PTR(&camera_imagesize_1920x1080_obj)) { - return IMAGESIZE_1920x1080; - } else if (obj == MP_ROM_PTR(&camera_imagesize_2048x1536_obj)) { - return IMAGESIZE_2048x1536; - } else if (obj == MP_ROM_PTR(&camera_imagesize_2560x1920_obj)) { - return IMAGESIZE_2560x1920; - } - return IMAGESIZE_NONE; -} - -mp_obj_t camera_imagesize_type_to_obj(camera_imagesize_t size) { - switch (size) { - case IMAGESIZE_320x240: - return (mp_obj_t)MP_ROM_PTR(&camera_imagesize_320x240_obj); - case IMAGESIZE_640x320: - return (mp_obj_t)MP_ROM_PTR(&camera_imagesize_640x320_obj); - case IMAGESIZE_1280x720: - return (mp_obj_t)MP_ROM_PTR(&camera_imagesize_1280x720_obj); - case IMAGESIZE_1280x960: - return (mp_obj_t)MP_ROM_PTR(&camera_imagesize_1280x960_obj); - case IMAGESIZE_1920x1080: - return (mp_obj_t)MP_ROM_PTR(&camera_imagesize_1920x1080_obj); - case IMAGESIZE_2048x1536: - return (mp_obj_t)MP_ROM_PTR(&camera_imagesize_2048x1536_obj); - case IMAGESIZE_2560x1920: - return (mp_obj_t)MP_ROM_PTR(&camera_imagesize_2560x1920_obj); - case IMAGESIZE_NONE: - default: - return (mp_obj_t)MP_ROM_PTR(&mp_const_none_obj); - } -} - -STATIC const mp_rom_map_elem_t camera_imagesize_locals_dict_table[] = { - {MP_ROM_QSTR(MP_QSTR_IMAGE_SIZE_320x240), MP_ROM_PTR(&camera_imagesize_320x240_obj)}, - {MP_ROM_QSTR(MP_QSTR_IMAGE_SIZE_640x320), MP_ROM_PTR(&camera_imagesize_640x320_obj)}, - {MP_ROM_QSTR(MP_QSTR_IMAGE_SIZE_1280x720), MP_ROM_PTR(&camera_imagesize_1280x720_obj)}, - {MP_ROM_QSTR(MP_QSTR_IMAGE_SIZE_1280x960), MP_ROM_PTR(&camera_imagesize_1280x960_obj)}, - {MP_ROM_QSTR(MP_QSTR_IMAGE_SIZE_1920x1080), MP_ROM_PTR(&camera_imagesize_1920x1080_obj)}, - {MP_ROM_QSTR(MP_QSTR_IMAGE_SIZE_2048x1536), MP_ROM_PTR(&camera_imagesize_2048x1536_obj)}, - {MP_ROM_QSTR(MP_QSTR_IMAGE_SIZE_2560x1920), MP_ROM_PTR(&camera_imagesize_2560x1920_obj)}, -}; -STATIC MP_DEFINE_CONST_DICT(camera_imagesize_locals_dict, camera_imagesize_locals_dict_table); - -STATIC void camera_imagesize_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { - qstr size = MP_QSTR_None; - if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&camera_imagesize_320x240_obj)) { - size = MP_QSTR_IMAGE_SIZE_320x240; - } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&camera_imagesize_640x320_obj)) { - size = MP_QSTR_IMAGE_SIZE_640x320; - } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&camera_imagesize_1280x720_obj)) { - size = MP_QSTR_IMAGE_SIZE_1280x720; - } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&camera_imagesize_1280x960_obj)) { - size = MP_QSTR_IMAGE_SIZE_1280x960; - } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&camera_imagesize_1920x1080_obj)) { - size = MP_QSTR_IMAGE_SIZE_1920x1080; - } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&camera_imagesize_2048x1536_obj)) { - size = MP_QSTR_IMAGE_SIZE_2048x1536; - } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&camera_imagesize_2560x1920_obj)) { - size = MP_QSTR_IMAGE_SIZE_2560x1920; - } - mp_printf(print, "%q.%q.%q", MP_QSTR_camera, MP_QSTR_ImageSize, size); -} - -const mp_obj_type_t camera_imagesize_type = { - { &mp_type_type }, - .name = MP_QSTR_ImageSize, - .print = camera_imagesize_print, - .locals_dict = (mp_obj_t)&camera_imagesize_locals_dict, -}; diff --git a/shared-bindings/camera/__init__.c b/shared-bindings/camera/__init__.c index 3398d1ade6..28cf7df575 100644 --- a/shared-bindings/camera/__init__.c +++ b/shared-bindings/camera/__init__.c @@ -39,7 +39,7 @@ STATIC const mp_rom_map_elem_t camera_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_Camera), MP_ROM_PTR(&camera_type) }, // Enum-like Classes. - { MP_ROM_QSTR(MP_QSTR_ImageSize), MP_ROM_PTR(&camera_imagesize_type) }, + { MP_ROM_QSTR(MP_QSTR_ImageSize), MP_ROM_PTR(&camera_imageformat_type) }, }; STATIC MP_DEFINE_CONST_DICT(camera_module_globals, camera_module_globals_table); From a25e3c2858e565e465849669c96da560b4af228f Mon Sep 17 00:00:00 2001 From: Kamil Tomaszewski Date: Fri, 11 Sep 2020 13:31:34 +0200 Subject: [PATCH 6/8] locale: make translate --- locale/circuitpython.pot | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 7bf2f851da..20cf75264a 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-09-13 14:21-0500\n" +"POT-Creation-Date: 2020-09-11 13:30+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -430,7 +430,7 @@ msgstr "" msgid "Buffer is not a bytearray." msgstr "" -#: shared-bindings/displayio/Display.c +#: ports/cxd56/common-hal/camera/Camera.c shared-bindings/displayio/Display.c #: shared-bindings/framebufferio/FramebufferDisplay.c msgid "Buffer is too small" msgstr "" @@ -676,10 +676,6 @@ msgstr "" msgid "Couldn't allocate input buffer" msgstr "" -#: ports/cxd56/common-hal/camera/Camera.c -msgid "Couldn't allocate picture buffer" -msgstr "" - #: shared-module/audiocore/WaveFile.c shared-module/audiomixer/Mixer.c #: shared-module/audiomp3/MP3Decoder.c msgid "Couldn't allocate second buffer" @@ -849,6 +845,10 @@ msgstr "" msgid "File exists" msgstr "" +#: ports/cxd56/common-hal/camera/Camera.c +msgid "Format not supported" +msgstr "" + #: shared-module/framebufferio/FramebufferDisplay.c #, c-format msgid "Framebuffer requires %d bytes" @@ -1006,10 +1006,6 @@ msgstr "" msgid "Invalid frequency supplied" msgstr "" -#: shared-bindings/camera/Camera.c -msgid "Invalid image size." -msgstr "" - #: supervisor/shared/safe_mode.c msgid "Invalid memory access." msgstr "" From ce7ee58e92eca840f75c2fcf885fe862f1ebec13 Mon Sep 17 00:00:00 2001 From: Kamil Tomaszewski Date: Mon, 14 Sep 2020 12:55:53 +0200 Subject: [PATCH 7/8] camera: Update camera module --- ports/cxd56/common-hal/camera/Camera.c | 38 +++++++++++++++----------- ports/cxd56/supervisor/port.c | 8 ++++-- shared-bindings/camera/Camera.c | 4 +-- shared-bindings/camera/__init__.c | 2 +- 4 files changed, 30 insertions(+), 22 deletions(-) diff --git a/ports/cxd56/common-hal/camera/Camera.c b/ports/cxd56/common-hal/camera/Camera.c index 9376822c8a..a4e197bf33 100644 --- a/ports/cxd56/common-hal/camera/Camera.c +++ b/ports/cxd56/common-hal/camera/Camera.c @@ -42,18 +42,28 @@ typedef struct { STATIC camera_dev_t camera_dev = {"/dev/video", -1}; +typedef struct { + uint16_t width; + uint16_t height; +} image_size_t; + +STATIC const image_size_t image_size_table[] = { + { VIDEO_HSIZE_QVGA, VIDEO_VSIZE_QVGA }, + { VIDEO_HSIZE_VGA, VIDEO_VSIZE_VGA }, + { VIDEO_HSIZE_HD, VIDEO_VSIZE_HD }, + { VIDEO_HSIZE_QUADVGA, VIDEO_VSIZE_QUADVGA }, + { VIDEO_HSIZE_FULLHD, VIDEO_VSIZE_FULLHD }, + { VIDEO_HSIZE_3M, VIDEO_VSIZE_3M }, + { VIDEO_HSIZE_5M, VIDEO_VSIZE_5M }, +}; + static bool camera_check_width_and_height(uint16_t width, uint16_t height) { - if ((width == VIDEO_HSIZE_QVGA && height == VIDEO_VSIZE_QVGA) || - (width == VIDEO_HSIZE_VGA && height == VIDEO_VSIZE_VGA) || - (width == VIDEO_HSIZE_HD && height == VIDEO_VSIZE_HD) || - (width == VIDEO_HSIZE_QUADVGA && height == VIDEO_VSIZE_QUADVGA) || - (width == VIDEO_HSIZE_FULLHD && height == VIDEO_VSIZE_FULLHD) || - (width == VIDEO_HSIZE_3M && height == VIDEO_VSIZE_3M) || - (width == VIDEO_HSIZE_5M && height == VIDEO_VSIZE_5M)) { - return true; - } else { - return false; + for (int i = 0; i < MP_ARRAY_SIZE(image_size_table); i++) { + if (image_size_table[i].width == width && image_size_table[i].height == height) { + return true; + } } + return false; } static bool camera_check_buffer_length(uint16_t width, uint16_t height, camera_imageformat_t format, size_t length) { @@ -61,18 +71,14 @@ static bool camera_check_buffer_length(uint16_t width, uint16_t height, camera_i // In SPRESENSE SDK, JPEG compression quality=80 by default. // In such setting, the maximum actual measured size of JPEG image // is about width * height * 2 / 9. - return length >= (size_t)(width * height * 2 / 9) ? true : false; + return length >= (size_t)(width * height * 2 / 9); } else { return false; } } static bool camera_check_format(camera_imageformat_t format) { - if (format == IMAGEFORMAT_JPG) { - return true; - } else { - return false; - } + return format == IMAGEFORMAT_JPG; } static void camera_set_format(enum v4l2_buf_type type, uint32_t pixformat, uint16_t width, uint16_t height) { diff --git a/ports/cxd56/supervisor/port.c b/ports/cxd56/supervisor/port.c index 6a32dc0f9e..6164f74113 100644 --- a/ports/cxd56/supervisor/port.c +++ b/ports/cxd56/supervisor/port.c @@ -46,7 +46,7 @@ #include "common-hal/pwmio/PWMOut.h" #include "common-hal/busio/UART.h" -#define HEAP_SIZE (1000 * 1024) +#define SPRESENSE_MEM_ALIGN (32) uint32_t* heap; uint32_t heap_size; @@ -57,8 +57,10 @@ safe_mode_t port_init(void) { // Wait until RTC is available while (g_rtc_enabled == false); - heap = memalign(32, HEAP_SIZE); - heap_size = HEAP_SIZE / sizeof(uint32_t); + heap = memalign(SPRESENSE_MEM_ALIGN, 128 * 1024); + uint32_t size = CONFIG_RAM_START + CONFIG_RAM_SIZE - (uint32_t)heap - 2 * SPRESENSE_MEM_ALIGN; + heap = realloc(heap, size); + heap_size = size / sizeof(uint32_t); if (board_requests_safe_mode()) { return USER_SAFE_MODE; diff --git a/shared-bindings/camera/Camera.c b/shared-bindings/camera/Camera.c index 3b839d802f..5fe54e429d 100644 --- a/shared-bindings/camera/Camera.c +++ b/shared-bindings/camera/Camera.c @@ -52,7 +52,7 @@ //| //| buffer = bytearray(512 * 1024) //| file = open("/sd/image.jpg","wb") -//| size = cam.take_picture() +//| size = cam.take_picture(buffer, camera.ImageFormat.JPG) //| file.write(buffer, size) //| file.close()""" //| @@ -99,7 +99,7 @@ STATIC void check_for_deinit(camera_obj_t *self) { //| def take_picture(self, buf: WriteableBuffer, format: ImageFormat) -> int: //| """Take picture and save to ``buf`` in the given ``format`` //| -//| :return: the size of the picture taken +//| :return: the number of bytes written into buf //| :rtype: int""" //| ... //| diff --git a/shared-bindings/camera/__init__.c b/shared-bindings/camera/__init__.c index 28cf7df575..080516d51c 100644 --- a/shared-bindings/camera/__init__.c +++ b/shared-bindings/camera/__init__.c @@ -39,7 +39,7 @@ STATIC const mp_rom_map_elem_t camera_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_Camera), MP_ROM_PTR(&camera_type) }, // Enum-like Classes. - { MP_ROM_QSTR(MP_QSTR_ImageSize), MP_ROM_PTR(&camera_imageformat_type) }, + { MP_ROM_QSTR(MP_QSTR_ImageFormat), MP_ROM_PTR(&camera_imageformat_type) }, }; STATIC MP_DEFINE_CONST_DICT(camera_module_globals, camera_module_globals_table); From 61687c81d82572ee5c014a9f167b2d73db73e2f4 Mon Sep 17 00:00:00 2001 From: Kamil Tomaszewski Date: Wed, 16 Sep 2020 13:55:57 +0200 Subject: [PATCH 8/8] camera: Pass width and height to take_picture() --- ports/cxd56/common-hal/camera/Camera.c | 37 ++--------- ports/cxd56/common-hal/camera/Camera.h | 2 - shared-bindings/camera/Camera.c | 92 +++++--------------------- shared-bindings/camera/Camera.h | 9 +-- 4 files changed, 22 insertions(+), 118 deletions(-) diff --git a/ports/cxd56/common-hal/camera/Camera.c b/ports/cxd56/common-hal/camera/Camera.c index a4e197bf33..35e2ab8822 100644 --- a/ports/cxd56/common-hal/camera/Camera.c +++ b/ports/cxd56/common-hal/camera/Camera.c @@ -118,9 +118,7 @@ static void camera_start_preview() { camera_start_streaming(V4L2_BUF_TYPE_VIDEO_CAPTURE); } -extern uint32_t _ebss; -extern uint32_t _stext; -void common_hal_camera_construct(camera_obj_t *self, uint16_t width, uint16_t height) { +void common_hal_camera_construct(camera_obj_t *self) { if (camera_dev.fd < 0) { if (video_initialize(camera_dev.devpath) < 0) { mp_raise_ValueError(translate("Could not initialize Camera")); @@ -131,17 +129,8 @@ void common_hal_camera_construct(camera_obj_t *self, uint16_t width, uint16_t he } } - if (!camera_check_width_and_height(width, height)) { - mp_raise_ValueError(translate("Size not supported")); - } - - self->width = width; - self->height = height; - camera_start_preview(); - camera_set_format(V4L2_BUF_TYPE_STILL_CAPTURE, V4L2_PIX_FMT_JPEG, width, height); - camera_start_streaming(V4L2_BUF_TYPE_STILL_CAPTURE); sleep(1); @@ -162,18 +151,18 @@ bool common_hal_camera_deinited(camera_obj_t *self) { return camera_dev.fd < 0; } -size_t common_hal_camera_take_picture(camera_obj_t *self, uint8_t *buffer, size_t len, camera_imageformat_t format) { - if (!camera_check_width_and_height(self->width, self->height)) { +size_t common_hal_camera_take_picture(camera_obj_t *self, uint8_t *buffer, size_t len, uint16_t width, uint16_t height, camera_imageformat_t format) { + if (!camera_check_width_and_height(width, height)) { mp_raise_ValueError(translate("Size not supported")); } - if (!camera_check_buffer_length(self->width, self->height, format, len)) { + if (!camera_check_buffer_length(width, height, format, len)) { mp_raise_ValueError(translate("Buffer is too small")); } if (!camera_check_format(format)) { mp_raise_ValueError(translate("Format not supported")); } - camera_set_format(V4L2_BUF_TYPE_STILL_CAPTURE, V4L2_PIX_FMT_JPEG, self->width, self->height); + camera_set_format(V4L2_BUF_TYPE_STILL_CAPTURE, V4L2_PIX_FMT_JPEG, width, height); v4l2_buffer_t buf; @@ -192,19 +181,3 @@ size_t common_hal_camera_take_picture(camera_obj_t *self, uint8_t *buffer, size_ return (size_t)buf.bytesused; } - -uint16_t common_hal_camera_get_width(camera_obj_t *self) { - return self->width; -} - -void common_hal_camera_set_width(camera_obj_t *self, uint16_t width) { - self->width = width; -} - -uint16_t common_hal_camera_get_height(camera_obj_t *self) { - return self->height; -} - -void common_hal_camera_set_height(camera_obj_t *self, uint16_t height) { - self->height = height; -} diff --git a/ports/cxd56/common-hal/camera/Camera.h b/ports/cxd56/common-hal/camera/Camera.h index 11fc102085..7056237d16 100644 --- a/ports/cxd56/common-hal/camera/Camera.h +++ b/ports/cxd56/common-hal/camera/Camera.h @@ -31,8 +31,6 @@ typedef struct { mp_obj_base_t base; - uint16_t width; - uint16_t height; } camera_obj_t; #endif // MICROPY_INCLUDED_CXD56_COMMON_HAL_CAMERA_CAMERA_H diff --git a/shared-bindings/camera/Camera.c b/shared-bindings/camera/Camera.c index 5fe54e429d..fd88ccab00 100644 --- a/shared-bindings/camera/Camera.c +++ b/shared-bindings/camera/Camera.c @@ -48,34 +48,26 @@ //| vfs = storage.VfsFat(sd) //| storage.mount(vfs, '/sd') //| -//| cam = camera.Camera(1920, 1080) +//| cam = camera.Camera() //| //| buffer = bytearray(512 * 1024) //| file = open("/sd/image.jpg","wb") -//| size = cam.take_picture(buffer, camera.ImageFormat.JPG) +//| size = cam.take_picture(buffer, width=1920, height=1080, format=camera.ImageFormat.JPG) //| file.write(buffer, size) //| file.close()""" //| -//| def __init__(self, width: int, height: int) -> None: -//| """Initialize camera. -//| -//| :param int width: Width in pixels -//| :param int height: Height in pixels""" +//| def __init__(self) -> None: +//| """Initialize camera.""" //| ... //| STATIC mp_obj_t camera_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { camera_obj_t *self = m_new_obj(camera_obj_t); self->base.type = &camera_type; - enum { ARG_width, ARG_height }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + // No arguments + mp_arg_check_num(n_args, kw_args, 0, 0, false); - common_hal_camera_construct(self, args[ARG_width].u_int, args[ARG_height].u_int); + common_hal_camera_construct(self); return MP_OBJ_FROM_PTR(self); } @@ -97,17 +89,20 @@ STATIC void check_for_deinit(camera_obj_t *self) { } //| def take_picture(self, buf: WriteableBuffer, format: ImageFormat) -> int: -//| """Take picture and save to ``buf`` in the given ``format`` +//| """Take picture and save to ``buf`` in the given ``format``. The size of the picture +//| taken is ``width`` by ``height`` in pixels. //| //| :return: the number of bytes written into buf //| :rtype: int""" //| ... //| STATIC mp_obj_t camera_obj_take_picture(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_buffer, ARG_format }; + enum { ARG_buffer, ARG_width, ARG_height, ARG_format }; static const mp_arg_t allowed_args[] = { { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_format, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_width, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_height, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_format, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, }; camera_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); check_for_deinit(self); @@ -119,70 +114,13 @@ STATIC mp_obj_t camera_obj_take_picture(size_t n_args, const mp_obj_t *pos_args, camera_imageformat_t format = camera_imageformat_obj_to_type(args[ARG_format].u_obj); - return MP_OBJ_NEW_SMALL_INT(common_hal_camera_take_picture(self, (uint8_t *)bufinfo.buf, bufinfo.len, format)); + return MP_OBJ_NEW_SMALL_INT(common_hal_camera_take_picture(self, (uint8_t *)bufinfo.buf, bufinfo.len, args[ARG_width].u_int, args[ARG_height].u_int, format)); } -MP_DEFINE_CONST_FUN_OBJ_KW(camera_take_picture_obj, 3, camera_obj_take_picture); - -//| width: int -//| """Image width in pixels.""" -//| -STATIC mp_obj_t camera_obj_get_width(mp_obj_t self_in) { - camera_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_camera_get_width(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(camera_get_width_obj, camera_obj_get_width); - -STATIC mp_obj_t camera_obj_set_width(mp_obj_t self_in, mp_obj_t value) { - camera_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - - common_hal_camera_set_width(self, mp_obj_get_int(value)); - - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(camera_set_width_obj, camera_obj_set_width); - -const mp_obj_property_t camera_width_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&camera_get_width_obj, - (mp_obj_t)&camera_set_width_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -//| height: int -//| """Image height in pixels.""" -//| -STATIC mp_obj_t camera_obj_get_height(mp_obj_t self_in) { - camera_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_camera_get_height(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(camera_get_height_obj, camera_obj_get_height); - -STATIC mp_obj_t camera_obj_set_height(mp_obj_t self_in, mp_obj_t value) { - camera_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - - common_hal_camera_set_height(self, mp_obj_get_int(value)); - - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(camera_set_height_obj, camera_obj_set_height); - -const mp_obj_property_t camera_height_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&camera_get_height_obj, - (mp_obj_t)&camera_set_height_obj, - (mp_obj_t)&mp_const_none_obj}, -}; +MP_DEFINE_CONST_FUN_OBJ_KW(camera_take_picture_obj, 2, camera_obj_take_picture); STATIC const mp_rom_map_elem_t camera_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&camera_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR_take_picture), MP_ROM_PTR(&camera_take_picture_obj) }, - - { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&camera_width_obj) }, - { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&camera_height_obj) }, }; STATIC MP_DEFINE_CONST_DICT(camera_locals_dict, camera_locals_dict_table); diff --git a/shared-bindings/camera/Camera.h b/shared-bindings/camera/Camera.h index 7ef13cd07e..8102672e49 100644 --- a/shared-bindings/camera/Camera.h +++ b/shared-bindings/camera/Camera.h @@ -32,14 +32,9 @@ extern const mp_obj_type_t camera_type; -void common_hal_camera_construct(camera_obj_t *self, uint16_t width, uint16_t height); +void common_hal_camera_construct(camera_obj_t *self); void common_hal_camera_deinit(camera_obj_t *self); bool common_hal_camera_deinited(camera_obj_t *self); -size_t common_hal_camera_take_picture(camera_obj_t *self, uint8_t *buffer, size_t len, camera_imageformat_t format); - -uint16_t common_hal_camera_get_width(camera_obj_t *self); -void common_hal_camera_set_width(camera_obj_t *self, uint16_t width); -uint16_t common_hal_camera_get_height(camera_obj_t *self); -void common_hal_camera_set_height(camera_obj_t *self, uint16_t height); +size_t common_hal_camera_take_picture(camera_obj_t *self, uint8_t *buffer, size_t len, uint16_t width, uint16_t height, camera_imageformat_t format); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_CAMERA_CAMERA_H