From aea9101e6b3da183adcd99f5377c799d194efd11 Mon Sep 17 00:00:00 2001 From: Nicolas Schodet Date: Tue, 12 Nov 2019 15:54:32 +0100 Subject: Replace SDL GUI with GTK+ GUI. --- moticam.c | 162 +++++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 112 insertions(+), 50 deletions(-) (limited to 'moticam.c') diff --git a/moticam.c b/moticam.c index fd4c1e5..6e487ea 100644 --- a/moticam.c +++ b/moticam.c @@ -37,18 +37,23 @@ struct moticam_device { struct device device; + libusb_context *usb; libusb_device_handle *handle; double exposure_ms; + bool exposure_pending; double gain; + bool gain_pending; size_t rawbuffer_size; uint8_t *rawbuffer; struct device_image image; + struct libusb_transfer *usb_transfer; + bool usb_transfer_done; }; static char * moticam_usb_poll(struct libusb_device_descriptor *desc); static struct device * -moticam_usb_open(libusb_device *usb_device); +moticam_usb_open(libusb_context *usb, libusb_device *usb_device); const struct device_driver moticam_device_driver = { "Moticam USB cameras", @@ -191,8 +196,7 @@ moticam_set_exposure(struct device *device, double exposure_ms) { struct moticam_device *mdev = (struct moticam_device *) device; mdev->exposure_ms = exposure_ms; - if (mdev->image.pixels) - moticam_control_exposure(device, exposure_ms); + mdev->exposure_pending = true; } static void @@ -200,8 +204,7 @@ moticam_set_gain(struct device *device, double gain) { struct moticam_device *mdev = (struct moticam_device *) device; mdev->gain = gain; - if (mdev->image.pixels) - moticam_control_gain(device, gain); + mdev->gain_pending = true; } static void @@ -209,12 +212,7 @@ moticam_set_resolution(struct device *device, int width, int height, int stride) { struct moticam_device *mdev = (struct moticam_device *) device; - /* Release previous configuration. */ - if (mdev->image.pixels) { - free(mdev->rawbuffer); - free(mdev->image.pixels); - moticam_control_exposure(&mdev->device, 30.0); - } + assert(!mdev->image.pixels); /* Choose stride. */ if (!stride) stride = width * sizeof(uint32_t); @@ -223,37 +221,49 @@ moticam_set_resolution(struct device *device, int width, int height, mdev->image.width = width; mdev->image.height = height; mdev->image.stride = stride; - /* Prepare sizes and buffers, request an extra frame to read the zero - * length packet. */ - int image_size = width * height; - int frame_size = 16384; - mdev->rawbuffer_size = (image_size + frame_size) - / frame_size * frame_size; - mdev->rawbuffer = utils_malloc(mdev->rawbuffer_size); - mdev->image.pixels = utils_malloc(stride * height); - /* Configure camera. */ - moticam_control_gain(&mdev->device, mdev->gain); - moticam_control_resolution(&mdev->device, width, height); - moticam_control_exposure(&mdev->device, mdev->exposure_ms); - utils_delay_us(100000); } -static bool -moticam_read_raw(struct device *device) +static void +moticam_transfer_cb(struct libusb_transfer *transfer) +{ + struct moticam_device *mdev = transfer->user_data; + mdev->usb_transfer_done = true; +} + +static void +moticam_start(struct device *device) { struct moticam_device *mdev = (struct moticam_device *) device; + assert(!mdev->image.pixels); + /* Configure camera. */ + moticam_control_exposure(&mdev->device, 30.0); + moticam_control_gain(&mdev->device, mdev->gain); + moticam_control_resolution(&mdev->device, mdev->image.width, + mdev->image.height); + moticam_control_exposure(&mdev->device, mdev->exposure_ms); + mdev->exposure_pending = false; + mdev->gain_pending = false; + utils_delay_us(100000); + /* Prepare sizes and buffers, request an extra frame to read the zero + * length packet. */ int image_size = mdev->image.width * mdev->image.height; - int transfered = 0; - int r = libusb_bulk_transfer(mdev->handle, 0x83, mdev->rawbuffer, - mdev->rawbuffer_size, &transfered, 0); + int frame_size = 16384; + mdev->rawbuffer_size = (image_size + frame_size) + / frame_size * frame_size; + mdev->rawbuffer = libusb_dev_mem_alloc(mdev->handle, + mdev->rawbuffer_size); + if (!mdev->rawbuffer) + utils_fatal("can not allocate raw buffer"); + mdev->image.pixels = utils_malloc( + mdev->image.stride * mdev->image.height); + /* Prepare and submit transfer. */ + mdev->usb_transfer = libusb_alloc_transfer(0); + libusb_fill_bulk_transfer(mdev->usb_transfer, mdev->handle, 0x83, + mdev->rawbuffer, mdev->rawbuffer_size, moticam_transfer_cb, mdev, + 30000); + int r = libusb_submit_transfer(mdev->usb_transfer); if (r) - utils_fatal("can not read data: %s", libusb_strerror(r)); - if (transfered != image_size) { - utils_warning("bad image size (%d), drop", transfered); - return false; - } else { - return true; - } + utils_fatal("can not submit transfer: %s", libusb_strerror(r)); } static const struct device_image * @@ -261,27 +271,73 @@ moticam_read(struct device *device) { struct moticam_device *mdev = (struct moticam_device *) device; assert(mdev->image.pixels); - if (moticam_read_raw(device)) { - image_bayer2argb(mdev->rawbuffer, mdev->image.pixels, mdev->image.width, - mdev->image.height, mdev->image.stride); - return &mdev->image; - } else { + if (mdev->usb_transfer_done) { + if (mdev->usb_transfer->status == LIBUSB_TRANSFER_COMPLETED) { + const int image_size = mdev->image.width * mdev->image.height; + const struct device_image *image = NULL; + /* Image received? Convert, else drop. */ + if (mdev->usb_transfer->actual_length == image_size) { + image_bayer2argb(mdev->rawbuffer, mdev->image.pixels, + mdev->image.width, mdev->image.height, + mdev->image.stride); + image = &mdev->image; + } + /* Pending updates? */ + if (mdev->exposure_pending) { + moticam_control_exposure(device, mdev->exposure_ms); + mdev->exposure_pending = false; + } + if (mdev->gain_pending) { + moticam_control_gain(device, mdev->gain); + mdev->gain_pending = false; + } + /* Start a new transfer. */ + mdev->usb_transfer_done = false; + int r = libusb_submit_transfer(mdev->usb_transfer); + if (r) + utils_fatal("can not submit transfer: %s", + libusb_strerror(r)); + /* Return converted image or NULL. */ + return image; + } else { + utils_fatal("transfer stopped: TODO"); + return NULL; + } + } else return NULL; - } } static void -moticam_close(struct device *device) +moticam_stop(struct device *device) { struct moticam_device *mdev = (struct moticam_device *) device; + assert(mdev->image.pixels); + /* Cancel transfer if running. */ + if (!mdev->usb_transfer_done) { + libusb_cancel_transfer(mdev->usb_transfer); + while (!mdev->usb_transfer_done) + libusb_handle_events(mdev->usb); + } + /* Release. */ + libusb_free_transfer(mdev->usb_transfer); + mdev->usb_transfer = NULL; + libusb_dev_mem_free(mdev->handle, mdev->rawbuffer, mdev->rawbuffer_size); + mdev->rawbuffer = NULL; + free(mdev->image.pixels); + mdev->image.pixels = NULL; + /* Stop camera. */ moticam_control_exposure(device, 0.0); moticam_control_exposure(device, 0.0); moticam_control_exposure(device, 0.0); +} + +static void +moticam_close(struct device *device) +{ + struct moticam_device *mdev = (struct moticam_device *) device; + if (mdev->image.pixels) + moticam_stop(device); libusb_close(mdev->handle); - if (mdev->image.pixels) { - free(mdev->rawbuffer); - free(mdev->image.pixels); - } free(device); } @@ -297,7 +353,7 @@ moticam_usb_poll(struct libusb_device_descriptor *desc) } static struct device * -moticam_usb_open(libusb_device *usb_device) +moticam_usb_open(libusb_context *usb, libusb_device *usb_device) { /* Create context. */ struct moticam_device *mdev = @@ -306,24 +362,30 @@ moticam_usb_open(libusb_device *usb_device) mdev->device.set_exposure = &moticam_set_exposure; mdev->device.set_gain = &moticam_set_gain; mdev->device.set_resolution = &moticam_set_resolution; + mdev->device.start = &moticam_start; mdev->device.read = &moticam_read; + mdev->device.stop = &moticam_stop; mdev->device.close = &moticam_close; + mdev->usb = usb; mdev->handle = NULL; mdev->exposure_ms = moticam_device_info.exposure_default_ms; + mdev->exposure_pending = false; mdev->gain = moticam_device_info.gain_default; + mdev->gain_pending = false; mdev->rawbuffer_size = 0; mdev->rawbuffer = NULL; mdev->image.width = 0; mdev->image.height = 0; mdev->image.stride = 0; mdev->image.pixels = NULL; + mdev->usb_transfer = NULL; + mdev->usb_transfer_done = false; /* Open USB device. */ int r = libusb_open(usb_device, &mdev->handle); if (r) utils_fatal("can not open device: %s", libusb_strerror(r)); - /* Initialize camera. */ + /* Reset camera. */ moticam_control_reset(&mdev->device); - moticam_control_exposure(&mdev->device, 30.0); /* Done. */ return &mdev->device; } -- cgit v1.2.3