summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base.c120
-rw-r--r--events.c25
-rw-r--r--private.h8
3 files changed, 126 insertions, 27 deletions
diff --git a/base.c b/base.c
index 53ebe4d..1355486 100644
--- a/base.c
+++ b/base.c
@@ -75,6 +75,19 @@
err = PCILIB_ERROR_INVALID_DATA; \
}
+#define LOCK(lock_name) \
+ err = pcilib_try_lock(ctx->lock_name##_lock); \
+ if (err) { \
+ pcilib_error("IPECamera is busy"); \
+ return PCILIB_ERROR_BUSY; \
+ } \
+ ctx->lock_name##_locked = 1;
+
+#define UNLOCK(lock_name) \
+ if (ctx->lock_name##_locked) { \
+ pcilib_unlock(ctx->lock_name##_lock); \
+ ctx->lock_name##_locked = 0; \
+ }
pcilib_context_t *ipecamera_init(pcilib_t *pcilib) {
int err = 0;
@@ -88,6 +101,16 @@ pcilib_context_t *ipecamera_init(pcilib_t *pcilib) {
memset(ctx, 0, sizeof(ipecamera_t));
+ ctx->run_lock = pcilib_get_lock(pcilib, PCILIB_LOCK_FLAGS_DEFAULT, "ipecamera");
+ ctx->stream_lock = pcilib_get_lock(pcilib, PCILIB_LOCK_FLAGS_DEFAULT, "ipecamera/stream");
+ ctx->trigger_lock = pcilib_get_lock(pcilib, PCILIB_LOCK_FLAGS_DEFAULT, "ipecamera/trigger");
+
+ if (!ctx->run_lock||!ctx->stream_lock||!ctx->trigger_lock) {
+ free(ctx);
+ pcilib_error("Failed to initialize locks to protect ipecamera operation");
+ return NULL;
+ }
+
ctx->buffer_size = IPECAMERA_DEFAULT_BUFFER_SIZE;
ctx->dim.bpp = sizeof(ipecamera_pixel_t) * 8;
@@ -152,6 +175,16 @@ void ipecamera_free(pcilib_context_t *vctx) {
if (vctx) {
ipecamera_t *ctx = (ipecamera_t*)vctx;
ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT);
+
+ if (ctx->trigger_lock)
+ pcilib_return_lock(vctx->pcilib, PCILIB_LOCK_FLAGS_DEFAULT, ctx->trigger_lock);
+
+ if (ctx->stream_lock)
+ pcilib_return_lock(vctx->pcilib, PCILIB_LOCK_FLAGS_DEFAULT, ctx->stream_lock);
+
+ if (ctx->run_lock)
+ pcilib_return_lock(vctx->pcilib, PCILIB_LOCK_FLAGS_DEFAULT, ctx->run_lock);
+
free(ctx);
}
}
@@ -210,40 +243,54 @@ int ipecamera_reset(pcilib_context_t *vctx) {
control = ctx->control_reg;
status = ctx->status_reg;
- // Set Reset bit to CMOSIS
- err = pcilib_write_register_by_id(pcilib, control, 0x1e4);
- if (err) {
- pcilib_error("Error setting FPGA reset bit");
- return err;
- }
- usleep(IPECAMERA_CMOSIS_RESET_DELAY);
+ LOCK(run);
+
+ ipecamera_debug(API, "ipecamera: starting");
+
+ if (ctx->firmware == IPECAMERA_FIRMWARE_UFO5) {
+ // Set Reset bit to CMOSIS
+ err = pcilib_write_register_by_id(pcilib, control, 0x1e4);
+ if (err) {
+ UNLOCK(run);
+ pcilib_error("Error setting FPGA reset bit");
+ return err;
+ }
+ usleep(IPECAMERA_CMOSIS_RESET_DELAY);
// Remove Reset bit to CMOSIS
- err = pcilib_write_register_by_id(pcilib, control, 0x1e1);
- if (err) {
- pcilib_error("Error reseting FPGA reset bit");
- return err;
- }
- usleep(IPECAMERA_CMOSIS_REGISTER_DELAY);
+ err = pcilib_write_register_by_id(pcilib, control, 0x1e1);
+ if (err) {
+ UNLOCK(run);
+ pcilib_error("Error reseting FPGA reset bit");
+ return err;
+ }
+ usleep(IPECAMERA_CMOSIS_REGISTER_DELAY);
// Special settings for CMOSIS v.2
- value = 01; err = pcilib_write_register_space(pcilib, "cmosis", 115, 1, &value);
- if (err) {
- pcilib_error("Error setting CMOSIS configuration");
- return err;
- }
- usleep(IPECAMERA_CMOSIS_REGISTER_DELAY);
+ value = 01; err = pcilib_write_register_space(pcilib, "cmosis", 115, 1, &value);
+ if (err) {
+ UNLOCK(run);
+ pcilib_error("Error setting CMOSIS configuration");
+ return err;
+ }
+ usleep(IPECAMERA_CMOSIS_REGISTER_DELAY);
- value = 07; err = pcilib_write_register_space(pcilib, "cmosis", 82, 1, &value);
- if (err) {
- pcilib_error("Error setting CMOSIS configuration");
- return err;
+ value = 07; err = pcilib_write_register_space(pcilib, "cmosis", 82, 1, &value);
+ if (err) {
+ UNLOCK(run);
+ pcilib_error("Error setting CMOSIS configuration");
+ return err;
+ }
+ usleep(IPECAMERA_CMOSIS_REGISTER_DELAY);
+ pcilib_warning("Reset procedure is not complete");
+ } else {
+ pcilib_warning("Reset procedure is not implemented");
}
- usleep(IPECAMERA_CMOSIS_REGISTER_DELAY);
// Set default parameters
err = pcilib_write_register_by_id(pcilib, control, IPECAMERA_IDLE);
if (err) {
+ UNLOCK(run);
pcilib_error("Error bringing FPGA in default mode");
return err;
}
@@ -255,13 +302,18 @@ int ipecamera_reset(pcilib_context_t *vctx) {
if (err) {
err = pcilib_read_register_by_id(pcilib, status, &value);
+ UNLOCK(run);
if (err) pcilib_error("Error reading status register");
else pcilib_error("Camera returns unexpected status (status: %lx)", value);
return PCILIB_ERROR_VERIFY;
}
- return pcilib_skip_dma(vctx->pcilib, ctx->rdma);
+ err = pcilib_skip_dma(vctx->pcilib, ctx->rdma);
+ UNLOCK(run);
+
+ ipecamera_debug(API, "ipecamera: reset done");
+ return err;
}
@@ -288,6 +340,8 @@ int ipecamera_start(pcilib_context_t *vctx, pcilib_event_t event_mask, pcilib_ev
return PCILIB_ERROR_INVALID_REQUEST;
}
+ LOCK(run);
+
ipecamera_debug(API, "ipecamera: starting");
ctx->event_id = 0;
@@ -308,6 +362,7 @@ int ipecamera_start(pcilib_context_t *vctx, pcilib_event_t event_mask, pcilib_ev
ctx->cmosis_outputs = CMOSIS20_MAX_CHANNELS;
break;
default:
+ UNLOCK(run);
pcilib_error("Can't start undefined version (%lu) of IPECamera", ctx->firmware);
return PCILIB_ERROR_INVALID_REQUEST;
}
@@ -322,6 +377,7 @@ int ipecamera_start(pcilib_context_t *vctx, pcilib_event_t event_mask, pcilib_ev
ctx->cmosis_outputs = 4;
break;
default:
+ UNLOCK(run);
pcilib_error("IPECamera reporting invalid output_mode 0x%lx", value);
return PCILIB_ERROR_INVALID_STATE;
}
@@ -604,7 +660,8 @@ int ipecamera_stop(pcilib_context_t *vctx, pcilib_event_flags_t flags) {
ctx->started = 0;
ipecamera_debug(API, "ipecamera: stopped");
-
+ UNLOCK(run);
+
return 0;
}
@@ -623,6 +680,9 @@ int ipecamera_trigger(pcilib_context_t *vctx, pcilib_event_t event, size_t trigg
return PCILIB_ERROR_NOTINITIALIZED;
}
+ ipecamera_debug(API, "ipecamera: trigger");
+ LOCK(trigger);
+
pcilib_sleep_until_deadline(&ctx->next_trigger);
/*
GET_REG(num_frames_reg, value);
@@ -645,9 +705,13 @@ int ipecamera_trigger(pcilib_context_t *vctx, pcilib_event_t event, size_t trigg
GET_REG(status2_reg, value);
} while ((value&0x40000000)&&(pcilib_calc_time_to_deadline(&deadline) > 0));
}
- if (value&0x40000000)
+ if (value&0x40000000) {
#endif /* IPECAMERA_TRIGGER_WAIT_IDLE */
+ UNLOCK(trigger);
return PCILIB_ERROR_BUSY;
+#ifdef IPECAMERA_TRIGGER_TIMEOUT
+ }
+#endif /* IPECAMERA_TRIGGER_WAIT_IDLE */
}
GET_REG(control_reg, value);
@@ -657,6 +721,8 @@ int ipecamera_trigger(pcilib_context_t *vctx, pcilib_event_t event, size_t trigg
// DS: We need to compute it differently, on top of that add exposure time and the time FPGA takes to read frame from CMOSIS
pcilib_calc_deadline(&ctx->next_trigger, IPECAMERA_NEXT_FRAME_DELAY);
+
+ UNLOCK(trigger);
return 0;
}
diff --git a/events.c b/events.c
index d286c73..8f740b8 100644
--- a/events.c
+++ b/events.c
@@ -19,6 +19,20 @@
#include "private.h"
#include "events.h"
+#define LOCK(lock_name) \
+ err = pcilib_lock(ctx->lock_name##_lock); \
+ if (err) { \
+ pcilib_error("IPECamera is busy"); \
+ return PCILIB_ERROR_BUSY; \
+ } \
+ ctx->lock_name##_locked = 1;
+
+#define UNLOCK(lock_name) \
+ if (ctx->lock_name##_locked) { \
+ pcilib_unlock(ctx->lock_name##_lock); \
+ ctx->lock_name##_locked = 0; \
+ }
+
int ipecamera_stream(pcilib_context_t *vctx, pcilib_event_callback_t callback, void *user) {
int run_flag = 1;
int res, err = 0;
@@ -34,6 +48,8 @@ int ipecamera_stream(pcilib_context_t *vctx, pcilib_event_callback_t callback, v
ipecamera_debug(API, "ipecamera: start streaming");
+ LOCK(stream);
+
ctx->streaming = 1;
ctx->run_streamer = 1;
@@ -79,6 +95,8 @@ int ipecamera_stream(pcilib_context_t *vctx, pcilib_event_callback_t callback, v
ctx->streaming = 0;
+ UNLOCK(stream);
+
ipecamera_debug(API, "ipecamera: streaming finished");
if (do_stop) {
@@ -89,6 +107,7 @@ int ipecamera_stream(pcilib_context_t *vctx, pcilib_event_callback_t callback, v
}
int ipecamera_next_event(pcilib_context_t *vctx, pcilib_timeout_t timeout, pcilib_event_id_t *evid, size_t info_size, pcilib_event_info_t *info) {
+ int err;
struct timeval tv;
ipecamera_t *ctx = (ipecamera_t*)vctx;
@@ -109,6 +128,8 @@ int ipecamera_next_event(pcilib_context_t *vctx, pcilib_timeout_t timeout, pcili
ipecamera_debug(API, "ipecamera: next_event");
+ LOCK(stream);
+
#ifdef IPECAMERA_ANNOUNCE_READY
if (((!ctx->preproc)&&(ctx->reported_id == ctx->event_id))||((ctx->preproc)&&(ctx->reported_id == ctx->preproc_id))) {
#else /* IPECAMERA_ANNOUNCE_READY */
@@ -138,6 +159,7 @@ int ipecamera_next_event(pcilib_context_t *vctx, pcilib_timeout_t timeout, pcili
}
if (ctx->reported_id == ctx->event_id) {
+ UNLOCK(stream);
ipecamera_debug(API, "ipecamera: next_event timed out");
return PCILIB_ERROR_TIMEOUT;
}
@@ -156,6 +178,7 @@ retry:
else if (info_size >= sizeof(pcilib_event_info_t))
memcpy(info, ctx->frame + ((ctx->reported_id-1)%ctx->buffer_size), sizeof(pcilib_event_info_t));
else {
+ UNLOCK(stream);
ipecamera_debug(API, "ipecamera: next_event returned a error");
return PCILIB_ERROR_INVALID_ARGUMENT;
}
@@ -163,6 +186,8 @@ retry:
if ((ctx->event_id - ctx->reported_id) >= ctx->buffer_size) goto retry;
+ UNLOCK(stream);
+
ipecamera_debug(API, "ipecamera: next_event returned");
return 0;
diff --git a/private.h b/private.h
index f15317e..a0034c8 100644
--- a/private.h
+++ b/private.h
@@ -4,6 +4,7 @@
#include <pthread.h>
#include <pcilib/model.h>
#include <pcilib/debug.h>
+#include <pcilib/locking.h>
#include "ipecamera.h"
#include "env.h"
@@ -163,6 +164,13 @@ struct ipecamera_s {
pcilib_context_t event;
UfoDecoder *ipedec;
+ pcilib_lock_t *run_lock; /**< Lock protecting global camera operation */
+ pcilib_lock_t *stream_lock; /**< Lock protecting stream/next_frame operations */
+ pcilib_lock_t *trigger_lock; /**< Lock protecting stream/next_frame operations */
+ int run_locked; /**< Flag indicating if camera is currently locked */
+ int stream_locked; /**< Flag indicating if camera is currently locked */
+ int trigger_locked; /**< Flag indicating if camera is currently locked */
+
char *data;
ipecamera_pixel_t *image;
size_t size;