szap2.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767
  1. /* szap -- simple zapping tool for the Linux DVB API
  2. *
  3. * szap operates on VDR (http://www.cadsoft.de/people/kls/vdr/index.htm)
  4. * satellite channel lists (e.g. from http://www.dxandy.de/cgi-bin/dvbchan.pl).
  5. * szap assumes you have a "Universal LNB" (i.e. with LOFs 9750/10600 MHz).
  6. *
  7. * Compilation: `gcc -Wall -I../../ost/include -O2 szap.c -o szap`
  8. * or, if your DVB driver is in the kernel source tree:
  9. * `gcc -Wall -DDVB_IN_KERNEL -O2 szap.c -o szap`
  10. *
  11. * Copyright (C) 2001 Johannes Stezenbach (js@convergence.de)
  12. * for convergence integrated media
  13. *
  14. * This program is free software; you can redistribute it and/or modify
  15. * it under the terms of the GNU General Public License as published by
  16. * the Free Software Foundation; either version 2 of the License, or
  17. * (at your option) any later version.
  18. *
  19. * This program is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU General Public License
  25. * along with this program; if not, write to the Free Software
  26. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  27. */
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <limits.h>
  31. #include <string.h>
  32. #include <errno.h>
  33. #include <sys/ioctl.h>
  34. #include <sys/types.h>
  35. #include <sys/stat.h>
  36. #include <sys/poll.h>
  37. #include <sys/param.h>
  38. #include <fcntl.h>
  39. #include <time.h>
  40. #include <unistd.h>
  41. #include <stdint.h>
  42. #include <sys/time.h>
  43. #include "../include/frontend.h"
  44. #include "../include/dmx.h"
  45. #include "../include/audio.h"
  46. #include "../include/version.h"
  47. #include "lnb.h"
  48. #ifndef TRUE
  49. #define TRUE (1==1)
  50. #endif
  51. #ifndef FALSE
  52. #define FALSE (1==0)
  53. #endif
  54. /* location of channel list file */
  55. #define CHANNEL_FILE "channels.conf"
  56. /* one line of the VDR channel file has the following format:
  57. * ^name:frequency_MHz:polarization:sat_no:symbolrate:vpid:apid:?:service_id$
  58. */
  59. #define FRONTENDDEVICE "/dev/dvb/adapter%d/frontend%d"
  60. #define DEMUXDEVICE "/dev/dvb/adapter%d/demux%d"
  61. #define AUDIODEVICE "/dev/dvb/adapter%d/audio%d"
  62. static struct lnb_types_st lnb_type;
  63. static int exit_after_tuning;
  64. static int interactive;
  65. static char *usage_str =
  66. "\nusage: szap -q\n"
  67. " list known channels\n"
  68. " szap [options] {-n channel-number|channel_name}\n"
  69. " zap to channel via number or full name (case insensitive)\n"
  70. " -a number : use given adapter (default 0)\n"
  71. " -f number : use given frontend (default 0)\n"
  72. " -d number : use given demux (default 0)\n"
  73. " -c file : read channels list from 'file'\n"
  74. " -b : enable Audio Bypass (default no)\n"
  75. " -x : exit after tuning\n"
  76. " -r : set up /dev/dvb/adapterX/dvr0 for TS recording\n"
  77. " -l lnb-type (DVB-S Only) (use -l help to print types) or \n"
  78. " -l low[,high[,switch]] in Mhz\n"
  79. " -i : run interactively, allowing you to type in channel names\n"
  80. " -p : add pat and pmt to TS recording (implies -r)\n"
  81. " or -n numbers for zapping\n"
  82. " -t : delivery system type DVB-S=0, DSS=1, DVB-S2=2\n";
  83. static int set_demux(int dmxfd, int pid, int pes_type, int dvr)
  84. {
  85. struct dmx_pes_filter_params pesfilter;
  86. if (pid < 0 || pid >= 0x1fff) /* ignore this pid to allow radio services */
  87. return TRUE;
  88. if (dvr) {
  89. int buffersize = 64 * 1024;
  90. if (ioctl(dmxfd, DMX_SET_BUFFER_SIZE, buffersize) == -1)
  91. perror("DMX_SET_BUFFER_SIZE failed");
  92. }
  93. pesfilter.pid = pid;
  94. pesfilter.input = DMX_IN_FRONTEND;
  95. pesfilter.output = dvr ? DMX_OUT_TS_TAP : DMX_OUT_DECODER;
  96. pesfilter.pes_type = pes_type;
  97. pesfilter.flags = DMX_IMMEDIATE_START;
  98. if (ioctl(dmxfd, DMX_SET_PES_FILTER, &pesfilter) == -1) {
  99. fprintf(stderr, "DMX_SET_PES_FILTER failed "
  100. "(PID = 0x%04x): %d %m\n", pid, errno);
  101. return FALSE;
  102. }
  103. return TRUE;
  104. }
  105. int get_pmt_pid(char *dmxdev, int sid)
  106. {
  107. int patfd, count;
  108. int pmt_pid = 0;
  109. int patread = 0;
  110. int section_length;
  111. unsigned char buft[4096];
  112. unsigned char *buf = buft;
  113. struct dmx_sct_filter_params f;
  114. memset(&f, 0, sizeof(f));
  115. f.pid = 0;
  116. f.filter.filter[0] = 0x00;
  117. f.filter.mask[0] = 0xff;
  118. f.timeout = 0;
  119. f.flags = DMX_IMMEDIATE_START | DMX_CHECK_CRC;
  120. if ((patfd = open(dmxdev, O_RDWR)) < 0) {
  121. perror("openening pat demux failed");
  122. return -1;
  123. }
  124. if (ioctl(patfd, DMX_SET_FILTER, &f) == -1) {
  125. perror("ioctl DMX_SET_FILTER failed");
  126. close(patfd);
  127. return -1;
  128. }
  129. while (!patread) {
  130. if (((count = read(patfd, buf, sizeof(buft))) < 0) && errno == EOVERFLOW)
  131. count = read(patfd, buf, sizeof(buft));
  132. if (count < 0) {
  133. perror("read_sections: read error");
  134. close(patfd);
  135. return -1;
  136. }
  137. section_length = ((buf[1] & 0x0f) << 8) | buf[2];
  138. if (count != section_length + 3)
  139. continue;
  140. buf += 8;
  141. section_length -= 8;
  142. patread = 1; /* assumes one section contains the whole pat */
  143. while (section_length > 0) {
  144. int service_id = (buf[0] << 8) | buf[1];
  145. if (service_id == sid) {
  146. pmt_pid = ((buf[2] & 0x1f) << 8) | buf[3];
  147. section_length = 0;
  148. }
  149. buf += 4;
  150. section_length -= 4;
  151. }
  152. }
  153. close(patfd);
  154. return pmt_pid;
  155. }
  156. struct diseqc_cmd {
  157. struct dvb_diseqc_master_cmd cmd;
  158. uint32_t wait;
  159. };
  160. void diseqc_send_msg(int fd, fe_sec_voltage_t v, struct diseqc_cmd *cmd,
  161. fe_sec_tone_mode_t t, fe_sec_mini_cmd_t b)
  162. {
  163. if (ioctl(fd, FE_SET_TONE, SEC_TONE_OFF) == -1)
  164. perror("FE_SET_TONE failed");
  165. if (ioctl(fd, FE_SET_VOLTAGE, v) == -1)
  166. perror("FE_SET_VOLTAGE failed");
  167. usleep(15 * 1000);
  168. if (ioctl(fd, FE_DISEQC_SEND_MASTER_CMD, &cmd->cmd) == -1)
  169. perror("FE_DISEQC_SEND_MASTER_CMD failed");
  170. usleep(cmd->wait * 1000);
  171. usleep(15 * 1000);
  172. if (ioctl(fd, FE_DISEQC_SEND_BURST, b) == -1)
  173. perror("FE_DISEQC_SEND_BURST failed");
  174. usleep(15 * 1000);
  175. if (ioctl(fd, FE_SET_TONE, t) == -1)
  176. perror("FE_SET_TONE failed");
  177. }
  178. /* digital satellite equipment control,
  179. * specification is available from http://www.eutelsat.com/
  180. */
  181. static int diseqc(int secfd, int sat_no, int pol_vert, int hi_band)
  182. {
  183. struct diseqc_cmd cmd =
  184. { {{0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00}, 4}, 0 };
  185. /**
  186. * param: high nibble: reset bits, low nibble set bits,
  187. * bits are: option, position, polarizaion, band
  188. */
  189. cmd.cmd.msg[3] =
  190. 0xf0 | (((sat_no * 4) & 0x0f) | (hi_band ? 1 : 0) | (pol_vert ? 0 : 2));
  191. diseqc_send_msg(secfd, pol_vert ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18,
  192. &cmd, hi_band ? SEC_TONE_ON : SEC_TONE_OFF,
  193. (sat_no / 4) % 2 ? SEC_MINI_B : SEC_MINI_A);
  194. return TRUE;
  195. }
  196. #define DVBS 0
  197. #define DSS 1
  198. #define DVBS2 2
  199. static int do_tune(int fefd, unsigned int ifreq, unsigned int sr, unsigned int delsys)
  200. {
  201. /* API Major=3, Minor=1 */
  202. struct dvb_frontend_parameters tuneto;
  203. struct dvb_frontend_event ev;
  204. /* API Major=3, Minor=2 */
  205. struct dvbfe_params fe_params;
  206. /* discard stale QPSK events */
  207. while (1) {
  208. if (ioctl(fefd, FE_GET_EVENT, &ev) == -1)
  209. break;
  210. }
  211. if ((DVB_API_VERSION == 3) && (DVB_API_VERSION_MINOR == 3)) {
  212. printf("\n%s: API version=%d, delivery system = %d\n", __func__, DVB_API_VERSION_MINOR, delsys);
  213. fe_params.frequency = ifreq;
  214. fe_params.inversion = INVERSION_AUTO;
  215. switch (delsys) {
  216. case DVBS:
  217. fe_params.delsys.dvbs.symbol_rate = sr;
  218. fe_params.delsys.dvbs.fec = FEC_AUTO;
  219. printf("%s: Frequency = %d, Srate = %d\n",
  220. __func__, fe_params.frequency, fe_params.delsys.dvbs.symbol_rate);
  221. break;
  222. case DSS:
  223. fe_params.delsys.dss.symbol_rate = sr;
  224. fe_params.delsys.dss.fec = FEC_AUTO;
  225. printf("%s: Frequency = %d, Srate = %d\n",
  226. __func__, fe_params.frequency, fe_params.delsys.dss.symbol_rate);
  227. break;
  228. case DVBS2:
  229. fe_params.delsys.dvbs2.symbol_rate = sr;
  230. fe_params.delsys.dvbs2.fec = FEC_AUTO;
  231. printf("%s: Frequency = %d, Srate = %d\n",
  232. __func__, fe_params.frequency, fe_params.delsys.dvbs2.symbol_rate);
  233. break;
  234. default:
  235. return -EINVAL;
  236. }
  237. printf("%s: Frequency = %d, Srate = %d\n\n\n",
  238. __func__, fe_params.frequency, fe_params.delsys.dvbs.symbol_rate);
  239. if (ioctl(fefd, DVBFE_SET_PARAMS, &fe_params) == -1) {
  240. perror("DVBFE_SET_PARAMS failed");
  241. return FALSE;
  242. }
  243. } else if ((DVB_API_VERSION == 3) && (DVB_API_VERSION_MINOR == 1)){
  244. tuneto.frequency = ifreq;
  245. tuneto.inversion = INVERSION_AUTO;
  246. tuneto.u.qpsk.symbol_rate = sr;
  247. tuneto.u.qpsk.fec_inner = FEC_AUTO;
  248. if (ioctl(fefd, FE_SET_FRONTEND, &tuneto) == -1) {
  249. perror("FE_SET_FRONTEND failed");
  250. return FALSE;
  251. }
  252. }
  253. return TRUE;
  254. }
  255. static
  256. int check_frontend (int fe_fd, int dvr)
  257. {
  258. (void)dvr;
  259. fe_status_t status;
  260. uint16_t snr, signal;
  261. uint32_t ber, uncorrected_blocks;
  262. int timeout = 0;
  263. do {
  264. if (ioctl(fe_fd, FE_READ_STATUS, &status) == -1)
  265. perror("FE_READ_STATUS failed");
  266. /* some frontends might not support all these ioctls, thus we
  267. * avoid printing errors
  268. */
  269. if (ioctl(fe_fd, FE_READ_SIGNAL_STRENGTH, &signal) == -1)
  270. signal = -2;
  271. if (ioctl(fe_fd, FE_READ_SNR, &snr) == -1)
  272. snr = -2;
  273. if (ioctl(fe_fd, FE_READ_BER, &ber) == -1)
  274. ber = -2;
  275. if (ioctl(fe_fd, FE_READ_UNCORRECTED_BLOCKS, &uncorrected_blocks) == -1)
  276. uncorrected_blocks = -2;
  277. printf ("status %02x | signal %04x | snr %04x | ber %08x | unc %08x | ",
  278. status, signal, snr, ber, uncorrected_blocks);
  279. if (status & FE_HAS_LOCK)
  280. printf("FE_HAS_LOCK");
  281. printf("\n");
  282. if (exit_after_tuning && ((status & FE_HAS_LOCK) || (++timeout >= 10)))
  283. break;
  284. usleep(1000000);
  285. } while (1);
  286. return 0;
  287. }
  288. static
  289. int zap_to(unsigned int adapter, unsigned int frontend, unsigned int demux,
  290. unsigned int sat_no, unsigned int freq, unsigned int pol,
  291. unsigned int sr, unsigned int vpid, unsigned int apid, int sid,
  292. int dvr, int rec_psi, int bypass, unsigned int delsys)
  293. {
  294. char fedev[128], dmxdev[128], auddev[128];
  295. static int fefd, dmxfda, dmxfdv, audiofd = -1, patfd, pmtfd;
  296. int pmtpid;
  297. uint32_t ifreq;
  298. int hiband, result;
  299. enum dvbfe_delsys delivery;
  300. switch (delsys) {
  301. case DVBS:
  302. printf("Delivery system=DVB-S\n");
  303. delivery = DVBFE_DELSYS_DVBS;
  304. break;
  305. case DSS:
  306. printf("Delivery system=DSS\n");
  307. delivery = DVBFE_DELSYS_DSS;
  308. break;
  309. case DVBS2:
  310. printf("Delivery system=DVB-S2\n");
  311. delivery = DVBFE_DELSYS_DVBS2;
  312. break;
  313. default:
  314. printf("Unsupported delivery system\n");
  315. return -EINVAL;
  316. }
  317. if (!fefd) {
  318. snprintf(fedev, sizeof(fedev), FRONTENDDEVICE, adapter, frontend);
  319. snprintf(dmxdev, sizeof(dmxdev), DEMUXDEVICE, adapter, demux);
  320. snprintf(auddev, sizeof(auddev), AUDIODEVICE, adapter, demux);
  321. printf("using '%s' and '%s'\n", fedev, dmxdev);
  322. if ((fefd = open(fedev, O_RDWR | O_NONBLOCK)) < 0) {
  323. perror("opening frontend failed");
  324. return FALSE;
  325. }
  326. result = ioctl(fefd, DVBFE_SET_DELSYS, &delivery);
  327. if (result < 0) {
  328. perror("ioctl DVBFE_SET_DELSYS failed");
  329. close(fefd);
  330. return FALSE;
  331. }
  332. if ((dmxfdv = open(dmxdev, O_RDWR)) < 0) {
  333. perror("opening video demux failed");
  334. close(fefd);
  335. return FALSE;
  336. }
  337. if ((dmxfda = open(dmxdev, O_RDWR)) < 0) {
  338. perror("opening audio demux failed");
  339. close(fefd);
  340. return FALSE;
  341. }
  342. if (dvr == 0) /* DMX_OUT_DECODER */
  343. audiofd = open(auddev, O_RDWR);
  344. if (rec_psi){
  345. if ((patfd = open(dmxdev, O_RDWR)) < 0) {
  346. perror("opening pat demux failed");
  347. close(audiofd);
  348. close(dmxfda);
  349. close(dmxfdv);
  350. close(fefd);
  351. return FALSE;
  352. }
  353. if ((pmtfd = open(dmxdev, O_RDWR)) < 0) {
  354. perror("opening pmt demux failed");
  355. close(patfd);
  356. close(audiofd);
  357. close(dmxfda);
  358. close(dmxfdv);
  359. close(fefd);
  360. return FALSE;
  361. }
  362. }
  363. }
  364. hiband = 0;
  365. if (lnb_type.switch_val && lnb_type.high_val &&
  366. freq >= lnb_type.switch_val)
  367. hiband = 1;
  368. if (hiband)
  369. ifreq = freq - lnb_type.high_val;
  370. else {
  371. if (freq < lnb_type.low_val)
  372. ifreq = lnb_type.low_val - freq;
  373. else
  374. ifreq = freq - lnb_type.low_val;
  375. }
  376. result = FALSE;
  377. if (diseqc(fefd, sat_no, pol, hiband))
  378. if (do_tune(fefd, ifreq, sr, delsys))
  379. if (set_demux(dmxfdv, vpid, DMX_PES_VIDEO, dvr))
  380. if (audiofd >= 0)
  381. (void)ioctl(audiofd, AUDIO_SET_BYPASS_MODE, bypass);
  382. if (set_demux(dmxfda, apid, DMX_PES_AUDIO, dvr)) {
  383. if (rec_psi) {
  384. pmtpid = get_pmt_pid(dmxdev, sid);
  385. if (pmtpid < 0) {
  386. result = FALSE;
  387. }
  388. if (pmtpid == 0) {
  389. fprintf(stderr,"couldn't find pmt-pid for sid %04x\n",sid);
  390. result = FALSE;
  391. }
  392. if (set_demux(patfd, 0, DMX_PES_OTHER, dvr))
  393. if (set_demux(pmtfd, pmtpid, DMX_PES_OTHER, dvr))
  394. result = TRUE;
  395. } else {
  396. result = TRUE;
  397. }
  398. }
  399. check_frontend (fefd, dvr);
  400. if (!interactive) {
  401. close(patfd);
  402. close(pmtfd);
  403. if (audiofd >= 0)
  404. close(audiofd);
  405. close(dmxfda);
  406. close(dmxfdv);
  407. close(fefd);
  408. }
  409. return result;
  410. }
  411. static int read_channels(const char *filename, int list_channels,
  412. uint32_t chan_no, const char *chan_name,
  413. unsigned int adapter, unsigned int frontend,
  414. unsigned int demux, int dvr, int rec_psi,
  415. int bypass, unsigned int delsys)
  416. {
  417. FILE *cfp;
  418. char buf[4096];
  419. char inp[256];
  420. char *field, *tmp, *p;
  421. unsigned int line;
  422. unsigned int freq, pol, sat_no, sr, vpid, apid, sid;
  423. int ret;
  424. again:
  425. line = 0;
  426. if (!(cfp = fopen(filename, "r"))) {
  427. fprintf(stderr, "error opening channel list '%s': %d %m\n",
  428. filename, errno);
  429. return FALSE;
  430. }
  431. if (interactive) {
  432. fprintf(stderr, "\n>>> ");
  433. if (!fgets(inp, sizeof(inp), stdin)) {
  434. printf("\n");
  435. return -1;
  436. }
  437. if (inp[0] == '-' && inp[1] == 'n') {
  438. chan_no = strtoul(inp+2, NULL, 0);
  439. chan_name = NULL;
  440. if (!chan_no) {
  441. fprintf(stderr, "bad channel number\n");
  442. goto again;
  443. }
  444. } else {
  445. p = strchr(inp, '\n');
  446. if (p)
  447. *p = '\0';
  448. chan_name = inp;
  449. chan_no = 0;
  450. }
  451. }
  452. while (!feof(cfp)) {
  453. if (fgets(buf, sizeof(buf), cfp)) {
  454. line++;
  455. if (chan_no && chan_no != line)
  456. continue;
  457. tmp = buf;
  458. field = strsep(&tmp, ":");
  459. if (!field)
  460. goto syntax_err;
  461. if (list_channels) {
  462. printf("%03u %s\n", line, field);
  463. continue;
  464. }
  465. if (chan_name && strcasecmp(chan_name, field) != 0)
  466. continue;
  467. printf("zapping to %d '%s':\n", line, field);
  468. if (!(field = strsep(&tmp, ":")))
  469. goto syntax_err;
  470. freq = strtoul(field, NULL, 0);
  471. if (!(field = strsep(&tmp, ":")))
  472. goto syntax_err;
  473. pol = (field[0] == 'h' ? 0 : 1);
  474. if (!(field = strsep(&tmp, ":")))
  475. goto syntax_err;
  476. sat_no = strtoul(field, NULL, 0);
  477. if (!(field = strsep(&tmp, ":")))
  478. goto syntax_err;
  479. sr = strtoul(field, NULL, 0) * 1000;
  480. if (!(field = strsep(&tmp, ":")))
  481. goto syntax_err;
  482. vpid = strtoul(field, NULL, 0);
  483. if (!vpid)
  484. vpid = 0x1fff;
  485. if (!(field = strsep(&tmp, ":")))
  486. goto syntax_err;
  487. p = strchr(field, ';');
  488. if (p) {
  489. *p = '\0';
  490. p++;
  491. if (bypass) {
  492. if (!p || !*p)
  493. goto syntax_err;
  494. field = p;
  495. }
  496. }
  497. apid = strtoul(field, NULL, 0);
  498. if (!apid)
  499. apid = 0x1fff;
  500. if (!(field = strsep(&tmp, ":")))
  501. goto syntax_err;
  502. sid = strtoul(field, NULL, 0);
  503. printf("sat %u, frequency = %u MHz %c, symbolrate %u, "
  504. "vpid = 0x%04x, apid = 0x%04x sid = 0x%04x\n",
  505. sat_no, freq, pol ? 'V' : 'H', sr, vpid, apid, sid);
  506. fclose(cfp);
  507. ret = zap_to(adapter, frontend, demux, sat_no, freq * 1000,
  508. pol, sr, vpid, apid, sid, dvr, rec_psi, bypass, delsys);
  509. if (interactive)
  510. goto again;
  511. if (ret)
  512. return TRUE;
  513. return FALSE;
  514. syntax_err:
  515. fprintf(stderr, "syntax error in line %u: '%s'\n", line, buf);
  516. } else if (ferror(cfp)) {
  517. fprintf(stderr, "error reading channel list '%s': %d %m\n",
  518. filename, errno);
  519. fclose(cfp);
  520. return FALSE;
  521. } else
  522. break;
  523. }
  524. fclose(cfp);
  525. if (!list_channels) {
  526. fprintf(stderr, "channel not found\n");
  527. if (!interactive)
  528. return FALSE;
  529. }
  530. if (interactive)
  531. goto again;
  532. return TRUE;
  533. }
  534. void
  535. bad_usage(char *pname, int prlnb)
  536. {
  537. int i;
  538. struct lnb_types_st *lnbp;
  539. char **cp;
  540. if (!prlnb) {
  541. fprintf (stderr, usage_str, pname);
  542. } else {
  543. i = 0;
  544. fprintf(stderr, "-l <lnb-type> or -l low[,high[,switch]] in Mhz\nwhere <lnb-type> is:\n");
  545. while(NULL != (lnbp = lnb_enum(i))) {
  546. fprintf (stderr, "%s\n", lnbp->name);
  547. for (cp = lnbp->desc; *cp ; cp++) {
  548. fprintf (stderr, " %s\n", *cp);
  549. }
  550. i++;
  551. }
  552. }
  553. }
  554. int main(int argc, char *argv[])
  555. {
  556. const char *home;
  557. char chanfile[2 * PATH_MAX];
  558. int list_channels = 0;
  559. unsigned int chan_no = 0;
  560. const char *chan_name = NULL;
  561. unsigned int adapter = 0, frontend = 0, demux = 0, dvr = 0, rec_psi = 0, delsys = 0;
  562. int bypass = 0;
  563. int opt, copt = 0;
  564. lnb_type = *lnb_enum(0);
  565. while ((opt = getopt(argc, argv, "hqrpn:a:f:d:t:c:l:xib")) != -1) {
  566. switch (opt) {
  567. case '?':
  568. case 'h':
  569. default:
  570. bad_usage(argv[0], 0);
  571. case 'b':
  572. bypass = 1;
  573. break;
  574. case 'q':
  575. list_channels = 1;
  576. break;
  577. case 'r':
  578. dvr = 1;
  579. break;
  580. case 'n':
  581. chan_no = strtoul(optarg, NULL, 0);
  582. break;
  583. case 'a':
  584. adapter = strtoul(optarg, NULL, 0);
  585. break;
  586. case 'f':
  587. frontend = strtoul(optarg, NULL, 0);
  588. break;
  589. case 'p':
  590. rec_psi = 1;
  591. break;
  592. case 'd':
  593. demux = strtoul(optarg, NULL, 0);
  594. break;
  595. case 't':
  596. delsys = strtoul(optarg, NULL, 0);
  597. break;
  598. case 'c':
  599. copt = 1;
  600. strncpy(chanfile, optarg, sizeof(chanfile));
  601. break;
  602. case 'l':
  603. if (lnb_decode(optarg, &lnb_type) < 0) {
  604. bad_usage(argv[0], 1);
  605. return -1;
  606. }
  607. break;
  608. case 'x':
  609. exit_after_tuning = 1;
  610. break;
  611. case 'i':
  612. interactive = 1;
  613. exit_after_tuning = 1;
  614. }
  615. }
  616. lnb_type.low_val *= 1000; /* convert to kiloherz */
  617. lnb_type.high_val *= 1000; /* convert to kiloherz */
  618. lnb_type.switch_val *= 1000; /* convert to kiloherz */
  619. if (optind < argc)
  620. chan_name = argv[optind];
  621. if (chan_name && chan_no) {
  622. bad_usage(argv[0], 0);
  623. return -1;
  624. }
  625. if (list_channels && (chan_name || chan_no)) {
  626. bad_usage(argv[0], 0);
  627. return -1;
  628. }
  629. if (!list_channels && !chan_name && !chan_no && !interactive) {
  630. bad_usage(argv[0], 0);
  631. return -1;
  632. }
  633. if (!copt) {
  634. if (!(home = getenv("HOME"))) {
  635. fprintf(stderr, "error: $HOME not set\n");
  636. return TRUE;
  637. }
  638. snprintf(chanfile, sizeof(chanfile),
  639. "%s/.szap/%i/%s", home, adapter, CHANNEL_FILE);
  640. if (access(chanfile, R_OK))
  641. snprintf(chanfile, sizeof(chanfile),
  642. "%s/.szap/%s", home, CHANNEL_FILE);
  643. }
  644. printf("reading channels from file '%s'\n", chanfile);
  645. if (rec_psi)
  646. dvr=1;
  647. if (!read_channels(chanfile, list_channels, chan_no, chan_name,
  648. adapter, frontend, demux, dvr, rec_psi, bypass, delsys))
  649. return TRUE;
  650. return FALSE;
  651. }