Mercurial > pt1
comparison recpt1/checksignal.c @ 113:e7b786c42ca0
add an utility to check signal strength.
author | Yoshiki Yazawa <yaz@honeyplanet.jp> |
---|---|
date | Fri, 19 Mar 2010 01:01:35 +0900 |
parents | |
children | 3eccf1ef4853 |
comparison
equal
deleted
inserted
replaced
112:38091ff0c8ed | 113:e7b786c42ca0 |
---|---|
1 /* -*- tab-width: 4; indent-tabs-mode: nil -*- */ | |
2 #include <stdio.h> | |
3 #include <fcntl.h> | |
4 #include <sys/types.h> | |
5 #include <sys/stat.h> | |
6 #include <time.h> | |
7 #include <stdlib.h> | |
8 #include <string.h> | |
9 #include <pthread.h> | |
10 #include <math.h> | |
11 #include <unistd.h> | |
12 #include <getopt.h> | |
13 #include <signal.h> | |
14 #include <errno.h> | |
15 #include <sys/time.h> | |
16 #include <ctype.h> | |
17 #include <libgen.h> | |
18 | |
19 #include <netdb.h> | |
20 #include <arpa/inet.h> | |
21 #include <netinet/in.h> | |
22 | |
23 #include <sys/ioctl.h> | |
24 #include "pt1_ioctl.h" | |
25 | |
26 #include "config.h" | |
27 #include "decoder.h" | |
28 #include "recpt1.h" | |
29 #include "version.h" | |
30 #include "mkpath.h" | |
31 | |
32 #include <sys/ipc.h> | |
33 #include <sys/msg.h> | |
34 #include "pt1_dev.h" | |
35 #include "tssplitter_lite.h" | |
36 | |
37 /* type definitions */ | |
38 typedef int boolean; | |
39 | |
40 typedef struct thread_data { | |
41 int ch; | |
42 int lnb; /* LNB voltage */ | |
43 int tfd; /* tuner fd */ | |
44 ISDB_T_FREQ_CONV_TABLE *table; | |
45 } thread_data; | |
46 | |
47 /* globals */ | |
48 boolean f_exit = FALSE; | |
49 | |
50 /* prototypes */ | |
51 int tune(char *channel, thread_data *tdata, char *device); | |
52 int close_tuner(thread_data *tdata); | |
53 | |
54 /* signal handler */ | |
55 void | |
56 handler(int dummy) | |
57 { | |
58 f_exit = TRUE; | |
59 } | |
60 | |
61 /* lookup frequency conversion table*/ | |
62 ISDB_T_FREQ_CONV_TABLE * | |
63 searchrecoff(char *channel) | |
64 { | |
65 int lp; | |
66 | |
67 for(lp = 0; isdb_t_conv_table[lp].parm_freq != NULL; lp++) { | |
68 /* return entry number in the table when strings match and | |
69 * lengths are same. */ | |
70 if((memcmp(isdb_t_conv_table[lp].parm_freq, channel, | |
71 strlen(channel)) == 0) && | |
72 (strlen(channel) == strlen(isdb_t_conv_table[lp].parm_freq))) { | |
73 return &isdb_t_conv_table[lp]; | |
74 } | |
75 } | |
76 return NULL; | |
77 } | |
78 | |
79 void | |
80 show_usage(char *cmd) | |
81 { | |
82 fprintf(stderr, "Usage: \n%s [--device devicefile] [--lnb voltage] channel\n", cmd); | |
83 fprintf(stderr, "\n"); | |
84 } | |
85 | |
86 void | |
87 show_options(void) | |
88 { | |
89 fprintf(stderr, "Options:\n"); | |
90 fprintf(stderr, "--device devicefile: Specify devicefile to use\n"); | |
91 fprintf(stderr, "--lnb voltage: Specify LNB voltage (0, 11, 15)\n"); | |
92 fprintf(stderr, "--help: Show this help\n"); | |
93 fprintf(stderr, "--version: Show version\n"); | |
94 fprintf(stderr, "--list: Show channel list\n"); | |
95 } | |
96 | |
97 void | |
98 show_channels(void) | |
99 { | |
100 FILE *f; | |
101 char *home; | |
102 char buf[255], filename[255]; | |
103 | |
104 fprintf(stderr, "Available Channels:\n"); | |
105 | |
106 home = getenv("HOME"); | |
107 sprintf(filename, "%s/.recpt1-channels", home); | |
108 f = fopen(filename, "r"); | |
109 if(f) { | |
110 while(fgets(buf, 255, f)) | |
111 fprintf(stderr, "%s", buf); | |
112 fclose(f); | |
113 } | |
114 else | |
115 fprintf(stderr, "13-62: Terrestrial Channels\n"); | |
116 | |
117 fprintf(stderr, "101ch: NHK BS1\n"); | |
118 fprintf(stderr, "102ch: NHK BS2\n"); | |
119 fprintf(stderr, "103ch: NHK BShi\n"); | |
120 fprintf(stderr, "141ch: BS Nittele\n"); | |
121 fprintf(stderr, "151ch: BS Asahi\n"); | |
122 fprintf(stderr, "161ch: BS-TBS\n"); | |
123 fprintf(stderr, "171ch: BS Japan\n"); | |
124 fprintf(stderr, "181ch: BS Fuji\n"); | |
125 fprintf(stderr, "191ch: WOWOW\n"); | |
126 fprintf(stderr, "192ch: WOWOW2\n"); | |
127 fprintf(stderr, "193ch: WOWOW3\n"); | |
128 fprintf(stderr, "200ch: Star Channel\n"); | |
129 fprintf(stderr, "211ch: BS11 Digital\n"); | |
130 fprintf(stderr, "222ch: TwellV\n"); | |
131 fprintf(stderr, "C13-C63: CATV Channels\n"); | |
132 fprintf(stderr, "CS2-CS24: CS Channels\n"); | |
133 } | |
134 | |
135 float | |
136 getsignal_isdb_s(int signal) | |
137 { | |
138 /* apply linear interpolation */ | |
139 static const float afLevelTable[] = { | |
140 24.07f, // 00 00 0 24.07dB | |
141 24.07f, // 10 00 4096 24.07dB | |
142 18.61f, // 20 00 8192 18.61dB | |
143 15.21f, // 30 00 12288 15.21dB | |
144 12.50f, // 40 00 16384 12.50dB | |
145 10.19f, // 50 00 20480 10.19dB | |
146 8.140f, // 60 00 24576 8.140dB | |
147 6.270f, // 70 00 28672 6.270dB | |
148 4.550f, // 80 00 32768 4.550dB | |
149 3.730f, // 88 00 34816 3.730dB | |
150 3.630f, // 88 FF 35071 3.630dB | |
151 2.940f, // 90 00 36864 2.940dB | |
152 1.420f, // A0 00 40960 1.420dB | |
153 0.000f // B0 00 45056 -0.01dB | |
154 }; | |
155 | |
156 unsigned char sigbuf[4]; | |
157 memset(sigbuf, '\0', sizeof(sigbuf)); | |
158 sigbuf[0] = (((signal & 0xFF00) >> 8) & 0XFF); | |
159 sigbuf[1] = (signal & 0xFF); | |
160 | |
161 /* calculate signal level */ | |
162 if(sigbuf[0] <= 0x10U) { | |
163 /* clipped maximum */ | |
164 return 24.07f; | |
165 } | |
166 else if (sigbuf[0] >= 0xB0U) { | |
167 /* clipped minimum */ | |
168 return 0.0f; | |
169 } | |
170 else { | |
171 /* linear interpolation */ | |
172 const float fMixRate = | |
173 (float)(((unsigned short)(sigbuf[0] & 0x0FU) << 8) | | |
174 (unsigned short)sigbuf[0]) / 4096.0f; | |
175 return afLevelTable[sigbuf[0] >> 4] * (1.0f - fMixRate) + | |
176 afLevelTable[(sigbuf[0] >> 4) + 0x01U] * fMixRate; | |
177 } | |
178 } | |
179 | |
180 void | |
181 calc_cn(int fd, int type) | |
182 { | |
183 int rc ; | |
184 double P ; | |
185 double CNR; | |
186 | |
187 if(ioctl(fd, GET_SIGNAL_STRENGTH, &rc) < 0) { | |
188 fprintf(stderr, "Tuner Select Error\n"); | |
189 return ; | |
190 } | |
191 | |
192 if(type == CHTYPE_GROUND) { | |
193 P = log10(5505024/(double)rc) * 10; | |
194 CNR = (0.000024 * P * P * P * P) - (0.0016 * P * P * P) + | |
195 (0.0398 * P * P) + (0.5491 * P)+3.0965; | |
196 } | |
197 else { | |
198 CNR = getsignal_isdb_s(rc); | |
199 } | |
200 fprintf(stderr, "\rC/N = %fdB", CNR); | |
201 } | |
202 | |
203 int | |
204 tune(char *channel, thread_data *tdata, char *device) | |
205 { | |
206 char **tuner; | |
207 int num_devs; | |
208 int lp; | |
209 FREQUENCY freq; | |
210 | |
211 /* get channel */ | |
212 tdata->table = searchrecoff(channel); | |
213 if(tdata->table == NULL) { | |
214 fprintf(stderr, "Invalid Channel: %s\n", channel); | |
215 return 1; | |
216 } | |
217 | |
218 freq.frequencyno = tdata->table->set_freq; | |
219 freq.slot = tdata->table->add_freq; | |
220 | |
221 /* open tuner */ | |
222 /* case 1: specified tuner device */ | |
223 if(device) { | |
224 fprintf(stderr, "device = %s\n", device); | |
225 tdata->tfd = open(device, O_RDONLY); | |
226 if(tdata->tfd < 0) { | |
227 fprintf(stderr, "Cannot open tuner device: %s\n", device); | |
228 return 1; | |
229 } | |
230 | |
231 /* power on LNB */ | |
232 if(tdata->table->type == CHTYPE_SATELLITE) { | |
233 if(ioctl(tdata->tfd, LNB_ENABLE, tdata->lnb) < 0) { | |
234 fprintf(stderr, "Power on LNB failed: %s\n", device); | |
235 } | |
236 } | |
237 | |
238 /* tune to specified channel */ | |
239 if(ioctl(tdata->tfd, SET_CHANNEL, &freq) < 0) { | |
240 close(tdata->tfd); | |
241 fprintf(stderr, "Cannot tune to the specified channel: %s\n", device); | |
242 return 1; | |
243 } | |
244 else { | |
245 tdata->ch = atoi(channel); | |
246 } | |
247 } | |
248 else { | |
249 /* case 2: loop around available devices */ | |
250 if(tdata->table->type == CHTYPE_SATELLITE) { | |
251 tuner = bsdev; | |
252 num_devs = NUM_BSDEV; | |
253 } | |
254 else { | |
255 tuner = isdb_t_dev; | |
256 num_devs = NUM_ISDB_T_DEV; | |
257 } | |
258 | |
259 for(lp = 0; lp < num_devs; lp++) { | |
260 tdata->tfd = open(tuner[lp], O_RDONLY); | |
261 if(tdata->tfd >= 0) { | |
262 /* power on LNB */ | |
263 if(tdata->table->type == CHTYPE_SATELLITE) { | |
264 if(ioctl(tdata->tfd, LNB_ENABLE, tdata->lnb) < 0) { | |
265 fprintf(stderr, "Warning: Power on LNB failed: %s\n", tuner[lp]); | |
266 } | |
267 } | |
268 | |
269 /* tune to specified channel */ | |
270 if(ioctl(tdata->tfd, SET_CHANNEL, &freq) < 0) { | |
271 close(tdata->tfd); | |
272 tdata->tfd = -1; | |
273 continue; | |
274 } | |
275 | |
276 fprintf(stderr, "device = %s\n", tuner[lp]); | |
277 break; /* found suitable tuner */ | |
278 } | |
279 } | |
280 | |
281 /* all tuners cannot be used */ | |
282 if(tdata->tfd < 0) { | |
283 fprintf(stderr, "Cannot tune to the specified channel\n"); | |
284 return 1; | |
285 } | |
286 else { | |
287 tdata->ch = atoi(channel); | |
288 } | |
289 } | |
290 | |
291 return 0; /* success */ | |
292 } | |
293 | |
294 int | |
295 close_tuner(thread_data *tdata) | |
296 { | |
297 int rv = 0; | |
298 | |
299 if(tdata->table->type == CHTYPE_SATELLITE) { | |
300 if(ioctl(tdata->tfd, LNB_DISABLE, 0) < 0) { | |
301 rv = 1; | |
302 } | |
303 } | |
304 close(tdata->tfd); | |
305 | |
306 return rv; | |
307 } | |
308 | |
309 int | |
310 main(int argc, char **argv) | |
311 { | |
312 static thread_data tdata; | |
313 int result; | |
314 int option_index; | |
315 struct option long_options[] = { | |
316 { "LNB", 1, NULL, 'n'}, | |
317 { "lnb", 1, NULL, 'n'}, | |
318 { "device", 1, NULL, 'd'}, | |
319 { "help", 0, NULL, 'h'}, | |
320 { "version", 0, NULL, 'v'}, | |
321 { "list", 0, NULL, 'l'}, | |
322 {0, 0, NULL, 0} /* terminate */ | |
323 }; | |
324 | |
325 char *device = NULL; | |
326 int val; | |
327 char *voltage[] = {"0V", "11V", "15V"}; | |
328 | |
329 while((result = getopt_long(argc, argv, "br:smn:ua:p:d:hvli:", | |
330 long_options, &option_index)) != -1) { | |
331 switch(result) { | |
332 case 'h': | |
333 fprintf(stderr, "\n"); | |
334 show_usage(argv[0]); | |
335 fprintf(stderr, "\n"); | |
336 show_options(); | |
337 fprintf(stderr, "\n"); | |
338 show_channels(); | |
339 fprintf(stderr, "\n"); | |
340 exit(0); | |
341 break; | |
342 case 'v': | |
343 fprintf(stderr, "%s %s\n", argv[0], version); | |
344 fprintf(stderr, "recorder command for PT1/2 digital tuner.\n"); | |
345 exit(0); | |
346 break; | |
347 case 'l': | |
348 show_channels(); | |
349 exit(0); | |
350 break; | |
351 /* following options require argument */ | |
352 case 'n': | |
353 val = atoi(optarg); | |
354 switch(val) { | |
355 case 11: | |
356 tdata.lnb = 1; | |
357 break; | |
358 case 15: | |
359 tdata.lnb = 2; | |
360 break; | |
361 default: | |
362 tdata.lnb = 0; | |
363 break; | |
364 } | |
365 fprintf(stderr, "LNB = %s\n", voltage[tdata.lnb]); | |
366 break; | |
367 case 'd': | |
368 device = optarg; | |
369 break; | |
370 } | |
371 } | |
372 | |
373 if(argc - optind < 1) { | |
374 fprintf(stderr, "channel must be specified!\n"); | |
375 fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]); | |
376 return 1; | |
377 } | |
378 | |
379 /* add signal handler */ | |
380 signal(SIGTERM, handler); | |
381 | |
382 /* tune */ | |
383 if(tune(argv[optind], &tdata, device) != 0) | |
384 return 1; | |
385 | |
386 while(1) { | |
387 if(f_exit) | |
388 break; | |
389 /* show signal strength */ | |
390 calc_cn(tdata.tfd, tdata.table->type); | |
391 sleep(1); | |
392 } | |
393 | |
394 /* close tuner */ | |
395 if(close_tuner(&tdata) != 0) | |
396 return 1; | |
397 | |
398 return 0; | |
399 } |