diff options
author | Dimitri Stolnikov <horiz0n@gmx.net> | 2012-08-08 21:21:46 +0200 |
---|---|---|
committer | Dimitri Stolnikov <horiz0n@gmx.net> | 2012-08-08 21:21:46 +0200 |
commit | 22b9d82fb5b99283c904061e53278f2f5fdc8252 (patch) | |
tree | 69487cb7cd73cfa7fa80dc19050a5e3c9547f9f3 /src | |
parent | b49a8336eeb7ad2e6ea9a00cec9b61a41b21d788 (diff) |
implement a more robust cancelation mechanism of async reader
Diffstat (limited to 'src')
-rw-r--r-- | src/librtlsdr.c | 35 |
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; } |