Преглед на файлове

implement a more robust cancelation mechanism of async reader

Dimitri Stolnikov преди 12 години
родител
ревизия
22b9d82fb5
променени са 1 файла, в които са добавени 27 реда и са изтрити 8 реда
  1. 27 8
      src/librtlsdr.c

+ 27 - 8
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;
 }