Project

General

Profile

Download (20 KB) Statistics
| Branch: | Tag: | Revision:
1 ce0473f5 Dimitri Stolnikov
/*
2
 * Copyright (C) 2012 by Dimitri Stolnikov <horiz0n@gmx.net>
3
 * Copyright (C) 2012 by Steve Markgraf <steve@steve-m.de>
4
 *
5
 * This program is free software: you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation, either version 2 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
 */
18
19
#include <errno.h>
20
#include <signal.h>
21
#include <string.h>
22
#include <stdio.h>
23
#include <stdlib.h>
24
#include <math.h>
25
#ifndef _WIN32
26
#include <unistd.h>
27
#define min(a, b) (((a) < (b)) ? (a) : (b))
28
#endif
29
30 ba4fd966 Dimitri Stolnikov
//cross platform usleep()
31
#ifdef _MSC_VER
32
#include <windows.h>
33
#define usleep(t) Sleep((t)/1000)
34
#else
35
#include <unistd.h>
36
#endif
37
38 ce0473f5 Dimitri Stolnikov
#include <libusb.h>
39
40
/*
41
 * All libusb callback functions should be marked with the LIBUSB_CALL macro
42
 * to ensure that they are compiled with the same calling convention as libusb.
43
 *
44
 * If the macro isn't available in older libusb versions, we simply define it.
45
 */
