aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDimitri Stolnikov <horiz0n@gmx.net>2012-08-08 21:21:46 +0200
committerDimitri Stolnikov <horiz0n@gmx.net>2012-08-08 21:21:46 +0200
commit22b9d82fb5b99283c904061e53278f2f5fdc8252 (patch)
tree69487cb7cd73cfa7fa80dc19050a5e3c9547f9f3 /src
parentb49a8336eeb7ad2e6ea9a00cec9b61a41b21d788 (diff)
implement a more robust cancelation mechanism of async reader
Diffstat (limited to 'src')
-rw-r--r--src/librtlsdr.c35
1 files changed, 27 insertions, 8 deletions
diff --git a/src/librtlsdr.c b/src/librtlsdr.c
index 1ed81ce..3a67b53 100644
--- a/src/librtlsdr.c
+++ b/src/librtlsdr.c
@@ -1143,6 +1143,10 @@ int rtlsdr_close(rtlsdr_dev_t *dev)
if (!dev)
return -1;
+ /* block until all async operations have been completed (if any) */
+ while (RTLSDR_INACTIVE != dev->async_status)
+ usleep(10);
+
rtlsdr_deinit_baseband(dev);
libusb_release_interface(dev->devh, 0);
@@ -1183,9 +1187,10 @@ static void LIBUSB_CALL _libusb_callback(struct libusb_transfer *xfer)
dev->cb(xfer->buffer, xfer->actual_length, dev->cb_ctx);
libusb_submit_transfer(xfer); /* resubmit transfer */
+ } else if (LIBUSB_TRANSFER_CANCELLED == xfer->status) {
+ /* nothing to do */
} else {
/*fprintf(stderr, "transfer status: %d\n", xfer->status);*/
- rtlsdr_cancel_async(dev); /* abort async loop */
}
}
@@ -1255,12 +1260,18 @@ int rtlsdr_read_async(rtlsdr_dev_t *dev, rtlsdr_read_async_cb_t cb, void *ctx,
uint32_t buf_num, uint32_t buf_len)
{
unsigned int i;
- int r;
+ int r = 0;
struct timeval tv = { 1, 0 };
+ enum rtlsdr_async_status next_status = RTLSDR_INACTIVE;
if (!dev)
return -1;
+ if (RTLSDR_INACTIVE != dev->async_status)
+ return -2;
+
+ dev->async_status = RTLSDR_RUNNING;
+
dev->cb = cb;
dev->cb_ctx = ctx;
@@ -1289,8 +1300,6 @@ int rtlsdr_read_async(rtlsdr_dev_t *dev, rtlsdr_read_async_cb_t cb, void *ctx,
libusb_submit_transfer(dev->xfer[i]);
}
- dev->async_status = RTLSDR_RUNNING;
-
while (RTLSDR_INACTIVE != dev->async_status) {
r = libusb_handle_events_timeout(dev->ctx, &tv);
if (r < 0) {
@@ -1301,7 +1310,7 @@ int rtlsdr_read_async(rtlsdr_dev_t *dev, rtlsdr_read_async_cb_t cb, void *ctx,
}
if (RTLSDR_CANCELING == dev->async_status) {
- dev->async_status = RTLSDR_INACTIVE;
+ next_status = RTLSDR_INACTIVE;
if (!dev->xfer)
break;
@@ -1310,19 +1319,22 @@ int rtlsdr_read_async(rtlsdr_dev_t *dev, rtlsdr_read_async_cb_t cb, void *ctx,
if (!dev->xfer[i])
continue;
- if (dev->xfer[i]->status == LIBUSB_TRANSFER_COMPLETED) {
+ if (LIBUSB_TRANSFER_CANCELLED !=
+ dev->xfer[i]->status) {
libusb_cancel_transfer(dev->xfer[i]);
- dev->async_status = RTLSDR_CANCELING;
+ next_status = RTLSDR_CANCELING;
}
}
- if (RTLSDR_INACTIVE == dev->async_status)
+ if (RTLSDR_INACTIVE == next_status)
break;
}
}
_rtlsdr_free_async_buffers(dev);
+ dev->async_status = next_status;
+
return r;
}
@@ -1331,11 +1343,18 @@ int rtlsdr_cancel_async(rtlsdr_dev_t *dev)
if (!dev)
return -1;
+ /* if streaming, try to cancel gracefully */
if (RTLSDR_RUNNING == dev->async_status) {
dev->async_status = RTLSDR_CANCELING;
return 0;
}
+ /* if called while in pending state, change the state forcefully */
+ if (RTLSDR_INACTIVE != dev->async_status) {
+ dev->async_status = RTLSDR_INACTIVE;
+ return 0;
+ }
+
return -2;
}