dvbscan.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. /*
  2. dvbscan utility
  3. Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. */
  16. #include <stdlib.h>
  17. #include <unistd.h>
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include <time.h>
  21. #include <libdvbsec/dvbsec_cfg.h>
  22. #include <libdvbcfg/dvbcfg_scanfile.h>
  23. #include <libdvbapi/dvbdemux.h>
  24. #include "dvbscan.h"
  25. #define OUTPUT_TYPE_RAW 1
  26. #define OUTPUT_TYPE_CHANNELS 2
  27. #define OUTPUT_TYPE_VDR12 3
  28. #define OUTPUT_TYPE_VDR13 4
  29. #define SERVICE_FILTER_TV 1
  30. #define SERVICE_FILTER_RADIO 2
  31. #define SERVICE_FILTER_OTHER 4
  32. #define SERVICE_FILTER_ENCRYPTED 8
  33. #define TIMEOUT_WAIT_LOCK 2
  34. // transponders we have yet to scan
  35. static struct transponder *toscan = NULL;
  36. static struct transponder *toscan_end = NULL;
  37. // transponders we have scanned
  38. static struct transponder *scanned = NULL;
  39. static struct transponder *scanned_end = NULL;
  40. static void usage(void)
  41. {
  42. static const char *_usage = "\n"
  43. " dvbscan: A digital tv channel scanning utility\n"
  44. " Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)\n\n"
  45. " usage: dvbscan <options> as follows:\n"
  46. " -h help\n"
  47. " -adapter <id> adapter to use (default 0)\n"
  48. " -frontend <id> frontend to use (default 0)\n"
  49. " -demux <id> demux to use (default 0)\n"
  50. " -secfile <filename> Optional sec.conf file.\n"
  51. " -secid <secid> ID of the SEC configuration to use, one of:\n"
  52. " * UNIVERSAL (default) - Europe, 10800 to 11800 MHz and 11600 to 12700 Mhz,\n"
  53. " Dual LO, loband 9750, hiband 10600 MHz.\n"
  54. " * DBS - Expressvu, North America, 12200 to 12700 MHz, Single LO, 11250 MHz.\n"
  55. " * STANDARD - 10945 to 11450 Mhz, Single LO, 10000 Mhz.\n"
  56. " * ENHANCED - Astra, 10700 to 11700 MHz, Single LO, 9750 MHz.\n"
  57. " * C-BAND - Big Dish, 3700 to 4200 MHz, Single LO, 5150 Mhz.\n"
  58. " * C-MULTI - Big Dish - Multipoint LNBf, 3700 to 4200 MHz,\n"
  59. " Dual LO, H:5150MHz, V:5750MHz.\n"
  60. " * One of the sec definitions from the secfile if supplied\n"
  61. " -satpos <position> Specify DISEQC switch position for DVB-S.\n"
  62. " -inversion <on|off|auto> Specify inversion (default: auto) (note: this option is ignored).\n"
  63. " -uk-ordering Use UK DVB-T channel ordering if present (note: this option is ignored).\n"
  64. " -timeout <secs> Specify filter timeout to use (standard specced values will be used by default)\n"
  65. " -filter <filter> Specify service filter, a comma seperated list of the following tokens:\n"
  66. " (If no filter is supplied, all services will be output)\n"
  67. " * tv - Output TV channels\n"
  68. " * radio - Output radio channels\n"
  69. " * other - Output other channels\n"
  70. " * encrypted - Output encrypted channels\n"
  71. " -out raw <filename>|- Output in raw format to <filename> or stdout\n"
  72. " channels <filename>|- Output in channels.conf format to <filename> or stdout.\n"
  73. " vdr12 <filename>|- Output in vdr 1.2.x format to <filename> or stdout.\n"
  74. " vdr13 <filename>|- Output in vdr 1.3.x format to <filename> or stdout.\n"
  75. " Note: this option is ignored.\n"
  76. " <initial scan file>\n";
  77. fprintf(stderr, "%s\n", _usage);
  78. exit(1);
  79. }
  80. static int scan_load_callback(struct dvbcfg_scanfile *channel, void *private_data)
  81. {
  82. struct dvbfe_info *feinfo = (struct dvbfe_info *) private_data;
  83. if (channel->fe_type != feinfo->type)
  84. return 0;
  85. struct transponder *t = new_transponder();
  86. append_transponder(t, &toscan, &toscan_end);
  87. memcpy(&t->params, &channel->fe_params, sizeof(struct dvbfe_parameters));
  88. add_frequency(t, t->params.frequency);
  89. t->params.frequency = 0;
  90. return 0;
  91. }
  92. int main(int argc, char *argv[])
  93. {
  94. uint32_t i;
  95. int argpos = 1;
  96. int adapter_id = 0;
  97. int frontend_id = 0;
  98. int demux_id = 0;
  99. char *secfile = NULL;
  100. char *secid = NULL;
  101. int satpos = 0;
  102. int service_filter = -1;
  103. int timeout = 5;
  104. char *scan_filename = NULL;
  105. struct dvbsec_config sec;
  106. int valid_sec = 0;
  107. while(argpos != argc) {
  108. if (!strcmp(argv[argpos], "-h")) {
  109. usage();
  110. } else if (!strcmp(argv[argpos], "-adapter")) {
  111. if ((argc - argpos) < 2)
  112. usage();
  113. if (sscanf(argv[argpos+1], "%i", &adapter_id) != 1)
  114. usage();
  115. argpos+=2;
  116. } else if (!strcmp(argv[argpos], "-frontend")) {
  117. if ((argc - argpos) < 2)
  118. usage();
  119. if (sscanf(argv[argpos+1], "%i", &frontend_id) != 1)
  120. usage();
  121. argpos+=2;
  122. } else if (!strcmp(argv[argpos], "-demux")) {
  123. if ((argc - argpos) < 2)
  124. usage();
  125. if (sscanf(argv[argpos+1], "%i", &demux_id) != 1)
  126. usage();
  127. argpos+=2;
  128. } else if (!strcmp(argv[argpos], "-secfile")) {
  129. if ((argc - argpos) < 2)
  130. usage();
  131. secfile = argv[argpos+1];
  132. argpos+=2;
  133. } else if (!strcmp(argv[argpos], "-secid")) {
  134. if ((argc - argpos) < 2)
  135. usage();
  136. secid = argv[argpos+1];
  137. argpos+=2;
  138. } else if (!strcmp(argv[argpos], "-satpos")) {
  139. if ((argc - argpos) < 2)
  140. usage();
  141. if (sscanf(argv[argpos+1], "%i", &satpos) != 1)
  142. usage();
  143. argpos+=2;
  144. } else if (!strcmp(argv[argpos], "-inversion")) {
  145. if ((argc - argpos) < 2)
  146. usage();
  147. argpos+=2;
  148. } else if (!strcmp(argv[argpos], "-uk-ordering")) {
  149. if ((argc - argpos) < 1)
  150. usage();
  151. } else if (!strcmp(argv[argpos], "-timeout")) {
  152. if ((argc - argpos) < 2)
  153. usage();
  154. if (sscanf(argv[argpos+1], "%i", &timeout) != 1)
  155. usage();
  156. argpos+=2;
  157. } else if (!strcmp(argv[argpos], "-filter")) {
  158. if ((argc - argpos) < 2)
  159. usage();
  160. service_filter = 0;
  161. if (!strstr(argv[argpos+1], "tv")) {
  162. service_filter |= SERVICE_FILTER_TV;
  163. }
  164. if (!strstr(argv[argpos+1], "radio")) {
  165. service_filter |= SERVICE_FILTER_RADIO;
  166. }
  167. if (!strstr(argv[argpos+1], "other")) {
  168. service_filter |= SERVICE_FILTER_OTHER;
  169. }
  170. if (!strstr(argv[argpos+1], "encrypted")) {
  171. service_filter |= SERVICE_FILTER_ENCRYPTED;
  172. }
  173. argpos+=2;
  174. } else if (!strcmp(argv[argpos], "-out")) {
  175. if ((argc - argpos) < 3)
  176. usage();
  177. } else {
  178. if ((argc - argpos) != 1)
  179. usage();
  180. scan_filename = argv[argpos];
  181. argpos++;
  182. }
  183. }
  184. // open the frontend & get its type
  185. struct dvbfe_handle *fe = dvbfe_open(adapter_id, frontend_id, 0);
  186. if (fe == NULL) {
  187. fprintf(stderr, "Failed to open frontend\n");
  188. exit(1);
  189. }
  190. struct dvbfe_info feinfo;
  191. if (dvbfe_get_info(fe, 0, &feinfo, DVBFE_INFO_QUERYTYPE_IMMEDIATE, 0) != 0) {
  192. fprintf(stderr, "Failed to query frontend\n");
  193. exit(1);
  194. }
  195. // default SEC with a DVBS card
  196. if ((secid == NULL) && (feinfo.type == DVBFE_TYPE_DVBS))
  197. secid = "UNIVERSAL";
  198. // look up SECID if one was supplied
  199. if (secid != NULL) {
  200. if (dvbsec_cfg_find(secfile, secid, &sec)) {
  201. fprintf(stderr, "Unable to find suitable sec/lnb configuration for channel\n");
  202. exit(1);
  203. }
  204. valid_sec = 1;
  205. }
  206. // load the initial scan file
  207. FILE *scan_file = fopen(scan_filename, "r");
  208. if (scan_file == NULL) {
  209. fprintf(stderr, "Could not open scan file %s\n", scan_filename);
  210. exit(1);
  211. }
  212. if (dvbcfg_scanfile_parse(scan_file, scan_load_callback, &feinfo) < 0) {
  213. fprintf(stderr, "Could not parse scan file %s\n", scan_filename);
  214. exit(1);
  215. }
  216. fclose(scan_file);
  217. // main scan loop
  218. while(toscan) {
  219. // get the first item on the toscan list
  220. struct transponder *tmp = first_transponder(&toscan, &toscan_end);
  221. // have we already seen this transponder?
  222. if (seen_transponder(tmp, scanned)) {
  223. free_transponder(tmp);
  224. continue;
  225. }
  226. // do we have a valid SEC configuration?
  227. struct dvbsec_config *psec = NULL;
  228. if (valid_sec)
  229. psec = &sec;
  230. // tune it
  231. int tuned_ok = 0;
  232. for(i=0; i < tmp->frequency_count; i++) {
  233. tmp->params.frequency = tmp->frequencies[i];
  234. if (dvbsec_set(fe,
  235. psec,
  236. tmp->polarization,
  237. (satpos & 0x01) ? DISEQC_SWITCH_B : DISEQC_SWITCH_A,
  238. (satpos & 0x02) ? DISEQC_SWITCH_B : DISEQC_SWITCH_A,
  239. &tmp->params,
  240. 0)) {
  241. fprintf(stderr, "Failed to set frontend\n");
  242. exit(1);
  243. }
  244. // wait for lock
  245. time_t starttime = time(NULL);
  246. while((time(NULL) - starttime) < TIMEOUT_WAIT_LOCK) {
  247. if (dvbfe_get_info(fe, DVBFE_INFO_LOCKSTATUS, &feinfo,
  248. DVBFE_INFO_QUERYTYPE_IMMEDIATE, 0) !=
  249. DVBFE_INFO_QUERYTYPE_IMMEDIATE) {
  250. fprintf(stderr, "Unable to query frontend status\n");
  251. exit(1);
  252. }
  253. if (feinfo.lock) {
  254. tuned_ok = 1;
  255. break;
  256. }
  257. usleep(100000);
  258. }
  259. }
  260. if (!tuned_ok) {
  261. free_transponder(tmp);
  262. continue;
  263. }
  264. // scan it
  265. switch(feinfo.type) {
  266. case DVBFE_TYPE_DVBS:
  267. case DVBFE_TYPE_DVBC:
  268. case DVBFE_TYPE_DVBT:
  269. dvbscan_scan_dvb(fe);
  270. break;
  271. case DVBFE_TYPE_ATSC:
  272. dvbscan_scan_atsc(fe);
  273. break;
  274. }
  275. // add to scanned list.
  276. append_transponder(tmp, &scanned, &scanned_end);
  277. }
  278. // FIXME: output the data
  279. return 0;
  280. }
  281. int create_section_filter(int adapter, int demux, uint16_t pid, uint8_t table_id)
  282. {
  283. int demux_fd = -1;
  284. uint8_t filter[18];
  285. uint8_t mask[18];
  286. // open the demuxer
  287. if ((demux_fd = dvbdemux_open_demux(adapter, demux, 0)) < 0) {
  288. return -1;
  289. }
  290. // create a section filter
  291. memset(filter, 0, sizeof(filter));
  292. memset(mask, 0, sizeof(mask));
  293. filter[0] = table_id;
  294. mask[0] = 0xFF;
  295. if (dvbdemux_set_section_filter(demux_fd, pid, filter, mask, 1, 1)) {
  296. close(demux_fd);
  297. return -1;
  298. }
  299. // done
  300. return demux_fd;
  301. }