46
#ifndef LIBUSB_CALL
47
#define LIBUSB_CALL
48
#endif
49
50
#include "osmosdr.h"
51
52
typedef struct osmosdr_tuner {
53
	/* tuner interface */
54
	int (*init)(void *);
55
	int (*exit)(void *);
56
	int (*set_freq)(void *, uint32_t freq /* Hz */);
57
	int (*set_bw)(void *, int bw /* Hz */);
58
	int (*set_gain)(void *, int gain /* dB */);
59
	int (*set_gain_mode)(void *, int manual);
60
} osmosdr_tuner_t;
61
62
enum osmosdr_async_status {
63
	OSMOSDR_INACTIVE = 0,
64
	OSMOSDR_CANCELING,
65
	OSMOSDR_RUNNING
66
};
67
68
struct osmosdr_dev {
69
	libusb_context *ctx;
70
	struct libusb_device_handle *devh;
71
	uint32_t xfer_buf_num;
72
	uint32_t xfer_buf_len;
73
	struct libusb_transfer **xfer;
74
	unsigned char **xfer_buf;
75
	osmosdr_read_async_cb_t cb;
76
	void *cb_ctx;
77
	enum osmosdr_async_status async_status;
78
	/* adc context */
79
	uint32_t rate; /* Hz */
80
	uint32_t adc_clock; /* Hz */
81
	/* tuner context */
82
	osmosdr_tuner_t *tuner;
83
	uint32_t freq; /* Hz */
84
	int gain; /* dB */
85
};
86
87
typedef struct osmosdr_dongle {
88
	uint16_t vid;
89
	uint16_t pid;
90
	const char *name;
91
} osmosdr_dongle_t;
92
93
static osmosdr_dongle_t known_devices[] = {
94 7d90bb80 Dimitri Stolnikov
	{ 0x16c0, 0x0763, "sysmocom OsmoSDR" },
95
	/* here come future modifications of the OsmoSDR */
96 ce0473f5 Dimitri Stolnikov
};
97
98
#define DEFAULT_BUF_NUMBER	32
99
#define DEFAULT_BUF_LENGTH	(16 * 32 * 512)
100
101 a630fc08 Dimitri Stolnikov
#define DEF_ADC_FREQ	4000000
102 ce0473f5 Dimitri Stolnikov
103
#define CTRL_IN		(LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN)
104
#define CTRL_OUT	(LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT)
105 bcc45534 Dimitri Stolnikov
#define FUNC(group, function) ((group << 8) | function)
106
107 ce0473f5 Dimitri Stolnikov
#define CTRL_TIMEOUT	300
108
#define BULK_TIMEOUT	0
109
110 bcc45534 Dimitri Stolnikov
int e4k_init(void *dev) {
111
	osmosdr_dev_t* devt = (osmosdr_dev_t*)dev;
112 9e2a7e19 Dimitri Stolnikov
	int res;
113
114
	res = libusb_control_transfer(devt->devh, CTRL_OUT, 0x07,
115
				      FUNC(3, 0), 0,
116
				      NULL, 0, CTRL_TIMEOUT);
117
118
	return res; /* 0 is success since we do not send any buffers out */
119 bcc45534 Dimitri Stolnikov
}
120
121
int e4k_exit(void *dev) { return 0; }
122
123
int e4k_set_freq(void *dev, uint32_t freq) {
124
	osmosdr_dev_t* devt = (osmosdr_dev_t*)dev;
125
	uint8_t buffer[4];
126 4eed4e78 Christian Daniel
	int res;
127 bcc45534 Dimitri Stolnikov
128
	buffer[0] = (uint8_t)(freq >> 24);
129
	buffer[1] = (uint8_t)(freq >> 16);
130
	buffer[2] = (uint8_t)(freq >> 8);
131
	buffer[3] = (uint8_t)(freq >> 0);
132
133 4eed4e78 Christian Daniel
	res = libusb_control_transfer(devt->devh, CTRL_OUT, 0x07,
134 9e2a7e19 Dimitri Stolnikov
				      FUNC(3, 5), 0,
135
				      buffer, sizeof(buffer), CTRL_TIMEOUT);
136 4eed4e78 Christian Daniel
137 9e2a7e19 Dimitri Stolnikov
	if (res == sizeof(buffer)) {
138 4eed4e78 Christian Daniel
		res = libusb_control_transfer(devt->devh, CTRL_OUT, 0x07,
139 9e2a7e19 Dimitri Stolnikov
					      FUNC(3, 9), 0,
140
					      NULL, 0, CTRL_TIMEOUT);
141 4eed4e78 Christian Daniel
	}
142 9e2a7e19 Dimitri Stolnikov
143 4eed4e78 Christian Daniel
	return res;
144 bcc45534 Dimitri Stolnikov
}
145
146
int e4k_set_bw(void *dev, int bw) { return 0; }
147
148
int e4k_set_lna_gain(void *dev, int32_t gain) {
149
	osmosdr_dev_t* devt = (osmosdr_dev_t*)dev;
150
	uint8_t buffer[4];
151 9e2a7e19 Dimitri Stolnikov
	int res;
152 bcc45534 Dimitri Stolnikov
153
	buffer[0] = (uint8_t)(gain >> 24);
154
	buffer[1] = (uint8_t)(gain >> 16);
155
	buffer[2] = (uint8_t)(gain >> 8);
156
	buffer[3] = (uint8_t)(gain >> 0);
157
158 9e2a7e19 Dimitri Stolnikov
	res = libusb_control_transfer(devt->devh, CTRL_OUT, 0x07,
159
				      FUNC(3, 0x0b), 0,
160
				      buffer, sizeof(buffer), CTRL_TIMEOUT);
161
162
	if (res == sizeof(buffer))
163
		res = 0;
164
165
	return res;
166 bcc45534 Dimitri Stolnikov
}
167
168
int e4k_mixer_gain_set(void *dev, int8_t gain) {
169
	osmosdr_dev_t* devt = (osmosdr_dev_t*)dev;
170
	uint8_t buffer[1];
171 9e2a7e19 Dimitri Stolnikov
	int res;
172 bcc45534 Dimitri Stolnikov
173
	buffer[0] = gain;
174
175 9e2a7e19 Dimitri Stolnikov
	res = libusb_control_transfer(devt->devh, CTRL_OUT, 0x07,
176
				      FUNC(3, 0x03), 0,
177
				      buffer, sizeof(buffer), CTRL_TIMEOUT);
178
179
	if (res == sizeof(buffer))
180
		res = 0;
181
182
	return res;
183 bcc45534 Dimitri Stolnikov
}
184
185
int e4k_set_enh_gain(void *dev, int32_t gain) {
186
	osmosdr_dev_t* devt = (osmosdr_dev_t*)dev;
187
	uint8_t buffer[4];
188 9e2a7e19 Dimitri Stolnikov
	int res;
189 bcc45534 Dimitri Stolnikov
190
	buffer[0] = (uint8_t)(gain >> 24);
191
	buffer[1] = (uint8_t)(gain >> 16);
192
	buffer[2] = (uint8_t)(gain >> 8);
193
	buffer[3] = (uint8_t)(gain >> 0);
194
195 9e2a7e19 Dimitri Stolnikov
	res = libusb_control_transfer(devt->devh, CTRL_OUT, 0x07,
196
				      FUNC(3, 0x0d), 0,
197
				      buffer, sizeof(buffer), CTRL_TIMEOUT);
198
199
	if (res == sizeof(buffer))
200
		res = 0;
201
202
	return res;
203 bcc45534 Dimitri Stolnikov
}
204
205
int e4k_set_gain(void *dev, int gain) {
206
	int8_t mixgain = (gain > 340) ? 12 : 4;
207 14f7dd44 Dimitri Stolnikov
#if 0
208 bcc45534 Dimitri Stolnikov
	int enhgain = (gain - 420);
209 14f7dd44 Dimitri Stolnikov
#endif
210
	if(e4k_set_lna_gain(dev, min(300, gain - mixgain * 10)))
211 bcc45534 Dimitri Stolnikov
		return -1;
212 9e2a7e19 Dimitri Stolnikov
	if(e4k_mixer_gain_set(dev, mixgain))
213 bcc45534 Dimitri Stolnikov
		return -1;
214 14f7dd44 Dimitri Stolnikov
#if 0 /* enhanced mixer gain seems to have no effect */
215 bcc45534 Dimitri Stolnikov
	if(enhgain >= 0)
216 9e2a7e19 Dimitri Stolnikov
		if(e4k_set_enh_gain(dev, enhgain))
217 bcc45534 Dimitri Stolnikov
			return -1;
218 14f7dd44 Dimitri Stolnikov
#endif
219 bcc45534 Dimitri Stolnikov
	return 0;
220
}
221
222
int e4k_set_gain_mode(void *dev, int manual) {
223
	osmosdr_dev_t* devt = (osmosdr_dev_t*)dev;
224
	uint8_t buffer[1];
225 9e2a7e19 Dimitri Stolnikov
	int res;
226 bcc45534 Dimitri Stolnikov
227
	buffer[0] = (uint8_t)manual;
228
229 9e2a7e19 Dimitri Stolnikov
	res = libusb_control_transfer(devt->devh, CTRL_OUT, 0x07,
230
				      FUNC(3, 0x0c), 0,
231
				      buffer, sizeof(buffer), CTRL_TIMEOUT);
232
233
	if (res == sizeof(buffer))
234
		res = 0;
235
236
	return res;
237 bcc45534 Dimitri Stolnikov
}
238
239
static osmosdr_tuner_t tuner = {
240
	e4k_init, e4k_exit,
241
	e4k_set_freq,
242
	e4k_set_bw, e4k_set_gain, e4k_set_gain_mode
243
};
244
245 7d90bb80 Dimitri Stolnikov
int osmosdr_get_usb_strings(osmosdr_dev_t *dev, char *manufact, char *product,
246
			    char *serial)
