12
#include <sys/ioctl.h>
17
#include <linux/videodev2.h>
23
static int tuner_index;
24
static struct v4l2_tuner tuner; /* set_freq/get_freq */
25
static struct v4l2_modulator modulator; /* set_freq/get_freq */
26
static int txsubchans; /* set_modulator */
27
static double freq; /* get/set frequency */
28
static struct v4l2_frequency vf; /* get_freq/set_freq */
29
static struct v4l2_hw_freq_seek freq_seek; /* freq-seek */
30
static double low, high; /* freq-seek frequency range */
31
static int mode = V4L2_TUNER_MODE_STEREO; /* set audio mode */
33
void tuner_usage(void)
35
printf("\nTuner/Modulator options:\n"
36
" -F, --get-freq query the frequency [VIDIOC_G_FREQUENCY]\n"
37
" -f, --set-freq=<freq>\n"
38
" set the frequency to <freq> MHz [VIDIOC_S_FREQUENCY]\n"
39
" -T, --get-tuner query the tuner settings [VIDIOC_G_TUNER]\n"
40
" -t, --set-tuner=<mode>\n"
41
" set the audio mode of the tuner [VIDIOC_S_TUNER]\n"
42
" Possible values: mono, stereo, lang2, lang1, bilingual\n"
43
" --tuner-index=<idx> Use idx as tuner idx for tuner/modulator commands\n"
44
" --list-freq-bands display all frequency bands for the tuner/modulator\n"
45
" [VIDIOC_ENUM_FREQ_BANDS]\n"
46
" --get-modulator query the modulator settings [VIDIOC_G_MODULATOR]\n"
47
" --set-modulator=<txsubchans>\n"
48
" set the sub-carrier modulation [VIDIOC_S_MODULATOR]\n"
49
" <txsubchans> is one of:\n"
50
" mono: Modulate as mono\n"
51
" mono-rds: Modulate as mono with RDS (radio only)\n"
52
" stereo: Modulate as stereo\n"
53
" stereo-rds: Modulate as stereo with RDS (radio only)\n"
54
" bilingual: Modulate as bilingual\n"
55
" mono-sap: Modulate as mono with Second Audio Program\n"
56
" stereo-sap: Modulate as stereo with Second Audio Program\n"
57
" --freq-seek=dir=<0/1>,wrap=<0/1>,spacing=<hz>,low=<freq>,high=<freq>\n"
58
" perform a hardware frequency seek [VIDIOC_S_HW_FREQ_SEEK]\n"
59
" dir is 0 (seek downward) or 1 (seek upward)\n"
60
" wrap is 0 (do not wrap around) or 1 (wrap around)\n"
61
" spacing sets the seek resolution (use 0 for default)\n"
62
" low and high set the low and high seek frequency range in MHz\n"
66
static const char *audmode2s(int audmode)
69
case V4L2_TUNER_MODE_STEREO: return "stereo";
70
case V4L2_TUNER_MODE_LANG1: return "lang1";
71
case V4L2_TUNER_MODE_LANG2: return "lang2";
72
case V4L2_TUNER_MODE_LANG1_LANG2: return "bilingual";
73
case V4L2_TUNER_MODE_MONO: return "mono";
74
default: return "unknown";
78
static std::string rxsubchans2s(int rxsubchans)
82
if (rxsubchans & V4L2_TUNER_SUB_MONO)
84
if (rxsubchans & V4L2_TUNER_SUB_STEREO)
86
if (rxsubchans & V4L2_TUNER_SUB_LANG1)
88
if (rxsubchans & V4L2_TUNER_SUB_LANG2)
90
if (rxsubchans & V4L2_TUNER_SUB_RDS)
95
static std::string txsubchans2s(int txsubchans)
99
if (txsubchans & V4L2_TUNER_SUB_MONO)
101
if (txsubchans & V4L2_TUNER_SUB_STEREO)
103
if (txsubchans & V4L2_TUNER_SUB_LANG1)
105
if (txsubchans & V4L2_TUNER_SUB_SAP)
107
if (txsubchans & V4L2_TUNER_SUB_RDS)
112
static std::string tcap2s(unsigned cap)
116
if (cap & V4L2_TUNER_CAP_LOW)
120
if (cap & V4L2_TUNER_CAP_NORM)
121
s += "multi-standard ";
122
if (cap & V4L2_TUNER_CAP_HWSEEK_BOUNDED)
123
s += "hwseek-bounded ";
124
if (cap & V4L2_TUNER_CAP_HWSEEK_WRAP)
126
if (cap & V4L2_TUNER_CAP_STEREO)
128
if (cap & V4L2_TUNER_CAP_LANG1)
130
if (cap & V4L2_TUNER_CAP_LANG2)
132
if (cap & V4L2_TUNER_CAP_RDS)
134
if (cap & V4L2_TUNER_CAP_RDS_BLOCK_IO)
135
s += "rds-block-I/O ";
136
if (cap & V4L2_TUNER_CAP_RDS_CONTROLS)
137
s += "rds-controls ";
138
if (cap & V4L2_TUNER_CAP_FREQ_BANDS)
140
if (cap & V4L2_TUNER_CAP_HWSEEK_PROG_LIM)
141
s += "hwseek-prog-lim ";
145
static std::string modulation2s(unsigned modulation)
147
switch (modulation) {
148
case V4L2_BAND_MODULATION_VSB:
150
case V4L2_BAND_MODULATION_FM:
152
case V4L2_BAND_MODULATION_AM:
158
static void parse_freq_seek(char *optarg, struct v4l2_hw_freq_seek &seek)
163
while (*subs != '\0') {
164
static const char *const subopts[] = {
173
switch (parse_subopt(&subs, subopts, &value)) {
175
seek.seek_upward = strtol(value, 0L, 0);
178
seek.wrap_around = strtol(value, 0L, 0);
181
seek.spacing = strtol(value, 0L, 0);
184
low = strtod(value, NULL);
187
high = strtod(value, NULL);
196
void tuner_cmd(int ch, char *optarg)
200
freq = strtod(optarg, NULL);
203
if (!strcmp(optarg, "stereo"))
204
mode = V4L2_TUNER_MODE_STEREO;
205
else if (!strcmp(optarg, "lang1"))
206
mode = V4L2_TUNER_MODE_LANG1;
207
else if (!strcmp(optarg, "lang2"))
208
mode = V4L2_TUNER_MODE_LANG2;
209
else if (!strcmp(optarg, "bilingual"))
210
mode = V4L2_TUNER_MODE_LANG1_LANG2;
211
else if (!strcmp(optarg, "mono"))
212
mode = V4L2_TUNER_MODE_MONO;
214
fprintf(stderr, "Unknown audio mode\n");
219
case OptSetModulator:
220
txsubchans = strtol(optarg, 0L, 0);
221
if (!strcmp(optarg, "stereo"))
222
txsubchans = V4L2_TUNER_SUB_STEREO;
223
else if (!strcmp(optarg, "stereo-sap"))
224
txsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_SAP;
225
else if (!strcmp(optarg, "bilingual"))
226
txsubchans = V4L2_TUNER_SUB_LANG1;
227
else if (!strcmp(optarg, "mono"))
228
txsubchans = V4L2_TUNER_SUB_MONO;
229
else if (!strcmp(optarg, "mono-sap"))
230
txsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_SAP;
231
else if (!strcmp(optarg, "stereo-rds"))
232
txsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_RDS;
233
else if (!strcmp(optarg, "mono-rds"))
234
txsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_RDS;
236
fprintf(stderr, "Unknown txsubchans value\n");
242
parse_freq_seek(optarg, freq_seek);
245
tuner_index = strtoul(optarg, NULL, 0);
250
void tuner_set(int fd)
252
__u32 type = (capabilities & V4L2_CAP_RADIO) ?
253
V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
256
if (capabilities & V4L2_CAP_MODULATOR) {
257
type = V4L2_TUNER_RADIO;
258
modulator.index = tuner_index;
259
if (doioctl(fd, VIDIOC_G_MODULATOR, &modulator) == 0)
260
fac = (modulator.capability & V4L2_TUNER_CAP_LOW) ? 16000 : 16;
261
} else if (capabilities & V4L2_CAP_TUNER) {
262
tuner.index = tuner_index;
263
if (doioctl(fd, VIDIOC_G_TUNER, &tuner) == 0) {
264
fac = (tuner.capability & V4L2_TUNER_CAP_LOW) ? 16000 : 16;
268
if (options[OptSetFreq]) {
270
vf.tuner = tuner_index;
271
vf.frequency = __u32(freq * fac);
272
if (doioctl(fd, VIDIOC_S_FREQUENCY, &vf) == 0)
273
printf("Frequency for tuner %d set to %d (%f MHz)\n",
274
vf.tuner, vf.frequency, vf.frequency / fac);
277
if (options[OptSetTuner]) {
278
struct v4l2_tuner vt;
280
memset(&vt, 0, sizeof(struct v4l2_tuner));
281
vt.index = tuner_index;
282
if (doioctl(fd, VIDIOC_G_TUNER, &vt) == 0) {
284
doioctl(fd, VIDIOC_S_TUNER, &vt);
288
if (options[OptListFreqBands]) {
289
struct v4l2_frequency_band band;
291
memset(&band, 0, sizeof(band));
292
band.tuner = tuner_index;
295
printf("ioctl: VIDIOC_ENUM_FREQ_BANDS\n");
296
while (test_ioctl(fd, VIDIOC_ENUM_FREQ_BANDS, &band) >= 0) {
299
printf("\tIndex : %d\n", band.index);
300
printf("\tModulation : %s\n", modulation2s(band.modulation).c_str());
301
printf("\tCapability : %s\n", tcap2s(band.capability).c_str());
302
if (band.capability & V4L2_TUNER_CAP_LOW)
303
printf("\tFrequency Range: %.3f MHz - %.3f MHz\n",
304
band.rangelow / 16000.0, band.rangehigh / 16000.0);
306
printf("\tFrequency Range: %.3f MHz - %.3f MHz\n",
307
band.rangelow / 16.0, band.rangehigh / 16.0);
312
if (options[OptSetModulator]) {
313
struct v4l2_modulator mt;
315
memset(&mt, 0, sizeof(struct v4l2_modulator));
316
mt.index = tuner_index;
317
if (doioctl(fd, VIDIOC_G_MODULATOR, &mt) == 0) {
318
mt.txsubchans = txsubchans;
319
doioctl(fd, VIDIOC_S_MODULATOR, &mt);
323
if (options[OptFreqSeek]) {
324
freq_seek.tuner = tuner_index;
325
freq_seek.type = type;
326
freq_seek.rangelow = __u32(low * fac);
327
freq_seek.rangehigh = __u32(high * fac);
328
doioctl(fd, VIDIOC_S_HW_FREQ_SEEK, &freq_seek);
332
void tuner_get(int fd)
334
if (options[OptGetFreq]) {
337
if (capabilities & V4L2_CAP_MODULATOR) {
338
vf.type = V4L2_TUNER_RADIO;
339
modulator.index = tuner_index;
340
if (doioctl(fd, VIDIOC_G_MODULATOR, &modulator) == 0)
341
fac = (modulator.capability & V4L2_TUNER_CAP_LOW) ? 16000 : 16;
343
vf.type = V4L2_TUNER_ANALOG_TV;
344
tuner.index = tuner_index;
345
if (doioctl(fd, VIDIOC_G_TUNER, &tuner) == 0) {
346
fac = (tuner.capability & V4L2_TUNER_CAP_LOW) ? 16000 : 16;
347
vf.type = tuner.type;
350
vf.tuner = tuner_index;
351
if (doioctl(fd, VIDIOC_G_FREQUENCY, &vf) == 0)
352
printf("Frequency for tuner %d: %d (%f MHz)\n",
353
vf.tuner, vf.frequency, vf.frequency / fac);
356
if (options[OptGetTuner]) {
357
struct v4l2_tuner vt;
359
memset(&vt, 0, sizeof(struct v4l2_tuner));
360
vt.index = tuner_index;
361
if (doioctl(fd, VIDIOC_G_TUNER, &vt) == 0) {
362
printf("Tuner %d:\n", vt.index);
363
printf("\tName : %s\n", vt.name);
364
printf("\tCapabilities : %s\n", tcap2s(vt.capability).c_str());
365
if (vt.capability & V4L2_TUNER_CAP_LOW)
366
printf("\tFrequency range : %.3f MHz - %.3f MHz\n",
367
vt.rangelow / 16000.0, vt.rangehigh / 16000.0);
369
printf("\tFrequency range : %.3f MHz - %.3f MHz\n",
370
vt.rangelow / 16.0, vt.rangehigh / 16.0);
371
printf("\tSignal strength/AFC : %d%%/%d\n", (int)((vt.signal / 655.35)+0.5), vt.afc);
372
printf("\tCurrent audio mode : %s\n", audmode2s(vt.audmode));
373
printf("\tAvailable subchannels: %s\n",
374
rxsubchans2s(vt.rxsubchans).c_str());
378
if (options[OptGetModulator]) {
379
struct v4l2_modulator mt;
381
memset(&mt, 0, sizeof(struct v4l2_modulator));
382
modulator.index = tuner_index;
383
if (doioctl(fd, VIDIOC_G_MODULATOR, &mt) == 0) {
384
printf("Modulator %d:\n", modulator.index);
385
printf("\tName : %s\n", mt.name);
386
printf("\tCapabilities : %s\n", tcap2s(mt.capability).c_str());
387
if (mt.capability & V4L2_TUNER_CAP_LOW)
388
printf("\tFrequency range : %.1f MHz - %.1f MHz\n",
389
mt.rangelow / 16000.0, mt.rangehigh / 16000.0);
391
printf("\tFrequency range : %.1f MHz - %.1f MHz\n",
392
mt.rangelow / 16.0, mt.rangehigh / 16.0);
393
printf("\tSubchannel modulation: %s\n",
394
txsubchans2s(mt.txsubchans).c_str());
399
void tuner_list(int fd)