summaryrefslogtreecommitdiff
path: root/moticam.c
diff options
context:
space:
mode:
authorNicolas Schodet2019-11-12 15:54:32 +0100
committerNicolas Schodet2019-11-14 00:41:59 +0100
commitaea9101e6b3da183adcd99f5377c799d194efd11 (patch)
treefc0129281c7459071918817e72377326e2d5b094 /moticam.c
parent2365eb0d2351308e9f2bf445dc59a84bedc03e7a (diff)
Replace SDL GUI with GTK+ GUI.
Diffstat (limited to 'moticam.c')
-rw-r--r--moticam.c162
1 files changed, 112 insertions, 50 deletions
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;
}