|
MythTV
0.26-pre
|
00001 /* 00002 * hdhomerun_config.c 00003 * 00004 * Copyright © 2006-2008 Silicondust USA Inc. <www.silicondust.com>. 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 3 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public 00017 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 00018 * 00019 * As a special exception to the GNU Lesser General Public License, 00020 * you may link, statically or dynamically, an application with a 00021 * publicly distributed version of the Library to produce an 00022 * executable file containing portions of the Library, and 00023 * distribute that executable file under terms of your choice, 00024 * without any of the additional requirements listed in clause 4 of 00025 * the GNU Lesser General Public License. 00026 * 00027 * By "a publicly distributed version of the Library", we mean 00028 * either the unmodified Library as distributed by Silicondust, or a 00029 * modified version of the Library that is distributed under the 00030 * conditions defined in the GNU Lesser General Public License. 00031 */ 00032 00033 #include "hdhomerun.h" 00034 00035 /* 00036 * The console output format should be set to UTF-8, however in XP and Vista this breaks batch file processing. 00037 * Attempting to restore on exit fails to restore if the program is terminated by the user. 00038 * Solution - set the output format each printf. 00039 */ 00040 #if defined(__WINDOWS__) 00041 #define printf console_printf 00042 #define vprintf console_vprintf 00043 #endif 00044 00045 static const char *appname; 00046 00047 struct hdhomerun_device_t *hd; 00048 00049 static int help(void) 00050 { 00051 printf("Usage:\n"); 00052 printf("\t%s discover\n", appname); 00053 printf("\t%s <id> get help\n", appname); 00054 printf("\t%s <id> get <item>\n", appname); 00055 printf("\t%s <id> set <item> <value>\n", appname); 00056 printf("\t%s <id> scan <tuner> [<filename>]\n", appname); 00057 printf("\t%s <id> save <tuner> <filename>\n", appname); 00058 printf("\t%s <id> upgrade <filename>\n", appname); 00059 return -1; 00060 } 00061 00062 static void extract_appname(const char *argv0) 00063 { 00064 const char *ptr = strrchr(argv0, '/'); 00065 if (ptr) { 00066 argv0 = ptr + 1; 00067 } 00068 ptr = strrchr(argv0, '\\'); 00069 if (ptr) { 00070 argv0 = ptr + 1; 00071 } 00072 appname = argv0; 00073 } 00074 00075 static bool_t contains(const char *arg, const char *cmpstr) 00076 { 00077 if (strcmp(arg, cmpstr) == 0) { 00078 return TRUE; 00079 } 00080 00081 if (*arg++ != '-') { 00082 return FALSE; 00083 } 00084 if (*arg++ != '-') { 00085 return FALSE; 00086 } 00087 if (strcmp(arg, cmpstr) == 0) { 00088 return TRUE; 00089 } 00090 00091 return FALSE; 00092 } 00093 00094 static uint32_t parse_ip_addr(const char *str) 00095 { 00096 unsigned long a[4]; 00097 if (sscanf(str, "%lu.%lu.%lu.%lu", &a[0], &a[1], &a[2], &a[3]) != 4) { 00098 return 0; 00099 } 00100 00101 return (uint32_t)((a[0] << 24) | (a[1] << 16) | (a[2] << 8) | (a[3] << 0)); 00102 } 00103 00104 static int discover_print(char *target_ip_str) 00105 { 00106 uint32_t target_ip = 0; 00107 if (target_ip_str) { 00108 target_ip = parse_ip_addr(target_ip_str); 00109 if (target_ip == 0) { 00110 fprintf(stderr, "invalid ip address: %s\n", target_ip_str); 00111 return -1; 00112 } 00113 } 00114 00115 struct hdhomerun_discover_device_t result_list[64]; 00116 int count = hdhomerun_discover_find_devices_custom(target_ip, HDHOMERUN_DEVICE_TYPE_TUNER, HDHOMERUN_DEVICE_ID_WILDCARD, result_list, 64); 00117 if (count < 0) { 00118 fprintf(stderr, "error sending discover request\n"); 00119 return -1; 00120 } 00121 if (count == 0) { 00122 printf("no devices found\n"); 00123 return 0; 00124 } 00125 00126 int index; 00127 for (index = 0; index < count; index++) { 00128 struct hdhomerun_discover_device_t *result = &result_list[index]; 00129 printf("hdhomerun device %08lX found at %u.%u.%u.%u\n", 00130 (unsigned long)result->device_id, 00131 (unsigned int)(result->ip_addr >> 24) & 0x0FF, (unsigned int)(result->ip_addr >> 16) & 0x0FF, 00132 (unsigned int)(result->ip_addr >> 8) & 0x0FF, (unsigned int)(result->ip_addr >> 0) & 0x0FF 00133 ); 00134 } 00135 00136 return count; 00137 } 00138 00139 static int cmd_get(const char *item) 00140 { 00141 char *ret_value; 00142 char *ret_error; 00143 if (hdhomerun_device_get_var(hd, item, &ret_value, &ret_error) < 0) { 00144 fprintf(stderr, "communication error sending request to hdhomerun device\n"); 00145 return -1; 00146 } 00147 00148 if (ret_error) { 00149 printf("%s\n", ret_error); 00150 return 0; 00151 } 00152 00153 printf("%s\n", ret_value); 00154 return 1; 00155 } 00156 00157 static int cmd_set_internal(const char *item, const char *value) 00158 { 00159 char *ret_error; 00160 if (hdhomerun_device_set_var(hd, item, value, NULL, &ret_error) < 0) { 00161 fprintf(stderr, "communication error sending request to hdhomerun device\n"); 00162 return -1; 00163 } 00164 00165 if (ret_error) { 00166 printf("%s\n", ret_error); 00167 return 0; 00168 } 00169 00170 return 1; 00171 } 00172 00173 static int cmd_set(const char *item, const char *value) 00174 { 00175 if (strcmp(value, "-") == 0) { 00176 char *buffer = NULL; 00177 size_t pos = 0; 00178 00179 while (1) { 00180 buffer = (char *)realloc(buffer, pos + 1024); 00181 if (!buffer) { 00182 fprintf(stderr, "out of memory\n"); 00183 return -1; 00184 } 00185 00186 size_t size = fread(buffer + pos, 1, 1024, stdin); 00187 pos += size; 00188 00189 if (size < 1024) { 00190 break; 00191 } 00192 } 00193 00194 buffer[pos] = 0; 00195 00196 int ret = cmd_set_internal(item, buffer); 00197 00198 free(buffer); 00199 return ret; 00200 } 00201 00202 return cmd_set_internal(item, value); 00203 } 00204 00205 static volatile sig_atomic_t sigabort_flag = FALSE; 00206 static volatile sig_atomic_t siginfo_flag = FALSE; 00207 00208 static void sigabort_handler(int arg) 00209 { 00210 sigabort_flag = TRUE; 00211 } 00212 00213 static void siginfo_handler(int arg) 00214 { 00215 siginfo_flag = TRUE; 00216 } 00217 00218 static void register_signal_handlers(sig_t sigpipe_handler, sig_t sigint_handler, sig_t siginfo_handler) 00219 { 00220 #if defined(SIGPIPE) 00221 signal(SIGPIPE, sigpipe_handler); 00222 #endif 00223 #if defined(SIGINT) 00224 signal(SIGINT, sigint_handler); 00225 #endif 00226 #if defined(SIGINFO) 00227 signal(SIGINFO, siginfo_handler); 00228 #endif 00229 } 00230 00231 static void cmd_scan_printf(FILE *fp, const char *fmt, ...) 00232 { 00233 va_list ap; 00234 va_start(ap, fmt); 00235 00236 if (fp) { 00237 va_list apc; 00238 va_copy(apc, ap); 00239 00240 vfprintf(fp, fmt, apc); 00241 fflush(fp); 00242 00243 va_end(apc); 00244 } 00245 00246 vprintf(fmt, ap); 00247 fflush(stdout); 00248 00249 va_end(ap); 00250 } 00251 00252 static int cmd_scan(const char *tuner_str, const char *filename) 00253 { 00254 if (hdhomerun_device_set_tuner_from_str(hd, tuner_str) <= 0) { 00255 fprintf(stderr, "invalid tuner number\n"); 00256 return -1; 00257 } 00258 00259 char *ret_error; 00260 if (hdhomerun_device_tuner_lockkey_request(hd, &ret_error) <= 0) { 00261 fprintf(stderr, "failed to lock tuner\n"); 00262 if (ret_error) { 00263 fprintf(stderr, "%s\n", ret_error); 00264 } 00265 return -1; 00266 } 00267 00268 hdhomerun_device_set_tuner_target(hd, "none"); 00269 00270 char *channelmap; 00271 if (hdhomerun_device_get_tuner_channelmap(hd, &channelmap) <= 0) { 00272 fprintf(stderr, "failed to query channelmap from device\n"); 00273 return -1; 00274 } 00275 00276 const char *channelmap_scan_group = hdhomerun_channelmap_get_channelmap_scan_group(channelmap); 00277 if (!channelmap_scan_group) { 00278 fprintf(stderr, "unknown channelmap '%s'\n", channelmap); 00279 return -1; 00280 } 00281 00282 if (hdhomerun_device_channelscan_init(hd, channelmap_scan_group) <= 0) { 00283 fprintf(stderr, "failed to initialize channel scan\n"); 00284 return -1; 00285 } 00286 00287 FILE *fp = NULL; 00288 if (filename) { 00289 fp = fopen(filename, "w"); 00290 if (!fp) { 00291 fprintf(stderr, "unable to create file: %s\n", filename); 00292 return -1; 00293 } 00294 } 00295 00296 register_signal_handlers(sigabort_handler, sigabort_handler, siginfo_handler); 00297 00298 int ret = 0; 00299 while (!sigabort_flag) { 00300 struct hdhomerun_channelscan_result_t result; 00301 ret = hdhomerun_device_channelscan_advance(hd, &result); 00302 if (ret <= 0) { 00303 break; 00304 } 00305 00306 cmd_scan_printf(fp, "SCANNING: %lu (%s)\n", 00307 (unsigned long)result.frequency, result.channel_str 00308 ); 00309 00310 ret = hdhomerun_device_channelscan_detect(hd, &result); 00311 if (ret < 0) { 00312 break; 00313 } 00314 if (ret == 0) { 00315 continue; 00316 } 00317 00318 cmd_scan_printf(fp, "LOCK: %s (ss=%u snq=%u seq=%u)\n", 00319 result.status.lock_str, result.status.signal_strength, 00320 result.status.signal_to_noise_quality, result.status.symbol_error_quality 00321 ); 00322 00323 if (result.transport_stream_id_detected) { 00324 cmd_scan_printf(fp, "TSID: 0x%04X\n", result.transport_stream_id); 00325 } 00326 00327 int i; 00328 for (i = 0; i < result.program_count; i++) { 00329 struct hdhomerun_channelscan_program_t *program = &result.programs[i]; 00330 cmd_scan_printf(fp, "PROGRAM %s\n", program->program_str); 00331 } 00332 } 00333 00334 hdhomerun_device_tuner_lockkey_release(hd); 00335 00336 if (fp) { 00337 fclose(fp); 00338 } 00339 if (ret < 0) { 00340 fprintf(stderr, "communication error sending request to hdhomerun device\n"); 00341 } 00342 return ret; 00343 } 00344 00345 static void cmd_save_print_stats(void) 00346 { 00347 struct hdhomerun_video_stats_t stats; 00348 hdhomerun_device_get_video_stats(hd, &stats); 00349 00350 fprintf(stderr, "%u packets received, %u overflow errors, %u network errors, %u transport errors, %u sequence errors\n", 00351 (unsigned int)stats.packet_count, 00352 (unsigned int)stats.overflow_error_count, 00353 (unsigned int)stats.network_error_count, 00354 (unsigned int)stats.transport_error_count, 00355 (unsigned int)stats.sequence_error_count 00356 ); 00357 } 00358 00359 static int cmd_save(const char *tuner_str, const char *filename) 00360 { 00361 if (hdhomerun_device_set_tuner_from_str(hd, tuner_str) <= 0) { 00362 fprintf(stderr, "invalid tuner number\n"); 00363 return -1; 00364 } 00365 00366 FILE *fp; 00367 if (strcmp(filename, "null") == 0) { 00368 fp = NULL; 00369 } else if (strcmp(filename, "-") == 0) { 00370 fp = stdout; 00371 } else { 00372 fp = fopen(filename, "wb"); 00373 if (!fp) { 00374 fprintf(stderr, "unable to create file %s\n", filename); 00375 return -1; 00376 } 00377 } 00378 00379 int ret = hdhomerun_device_stream_start(hd); 00380 if (ret <= 0) { 00381 fprintf(stderr, "unable to start stream\n"); 00382 if (fp && fp != stdout) { 00383 fclose(fp); 00384 } 00385 return ret; 00386 } 00387 00388 register_signal_handlers(sigabort_handler, sigabort_handler, siginfo_handler); 00389 00390 struct hdhomerun_video_stats_t stats_old, stats_cur; 00391 hdhomerun_device_get_video_stats(hd, &stats_old); 00392 00393 uint64_t next_progress = getcurrenttime() + 1000; 00394 00395 while (!sigabort_flag) { 00396 uint64_t loop_start_time = getcurrenttime(); 00397 00398 if (siginfo_flag) { 00399 fprintf(stderr, "\n"); 00400 cmd_save_print_stats(); 00401 siginfo_flag = FALSE; 00402 } 00403 00404 size_t actual_size; 00405 uint8_t *ptr = hdhomerun_device_stream_recv(hd, VIDEO_DATA_BUFFER_SIZE_1S, &actual_size); 00406 if (!ptr) { 00407 msleep_approx(64); 00408 continue; 00409 } 00410 00411 if (fp) { 00412 if (fwrite(ptr, 1, actual_size, fp) != actual_size) { 00413 fprintf(stderr, "error writing output\n"); 00414 return -1; 00415 } 00416 } 00417 00418 if (loop_start_time >= next_progress) { 00419 next_progress += 1000; 00420 if (loop_start_time >= next_progress) { 00421 next_progress = loop_start_time + 1000; 00422 } 00423 00424 /* Windows - indicate activity to suppress auto sleep mode. */ 00425 #if defined(__WINDOWS__) 00426 SetThreadExecutionState(ES_SYSTEM_REQUIRED); 00427 #endif 00428 00429 /* Video stats. */ 00430 hdhomerun_device_get_video_stats(hd, &stats_cur); 00431 00432 if (stats_cur.overflow_error_count > stats_old.overflow_error_count) { 00433 fprintf(stderr, "o"); 00434 } else if (stats_cur.network_error_count > stats_old.network_error_count) { 00435 fprintf(stderr, "n"); 00436 } else if (stats_cur.transport_error_count > stats_old.transport_error_count) { 00437 fprintf(stderr, "t"); 00438 } else if (stats_cur.sequence_error_count > stats_old.sequence_error_count) { 00439 fprintf(stderr, "s"); 00440 } else { 00441 fprintf(stderr, "."); 00442 } 00443 00444 stats_old = stats_cur; 00445 fflush(stderr); 00446 } 00447 00448 int32_t delay = 64 - (int32_t)(getcurrenttime() - loop_start_time); 00449 if (delay <= 0) { 00450 continue; 00451 } 00452 00453 msleep_approx(delay); 00454 } 00455 00456 if (fp) { 00457 fclose(fp); 00458 } 00459 00460 hdhomerun_device_stream_stop(hd); 00461 00462 fprintf(stderr, "\n"); 00463 fprintf(stderr, "-- Video statistics --\n"); 00464 cmd_save_print_stats(); 00465 00466 return 0; 00467 } 00468 00469 static int cmd_upgrade(const char *filename) 00470 { 00471 FILE *fp = fopen(filename, "rb"); 00472 if (!fp) { 00473 fprintf(stderr, "unable to open file %s\n", filename); 00474 return -1; 00475 } 00476 00477 printf("uploading firmware...\n"); 00478 if (hdhomerun_device_upgrade(hd, fp) <= 0) { 00479 fprintf(stderr, "error sending upgrade file to hdhomerun device\n"); 00480 fclose(fp); 00481 return -1; 00482 } 00483 00484 fclose(fp); 00485 msleep_minimum(2000); 00486 00487 printf("upgrading firmware...\n"); 00488 msleep_minimum(8000); 00489 00490 printf("rebooting...\n"); 00491 int count = 0; 00492 char *version_str; 00493 while (1) { 00494 if (hdhomerun_device_get_version(hd, &version_str, NULL) >= 0) { 00495 break; 00496 } 00497 00498 count++; 00499 if (count > 30) { 00500 fprintf(stderr, "error finding device after firmware upgrade\n"); 00501 return -1; 00502 } 00503 00504 msleep_minimum(1000); 00505 } 00506 00507 printf("upgrade complete - now running firmware %s\n", version_str); 00508 return 0; 00509 } 00510 00511 static int cmd_execute(void) 00512 { 00513 char *ret_value; 00514 char *ret_error; 00515 if (hdhomerun_device_get_var(hd, "/sys/boot", &ret_value, &ret_error) < 0) { 00516 fprintf(stderr, "communication error sending request to hdhomerun device\n"); 00517 return -1; 00518 } 00519 00520 if (ret_error) { 00521 printf("%s\n", ret_error); 00522 return 0; 00523 } 00524 00525 char *end = ret_value + strlen(ret_value); 00526 char *pos = ret_value; 00527 00528 while (1) { 00529 if (pos >= end) { 00530 break; 00531 } 00532 00533 char *eol_r = strchr(pos, '\r'); 00534 if (!eol_r) { 00535 eol_r = end; 00536 } 00537 00538 char *eol_n = strchr(pos, '\n'); 00539 if (!eol_n) { 00540 eol_n = end; 00541 } 00542 00543 char *eol = eol_r; 00544 if (eol_n < eol) { 00545 eol = eol_n; 00546 } 00547 00548 char *sep = strchr(pos, ' '); 00549 if (!sep || sep > eol) { 00550 pos = eol + 1; 00551 continue; 00552 } 00553 00554 *sep = 0; 00555 *eol = 0; 00556 00557 char *item = pos; 00558 char *value = sep + 1; 00559 00560 printf("set %s \"%s\"\n", item, value); 00561 00562 cmd_set_internal(item, value); 00563 00564 pos = eol + 1; 00565 } 00566 00567 return 1; 00568 } 00569 00570 static int main_cmd(int argc, char *argv[]) 00571 { 00572 if (argc < 1) { 00573 return help(); 00574 } 00575 00576 char *cmd = *argv++; argc--; 00577 00578 if (contains(cmd, "key")) { 00579 if (argc < 2) { 00580 return help(); 00581 } 00582 uint32_t lockkey = strtoul(argv[0], NULL, 0); 00583 hdhomerun_device_tuner_lockkey_use_value(hd, lockkey); 00584 00585 cmd = argv[1]; 00586 argv+=2; argc-=2; 00587 } 00588 00589 if (contains(cmd, "get")) { 00590 if (argc < 1) { 00591 return help(); 00592 } 00593 return cmd_get(argv[0]); 00594 } 00595 00596 if (contains(cmd, "set")) { 00597 if (argc < 2) { 00598 return help(); 00599 } 00600 return cmd_set(argv[0], argv[1]); 00601 } 00602 00603 if (contains(cmd, "scan")) { 00604 if (argc < 1) { 00605 return help(); 00606 } 00607 if (argc < 2) { 00608 return cmd_scan(argv[0], NULL); 00609 } else { 00610 return cmd_scan(argv[0], argv[1]); 00611 } 00612 } 00613 00614 if (contains(cmd, "save")) { 00615 if (argc < 2) { 00616 return help(); 00617 } 00618 return cmd_save(argv[0], argv[1]); 00619 } 00620 00621 if (contains(cmd, "upgrade")) { 00622 if (argc < 1) { 00623 return help(); 00624 } 00625 return cmd_upgrade(argv[0]); 00626 } 00627 00628 if (contains(cmd, "execute")) { 00629 return cmd_execute(); 00630 } 00631 00632 return help(); 00633 } 00634 00635 static int main_internal(int argc, char *argv[]) 00636 { 00637 #if defined(__WINDOWS__) 00638 /* Initialize network socket support. */ 00639 WORD wVersionRequested = MAKEWORD(2, 0); 00640 WSADATA wsaData; 00641 WSAStartup(wVersionRequested, &wsaData); 00642 #endif 00643 00644 extract_appname(argv[0]); 00645 argv++; 00646 argc--; 00647 00648 if (argc == 0) { 00649 return help(); 00650 } 00651 00652 char *id_str = *argv++; argc--; 00653 if (contains(id_str, "help")) { 00654 return help(); 00655 } 00656 if (contains(id_str, "discover")) { 00657 if (argc < 1) { 00658 return discover_print(NULL); 00659 } else { 00660 return discover_print(argv[0]); 00661 } 00662 } 00663 00664 /* Device object. */ 00665 hd = hdhomerun_device_create_from_str(id_str, NULL); 00666 if (!hd) { 00667 fprintf(stderr, "invalid device id: %s\n", id_str); 00668 return -1; 00669 } 00670 00671 /* Device ID check. */ 00672 uint32_t device_id_requested = hdhomerun_device_get_device_id_requested(hd); 00673 if (!hdhomerun_discover_validate_device_id(device_id_requested)) { 00674 fprintf(stderr, "invalid device id: %08lX\n", (unsigned long)device_id_requested); 00675 } 00676 00677 /* Connect to device and check model. */ 00678 const char *model = hdhomerun_device_get_model_str(hd); 00679 if (!model) { 00680 fprintf(stderr, "unable to connect to device\n"); 00681 hdhomerun_device_destroy(hd); 00682 return -1; 00683 } 00684 00685 /* Command. */ 00686 int ret = main_cmd(argc, argv); 00687 00688 /* Cleanup. */ 00689 hdhomerun_device_destroy(hd); 00690 00691 /* Complete. */ 00692 return ret; 00693 } 00694 00695 int main(int argc, char *argv[]) 00696 { 00697 int ret = main_internal(argc, argv); 00698 if (ret <= 0) { 00699 return 1; 00700 } 00701 return 0; 00702 }
1.7.6.1