From 129324b3dd1fd40206426ac39c7d02d747015859 Mon Sep 17 00:00:00 2001 From: Dimitri Stolnikov Date: Sun, 20 May 2012 14:02:53 +0200 Subject: rename osmosdr.c to libosmosdr.c --- software/libosmosdr/src/CMakeLists.txt | 4 +- software/libosmosdr/src/Makefile.am | 2 +- software/libosmosdr/src/libosmosdr.c | 618 +++++++++++++++++++++++++++++++++ software/libosmosdr/src/osmosdr.c | 618 --------------------------------- 4 files changed, 621 insertions(+), 621 deletions(-) create mode 100644 software/libosmosdr/src/libosmosdr.c delete mode 100644 software/libosmosdr/src/osmosdr.c diff --git a/software/libosmosdr/src/CMakeLists.txt b/software/libosmosdr/src/CMakeLists.txt index 7cd234b..3f4e054 100644 --- a/software/libosmosdr/src/CMakeLists.txt +++ b/software/libosmosdr/src/CMakeLists.txt @@ -21,7 +21,7 @@ # Setup library ######################################################################## add_library(osmosdr_shared SHARED - osmosdr.c + libosmosdr.c ) target_link_libraries(osmosdr_shared @@ -33,7 +33,7 @@ set_target_properties(osmosdr_shared PROPERTIES OUTPUT_NAME osmosdr) set_target_properties(osmosdr_shared PROPERTIES SOVERSION 0 VERSION 0.0.0) add_library(osmosdr_static STATIC - osmosdr.c + libosmosdr.c ) target_link_libraries(osmosdr_static diff --git a/software/libosmosdr/src/Makefile.am b/software/libosmosdr/src/Makefile.am index a930375..add6f24 100644 --- a/software/libosmosdr/src/Makefile.am +++ b/software/libosmosdr/src/Makefile.am @@ -7,5 +7,5 @@ AM_CFLAGS = -fPIC -Wall lib_LTLIBRARIES = libosmosdr.la -libosmosdr_la_SOURCES = osmosdr.c +libosmosdr_la_SOURCES = libosmosdr.c libosmosdr_la_LDFLAGS = -version-info $(LIBVERSION) diff --git a/software/libosmosdr/src/libosmosdr.c b/software/libosmosdr/src/libosmosdr.c new file mode 100644 index 0000000..fb90520 --- /dev/null +++ b/software/libosmosdr/src/libosmosdr.c @@ -0,0 +1,618 @@ +/* + * Copyright (C) 2012 by Dimitri Stolnikov + * Copyright (C) 2012 by Steve Markgraf + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#ifndef _WIN32 +#include +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +#include + +/* + * All libusb callback functions should be marked with the LIBUSB_CALL macro + * to ensure that they are compiled with the same calling convention as libusb. + * + * If the macro isn't available in older libusb versions, we simply define it. + */ +#ifndef LIBUSB_CALL +#define LIBUSB_CALL +#endif + +#include "osmosdr.h" + +typedef struct osmosdr_tuner { + /* tuner interface */ + int (*init)(void *); + int (*exit)(void *); + int (*set_freq)(void *, uint32_t freq /* Hz */); + int (*set_bw)(void *, int bw /* Hz */); + int (*set_gain)(void *, int gain /* dB */); + int (*set_gain_mode)(void *, int manual); +} osmosdr_tuner_t; + +enum osmosdr_async_status { + OSMOSDR_INACTIVE = 0, + OSMOSDR_CANCELING, + OSMOSDR_RUNNING +}; + +struct osmosdr_dev { + libusb_context *ctx; + struct libusb_device_handle *devh; + uint32_t xfer_buf_num; + uint32_t xfer_buf_len; + struct libusb_transfer **xfer; + unsigned char **xfer_buf; + osmosdr_read_async_cb_t cb; + void *cb_ctx; + enum osmosdr_async_status async_status; + /* adc context */ + uint32_t rate; /* Hz */ + uint32_t adc_clock; /* Hz */ + /* tuner context */ + osmosdr_tuner_t *tuner; + uint32_t tun_clock; /* Hz */ + uint32_t freq; /* Hz */ + int gain; /* dB */ +}; + +typedef struct osmosdr_dongle { + uint16_t vid; + uint16_t pid; + const char *name; +} osmosdr_dongle_t; + +static osmosdr_dongle_t known_devices[] = { + { 0x16c0, 0x0763, "OsmoSDR" }, + /* for future modifications of the OsmoSDR */ +}; + +#define DEFAULT_BUF_NUMBER 32 +#define DEFAULT_BUF_LENGTH (16 * 32 * 512) + +// TODO: change the constants according to the limits imposed by the hardware + +#define DEF_ADC_FREQ 28800000 +#define MIN_ADC_FREQ (DEF_ADC_FREQ - 1000) +#define MAX_ADC_FREQ (DEF_ADC_FREQ + 1000) + +#define DEF_E4K_FREQ 28800000 +#define MIN_E4K_FREQ (DEF_E4K_FREQ - 1000) +#define MAX_E4K_FREQ (DEF_E4K_FREQ + 1000) + +#define MAX_SAMP_RATE 3200000 + +#define CTRL_IN (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN) +#define CTRL_OUT (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT) +#define CTRL_TIMEOUT 300 +#define BULK_TIMEOUT 0 + +int osmosdr_set_xtal_freq(osmosdr_dev_t *dev, uint32_t adc_clock, uint32_t tun_clock) +{ + int r = 0; + + if (!dev) + return -1; + + if (adc_clock > 0 && + (adc_clock < MIN_ADC_FREQ || adc_clock > MAX_ADC_FREQ)) + return -2; + + if (dev->adc_clock != adc_clock) { + if (0 == adc_clock) + adc_clock = DEF_ADC_FREQ; + + dev->adc_clock = adc_clock; + + /* update xtal-dependent settings */ + if (dev->rate) + r = osmosdr_set_sample_rate(dev, dev->rate); + } + + if (dev->tun_clock != tun_clock) { + if (0 == tun_clock) + tun_clock = dev->adc_clock; + + dev->tun_clock = tun_clock; + + /* update xtal-dependent settings */ + if (dev->freq) + r = osmosdr_set_center_freq(dev, dev->freq); + } + + return r; +} + +int osmosdr_get_xtal_freq(osmosdr_dev_t *dev, uint32_t *adc_clock, uint32_t *tun_clock) +{ + if (!dev) + return -1; + + *adc_clock = dev->adc_clock; + + if (!dev->tuner) + return -2; + + *tun_clock = dev->tun_clock; + + return 0; +} + +int osmosdr_set_center_freq(osmosdr_dev_t *dev, uint32_t freq) +{ + int r = -1; + double f = (double) freq; + + if (!dev || !dev->tuner) + return -1; + + if (dev->tuner->set_freq) { + /* TODO: r = dev->tuner->set_freq(dev, freq); */ + } + + if (!r) + dev->freq = freq; + else + dev->freq = 0; + + return r; +} + +uint32_t osmosdr_get_center_freq(osmosdr_dev_t *dev) +{ + if (!dev || !dev->tuner) + return 0; + + return dev->freq; +} + +int osmosdr_set_tuner_gain(osmosdr_dev_t *dev, int gain) +{ + int r = 0; + + if (!dev || !dev->tuner) + return -1; + + if (dev->tuner->set_gain) { + /* TODO: r = dev->tuner->set_gain((void *)dev, gain); */ + } + + if (!r) + dev->gain = gain; + else + dev->gain = 0; + + return r; +} + +int osmosdr_get_tuner_gain(osmosdr_dev_t *dev) +{ + if (!dev || !dev->tuner) + return 0; + + return dev->gain; +} + +int osmosdr_set_tuner_gain_mode(osmosdr_dev_t *dev, int mode) +{ + int r = 0; + + if (!dev || !dev->tuner) + return -1; + + if (dev->tuner->set_gain_mode) { + /* TODO: r = dev->tuner->set_gain_mode((void *)dev, mode); */ + } + + return r; +} + +int osmosdr_set_sample_rate(osmosdr_dev_t *dev, uint32_t samp_rate) +{ + uint16_t r = 0; + + if (!dev) + return -1; + + /* check for the maximum rate the resampler supports */ + if (samp_rate > MAX_SAMP_RATE) + samp_rate = MAX_SAMP_RATE; + + if (dev->tuner && dev->tuner->set_bw) { + /* TODO: dev->tuner->set_bw(dev, samp_rate); */ + } + + if (!r) + dev->rate = samp_rate; + else + dev->rate = 0; + + return 0; +} + +uint32_t osmosdr_get_sample_rate(osmosdr_dev_t *dev) +{ + if (!dev) + return 0; + + return dev->rate; +} + +osmosdr_dongle_t *find_known_device(uint16_t vid, uint16_t pid) +{ + unsigned int i; + osmosdr_dongle_t *device = NULL; + + for (i = 0; i < sizeof(known_devices)/sizeof(osmosdr_dongle_t); i++ ) { + if (known_devices[i].vid == vid && known_devices[i].pid == pid) { + device = &known_devices[i]; + break; + } + } + + return device; +} + +uint32_t osmosdr_get_device_count(void) +{ + int i; + libusb_context *ctx; + libusb_device **list; + uint32_t device_count = 0; + struct libusb_device_descriptor dd; + ssize_t cnt; + + libusb_init(&ctx); + + cnt = libusb_get_device_list(ctx, &list); + + for (i = 0; i < cnt; i++) { + libusb_get_device_descriptor(list[i], &dd); + + if (find_known_device(dd.idVendor, dd.idProduct)) + device_count++; + } + + libusb_free_device_list(list, 1); + + libusb_exit(ctx); + + return device_count; +} + +const char *osmosdr_get_device_name(uint32_t index) +{ + int i; + libusb_context *ctx; + libusb_device **list; + struct libusb_device_descriptor dd; + osmosdr_dongle_t *device = NULL; + uint32_t device_count = 0; + ssize_t cnt; + + libusb_init(&ctx); + + cnt = libusb_get_device_list(ctx, &list); + + for (i = 0; i < cnt; i++) { + libusb_get_device_descriptor(list[i], &dd); + + device = find_known_device(dd.idVendor, dd.idProduct); + + if (device) { + device_count++; + + if (index == device_count - 1) + break; + } + } + + libusb_free_device_list(list, 1); + + libusb_exit(ctx); + + if (device) + return device->name; + else + return ""; +} + +int osmosdr_open(osmosdr_dev_t **out_dev, uint32_t index) +{ + int r; + int i; + libusb_device **list; + osmosdr_dev_t *dev = NULL; + libusb_device *device = NULL; + uint32_t device_count = 0; + struct libusb_device_descriptor dd; + uint8_t reg; + ssize_t cnt; + + dev = malloc(sizeof(osmosdr_dev_t)); + if (NULL == dev) + return -ENOMEM; + + memset(dev, 0, sizeof(osmosdr_dev_t)); + + libusb_init(&dev->ctx); + + cnt = libusb_get_device_list(dev->ctx, &list); + + for (i = 0; i < cnt; i++) { + device = list[i]; + + libusb_get_device_descriptor(list[i], &dd); + + if (find_known_device(dd.idVendor, dd.idProduct)) { + device_count++; + } + + if (index == device_count - 1) + break; + + device = NULL; + } + + if (!device) { + r = -1; + goto err; + } + + r = libusb_open(device, &dev->devh); + if (r < 0) { + libusb_free_device_list(list, 1); + fprintf(stderr, "usb_open error %d\n", r); + goto err; + } + + libusb_free_device_list(list, 1); + + r = libusb_claim_interface(dev->devh, 0); + if (r < 0) { + fprintf(stderr, "usb_claim_interface error %d\n", r); + goto err; + } + + dev->adc_clock = DEF_ADC_FREQ; + + /* TODO: osmosdr_init_baseband(dev); */ + +found: + if (dev->tuner) { + dev->tun_clock = dev->adc_clock; + + if (dev->tuner->init) { + /* TODO: r = dev->tuner->init(dev); */ + } + } + + *out_dev = dev; + + return 0; +err: + if (dev) { + if (dev->ctx) + libusb_exit(dev->ctx); + + free(dev); + } + + return r; +} + +int osmosdr_close(osmosdr_dev_t *dev) +{ + if (!dev) + return -1; + + /* TODO: osmosdr_deinit_baseband(dev); */ + + libusb_release_interface(dev->devh, 0); + libusb_close(dev->devh); + + libusb_exit(dev->ctx); + + free(dev); + + return 0; +} + +int osmosdr_reset_buffer(osmosdr_dev_t *dev) +{ + if (!dev) + return -1; + + /* TODO: implement */ + + return 0; +} + +int osmosdr_read_sync(osmosdr_dev_t *dev, void *buf, int len, int *n_read) +{ + if (!dev) + return -1; + + return libusb_bulk_transfer(dev->devh, 0x81, buf, len, n_read, BULK_TIMEOUT); +} + +static void LIBUSB_CALL _libusb_callback(struct libusb_transfer *xfer) +{ + osmosdr_dev_t *dev = (osmosdr_dev_t *)xfer->user_data; + + if (LIBUSB_TRANSFER_COMPLETED == xfer->status) { + if (dev->cb) + dev->cb(xfer->buffer, xfer->actual_length, dev->cb_ctx); + + libusb_submit_transfer(xfer); /* resubmit transfer */ + } else { + /*fprintf(stderr, "transfer status: %d\n", xfer->status);*/ + osmosdr_cancel_async(dev); /* abort async loop */ + } +} + +static int _osmosdr_alloc_async_buffers(osmosdr_dev_t *dev) +{ + unsigned int i; + + if (!dev) + return -1; + + if (!dev->xfer) { + dev->xfer = malloc(dev->xfer_buf_num * + sizeof(struct libusb_transfer *)); + + for(i = 0; i < dev->xfer_buf_num; ++i) + dev->xfer[i] = libusb_alloc_transfer(0); + } + + if (!dev->xfer_buf) { + dev->xfer_buf = malloc(dev->xfer_buf_num * + sizeof(unsigned char *)); + + for(i = 0; i < dev->xfer_buf_num; ++i) + dev->xfer_buf[i] = malloc(dev->xfer_buf_len); + } + + return 0; +} + +static int _osmosdr_free_async_buffers(osmosdr_dev_t *dev) +{ + unsigned int i; + + if (!dev) + return -1; + + if (dev->xfer) { + for(i = 0; i < dev->xfer_buf_num; ++i) { + if (dev->xfer[i]) { + libusb_free_transfer(dev->xfer[i]); + } + } + + free(dev->xfer); + dev->xfer = NULL; + } + + if (dev->xfer_buf) { + for(i = 0; i < dev->xfer_buf_num; ++i) { + if (dev->xfer_buf[i]) + free(dev->xfer_buf[i]); + } + + free(dev->xfer_buf); + dev->xfer_buf = NULL; + } + + return 0; +} + +int osmosdr_read_async(osmosdr_dev_t *dev, osmosdr_read_async_cb_t cb, void *ctx, + uint32_t buf_num, uint32_t buf_len) +{ + unsigned int i; + int r; + struct timeval tv = { 1, 0 }; + + if (!dev) + return -1; + + dev->cb = cb; + dev->cb_ctx = ctx; + + if (buf_num > 0) + dev->xfer_buf_num = buf_num; + else + dev->xfer_buf_num = DEFAULT_BUF_NUMBER; + + if (buf_len > 0 && buf_len % 512 == 0) /* len must be multiple of 512 */ + dev->xfer_buf_len = buf_len; + else + dev->xfer_buf_len = DEFAULT_BUF_LENGTH; + + _osmosdr_alloc_async_buffers(dev); + + for(i = 0; i < dev->xfer_buf_num; ++i) { + libusb_fill_bulk_transfer(dev->xfer[i], + dev->devh, + 0x81, + dev->xfer_buf[i], + dev->xfer_buf_len, + _libusb_callback, + (void *)dev, + BULK_TIMEOUT); + + libusb_submit_transfer(dev->xfer[i]); + } + + dev->async_status = OSMOSDR_RUNNING; + + while (OSMOSDR_INACTIVE != dev->async_status) { + r = libusb_handle_events_timeout(dev->ctx, &tv); + if (r < 0) { + /*fprintf(stderr, "handle_events returned: %d\n", r);*/ + if (r == LIBUSB_ERROR_INTERRUPTED) /* stray signal */ + continue; + break; + } + + if (OSMOSDR_CANCELING == dev->async_status) { + dev->async_status = OSMOSDR_INACTIVE; + + if (!dev->xfer) + break; + + for(i = 0; i < dev->xfer_buf_num; ++i) { + if (!dev->xfer[i]) + continue; + + if (dev->xfer[i]->status == LIBUSB_TRANSFER_COMPLETED) { + libusb_cancel_transfer(dev->xfer[i]); + dev->async_status = OSMOSDR_CANCELING; + } + } + + if (OSMOSDR_INACTIVE == dev->async_status) + break; + } + } + + _osmosdr_free_async_buffers(dev); + + return r; +} + +int osmosdr_cancel_async(osmosdr_dev_t *dev) +{ + if (!dev) + return -1; + + if (OSMOSDR_RUNNING == dev->async_status) { + dev->async_status = OSMOSDR_CANCELING; + return 0; + } + + return -2; +} diff --git a/software/libosmosdr/src/osmosdr.c b/software/libosmosdr/src/osmosdr.c deleted file mode 100644 index fb90520..0000000 --- a/software/libosmosdr/src/osmosdr.c +++ /dev/null @@ -1,618 +0,0 @@ -/* - * Copyright (C) 2012 by Dimitri Stolnikov - * Copyright (C) 2012 by Steve Markgraf - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#ifndef _WIN32 -#include -#define min(a, b) (((a) < (b)) ? (a) : (b)) -#endif - -#include - -/* - * All libusb callback functions should be marked with the LIBUSB_CALL macro - * to ensure that they are compiled with the same calling convention as libusb. - * - * If the macro isn't available in older libusb versions, we simply define it. - */ -#ifndef LIBUSB_CALL -#define LIBUSB_CALL -#endif - -#include "osmosdr.h" - -typedef struct osmosdr_tuner { - /* tuner interface */ - int (*init)(void *); - int (*exit)(void *); - int (*set_freq)(void *, uint32_t freq /* Hz */); - int (*set_bw)(void *, int bw /* Hz */); - int (*set_gain)(void *, int gain /* dB */); - int (*set_gain_mode)(void *, int manual); -} osmosdr_tuner_t; - -enum osmosdr_async_status { - OSMOSDR_INACTIVE = 0, - OSMOSDR_CANCELING, - OSMOSDR_RUNNING -}; - -struct osmosdr_dev { - libusb_context *ctx; - struct libusb_device_handle *devh; - uint32_t xfer_buf_num; - uint32_t xfer_buf_len; - struct libusb_transfer **xfer; - unsigned char **xfer_buf; - osmosdr_read_async_cb_t cb; - void *cb_ctx; - enum osmosdr_async_status async_status; - /* adc context */ - uint32_t rate; /* Hz */ - uint32_t adc_clock; /* Hz */ - /* tuner context */ - osmosdr_tuner_t *tuner; - uint32_t tun_clock; /* Hz */ - uint32_t freq; /* Hz */ - int gain; /* dB */ -}; - -typedef struct osmosdr_dongle { - uint16_t vid; - uint16_t pid; - const char *name; -} osmosdr_dongle_t; - -static osmosdr_dongle_t known_devices[] = { - { 0x16c0, 0x0763, "OsmoSDR" }, - /* for future modifications of the OsmoSDR */ -}; - -#define DEFAULT_BUF_NUMBER 32 -#define DEFAULT_BUF_LENGTH (16 * 32 * 512) - -// TODO: change the constants according to the limits imposed by the hardware - -#define DEF_ADC_FREQ 28800000 -#define MIN_ADC_FREQ (DEF_ADC_FREQ - 1000) -#define MAX_ADC_FREQ (DEF_ADC_FREQ + 1000) - -#define DEF_E4K_FREQ 28800000 -#define MIN_E4K_FREQ (DEF_E4K_FREQ - 1000) -#define MAX_E4K_FREQ (DEF_E4K_FREQ + 1000) - -#define MAX_SAMP_RATE 3200000 - -#define CTRL_IN (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN) -#define CTRL_OUT (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT) -#define CTRL_TIMEOUT 300 -#define BULK_TIMEOUT 0 - -int osmosdr_set_xtal_freq(osmosdr_dev_t *dev, uint32_t adc_clock, uint32_t tun_clock) -{ - int r = 0; - - if (!dev) - return -1; - - if (adc_clock > 0 && - (adc_clock < MIN_ADC_FREQ || adc_clock > MAX_ADC_FREQ)) - return -2; - - if (dev->adc_clock != adc_clock) { - if (0 == adc_clock) - adc_clock = DEF_ADC_FREQ; - - dev->adc_clock = adc_clock; - - /* update xtal-dependent settings */ - if (dev->rate) - r = osmosdr_set_sample_rate(dev, dev->rate); - } - - if (dev->tun_clock != tun_clock) { - if (0 == tun_clock) - tun_clock = dev->adc_clock; - - dev->tun_clock = tun_clock; - - /* update xtal-dependent settings */ - if (dev->freq) - r = osmosdr_set_center_freq(dev, dev->freq); - } - - return r; -} - -int osmosdr_get_xtal_freq(osmosdr_dev_t *dev, uint32_t *adc_clock, uint32_t *tun_clock) -{ - if (!dev) - return -1; - - *adc_clock = dev->adc_clock; - - if (!dev->tuner) - return -2; - - *tun_clock = dev->tun_clock; - - return 0; -} - -int osmosdr_set_center_freq(osmosdr_dev_t *dev, uint32_t freq) -{ - int r = -1; - double f = (double) freq; - - if (!dev || !dev->tuner) - return -1; - - if (dev->tuner->set_freq) { - /* TODO: r = dev->tuner->set_freq(dev, freq); */ - } - - if (!r) - dev->freq = freq; - else - dev->freq = 0; - - return r; -} - -uint32_t osmosdr_get_center_freq(osmosdr_dev_t *dev) -{ - if (!dev || !dev->tuner) - return 0; - - return dev->freq; -} - -int osmosdr_set_tuner_gain(osmosdr_dev_t *dev, int gain) -{ - int r = 0; - - if (!dev || !dev->tuner) - return -1; - - if (dev->tuner->set_gain) { - /* TODO: r = dev->tuner->set_gain((void *)dev, gain); */ - } - - if (!r) - dev->gain = gain; - else - dev->gain = 0; - - return r; -} - -int osmosdr_get_tuner_gain(osmosdr_dev_t *dev) -{ - if (!dev || !dev->tuner) - return 0; - - return dev->gain; -} - -int osmosdr_set_tuner_gain_mode(osmosdr_dev_t *dev, int mode) -{ - int r = 0; - - if (!dev || !dev->tuner) - return -1; - - if (dev->tuner->set_gain_mode) { - /* TODO: r = dev->tuner->set_gain_mode((void *)dev, mode); */ - } - - return r; -} - -int osmosdr_set_sample_rate(osmosdr_dev_t *dev, uint32_t samp_rate) -{ - uint16_t r = 0; - - if (!dev) - return -1; - - /* check for the maximum rate the resampler supports */ - if (samp_rate > MAX_SAMP_RATE) - samp_rate = MAX_SAMP_RATE; - - if (dev->tuner && dev->tuner->set_bw) { - /* TODO: dev->tuner->set_bw(dev, samp_rate); */ - } - - if (!r) - dev->rate = samp_rate; - else - dev->rate = 0; - - return 0; -} - -uint32_t osmosdr_get_sample_rate(osmosdr_dev_t *dev) -{ - if (!dev) - return 0; - - return dev->rate; -} - -osmosdr_dongle_t *find_known_device(uint16_t vid, uint16_t pid) -{ - unsigned int i; - osmosdr_dongle_t *device = NULL; - - for (i = 0; i < sizeof(known_devices)/sizeof(osmosdr_dongle_t); i++ ) { - if (known_devices[i].vid == vid && known_devices[i].pid == pid) { - device = &known_devices[i]; - break; - } - } - - return device; -} - -uint32_t osmosdr_get_device_count(void) -{ - int i; - libusb_context *ctx; - libusb_device **list; - uint32_t device_count = 0; - struct libusb_device_descriptor dd; - ssize_t cnt; - - libusb_init(&ctx); - - cnt = libusb_get_device_list(ctx, &list); - - for (i = 0; i < cnt; i++) { - libusb_get_device_descriptor(list[i], &dd); - - if (find_known_device(dd.idVendor, dd.idProduct)) - device_count++; - } - - libusb_free_device_list(list, 1); - - libusb_exit(ctx); - - return device_count; -} - -const char *osmosdr_get_device_name(uint32_t index) -{ - int i; - libusb_context *ctx; - libusb_device **list; - struct libusb_device_descriptor dd; - osmosdr_dongle_t *device = NULL; - uint32_t device_count = 0; - ssize_t cnt; - - libusb_init(&ctx); - - cnt = libusb_get_device_list(ctx, &list); - - for (i = 0; i < cnt; i++) { - libusb_get_device_descriptor(list[i], &dd); - - device = find_known_device(dd.idVendor, dd.idProduct); - - if (device) { - device_count++; - - if (index == device_count - 1) - break; - } - } - - libusb_free_device_list(list, 1); - - libusb_exit(ctx); - - if (device) - return device->name; - else - return ""; -} - -int osmosdr_open(osmosdr_dev_t **out_dev, uint32_t index) -{ - int r; - int i; - libusb_device **list; - osmosdr_dev_t *dev = NULL; - libusb_device *device = NULL; - uint32_t device_count = 0; - struct libusb_device_descriptor dd; - uint8_t reg; - ssize_t cnt; - - dev = malloc(sizeof(osmosdr_dev_t)); - if (NULL == dev) - return -ENOMEM; - - memset(dev, 0, sizeof(osmosdr_dev_t)); - - libusb_init(&dev->ctx); - - cnt = libusb_get_device_list(dev->ctx, &list); - - for (i = 0; i < cnt; i++) { - device = list[i]; - - libusb_get_device_descriptor(list[i], &dd); - - if (find_known_device(dd.idVendor, dd.idProduct)) { - device_count++; - } - - if (index == device_count - 1) - break; - - device = NULL; - } - - if (!device) { - r = -1; - goto err; - } - - r = libusb_open(device, &dev->devh); - if (r < 0) { - libusb_free_device_list(list, 1); - fprintf(stderr, "usb_open error %d\n", r); - goto err; - } - - libusb_free_device_list(list, 1); - - r = libusb_claim_interface(dev->devh, 0); - if (r < 0) { - fprintf(stderr, "usb_claim_interface error %d\n", r); - goto err; - } - - dev->adc_clock = DEF_ADC_FREQ; - - /* TODO: osmosdr_init_baseband(dev); */ - -found: - if (dev->tuner) { - dev->tun_clock = dev->adc_clock; - - if (dev->tuner->init) { - /* TODO: r = dev->tuner->init(dev); */ - } - } - - *out_dev = dev; - - return 0; -err: - if (dev) { - if (dev->ctx) - libusb_exit(dev->ctx); - - free(dev); - } - - return r; -} - -int osmosdr_close(osmosdr_dev_t *dev) -{ - if (!dev) - return -1; - - /* TODO: osmosdr_deinit_baseband(dev); */ - - libusb_release_interface(dev->devh, 0); - libusb_close(dev->devh); - - libusb_exit(dev->ctx); - - free(dev); - - return 0; -} - -int osmosdr_reset_buffer(osmosdr_dev_t *dev) -{ - if (!dev) - return -1; - - /* TODO: implement */ - - return 0; -} - -int osmosdr_read_sync(osmosdr_dev_t *dev, void *buf, int len, int *n_read) -{ - if (!dev) - return -1; - - return libusb_bulk_transfer(dev->devh, 0x81, buf, len, n_read, BULK_TIMEOUT); -} - -static void LIBUSB_CALL _libusb_callback(struct libusb_transfer *xfer) -{ - osmosdr_dev_t *dev = (osmosdr_dev_t *)xfer->user_data; - - if (LIBUSB_TRANSFER_COMPLETED == xfer->status) { - if (dev->cb) - dev->cb(xfer->buffer, xfer->actual_length, dev->cb_ctx); - - libusb_submit_transfer(xfer); /* resubmit transfer */ - } else { - /*fprintf(stderr, "transfer status: %d\n", xfer->status);*/ - osmosdr_cancel_async(dev); /* abort async loop */ - } -} - -static int _osmosdr_alloc_async_buffers(osmosdr_dev_t *dev) -{ - unsigned int i; - - if (!dev) - return -1; - - if (!dev->xfer) { - dev->xfer = malloc(dev->xfer_buf_num * - sizeof(struct libusb_transfer *)); - - for(i = 0; i < dev->xfer_buf_num; ++i) - dev->xfer[i] = libusb_alloc_transfer(0); - } - - if (!dev->xfer_buf) { - dev->xfer_buf = malloc(dev->xfer_buf_num * - sizeof(unsigned char *)); - - for(i = 0; i < dev->xfer_buf_num; ++i) - dev->xfer_buf[i] = malloc(dev->xfer_buf_len); - } - - return 0; -} - -static int _osmosdr_free_async_buffers(osmosdr_dev_t *dev) -{ - unsigned int i; - - if (!dev) - return -1; - - if (dev->xfer) { - for(i = 0; i < dev->xfer_buf_num; ++i) { - if (dev->xfer[i]) { - libusb_free_transfer(dev->xfer[i]); - } - } - - free(dev->xfer); - dev->xfer = NULL; - } - - if (dev->xfer_buf) { - for(i = 0; i < dev->xfer_buf_num; ++i) { - if (dev->xfer_buf[i]) - free(dev->xfer_buf[i]); - } - - free(dev->xfer_buf); - dev->xfer_buf = NULL; - } - - return 0; -} - -int osmosdr_read_async(osmosdr_dev_t *dev, osmosdr_read_async_cb_t cb, void *ctx, - uint32_t buf_num, uint32_t buf_len) -{ - unsigned int i; - int r; - struct timeval tv = { 1, 0 }; - - if (!dev) - return -1; - - dev->cb = cb; - dev->cb_ctx = ctx; - - if (buf_num > 0) - dev->xfer_buf_num = buf_num; - else - dev->xfer_buf_num = DEFAULT_BUF_NUMBER; - - if (buf_len > 0 && buf_len % 512 == 0) /* len must be multiple of 512 */ - dev->xfer_buf_len = buf_len; - else - dev->xfer_buf_len = DEFAULT_BUF_LENGTH; - - _osmosdr_alloc_async_buffers(dev); - - for(i = 0; i < dev->xfer_buf_num; ++i) { - libusb_fill_bulk_transfer(dev->xfer[i], - dev->devh, - 0x81, - dev->xfer_buf[i], - dev->xfer_buf_len, - _libusb_callback, - (void *)dev, - BULK_TIMEOUT); - - libusb_submit_transfer(dev->xfer[i]); - } - - dev->async_status = OSMOSDR_RUNNING; - - while (OSMOSDR_INACTIVE != dev->async_status) { - r = libusb_handle_events_timeout(dev->ctx, &tv); - if (r < 0) { - /*fprintf(stderr, "handle_events returned: %d\n", r);*/ - if (r == LIBUSB_ERROR_INTERRUPTED) /* stray signal */ - continue; - break; - } - - if (OSMOSDR_CANCELING == dev->async_status) { - dev->async_status = OSMOSDR_INACTIVE; - - if (!dev->xfer) - break; - - for(i = 0; i < dev->xfer_buf_num; ++i) { - if (!dev->xfer[i]) - continue; - - if (dev->xfer[i]->status == LIBUSB_TRANSFER_COMPLETED) { - libusb_cancel_transfer(dev->xfer[i]); - dev->async_status = OSMOSDR_CANCELING; - } - } - - if (OSMOSDR_INACTIVE == dev->async_status) - break; - } - } - - _osmosdr_free_async_buffers(dev); - - return r; -} - -int osmosdr_cancel_async(osmosdr_dev_t *dev) -{ - if (!dev) - return -1; - - if (OSMOSDR_RUNNING == dev->async_status) { - dev->async_status = OSMOSDR_CANCELING; - return 0; - } - - return -2; -} -- cgit v1.2.3