247
{
248
	struct libusb_device_descriptor dd;
249
	libusb_device *device = NULL;
250
	const int buf_max = 256;
251
	int r = 0;
252
253
	if (!dev || !dev->devh)
254
		return -1;
255
256
	device = libusb_get_device(dev->devh);
257
258
	r = libusb_get_device_descriptor(device, &dd);
259
	if (r < 0)
260
		return -1;
261
262
	if (manufact) {
263
		memset(manufact, 0, buf_max);
264
		libusb_get_string_descriptor_ascii(dev->devh, dd.iManufacturer,
265
						   (unsigned char *)manufact,
266
						   buf_max);
267
	}
268
269
	if (product) {
270
		memset(product, 0, buf_max);
271
		libusb_get_string_descriptor_ascii(dev->devh, dd.iProduct,
272
						   (unsigned char *)product,
273
						   buf_max);
274
	}
275
276
	if (serial) {
277
		memset(serial, 0, buf_max);
278
		libusb_get_string_descriptor_ascii(dev->devh, dd.iSerialNumber,
279
						   (unsigned char *)serial,
280
						   buf_max);
281
	}
282
283
	return 0;
284
}
285
286 ce0473f5 Dimitri Stolnikov
int osmosdr_set_center_freq(osmosdr_dev_t *dev, uint32_t freq)
287
{
288 9e2a7e19 Dimitri Stolnikov
	int r = -2;
289 ce0473f5 Dimitri Stolnikov
290
	if (!dev || !dev->tuner)
291
		return -1;
292
293 a630fc08 Dimitri Stolnikov
	if (dev->tuner->set_freq)
294 bcc45534 Dimitri Stolnikov
		r = dev->tuner->set_freq(dev, freq);
295 ce0473f5 Dimitri Stolnikov
296
	if (!r)
297
		dev->freq = freq;
298
	else
299
		dev->freq = 0;
300
301
	return r;
302
}
303
304
uint32_t osmosdr_get_center_freq(osmosdr_dev_t *dev)
305
{
306
	if (!dev || !dev->tuner)
307
		return 0;
308
309
	return dev->freq;
310
}
311
312 292a9868 Dimitri Stolnikov
int osmosdr_get_tuner_gains(osmosdr_dev_t *dev, int *gains)
313
{
314 14f7dd44 Dimitri Stolnikov
	/* all gain values are expressed in tenths of a dB */
315 292a9868 Dimitri Stolnikov
	const int e4k_gains[] = { -10, 15, 40, 65, 90, 115, 140, 165, 190, 215,
316 14f7dd44 Dimitri Stolnikov
				  240, 290, 340, 420 };
317 292a9868 Dimitri Stolnikov
	int len = sizeof(e4k_gains);
318
319
	if (!dev)
320
		return -1;
321
322
	if (!gains) { /* no buffer provided, just return the count */
323
		return len / sizeof(int);
324
	} else {
325
		if (len)
326
			memcpy(gains, e4k_gains, len);
327
328
		return len / sizeof(int);
329
	}
330
}
331
332 ce0473f5 Dimitri Stolnikov
int osmosdr_set_tuner_gain(osmosdr_dev_t *dev, int gain)
333
{
334 9e2a7e19 Dimitri Stolnikov
	int r = -2;
335 ce0473f5 Dimitri Stolnikov
336
	if (!dev || !dev->tuner)
337
		return -1;
338
339 a630fc08 Dimitri Stolnikov
	if (dev->tuner->set_gain)
340 bcc45534 Dimitri Stolnikov
		r = dev->tuner->set_gain((void *)dev, gain);
341 ce0473f5 Dimitri Stolnikov
342
	if (!r)
343
		dev->gain = gain;
344
	else
345
		dev->gain = 0;
346
347
	return r;
348
}
349
350
int osmosdr_get_tuner_gain(osmosdr_dev_t *dev)
351
{
352
	if (!dev || !dev->tuner)
353
		return 0;
354
355
	return dev->gain;
356
}
357
358
int osmosdr_set_tuner_gain_mode(osmosdr_dev_t *dev, int mode)
359
{
360 9e2a7e19 Dimitri Stolnikov
	int r = -2;
361 ce0473f5 Dimitri Stolnikov
362
	if (!dev || !dev->tuner)
363
		return -1;
364
365 a630fc08 Dimitri Stolnikov
	if (dev->tuner->set_gain_mode)
366 bcc45534 Dimitri Stolnikov
		r = dev->tuner->set_gain_mode((void *)dev, mode);
367 ce0473f5 Dimitri Stolnikov
368
	return r;
369
}
370
371 4eed4e78 Christian Daniel
int osmosdr_set_tuner_lna_gain(osmosdr_dev_t *dev, int gain)
372
{
373
	osmosdr_dev_t* devt = (osmosdr_dev_t*)dev;
374
	uint8_t buffer[4];
375
376
	buffer[0] = (gain >> 24);
377
	buffer[1] = (gain >> 16);
378
	buffer[2] = (gain >> 8);
379
	buffer[3] = (gain >> 0);
380
381
	return libusb_control_transfer(devt->devh, CTRL_OUT, 0x07,
382
				       FUNC(3, 0x0b), 0,
383 9e2a7e19 Dimitri Stolnikov
				       buffer, sizeof(buffer), CTRL_TIMEOUT);
384 4eed4e78 Christian Daniel
}
385
386
int osmosdr_set_tuner_mixer_gain(osmosdr_dev_t *dev, int gain)
387
{
388
	osmosdr_dev_t* devt = (osmosdr_dev_t*)dev;
389
	uint8_t buffer[1];
390
391
	buffer[0] = gain / 10;
392
393
	return libusb_control_transfer(devt->devh, CTRL_OUT, 0x07,
394
				       FUNC(3, 0x03), 0,
395 9e2a7e19 Dimitri Stolnikov
				       buffer, sizeof(buffer), CTRL_TIMEOUT);
396 4eed4e78 Christian Daniel
}
397
398
int osmosdr_set_tuner_mixer_enh(osmosdr_dev_t *dev, int enh)
399
{
400
	osmosdr_dev_t* devt = (osmosdr_dev_t*)dev;
401
	uint8_t buffer[4];
402
403
	buffer[0] = (enh >> 24);
404
	buffer[1] = (enh >> 16);
405
	buffer[2] = (enh >> 8);
406
	buffer[3] = (enh >> 0);
407
408
	return libusb_control_transfer(devt->devh, CTRL_OUT, 0x07,
409
				       FUNC(3, 0x0d), 0,
410 9e2a7e19 Dimitri Stolnikov
				       buffer, sizeof(buffer), CTRL_TIMEOUT);
411 4eed4e78 Christian Daniel
}
412
413
int osmosdr_set_tuner_if_gain(osmosdr_dev_t *dev, int stage, int gain)
414
{
415
	osmosdr_dev_t* devt = (osmosdr_dev_t*)dev;
416
	uint8_t buffer[5];
417
418
	buffer[0] = stage;
419
	gain /= 10;
420
	buffer[1] = (gain >> 24);
421
	buffer[2] = (gain >> 16);
422
	buffer[3] = (gain >> 8);
423
	buffer[4] = (gain >> 0);
424
425
	return libusb_control_transfer(devt->devh, CTRL_OUT, 0x07,
426
				       FUNC(3, 0x02), 0,
427 9e2a7e19 Dimitri Stolnikov
				       buffer, sizeof(buffer), CTRL_TIMEOUT);
428 4eed4e78 Christian Daniel
}
429
430 a630fc08 Dimitri Stolnikov
/* two raised to the power of n */
431
#define TWO_POW(n)		(1ULL<<(n))
432
433
uint32_t osmosdr_get_sample_rates(osmosdr_dev_t *dev, uint32_t *rates)
434
{
435
	int n;
436
437
	if (!dev)
438
		return -1;
439
440
	if (!rates) { /* no buffer provided, just return the count */
441
		return 5;
442
	} else {
443
		for (n = 6; n > 1; n--) /* 64 to 4 */
444
			*(rates++) = dev->adc_clock / TWO_POW(n);
445
446
		return 5;
447
	}
448
449
	return 0;
450
}
451
452 ce0473f5 Dimitri Stolnikov
int osmosdr_set_sample_rate(osmosdr_dev_t *dev, uint32_t samp_rate)
453
{
454 a630fc08 Dimitri Stolnikov
	int n, decim = 3;
455
	int r = 0;
456
	unsigned int req_decim = 0;
457 ce0473f5 Dimitri Stolnikov
458
	if (!dev)
459
		return -1;
460
461 a630fc08 Dimitri Stolnikov
	/* TODO: implement arbitrary rates by steering the master clock */
462
463
	req_decim = dev->adc_clock / samp_rate;
464 ce0473f5 Dimitri Stolnikov
465 a630fc08 Dimitri Stolnikov
	for (n = 2; n <= 6; n++) { /* 4 to 64 */
466
		if (TWO_POW(n) == req_decim) {
467
			decim = n;
468
			break;
469
		}
470 ce0473f5 Dimitri Stolnikov
	}
471
472 a630fc08 Dimitri Stolnikov
	samp_rate = dev->adc_clock / TWO_POW(decim);
473
474
	r = osmosdr_set_fpga_decimation(dev, decim);
475 9e2a7e19 Dimitri Stolnikov
	if (r >= 0) {
476 a630fc08 Dimitri Stolnikov
		if (dev->tuner && dev->tuner->set_bw)
477
			dev->tuner->set_bw(dev, samp_rate);
478
479 ce0473f5 Dimitri Stolnikov
		dev->rate = samp_rate;
480 a630fc08 Dimitri Stolnikov
	} else {
481 ce0473f5 Dimitri Stolnikov
		dev->rate = 0;
482 a630fc08 Dimitri Stolnikov
	}
483 ce0473f5 Dimitri Stolnikov
484 a630fc08 Dimitri Stolnikov
	return r;
485 ce0473f5 Dimitri Stolnikov
}
486
487
uint32_t osmosdr_get_sample_rate(osmosdr_dev_t *dev)
488
{
489
	if (!dev)
490
		return 0;
491
492
	return dev->rate;
493
}
494
495 4eed4e78 Christian Daniel
int osmosdr_set_fpga_reg(osmosdr_dev_t *dev, uint8_t reg, uint32_t value)
496
{
497
	osmosdr_dev_t* devt = (osmosdr_dev_t*)dev;
498
	uint8_t buffer[5];
499
500
	buffer[0] = reg;
501
	buffer[1] = (uint8_t)(value >> 24);
502
	buffer[2] = (uint8_t)(value >> 16);
503
	buffer[3] = (uint8_t)(value >> 8);
504
	buffer[4] = (uint8_t)(value >> 0);
505
506
	return libusb_control_transfer(devt->devh, CTRL_OUT, 0x07,
507
				       FUNC(1, 0x01), 0,
508 9e2a7e19 Dimitri Stolnikov
				       buffer, sizeof(buffer), CTRL_TIMEOUT);
509 4eed4e78 Christian Daniel
}
510
511
int osmosdr_set_fpga_decimation(osmosdr_dev_t *dev, int dec)
512
{
513
	osmosdr_dev_t* devt = (osmosdr_dev_t*)dev;
514
	uint8_t buffer[1];
515
516
	if((dec < 0) || (dec > 6))
517
		return -1;
518
519
	buffer[0] = dec;
520
521
	return libusb_control_transfer(devt->devh, CTRL_OUT, 0x07,
522
				       FUNC(1, 0x02), 0,
523 9e2a7e19 Dimitri Stolnikov
				       buffer, sizeof(buffer), CTRL_TIMEOUT);
524 4eed4e78 Christian Daniel
}
525
526
int osmosdr_set_fpga_iq_swap(osmosdr_dev_t *dev, int sw)
527
{
528
	osmosdr_dev_t* devt = (osmosdr_dev_t*)dev;
529
	uint8_t buffer[1];
530
531
	if((sw < 0) || (sw > 1))
532
		return -1;
533
534
	buffer[0] = sw;
535
536
	return libusb_control_transfer(devt->devh, CTRL_OUT, 0x07,
537
				       FUNC(1, 0x03), 0,
538 9e2a7e19 Dimitri Stolnikov
				       buffer, sizeof(buffer), CTRL_TIMEOUT);
539 4eed4e78 Christian Daniel
}
540
541
int osmosdr_set_fpga_iq_gain(osmosdr_dev_t *dev, uint16_t igain, uint16_t qgain)
542
{
543
	osmosdr_dev_t* devt = (osmosdr_dev_t*)dev;
544
	uint8_t buffer[4];
545
546
	buffer[0] = (uint8_t)(igain >> 8);
547
	buffer[1] = (uint8_t)(igain >> 0);
548
	buffer[2] = (uint8_t)(qgain >> 8);
549
	buffer[3] = (uint8_t)(qgain >> 0);
550
551
	return libusb_control_transfer(devt->devh, CTRL_OUT, 0x07,
552
				       FUNC(1, 0x04), 0,
553 9e2a7e19 Dimitri Stolnikov
				       buffer, sizeof(buffer), CTRL_TIMEOUT);
554 4eed4e78 Christian Daniel
}
555
556
int osmosdr_set_fpga_iq_ofs(osmosdr_dev_t *dev, int16_t iofs, int16_t qofs)
557
{
558
	osmosdr_dev_t* devt = (osmosdr_dev_t*)dev;
559
	uint8_t buffer[4];
560
561
	buffer[0] = (uint8_t)(iofs >> 8);
562
	buffer[1] = (uint8_t)(iofs >> 0);
563
	buffer[2] = (uint8_t)(qofs >> 8);
564
	buffer[3] = (uint8_t)(qofs >> 0);
565
566
	return libusb_control_transfer(devt->devh, CTRL_OUT, 0x07,
567
				       FUNC(1, 0x05), 0,
568 9e2a7e19 Dimitri Stolnikov
				       buffer, sizeof(buffer), CTRL_TIMEOUT);
569 4eed4e78 Christian Daniel
}
570
571 233c5b72 Dimitri Stolnikov
static osmosdr_dongle_t *find_known_device(uint16_t vid, uint16_t pid)
572 ce0473f5 Dimitri Stolnikov
{
573
	unsigned int i;
574
	osmosdr_dongle_t *device = NULL;
575
576
	for (i = 0; i < sizeof(known_devices)/sizeof(osmosdr_dongle_t); i++ ) {
577
		if (known_devices[i].vid == vid && known_devices[i].pid == pid) {
578
			device = &known_devices[i];
579
			break;
580
		}
581
	}
582
583
	return device;
584
}
585
586
uint32_t osmosdr_get_device_count(void)
587
{
588
	int i;
589
	libusb_context *ctx;
590
	libusb_device **list;
591
	struct libusb_device_descriptor dd;
592 7d90bb80 Dimitri Stolnikov
	uint32_t device_count = 0;
593 ce0473f5 Dimitri Stolnikov
	ssize_t cnt;
594
595
	libusb_init(&ctx);
596
597
	cnt = libusb_get_device_list(ctx, &list);
598
599
	for (i = 0; i < cnt; i++) {
600
		libusb_get_device_descriptor(list[i], &dd);
601
602
		if (find_known_device(dd.idVendor, dd.idProduct))
603
			device_count++;
604
	}
605
606 790aa13a Dimitri Stolnikov
	libusb_free_device_list(list, 1);
607 ce0473f5 Dimitri Stolnikov
608
	libusb_exit(ctx);
609
610
	return device_count;
611
}
612
613
const char *osmosdr_get_device_name(uint32_t index)
614
{
615
	int i;
616
	libusb_context *ctx;
617
	libusb_device **list;
618
	struct libusb_device_descriptor dd;
619
	osmosdr_dongle_t *device = NULL;
620
	uint32_t device_count = 0;
621
	ssize_t cnt;
622
623
	libusb_init(&ctx);
624
625
	cnt = libusb_get_device_list(ctx, &list);
626
627
	for (i = 0; i < cnt; i++) {
628
		libusb_get_device_descriptor(list[i], &dd);
629
630
		device = find_known_device(dd.idVendor, dd.idProduct);
631
632
		if (device) {
633
			device_count++;
634
635
			if (index == device_count - 1)
636
				break;
637 41eb5416 Dimitri Stolnikov
638
			device = NULL;
639 ce0473f5 Dimitri Stolnikov
		}
640
	}
641
642 790aa13a Dimitri Stolnikov
	libusb_free_device_list(list, 1);
643 ce0473f5 Dimitri Stolnikov
644
	libusb_exit(ctx);
645
646
	if (device)
647
		return device->name;
648
	else
649
		return "";
650
}
651
652 7d90bb80 Dimitri Stolnikov
int osmosdr_get_device_usb_strings(uint32_t index, char *manufact,
653
				   char *product, char *serial)
