summaryrefslogtreecommitdiff
path: root/moticam.c
diff options
context:
space:
mode:
Diffstat (limited to 'moticam.c')
-rw-r--r--moticam.c254
1 files changed, 162 insertions, 92 deletions
diff --git a/moticam.c b/moticam.c
index 4e83225..232fb77 100644
--- a/moticam.c
+++ b/moticam.c
@@ -22,13 +22,7 @@
* Web: http://ni.fr.eu.org/
* Email: <nico at ni.fr.eu.org>
*/
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdbool.h>
-
-#include "device.h"
-#include "image.h"
+#include "moticam.h"
#include "utils.h"
#define ID_VENDOR 0x232f
@@ -56,8 +50,13 @@ struct moticam_device {
static char *
moticam_usb_poll(struct libusb_device_descriptor *desc);
+
static struct device *
-moticam_usb_open(libusb_context *usb, libusb_device *usb_device);
+moticam_usb_open(libusb_context *usb, libusb_device *usb_device,
+ GError **error);
+
+static bool
+moticam_stop(struct device *device, GError **error);
const struct device_driver moticam_device_driver = {
"Moticam USB cameras",
@@ -84,46 +83,58 @@ static const struct device_info moticam_device_info = {
.resolution = moticam_device_info_resolution,
};
-static void
-moticam_control_vendor(struct device *device, uint16_t wValue,
- const uint8_t *data, int data_cnt)
+static bool
+moticam_control_vendor(struct moticam_device *mdev, uint16_t wValue,
+ const uint8_t *data, int data_cnt, GError **error)
{
- struct moticam_device *mdev = (struct moticam_device *) device;
+ g_return_val_if_fail(error == NULL || *error == NULL, false);
int r = libusb_control_transfer(mdev->handle, LIBUSB_REQUEST_TYPE_VENDOR,
240, wValue, 0, (uint8_t *) data, data_cnt, 0);
- if (r < 0)
- utils_fatal("can not send vendor control: %s", libusb_strerror(r));
+ if (r < 0) {
+ g_set_error(error, DEVICE_ERROR, DEVICE_ERROR_USB,
+ "can not send vendor control: %s", libusb_strerror(r));
+ return false;
+ }
+ return true;
}
-static void
-moticam_control_vendor_w(struct device *device, uint16_t wValue,
- const uint16_t data0)
+static bool
+moticam_control_vendor_w(struct moticam_device *mdev, uint16_t wValue,
+ const uint16_t data0, GError **error)
{
+ g_return_val_if_fail(error == NULL || *error == NULL, false);
uint8_t data[] = { (uint8_t) (data0 >> 8), (uint8_t) data0 };
- moticam_control_vendor(device, wValue, data, sizeof(data));
+ return moticam_control_vendor(mdev, wValue, data, sizeof(data), error);
}
-static void
-moticam_control_reset(struct device *device)
+static bool
+moticam_control_reset(struct moticam_device *mdev, GError **error)
{
- moticam_control_vendor_w(device, 0xba00, 0x0000);
- moticam_control_vendor_w(device, 0xba00, 0x0001);
+ g_return_val_if_fail(error == NULL || *error == NULL, false);
+ if (!moticam_control_vendor_w(mdev, 0xba00, 0x0000, error))
+ return false;
+ if (!moticam_control_vendor_w(mdev, 0xba00, 0x0001, error))
+ return false;
+ return true;
}
-static void
-moticam_control_exposure(struct device *device, double exposure_ms)
+static bool
+moticam_control_exposure(struct moticam_device *mdev, double exposure_ms,
+ GError **error)
{
+ g_return_val_if_fail(error == NULL || *error == NULL, false);
int exposure_w = exposure_ms * 12.82;
if (exposure_w < 0x000c)
exposure_w = 0x000c;
else if (exposure_w > 0xffff)
exposure_w = 0xffff;
- moticam_control_vendor_w(device, 0xba09, exposure_w);
+ return moticam_control_vendor_w(mdev, 0xba09, exposure_w, error);
}
-static void
-moticam_control_gain(struct device *device, double gain)
+static bool
+moticam_control_gain(struct moticam_device *mdev, double gain, GError **error)
{
+ g_return_val_if_fail(error == NULL || *error == NULL, false);
double gmin, gmax;
int xmin, xmax;
bool up = false;
@@ -151,42 +162,52 @@ moticam_control_gain(struct device *device, double gain)
x = xmax;
if (up)
x = (x << 8) | 0x60;
- moticam_control_vendor_w(device, 0xba2d, x);
- moticam_control_vendor_w(device, 0xba2b, x);
- moticam_control_vendor_w(device, 0xba2e, x);
- moticam_control_vendor_w(device, 0xba2c, x);
+ if (!moticam_control_vendor_w(mdev, 0xba2d, x, error))
+ return false;
+ if (!moticam_control_vendor_w(mdev, 0xba2b, x, error))
+ return false;
+ if (!moticam_control_vendor_w(mdev, 0xba2e, x, error))
+ return false;
+ if (!moticam_control_vendor_w(mdev, 0xba2c, x, error))
+ return false;
+ return true;
}
-static void
-moticam_control_resolution(struct device *device, int width, int height)
+static bool
+moticam_control_resolution(struct moticam_device *mdev, int width, int height,
+ GError **error)
{
+ g_return_val_if_fail(error == NULL || *error == NULL, false);
static const uint8_t control_init[] = {
0x00, 0x14, 0x00, 0x20, 0x05, 0xff, 0x07, 0xff };
- moticam_control_vendor(device, 0xba01, control_init,
- sizeof(control_init));
+ if (!moticam_control_vendor(mdev, 0xba01, control_init,
+ sizeof(control_init), error))
+ return false;
static const uint8_t control_512x384[] = { 0x00, 0x03, 0x00, 0x03 };
static const uint8_t control_1024x768[] = { 0x00, 0x11, 0x00, 0x11 };
static const uint8_t control_2048x1536[] = { 0x00, 0x00, 0x00, 0x00 };
+ bool ret;
switch (width)
{
case 512:
- assert(height == 384);
- moticam_control_vendor(device, 0xba22, control_512x384,
- sizeof(control_512x384));
+ g_assert(height == 384);
+ ret = moticam_control_vendor(mdev, 0xba22, control_512x384,
+ sizeof(control_512x384), error);
break;
case 1024:
- assert(height == 768);
- moticam_control_vendor(device, 0xba22, control_1024x768,
- sizeof(control_1024x768));
+ g_assert(height == 768);
+ ret = moticam_control_vendor(mdev, 0xba22, control_1024x768,
+ sizeof(control_1024x768), error);
break;
case 2048:
- assert(height == 1536);
- moticam_control_vendor(device, 0xba22, control_2048x1536,
- sizeof(control_2048x1536));
+ g_assert(height == 1536);
+ ret = moticam_control_vendor(mdev, 0xba22, control_2048x1536,
+ sizeof(control_2048x1536), error);
break;
default:
- assert(0);
+ g_assert_not_reached();
}
+ return ret;
}
static const struct device_info *
@@ -216,7 +237,7 @@ moticam_set_resolution(struct device *device, int width, int height,
int stride)
{
struct moticam_device *mdev = (struct moticam_device *) device;
- assert(!mdev->current_image);
+ g_assert(!mdev->current_image);
/* Ignore stride, store parameters. */
mdev->width = width;
mdev->height = height;
@@ -229,16 +250,21 @@ moticam_transfer_cb(struct libusb_transfer *transfer)
mdev->usb_transfer_done = true;
}
-static void
-moticam_start(struct device *device)
+static bool
+moticam_start(struct device *device, GError **error)
{
+ g_return_val_if_fail(error == NULL || *error == NULL, false);
struct moticam_device *mdev = (struct moticam_device *) device;
- assert(!mdev->current_image);
+ g_assert(!mdev->current_image);
/* Configure camera. */
- moticam_control_exposure(&mdev->device, 30.0);
- moticam_control_gain(&mdev->device, mdev->gain);
- moticam_control_resolution(&mdev->device, mdev->width, mdev->height);
- moticam_control_exposure(&mdev->device, mdev->exposure_ms);
+ if (!moticam_control_exposure(mdev, 30.0, error))
+ return false;
+ if (!moticam_control_gain(mdev, mdev->gain, error))
+ return false;
+ if (!moticam_control_resolution(mdev, mdev->width, mdev->height, error))
+ return false;
+ if (!moticam_control_exposure(mdev, mdev->exposure_ms, error))
+ return false;
mdev->exposure_pending = false;
mdev->gain_pending = false;
utils_delay_us(100000);
@@ -257,8 +283,8 @@ moticam_start(struct device *device)
image->pixels = libusb_dev_mem_alloc(mdev->handle,
mdev->rawbuffer_size);
if (!image->pixels)
- utils_fatal("can not allocate raw buffer");
- assert(image->refs == 0);
+ g_error("can not allocate raw buffer");
+ g_assert(image->refs == 0);
image->release = NULL;
image->release_user_data = NULL;
}
@@ -272,19 +298,27 @@ moticam_start(struct device *device)
mdev->current_image->pixels, mdev->rawbuffer_size,
moticam_transfer_cb, mdev, 30000);
int r = libusb_submit_transfer(mdev->usb_transfer);
- if (r)
- utils_fatal("can not submit transfer: %s", libusb_strerror(r));
+ if (r) {
+ g_set_error(error, DEVICE_ERROR, DEVICE_ERROR_USB,
+ "can not submit transfer: %s", libusb_strerror(r));
+ /* Cancel start. */
+ moticam_stop(device, NULL);
+ return false;
+ }
+ return true;
}
static struct image *
-moticam_read(struct device *device)
+moticam_read(struct device *device, GError **error)
{
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
struct moticam_device *mdev = (struct moticam_device *) device;
- assert(mdev->current_image);
+ g_assert(mdev->current_image);
if (mdev->usb_transfer_done) {
if (mdev->usb_transfer->status == LIBUSB_TRANSFER_COMPLETED) {
const int image_size = mdev->width * mdev->height;
struct image *image = NULL;
+ bool error_set = false;
/* Image received? Return it, else drop. */
if (!mdev->drop
&& mdev->usb_transfer->actual_length == image_size) {
@@ -296,42 +330,67 @@ moticam_read(struct device *device)
if (mdev->drop)
mdev->drop--;
/* Pending updates? */
- if (mdev->exposure_pending) {
- moticam_control_exposure(device, mdev->exposure_ms);
- mdev->exposure_pending = false;
+ if (image && !error_set && mdev->exposure_pending) {
+ if (!moticam_control_exposure(mdev, mdev->exposure_ms, error))
+ error_set = true;
+ else
+ mdev->exposure_pending = false;
}
- if (mdev->gain_pending) {
- moticam_control_gain(device, mdev->gain);
- mdev->gain_pending = false;
+ if (image && !error_set && mdev->gain_pending) {
+ if (!moticam_control_gain(mdev, mdev->gain, error))
+ error_set = true;
+ else
+ mdev->gain_pending = false;
}
/* Start a new transfer. */
- assert(mdev->current_image->refs == 0);
- mdev->usb_transfer_done = false;
- mdev->usb_transfer->buffer = mdev->current_image->pixels;
- int r = libusb_submit_transfer(mdev->usb_transfer);
- if (r)
- utils_fatal("can not submit transfer: %s",
- libusb_strerror(r));
+ if (!error_set) {
+ g_assert(mdev->current_image->refs == 0);
+ mdev->usb_transfer_done = false;
+ mdev->usb_transfer->buffer = mdev->current_image->pixels;
+ int r = libusb_submit_transfer(mdev->usb_transfer);
+ if (r) {
+ g_set_error(error, DEVICE_ERROR, DEVICE_ERROR_USB,
+ "can not submit transfer: %s", libusb_strerror(r));
+ error_set = true;
+ }
+ }
/* Return image or NULL. */
+ if (error_set && image) {
+ image_unref(image);
+ image = NULL;
+ }
return image;
} else {
- utils_fatal("transfer stopped: TODO");
+ g_set_error(error, DEVICE_ERROR, DEVICE_ERROR_USB,
+ "transfer stopped");
return NULL;
}
} else
return NULL;
}
-static void
-moticam_stop(struct device *device)
+static bool
+moticam_stop(struct device *device, GError **error)
{
+ g_return_val_if_fail(error == NULL || *error == NULL, false);
struct moticam_device *mdev = (struct moticam_device *) device;
- assert(mdev->current_image);
+ g_assert(mdev->current_image);
+ bool ret = true;
/* 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);
+ int r = libusb_cancel_transfer(mdev->usb_transfer);
+ if (r && r != LIBUSB_ERROR_NOT_FOUND) {
+ g_set_error(error, DEVICE_ERROR, DEVICE_ERROR_USB,
+ "can not cancel transfer: %s", libusb_strerror(r));
+ ret = false;
+ }
+ while (!mdev->usb_transfer_done) {
+ int r = libusb_handle_events(mdev->usb);
+ if (r) {
+ g_error("unable to handle libusb events: %s",
+ libusb_strerror(r));
+ }
+ }
}
/* Release. */
libusb_free_transfer(mdev->usb_transfer);
@@ -344,19 +403,22 @@ moticam_stop(struct device *device)
mdev->current_image = NULL;
mdev->other_image = NULL;
/* Stop camera. */
- moticam_control_exposure(device, 0.0);
- moticam_control_exposure(device, 0.0);
- moticam_control_exposure(device, 0.0);
+ for (int i = 0; ret && i < 3; i++)
+ ret = moticam_control_exposure(mdev, 0.0, error);
+ return ret;
}
-static void
-moticam_close(struct device *device)
+static bool
+moticam_close(struct device *device, GError **error)
{
+ g_return_val_if_fail(error == NULL || *error == NULL, false);
struct moticam_device *mdev = (struct moticam_device *) device;
+ bool ret = true;
if (mdev->current_image)
- moticam_stop(device);
+ ret = moticam_stop(device, error);
libusb_close(mdev->handle);
free(device);
+ return ret;
}
static char *
@@ -365,17 +427,18 @@ moticam_usb_poll(struct libusb_device_descriptor *desc)
if (desc->idVendor == ID_VENDOR
&& (desc->idProduct == ID_PRODUCT
|| desc->idProduct == ID_PRODUCT_USB3))
- return strdup("Moticam 3+");
+ return g_strdup("Moticam 3+");
else
return NULL;
}
static struct device *
-moticam_usb_open(libusb_context *usb, libusb_device *usb_device)
+moticam_usb_open(libusb_context *usb, libusb_device *usb_device,
+ GError **error)
{
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
/* Create context. */
- struct moticam_device *mdev =
- utils_malloc(sizeof(struct moticam_device));
+ struct moticam_device *mdev = g_new(struct moticam_device, 1);
mdev->device.get_info = &moticam_get_info;
mdev->device.set_exposure = &moticam_set_exposure;
mdev->device.set_gain = &moticam_set_gain;
@@ -403,10 +466,17 @@ moticam_usb_open(libusb_context *usb, libusb_device *usb_device)
mdev->drop = 1;
/* Open USB device. */
int r = libusb_open(usb_device, &mdev->handle);
- if (r)
- utils_fatal("can not open device: %s", libusb_strerror(r));
+ if (r) {
+ g_set_error(error, DEVICE_ERROR, DEVICE_ERROR_USB,
+ "can not open device: %s", libusb_strerror(r));
+ g_free(mdev);
+ return NULL;
+ }
/* Reset camera. */
- moticam_control_reset(&mdev->device);
+ if (!moticam_control_reset(mdev, error)) {
+ g_free(mdev);
+ return NULL;
+ }
/* Done. */
return &mdev->device;
}