654
{
655
	int r = -2;
656
	int i;
657
	libusb_context *ctx;
658
	libusb_device **list;
659
	struct libusb_device_descriptor dd;
660
	osmosdr_dev_t devt;
661
	uint32_t device_count = 0;
662
	ssize_t cnt;
663
664
	libusb_init(&ctx);
665
666
	cnt = libusb_get_device_list(ctx, &list);
667
668
	for (i = 0; i < cnt; i++) {
669
		libusb_get_device_descriptor(list[i], &dd);
670
671 41eb5416 Dimitri Stolnikov
		if (find_known_device(dd.idVendor, dd.idProduct))
672 7d90bb80 Dimitri Stolnikov
			device_count++;
673
674 41eb5416 Dimitri Stolnikov
		if (index == device_count - 1) {
675
			r = libusb_open(list[i], &devt.devh);
676
			if (!r) {
677
				r = osmosdr_get_usb_strings(&devt,
678
							    manufact,
679
							    product,
680
							    serial);
681
				libusb_close(devt.devh);
682 7d90bb80 Dimitri Stolnikov
			}
683 41eb5416 Dimitri Stolnikov
			break;
684 7d90bb80 Dimitri Stolnikov
		}
685
	}
686
687
	libusb_free_device_list(list, 1);
688
689
	libusb_exit(ctx);
690
691
	return r;
692
}
693
694 ce0473f5 Dimitri Stolnikov
int osmosdr_open(osmosdr_dev_t **out_dev, uint32_t index)
695
{
696
	int r;
697
	int i;
698
	libusb_device **list;
699
	osmosdr_dev_t *dev = NULL;
700
	libusb_device *device = NULL;
701
	uint32_t device_count = 0;
702
	struct libusb_device_descriptor dd;
703
	ssize_t cnt;
704
705
	dev = malloc(sizeof(osmosdr_dev_t));
706
	if (NULL == dev)
707
		return -ENOMEM;
708
709
	memset(dev, 0, sizeof(osmosdr_dev_t));
710
711
	libusb_init(&dev->ctx);
712
713
	cnt = libusb_get_device_list(dev->ctx, &list);
714
715
	for (i = 0; i < cnt; i++) {
716
		device = list[i];
717
718
		libusb_get_device_descriptor(list[i], &dd);
719
720 41eb5416 Dimitri Stolnikov
		if (find_known_device(dd.idVendor, dd.idProduct))
721 ce0473f5 Dimitri Stolnikov
			device_count++;
722
723
		if (index == device_count - 1)
724
			break;
725
726
		device = NULL;
727
	}
728
729
	if (!device) {
730
		r = -1;
731
		goto err;
732
	}
733
734
	r = libusb_open(device, &dev->devh);
735
	if (r < 0) {
736 790aa13a Dimitri Stolnikov
		libusb_free_device_list(list, 1);
737 ce0473f5 Dimitri Stolnikov
		fprintf(stderr, "usb_open error %d\n", r);
738
		goto err;
739
	}
740
741 790aa13a Dimitri Stolnikov
	libusb_free_device_list(list, 1);
742 ce0473f5 Dimitri Stolnikov
743
	r = libusb_claim_interface(dev->devh, 0);
744
	if (r < 0) {
745
		fprintf(stderr, "usb_claim_interface error %d\n", r);
746
		goto err;
747
	}
748
749
	dev->adc_clock = DEF_ADC_FREQ;
750
751 9e2a7e19 Dimitri Stolnikov
	dev->tuner = &tuner; /* so far we have only one tuner */
752 bcc45534 Dimitri Stolnikov
753 9e2a7e19 Dimitri Stolnikov
	if (dev->tuner->init) {
754
		r = dev->tuner->init(dev);
755 ce0473f5 Dimitri Stolnikov
	}
756
757
	*out_dev = dev;
758
759
	return 0;
760
err:
761
	if (dev) {
762
		if (dev->ctx)
763
			libusb_exit(dev->ctx);
764
765
		free(dev);
766
	}
767
768
	return r;
769
}
770
771
int osmosdr_close(osmosdr_dev_t *dev)
772
{
773
	if (!dev)
774
		return -1;
775
776 a09144bc Dimitri Stolnikov
	/* block until all async operations have been completed (if any) */
777
	while (OSMOSDR_INACTIVE != dev->async_status)
778
		usleep(10);
779
780 ce0473f5 Dimitri Stolnikov
	libusb_release_interface(dev->devh, 0);
781
	libusb_close(dev->devh);
782
783
	libusb_exit(dev->ctx);
784
785
	free(dev);
786
787
	return 0;
788
}
789
790
int osmosdr_reset_buffer(osmosdr_dev_t *dev)
791
{
792
	if (!dev)
793
		return -1;
794
795
	/* TODO: implement */
796
797
	return 0;
798
}
799
800
int osmosdr_read_sync(osmosdr_dev_t *dev, void *buf, int len, int *n_read)
801
{
802
	if (!dev)
803
		return -1;
804
805 5b2f5902 Dimitri Stolnikov
	return libusb_bulk_transfer(dev->devh, 0x86, buf, len, n_read, BULK_TIMEOUT);
806 ce0473f5 Dimitri Stolnikov
}
807
808
static void LIBUSB_CALL _libusb_callback(struct libusb_transfer *xfer)
809
{
810
	osmosdr_dev_t *dev = (osmosdr_dev_t *)xfer->user_data;
811
812
	if (LIBUSB_TRANSFER_COMPLETED == xfer->status) {
813
		if (dev->cb)
814
			dev->cb(xfer->buffer, xfer->actual_length, dev->cb_ctx);
815
816
		libusb_submit_transfer(xfer); /* resubmit transfer */
817 a09144bc Dimitri Stolnikov
	} else if (LIBUSB_TRANSFER_CANCELLED == xfer->status) {
818
		/* nothing to do */
819 ce0473f5 Dimitri Stolnikov
	} else {
820
		/*fprintf(stderr, "transfer status: %d\n", xfer->status);*/
821
	}
822
}
823
824
static int _osmosdr_alloc_async_buffers(osmosdr_dev_t *dev)
825
{
826
	unsigned int i;
827
828
	if (!dev)
829
		return -1;
830
831
	if (!dev->xfer) {
832
		dev->xfer = malloc(dev->xfer_buf_num *
833
				   sizeof(struct libusb_transfer *));
834
835
		for(i = 0; i < dev->xfer_buf_num; ++i)
836
			dev->xfer[i] = libusb_alloc_transfer(0);
837
	}
838
839
	if (!dev->xfer_buf) {
840
		dev->xfer_buf = malloc(dev->xfer_buf_num *
841
					   sizeof(unsigned char *));
842
843
		for(i = 0; i < dev->xfer_buf_num; ++i)
844
			dev->xfer_buf[i] = malloc(dev->xfer_buf_len);
845
	}
846
847
	return 0;
848
}
849
850
static int _osmosdr_free_async_buffers(osmosdr_dev_t *dev)
851
{
852
	unsigned int i;
853
854
	if (!dev)
855
		return -1;
856
857
	if (dev->xfer) {
858
		for(i = 0; i < dev->xfer_buf_num; ++i) {
859
			if (dev->xfer[i]) {
860
				libusb_free_transfer(dev->xfer[i]);
861
			}
862
		}
863
864
		free(dev->xfer);
865
		dev->xfer = NULL;
866
	}
867
868
	if (dev->xfer_buf) {
869
		for(i = 0; i < dev->xfer_buf_num; ++i) {
870
			if (dev->xfer_buf[i])
871
				free(dev->xfer_buf[i]);
872
		}
873
874
		free(dev->xfer_buf);
875
		dev->xfer_buf = NULL;
876
	}
877
878
	return 0;
879
}
880
881
int osmosdr_read_async(osmosdr_dev_t *dev, osmosdr_read_async_cb_t cb, void *ctx,
882
		       uint32_t buf_num, uint32_t buf_len)
883
{
884
	unsigned int i;
885 a09144bc Dimitri Stolnikov
	int r = 0;
886 ce0473f5 Dimitri Stolnikov
	struct timeval tv = { 1, 0 };
887 a09144bc Dimitri Stolnikov
	enum osmosdr_async_status next_status = OSMOSDR_INACTIVE;
888 ce0473f5 Dimitri Stolnikov
889
	if (!dev)
890
		return -1;
891
892 a09144bc Dimitri Stolnikov
	if (OSMOSDR_INACTIVE != dev->async_status)
893
		return -2;
894
895
	dev->async_status = OSMOSDR_RUNNING;
896
897 ce0473f5 Dimitri Stolnikov
	dev->cb = cb;
898
	dev->cb_ctx = ctx;
899
900
	if (buf_num > 0)
901
		dev->xfer_buf_num = buf_num;
902
	else
903
		dev->xfer_buf_num = DEFAULT_BUF_NUMBER;
904
905
	if (buf_len > 0 && buf_len % 512 == 0) /* len must be multiple of 512 */
906
		dev->xfer_buf_len = buf_len;
907
	else
908
		dev->xfer_buf_len = DEFAULT_BUF_LENGTH;
909
910
	_osmosdr_alloc_async_buffers(dev);
911
912
	for(i = 0; i < dev->xfer_buf_num; ++i) {
913
		libusb_fill_bulk_transfer(dev->xfer[i],
914
					  dev->devh,
915 5b2f5902 Dimitri Stolnikov
					  0x86,
916 ce0473f5 Dimitri Stolnikov
					  dev->xfer_buf[i],
917
					  dev->xfer_buf_len,
918
					  _libusb_callback,
919
					  (void *)dev,
920
					  BULK_TIMEOUT);
921
922
		libusb_submit_transfer(dev->xfer[i]);
923
	}
924
925
	while (OSMOSDR_INACTIVE != dev->async_status) {
926
		r = libusb_handle_events_timeout(dev->ctx, &tv);
927
		if (r < 0) {
928
			/*fprintf(stderr, "handle_events returned: %d\n", r);*/
929
			if (r == LIBUSB_ERROR_INTERRUPTED) /* stray signal */
930
				continue;
931
			break;
932
		}
933
934
		if (OSMOSDR_CANCELING == dev->async_status) {
935 a09144bc Dimitri Stolnikov
			next_status = OSMOSDR_INACTIVE;
936 ce0473f5 Dimitri Stolnikov
937
			if (!dev->xfer)
938
				break;
939
940
			for(i = 0; i < dev->xfer_buf_num; ++i) {
941
				if (!dev->xfer[i])
942
					continue;
943
944 a09144bc Dimitri Stolnikov
				if (LIBUSB_TRANSFER_CANCELLED !=
945
						dev->xfer[i]->status) {
946 ce0473f5 Dimitri Stolnikov
					libusb_cancel_transfer(dev->xfer[i]);
947 a09144bc Dimitri Stolnikov
					next_status = OSMOSDR_CANCELING;
948 ce0473f5 Dimitri Stolnikov
				}
949
			}
950
951 a09144bc Dimitri Stolnikov
			if (OSMOSDR_INACTIVE == next_status)
952 ce0473f5 Dimitri Stolnikov
				break;
953
		}
954
	}
955
956
	_osmosdr_free_async_buffers(dev);
957
958 a09144bc Dimitri Stolnikov
	dev->async_status = next_status;
959
960 ce0473f5 Dimitri Stolnikov
	return r;
961
}
962
963
int osmosdr_cancel_async(osmosdr_dev_t *dev)
964
{
965
	if (!dev)
966
		return -1;
967
968 a09144bc Dimitri Stolnikov
	/* if streaming, try to cancel gracefully */
969 ce0473f5 Dimitri Stolnikov
	if (OSMOSDR_RUNNING == dev->async_status) {
970
		dev->async_status = OSMOSDR_CANCELING;
971
		return 0;
972
	}
973
974 a09144bc Dimitri Stolnikov
	/* if called while in pending state, change the state forcefully */
975
	if (OSMOSDR_INACTIVE != dev->async_status) {
976
		dev->async_status = OSMOSDR_INACTIVE;
977
		return 0;
978
	}
979
980 ce0473f5 Dimitri Stolnikov
	return -2;
981
}
Add picture from clipboard (Maximum size: 48.8 MB)