MythTV  0.26-pre
hdhomerun_device.c
Go to the documentation of this file.
00001 /*
00002  * hdhomerun_device.c
00003  *
00004  * Copyright © 2006-2010 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 struct hdhomerun_device_t {
00036         struct hdhomerun_control_sock_t *cs;
00037         struct hdhomerun_video_sock_t *vs;
00038         struct hdhomerun_debug_t *dbg;
00039         struct hdhomerun_channelscan_t *scan;
00040         uint32_t multicast_ip;
00041         uint16_t multicast_port;
00042         uint32_t device_id;
00043         unsigned int tuner;
00044         uint32_t lockkey;
00045         char name[32];
00046         char model[32];
00047 };
00048 
00049 static int hdhomerun_device_set_device_normal(struct hdhomerun_device_t *hd, uint32_t device_id, uint32_t device_ip)
00050 {
00051         if (!hd->cs) {
00052                 hd->cs = hdhomerun_control_create(0, 0, hd->dbg);
00053                 if (!hd->cs) {
00054                         hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_device: failed to create control object\n");
00055                         return -1;
00056                 }
00057         }
00058 
00059         hdhomerun_control_set_device(hd->cs, device_id, device_ip);
00060 
00061         if ((device_id == 0) || (device_id == HDHOMERUN_DEVICE_ID_WILDCARD)) {
00062                 device_id = hdhomerun_control_get_device_id(hd->cs);
00063         }
00064 
00065         hd->multicast_ip = 0;
00066         hd->multicast_port = 0;
00067         hd->device_id = device_id;
00068         hd->tuner = 0;
00069         hd->lockkey = 0;
00070 
00071         sprintf(hd->name, "%08lX-%u", (unsigned long)hd->device_id, hd->tuner);
00072         hd->model[0] = 0; /* clear cached model string */
00073 
00074         return 1;
00075 }
00076 
00077 static int hdhomerun_device_set_device_multicast(struct hdhomerun_device_t *hd, uint32_t multicast_ip)
00078 {
00079         if (hd->cs) {
00080                 hdhomerun_control_destroy(hd->cs);
00081                 hd->cs = NULL;
00082         }
00083 
00084         hd->multicast_ip = multicast_ip;
00085         hd->multicast_port = 0;
00086         hd->device_id = 0;
00087         hd->tuner = 0;
00088         hd->lockkey = 0;
00089 
00090         unsigned long ip = multicast_ip;
00091         sprintf(hd->name, "%lu.%lu.%lu.%lu", (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, (ip >> 0) & 0xFF);
00092         sprintf(hd->model, "multicast");
00093 
00094         return 1;
00095 }
00096 
00097 int hdhomerun_device_set_device(struct hdhomerun_device_t *hd, uint32_t device_id, uint32_t device_ip)
00098 {
00099         if ((device_id == 0) && (device_ip == 0)) {
00100                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_device: device not specified\n");
00101                 return -1;
00102         }
00103 
00104         if (hdhomerun_discover_is_ip_multicast(device_ip)) {
00105                 return hdhomerun_device_set_device_multicast(hd, device_ip);
00106         }
00107 
00108         return hdhomerun_device_set_device_normal(hd, device_id, device_ip);
00109 }
00110 
00111 int hdhomerun_device_set_tuner(struct hdhomerun_device_t *hd, unsigned int tuner)
00112 {
00113         if (hd->multicast_ip != 0) {
00114                 if (tuner != 0) {
00115                         hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_tuner: tuner cannot be specified in multicast mode\n");
00116                         return -1;
00117                 }
00118 
00119                 return 1;
00120         }
00121 
00122         hd->tuner = tuner;
00123         sprintf(hd->name, "%08lX-%u", (unsigned long)hd->device_id, hd->tuner);
00124 
00125         return 1;
00126 }
00127 
00128 struct hdhomerun_device_t *hdhomerun_device_create(uint32_t device_id, uint32_t device_ip, unsigned int tuner, struct hdhomerun_debug_t *dbg)
00129 {
00130         struct hdhomerun_device_t *hd = (struct hdhomerun_device_t *)calloc(1, sizeof(struct hdhomerun_device_t));
00131         if (!hd) {
00132                 hdhomerun_debug_printf(dbg, "hdhomerun_device_create: failed to allocate device object\n");
00133                 return NULL;
00134         }
00135 
00136         hd->dbg = dbg;
00137 
00138         if ((device_id == 0) && (device_ip == 0) && (tuner == 0)) {
00139                 return hd;
00140         }
00141 
00142         if (hdhomerun_device_set_device(hd, device_id, device_ip) <= 0) {
00143                 free(hd);
00144                 return NULL;
00145         }
00146         if (hdhomerun_device_set_tuner(hd, tuner) <= 0) {
00147                 free(hd);
00148                 return NULL;
00149         }
00150 
00151         return hd;
00152 }
00153 
00154 void hdhomerun_device_destroy(struct hdhomerun_device_t *hd)
00155 {
00156         if (hd->scan) {
00157                 channelscan_destroy(hd->scan);
00158         }
00159 
00160         if (hd->vs) {
00161                 hdhomerun_video_destroy(hd->vs);
00162         }
00163 
00164         if (hd->cs) {
00165                 hdhomerun_control_destroy(hd->cs);
00166         }
00167 
00168         free(hd);
00169 }
00170 
00171 static bool_t is_hex_char(char c)
00172 {
00173         if ((c >= '0') && (c <= '9')) {
00174                 return TRUE;
00175         }
00176         if ((c >= 'A') && (c <= 'F')) {
00177                 return TRUE;
00178         }
00179         if ((c >= 'a') && (c <= 'f')) {
00180                 return TRUE;
00181         }
00182         return FALSE;
00183 }
00184 
00185 static struct hdhomerun_device_t *hdhomerun_device_create_from_str_device_id(const char *device_str, struct hdhomerun_debug_t *dbg)
00186 {
00187         int i;
00188         const char *ptr = device_str;
00189         for (i = 0; i < 8; i++) {
00190                 if (!is_hex_char(*ptr++)) {
00191                         return NULL;
00192                 }
00193         }
00194 
00195         if (*ptr == 0) {
00196                 unsigned long device_id;
00197                 if (sscanf(device_str, "%lx", &device_id) != 1) {
00198                         return NULL;
00199                 }
00200                 return hdhomerun_device_create((uint32_t)device_id, 0, 0, dbg);
00201         }
00202 
00203         if (*ptr == '-') {
00204                 unsigned long device_id;
00205                 unsigned int tuner;
00206                 if (sscanf(device_str, "%lx-%u", &device_id, &tuner) != 2) {
00207                         return NULL;
00208                 }
00209                 return hdhomerun_device_create((uint32_t)device_id, 0, tuner, dbg);
00210         }
00211 
00212         return NULL;
00213 }
00214 
00215 static struct hdhomerun_device_t *hdhomerun_device_create_from_str_ip_result(unsigned long a[4], unsigned int port, unsigned int tuner, struct hdhomerun_debug_t *dbg)
00216 {
00217         unsigned long device_ip = (a[0] << 24) | (a[1] << 16) | (a[2] << 8) | (a[3] << 0);
00218         struct hdhomerun_device_t *hd = hdhomerun_device_create(HDHOMERUN_DEVICE_ID_WILDCARD, (uint32_t)device_ip, tuner, dbg);
00219         if (!hd) {
00220                 return NULL;
00221         }
00222 
00223         if (hd->multicast_ip != 0) {
00224                 hd->multicast_port = (uint16_t)port;
00225         }
00226 
00227         return hd;
00228 }
00229 
00230 static struct hdhomerun_device_t *hdhomerun_device_create_from_str_ip(const char *device_str, struct hdhomerun_debug_t *dbg)
00231 {
00232         unsigned long a[4];
00233         unsigned int port = 0;
00234         unsigned int tuner = 0;
00235 
00236         if (sscanf(device_str, "%lu.%lu.%lu.%lu:%u", &a[0], &a[1], &a[2], &a[3], &port) == 5) {
00237                 return hdhomerun_device_create_from_str_ip_result(a, port, tuner, dbg);
00238         }
00239         if (sscanf(device_str, "%lu.%lu.%lu.%lu-%u", &a[0], &a[1], &a[2], &a[3], &tuner) == 5) {
00240                 return hdhomerun_device_create_from_str_ip_result(a, port, tuner, dbg);
00241         }
00242         if (sscanf(device_str, "%lu.%lu.%lu.%lu", &a[0], &a[1], &a[2], &a[3]) == 4) {
00243                 return hdhomerun_device_create_from_str_ip_result(a, port, tuner, dbg);
00244         }
00245 
00246         return NULL;
00247 }
00248 
00249 static struct hdhomerun_device_t *hdhomerun_device_create_from_str_dns(const char *device_str, struct hdhomerun_debug_t *dbg)
00250 {
00251 #if defined(__CYGWIN__)
00252         return NULL;
00253 #else
00254         struct addrinfo hints;
00255         memset(&hints, 0, sizeof(hints));
00256         hints.ai_family = AF_INET;
00257         hints.ai_socktype = SOCK_STREAM;
00258         hints.ai_protocol = IPPROTO_TCP;
00259 
00260         struct addrinfo *sock_info;
00261         if (getaddrinfo(device_str, "65001", &hints, &sock_info) != 0) {
00262                 return NULL;
00263         }
00264 
00265         struct sockaddr_in *sock_addr = (struct sockaddr_in *)sock_info->ai_addr;
00266         uint32_t device_ip = ntohl(sock_addr->sin_addr.s_addr);
00267         freeaddrinfo(sock_info);
00268 
00269         if (device_ip == 0) {
00270                 return NULL;
00271         }
00272 
00273         return hdhomerun_device_create(HDHOMERUN_DEVICE_ID_WILDCARD, (uint32_t)device_ip, 0, dbg);
00274 #endif
00275 }
00276 
00277 struct hdhomerun_device_t *hdhomerun_device_create_from_str(const char *device_str, struct hdhomerun_debug_t *dbg)
00278 {
00279         struct hdhomerun_device_t *device = hdhomerun_device_create_from_str_device_id(device_str, dbg);
00280         if (device) {
00281                 return device;
00282         }
00283 
00284         device = hdhomerun_device_create_from_str_ip(device_str, dbg);
00285         if (device) {
00286                 return device;
00287         }
00288 
00289         device = hdhomerun_device_create_from_str_dns(device_str, dbg);
00290         if (device) {
00291                 return device;
00292         }
00293 
00294         return NULL;
00295 }
00296 
00297 int hdhomerun_device_set_tuner_from_str(struct hdhomerun_device_t *hd, const char *tuner_str)
00298 {
00299         unsigned int tuner;
00300         if (sscanf(tuner_str, "%u", &tuner) == 1) {
00301                 hdhomerun_device_set_tuner(hd, tuner);
00302                 return 1;
00303         }
00304         if (sscanf(tuner_str, "/tuner%u", &tuner) == 1) {
00305                 hdhomerun_device_set_tuner(hd, tuner);
00306                 return 1;
00307         }
00308 
00309         return -1;
00310 }
00311 
00312 const char *hdhomerun_device_get_name(struct hdhomerun_device_t *hd)
00313 {
00314         return hd->name;
00315 }
00316 
00317 uint32_t hdhomerun_device_get_device_id(struct hdhomerun_device_t *hd)
00318 {
00319         return hd->device_id;
00320 }
00321 
00322 uint32_t hdhomerun_device_get_device_ip(struct hdhomerun_device_t *hd)
00323 {
00324         if (hd->multicast_ip != 0) {
00325                 return hd->multicast_ip;
00326         }
00327         if (hd->cs) {
00328                 return hdhomerun_control_get_device_ip(hd->cs);
00329         }
00330 
00331         return 0;
00332 }
00333 
00334 uint32_t hdhomerun_device_get_device_id_requested(struct hdhomerun_device_t *hd)
00335 {
00336         if (hd->multicast_ip != 0) {
00337                 return 0;
00338         }
00339         if (hd->cs) {
00340                 return hdhomerun_control_get_device_id_requested(hd->cs);
00341         }
00342 
00343         return 0;
00344 }
00345 
00346 uint32_t hdhomerun_device_get_device_ip_requested(struct hdhomerun_device_t *hd)
00347 {
00348         if (hd->multicast_ip != 0) {
00349                 return hd->multicast_ip;
00350         }
00351         if (hd->cs) {
00352                 return hdhomerun_control_get_device_ip_requested(hd->cs);
00353         }
00354 
00355         return 0;
00356 }
00357 
00358 unsigned int hdhomerun_device_get_tuner(struct hdhomerun_device_t *hd)
00359 {
00360         return hd->tuner;
00361 }
00362 
00363 struct hdhomerun_control_sock_t *hdhomerun_device_get_control_sock(struct hdhomerun_device_t *hd)
00364 {
00365         return hd->cs;
00366 }
00367 
00368 struct hdhomerun_video_sock_t *hdhomerun_device_get_video_sock(struct hdhomerun_device_t *hd)
00369 {
00370         if (hd->vs) {
00371                 return hd->vs;
00372         }
00373 
00374         bool_t allow_port_reuse = (hd->multicast_port != 0);
00375 
00376         hd->vs = hdhomerun_video_create(hd->multicast_port, allow_port_reuse, VIDEO_DATA_BUFFER_SIZE_1S * 2, hd->dbg);
00377         if (!hd->vs) {
00378                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_video_sock: failed to create video object\n");
00379                 return NULL;
00380         }
00381 
00382         return hd->vs;
00383 }
00384 
00385 uint32_t hdhomerun_device_get_local_machine_addr(struct hdhomerun_device_t *hd)
00386 {
00387         if (hd->cs) {
00388                 return hdhomerun_control_get_local_addr(hd->cs);
00389         }
00390 
00391         return 0;
00392 }
00393 
00394 static uint32_t hdhomerun_device_get_status_parse(const char *status_str, const char *tag)
00395 {
00396         const char *ptr = strstr(status_str, tag);
00397         if (!ptr) {
00398                 return 0;
00399         }
00400 
00401         unsigned long value = 0;
00402         sscanf(ptr + strlen(tag), "%lu", &value);
00403 
00404         return (uint32_t)value;
00405 }
00406 
00407 static bool_t hdhomerun_device_get_tuner_status_lock_is_bcast(struct hdhomerun_tuner_status_t *status)
00408 {
00409         if (strcmp(status->lock_str, "8vsb") == 0) {
00410                 return TRUE;
00411         }
00412         if (strncmp(status->lock_str, "t8", 2) == 0) {
00413                 return TRUE;
00414         }
00415         if (strncmp(status->lock_str, "t7", 2) == 0) {
00416                 return TRUE;
00417         }
00418         if (strncmp(status->lock_str, "t6", 2) == 0) {
00419                 return TRUE;
00420         }
00421 
00422         return FALSE;
00423 }
00424 
00425 uint32_t hdhomerun_device_get_tuner_status_ss_color(struct hdhomerun_tuner_status_t *status)
00426 {
00427         unsigned int ss_yellow_min;
00428         unsigned int ss_green_min;
00429 
00430         if (!status->lock_supported) {
00431                 return HDHOMERUN_STATUS_COLOR_NEUTRAL;
00432         }
00433 
00434         if (hdhomerun_device_get_tuner_status_lock_is_bcast(status)) {
00435                 ss_yellow_min = 50;     /* -30dBmV */
00436                 ss_green_min = 75;      /* -15dBmV */
00437         } else {
00438                 ss_yellow_min = 80;     /* -12dBmV */
00439                 ss_green_min = 90;      /* -6dBmV */
00440         }
00441 
00442         if (status->signal_strength >= ss_green_min) {
00443                 return HDHOMERUN_STATUS_COLOR_GREEN;
00444         }
00445         if (status->signal_strength >= ss_yellow_min) {
00446                 return HDHOMERUN_STATUS_COLOR_YELLOW;
00447         }
00448 
00449         return HDHOMERUN_STATUS_COLOR_RED;
00450 }
00451 
00452 uint32_t hdhomerun_device_get_tuner_status_snq_color(struct hdhomerun_tuner_status_t *status)
00453 {
00454         if (status->signal_to_noise_quality >= 70) {
00455                 return HDHOMERUN_STATUS_COLOR_GREEN;
00456         }
00457         if (status->signal_to_noise_quality >= 50) {
00458                 return HDHOMERUN_STATUS_COLOR_YELLOW;
00459         }
00460 
00461         return HDHOMERUN_STATUS_COLOR_RED;
00462 }
00463 
00464 uint32_t hdhomerun_device_get_tuner_status_seq_color(struct hdhomerun_tuner_status_t *status)
00465 {
00466         if (status->symbol_error_quality >= 100) {
00467                 return HDHOMERUN_STATUS_COLOR_GREEN;
00468         }
00469 
00470         return HDHOMERUN_STATUS_COLOR_RED;
00471 }
00472 
00473 int hdhomerun_device_get_tuner_status(struct hdhomerun_device_t *hd, char **pstatus_str, struct hdhomerun_tuner_status_t *status)
00474 {
00475         if (!hd->cs) {
00476                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_tuner_status: device not set\n");
00477                 return -1;
00478         }
00479 
00480         memset(status, 0, sizeof(struct hdhomerun_tuner_status_t));
00481 
00482         char name[32];
00483         sprintf(name, "/tuner%u/status", hd->tuner);
00484 
00485         char *status_str;
00486         int ret = hdhomerun_control_get(hd->cs, name, &status_str, NULL);
00487         if (ret <= 0) {
00488                 return ret;
00489         }
00490 
00491         if (pstatus_str) {
00492                 *pstatus_str = status_str;
00493         }
00494 
00495         if (status) {
00496                 char *channel = strstr(status_str, "ch=");
00497                 if (channel) {
00498                         sscanf(channel + 3, "%31s", status->channel);
00499                 }
00500 
00501                 char *lock = strstr(status_str, "lock=");
00502                 if (lock) {
00503                         sscanf(lock + 5, "%31s", status->lock_str);
00504                 }
00505 
00506                 status->signal_strength = (unsigned int)hdhomerun_device_get_status_parse(status_str, "ss=");
00507                 status->signal_to_noise_quality = (unsigned int)hdhomerun_device_get_status_parse(status_str, "snq=");
00508                 status->symbol_error_quality = (unsigned int)hdhomerun_device_get_status_parse(status_str, "seq=");
00509                 status->raw_bits_per_second = hdhomerun_device_get_status_parse(status_str, "bps=");
00510                 status->packets_per_second = hdhomerun_device_get_status_parse(status_str, "pps=");
00511 
00512                 status->signal_present = status->signal_strength >= 45;
00513 
00514                 if (strcmp(status->lock_str, "none") != 0) {
00515                         if (status->lock_str[0] == '(') {
00516                                 status->lock_unsupported = TRUE;
00517                         } else {
00518                                 status->lock_supported = TRUE;
00519                         }
00520                 }
00521         }
00522 
00523         return 1;
00524 }
00525 
00526 int hdhomerun_device_get_oob_status(struct hdhomerun_device_t *hd, char **pstatus_str, struct hdhomerun_tuner_status_t *status)
00527 {
00528         if (!hd->cs) {
00529                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_oob_status: device not set\n");
00530                 return -1;
00531         }
00532 
00533         memset(status, 0, sizeof(struct hdhomerun_tuner_status_t));
00534 
00535         char *status_str;
00536         int ret = hdhomerun_control_get(hd->cs, "/oob/status", &status_str, NULL);
00537         if (ret <= 0) {
00538                 return ret;
00539         }
00540 
00541         if (pstatus_str) {
00542                 *pstatus_str = status_str;
00543         }
00544 
00545         if (status) {
00546                 char *channel = strstr(status_str, "ch=");
00547                 if (channel) {
00548                         sscanf(channel + 3, "%31s", status->channel);
00549                 }
00550 
00551                 char *lock = strstr(status_str, "lock=");
00552                 if (lock) {
00553                         sscanf(lock + 5, "%31s", status->lock_str);
00554                 }
00555 
00556                 status->signal_strength = (unsigned int)hdhomerun_device_get_status_parse(status_str, "ss=");
00557                 status->signal_to_noise_quality = (unsigned int)hdhomerun_device_get_status_parse(status_str, "snq=");
00558                 status->signal_present = status->signal_strength >= 45;
00559                 status->lock_supported = (strcmp(status->lock_str, "none") != 0);
00560         }
00561 
00562         return 1;
00563 }
00564 
00565 int hdhomerun_device_get_tuner_vstatus(struct hdhomerun_device_t *hd, char **pvstatus_str, struct hdhomerun_tuner_vstatus_t *vstatus)
00566 {
00567         if (!hd->cs) {
00568                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_tuner_vstatus: device not set\n");
00569                 return -1;
00570         }
00571 
00572         memset(vstatus, 0, sizeof(struct hdhomerun_tuner_vstatus_t));
00573 
00574         char var_name[32];
00575         sprintf(var_name, "/tuner%u/vstatus", hd->tuner);
00576 
00577         char *vstatus_str;
00578         int ret = hdhomerun_control_get(hd->cs, var_name, &vstatus_str, NULL);
00579         if (ret <= 0) {
00580                 return ret;
00581         }
00582 
00583         if (pvstatus_str) {
00584                 *pvstatus_str = vstatus_str;
00585         }
00586 
00587         if (vstatus) {
00588                 char *vch = strstr(vstatus_str, "vch=");
00589                 if (vch) {
00590                         sscanf(vch + 4, "%31s", vstatus->vchannel);
00591                 }
00592 
00593                 char *name = strstr(vstatus_str, "name=");
00594                 if (name) {
00595                         sscanf(name + 5, "%31s", vstatus->name);
00596                 }
00597 
00598                 char *auth = strstr(vstatus_str, "auth=");
00599                 if (auth) {
00600                         sscanf(auth + 5, "%31s", vstatus->auth);
00601                 }
00602 
00603                 char *cci = strstr(vstatus_str, "cci=");
00604                 if (cci) {
00605                         sscanf(cci + 4, "%31s", vstatus->cci);
00606                 }
00607 
00608                 char *cgms = strstr(vstatus_str, "cgms=");
00609                 if (cgms) {
00610                         sscanf(cgms + 5, "%31s", vstatus->cgms);
00611                 }
00612 
00613                 if (strncmp(vstatus->auth, "not-subscribed", 14) == 0) {
00614                         vstatus->not_subscribed = TRUE;
00615                 }
00616 
00617                 if (strncmp(vstatus->auth, "error", 5) == 0) {
00618                         vstatus->not_available = TRUE;
00619                 }
00620                 if (strncmp(vstatus->auth, "dialog", 6) == 0) {
00621                         vstatus->not_available = TRUE;
00622                 }
00623 
00624                 if (strncmp(vstatus->cci, "protected", 9) == 0) {
00625                         vstatus->copy_protected = TRUE;
00626                 }
00627                 if (strncmp(vstatus->cgms, "protected", 9) == 0) {
00628                         vstatus->copy_protected = TRUE;
00629                 }
00630         }
00631 
00632         return 1;
00633 }
00634 
00635 int hdhomerun_device_get_tuner_streaminfo(struct hdhomerun_device_t *hd, char **pstreaminfo)
00636 {
00637         if (!hd->cs) {
00638                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_tuner_streaminfo: device not set\n");
00639                 return -1;
00640         }
00641 
00642         char name[32];
00643         sprintf(name, "/tuner%u/streaminfo", hd->tuner);
00644         return hdhomerun_control_get(hd->cs, name, pstreaminfo, NULL);
00645 }
00646 
00647 int hdhomerun_device_get_tuner_channel(struct hdhomerun_device_t *hd, char **pchannel)
00648 {
00649         if (!hd->cs) {
00650                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_tuner_channel: device not set\n");
00651                 return -1;
00652         }
00653 
00654         char name[32];
00655         sprintf(name, "/tuner%u/channel", hd->tuner);
00656         return hdhomerun_control_get(hd->cs, name, pchannel, NULL);
00657 }
00658 
00659 int hdhomerun_device_get_tuner_vchannel(struct hdhomerun_device_t *hd, char **pvchannel)
00660 {
00661         if (!hd->cs) {
00662                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_tuner_vchannel: device not set\n");
00663                 return -1;
00664         }
00665 
00666         char name[32];
00667         sprintf(name, "/tuner%u/vchannel", hd->tuner);
00668         return hdhomerun_control_get(hd->cs, name, pvchannel, NULL);
00669 }
00670 
00671 int hdhomerun_device_get_tuner_channelmap(struct hdhomerun_device_t *hd, char **pchannelmap)
00672 {
00673         if (!hd->cs) {
00674                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_tuner_channelmap: device not set\n");
00675                 return -1;
00676         }
00677 
00678         char name[32];
00679         sprintf(name, "/tuner%u/channelmap", hd->tuner);
00680         return hdhomerun_control_get(hd->cs, name, pchannelmap, NULL);
00681 }
00682 
00683 int hdhomerun_device_get_tuner_filter(struct hdhomerun_device_t *hd, char **pfilter)
00684 {
00685         if (!hd->cs) {
00686                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_tuner_filter: device not set\n");
00687                 return -1;
00688         }
00689 
00690         char name[32];
00691         sprintf(name, "/tuner%u/filter", hd->tuner);
00692         return hdhomerun_control_get(hd->cs, name, pfilter, NULL);
00693 }
00694 
00695 int hdhomerun_device_get_tuner_program(struct hdhomerun_device_t *hd, char **pprogram)
00696 {
00697         if (!hd->cs) {
00698                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_tuner_program: device not set\n");
00699                 return -1;
00700         }
00701 
00702         char name[32];
00703         sprintf(name, "/tuner%u/program", hd->tuner);
00704         return hdhomerun_control_get(hd->cs, name, pprogram, NULL);
00705 }
00706 
00707 int hdhomerun_device_get_tuner_target(struct hdhomerun_device_t *hd, char **ptarget)
00708 {
00709         if (!hd->cs) {
00710                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_tuner_target: device not set\n");
00711                 return -1;
00712         }
00713 
00714         char name[32];
00715         sprintf(name, "/tuner%u/target", hd->tuner);
00716         return hdhomerun_control_get(hd->cs, name, ptarget, NULL);
00717 }
00718 
00719 static int hdhomerun_device_get_tuner_plotsample_internal(struct hdhomerun_device_t *hd, const char *name, struct hdhomerun_plotsample_t **psamples, size_t *pcount)
00720 {
00721         char *result;
00722         int ret = hdhomerun_control_get(hd->cs, name, &result, NULL);
00723         if (ret <= 0) {
00724                 return ret;
00725         }
00726 
00727         struct hdhomerun_plotsample_t *samples = (struct hdhomerun_plotsample_t *)result;
00728         *psamples = samples;
00729         size_t count = 0;
00730 
00731         while (1) {
00732                 char *ptr = strchr(result, ' ');
00733                 if (!ptr) {
00734                         break;
00735                 }
00736                 *ptr++ = 0;
00737 
00738                 unsigned long raw;
00739                 if (sscanf(result, "%lx", &raw) != 1) {
00740                         break;
00741                 }
00742 
00743                 uint16_t real = (raw >> 12) & 0x0FFF;
00744                 if (real & 0x0800) {
00745                         real |= 0xF000;
00746                 }
00747 
00748                 uint16_t imag = (raw >> 0) & 0x0FFF;
00749                 if (imag & 0x0800) {
00750                         imag |= 0xF000;
00751                 }
00752 
00753                 samples->real = (int16_t)real;
00754                 samples->imag = (int16_t)imag;
00755                 samples++;
00756                 count++;
00757 
00758                 result = ptr;
00759         }
00760 
00761         *pcount = count;
00762         return 1;
00763 }
00764 
00765 int hdhomerun_device_get_tuner_plotsample(struct hdhomerun_device_t *hd, struct hdhomerun_plotsample_t **psamples, size_t *pcount)
00766 {
00767         if (!hd->cs) {
00768                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_tuner_plotsample: device not set\n");
00769                 return -1;
00770         }
00771 
00772         char name[32];
00773         sprintf(name, "/tuner%u/plotsample", hd->tuner);
00774         return hdhomerun_device_get_tuner_plotsample_internal(hd, name, psamples, pcount);
00775 }
00776 
00777 int hdhomerun_device_get_oob_plotsample(struct hdhomerun_device_t *hd, struct hdhomerun_plotsample_t **psamples, size_t *pcount)
00778 {
00779         if (!hd->cs) {
00780                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_oob_plotsample: device not set\n");
00781                 return -1;
00782         }
00783 
00784         return hdhomerun_device_get_tuner_plotsample_internal(hd, "/oob/plotsample", psamples, pcount);
00785 }
00786 
00787 int hdhomerun_device_get_tuner_lockkey_owner(struct hdhomerun_device_t *hd, char **powner)
00788 {
00789         if (!hd->cs) {
00790                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_tuner_lockkey_owner: device not set\n");
00791                 return -1;
00792         }
00793 
00794         char name[32];
00795         sprintf(name, "/tuner%u/lockkey", hd->tuner);
00796         return hdhomerun_control_get(hd->cs, name, powner, NULL);
00797 }
00798 
00799 int hdhomerun_device_get_ir_target(struct hdhomerun_device_t *hd, char **ptarget)
00800 {
00801         if (!hd->cs) {
00802                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_ir_target: device not set\n");
00803                 return -1;
00804         }
00805 
00806         return hdhomerun_control_get(hd->cs, "/ir/target", ptarget, NULL);
00807 }
00808 
00809 int hdhomerun_device_get_lineup_location(struct hdhomerun_device_t *hd, char **plocation)
00810 {
00811         if (!hd->cs) {
00812                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_lineup_location: device not set\n");
00813                 return -1;
00814         }
00815 
00816         return hdhomerun_control_get(hd->cs, "/lineup/location", plocation, NULL);
00817 }
00818 
00819 int hdhomerun_device_get_version(struct hdhomerun_device_t *hd, char **pversion_str, uint32_t *pversion_num)
00820 {
00821         if (!hd->cs) {
00822                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_version: device not set\n");
00823                 return -1;
00824         }
00825 
00826         char *version_str;
00827         int ret = hdhomerun_control_get(hd->cs, "/sys/version", &version_str, NULL);
00828         if (ret <= 0) {
00829                 return ret;
00830         }
00831 
00832         if (pversion_str) {
00833                 *pversion_str = version_str;
00834         }
00835 
00836         if (pversion_num) {
00837                 unsigned long version_num;
00838                 if (sscanf(version_str, "%lu", &version_num) != 1) {
00839                         *pversion_num = 0;
00840                 } else {
00841                         *pversion_num = (uint32_t)version_num;
00842                 }
00843         }
00844 
00845         return 1;
00846 }
00847 
00848 int hdhomerun_device_get_supported(struct hdhomerun_device_t *hd, char *prefix, char **pstr)
00849 {
00850         if (!hd->cs) {
00851                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_tuner_channel: device not set\n");
00852                 return -1;
00853         }
00854 
00855         char *features;
00856         int ret = hdhomerun_control_get(hd->cs, "/sys/features", &features, NULL);
00857         if (ret <= 0) {
00858                 return ret;
00859         }
00860 
00861         if (!prefix) {
00862                 *pstr = features;
00863                 return 1;
00864         }
00865 
00866         char *ptr = strstr(features, prefix);
00867         if (!ptr) {
00868                 return 0;
00869         }
00870 
00871         ptr += strlen(prefix);
00872         *pstr = ptr;
00873 
00874         ptr = strchr(ptr, '\n');
00875         if (ptr) {
00876                 *ptr = 0;
00877         }
00878 
00879         return 1;
00880 }
00881 
00882 int hdhomerun_device_set_tuner_channel(struct hdhomerun_device_t *hd, const char *channel)
00883 {
00884         if (!hd->cs) {
00885                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_tuner_channel: device not set\n");
00886                 return -1;
00887         }
00888 
00889         char name[32];
00890         sprintf(name, "/tuner%u/channel", hd->tuner);
00891         return hdhomerun_control_set_with_lockkey(hd->cs, name, channel, hd->lockkey, NULL, NULL);
00892 }
00893 
00894 int hdhomerun_device_set_tuner_vchannel(struct hdhomerun_device_t *hd, const char *vchannel)
00895 {
00896         if (!hd->cs) {
00897                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_tuner_vchannel: device not set\n");
00898                 return -1;
00899         }
00900 
00901         char name[32];
00902         sprintf(name, "/tuner%u/vchannel", hd->tuner);
00903         return hdhomerun_control_set_with_lockkey(hd->cs, name, vchannel, hd->lockkey, NULL, NULL);
00904 }
00905 
00906 int hdhomerun_device_set_tuner_channelmap(struct hdhomerun_device_t *hd, const char *channelmap)
00907 {
00908         if (!hd->cs) {
00909                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_tuner_channelmap: device not set\n");
00910                 return -1;
00911         }
00912 
00913         char name[32];
00914         sprintf(name, "/tuner%u/channelmap", hd->tuner);
00915         return hdhomerun_control_set_with_lockkey(hd->cs, name, channelmap, hd->lockkey, NULL, NULL);
00916 }
00917 
00918 int hdhomerun_device_set_tuner_filter(struct hdhomerun_device_t *hd, const char *filter)
00919 {
00920         if (!hd->cs) {
00921                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_tuner_filter: device not set\n");
00922                 return -1;
00923         }
00924 
00925         char name[32];
00926         sprintf(name, "/tuner%u/filter", hd->tuner);
00927         return hdhomerun_control_set_with_lockkey(hd->cs, name, filter, hd->lockkey, NULL, NULL);
00928 }
00929 
00930 static int hdhomerun_device_set_tuner_filter_by_array_append(char **pptr, char *end, uint16_t range_begin, uint16_t range_end)
00931 {
00932         char *ptr = *pptr;
00933 
00934         size_t available = end - ptr;
00935         size_t required;
00936 
00937         if (range_begin == range_end) {
00938                 required = snprintf(ptr, available, "0x%04x ", range_begin) + 1;
00939         } else {
00940                 required = snprintf(ptr, available, "0x%04x-0x%04x ", range_begin, range_end) + 1;
00941         }
00942 
00943         if (required > available) {
00944                 return FALSE;
00945         }
00946 
00947         *pptr = strchr(ptr, 0);
00948         return TRUE;
00949 }
00950 
00951 int hdhomerun_device_set_tuner_filter_by_array(struct hdhomerun_device_t *hd, unsigned char filter_array[0x2000])
00952 {
00953         char filter[1024];
00954         char *ptr = filter;
00955         char *end = filter + sizeof(filter);
00956 
00957         uint16_t range_begin = 0xFFFF;
00958         uint16_t range_end = 0xFFFF;
00959 
00960         uint16_t i;
00961         for (i = 0; i <= 0x1FFF; i++) {
00962                 if (!filter_array[i]) {
00963                         if (range_begin == 0xFFFF) {
00964                                 continue;
00965                         }
00966                         if (!hdhomerun_device_set_tuner_filter_by_array_append(&ptr, end, range_begin, range_end)) {
00967                                 return 0;
00968                         }
00969                         range_begin = 0xFFFF;
00970                         range_end = 0xFFFF;
00971                         continue;
00972                 }
00973 
00974                 if (range_begin == 0xFFFF) {
00975                         range_begin = i;
00976                         range_end = i;
00977                         continue;
00978                 }
00979 
00980                 range_end = i;
00981         }
00982 
00983         if (range_begin != 0xFFFF) {
00984                 if (!hdhomerun_device_set_tuner_filter_by_array_append(&ptr, end, range_begin, range_end)) {
00985                         return 0;
00986                 }
00987         }
00988 
00989         /* Remove trailing space. */
00990         if (ptr > filter) {
00991                 ptr--;
00992         }
00993         *ptr = 0;
00994 
00995         return hdhomerun_device_set_tuner_filter(hd, filter);
00996 }
00997 
00998 int hdhomerun_device_set_tuner_program(struct hdhomerun_device_t *hd, const char *program)
00999 {
01000         if (!hd->cs) {
01001                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_tuner_program: device not set\n");
01002                 return -1;
01003         }
01004 
01005         char name[32];
01006         sprintf(name, "/tuner%u/program", hd->tuner);
01007         return hdhomerun_control_set_with_lockkey(hd->cs, name, program, hd->lockkey, NULL, NULL);
01008 }
01009 
01010 int hdhomerun_device_set_tuner_target(struct hdhomerun_device_t *hd, const char *target)
01011 {
01012         if (!hd->cs) {
01013                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_tuner_target: device not set\n");
01014                 return -1;
01015         }
01016 
01017         char name[32];
01018         sprintf(name, "/tuner%u/target", hd->tuner);
01019         return hdhomerun_control_set_with_lockkey(hd->cs, name, target, hd->lockkey, NULL, NULL);
01020 }
01021 
01022 static int hdhomerun_device_set_tuner_target_to_local(struct hdhomerun_device_t *hd, const char *protocol)
01023 {
01024         if (!hd->cs) {
01025                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_tuner_target_to_local: device not set\n");
01026                 return -1;
01027         }
01028         if (!hd->vs) {
01029                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_tuner_target_to_local: video not initialized\n");
01030                 return -1;
01031         }
01032 
01033         /* Set target. */
01034         char target[64];
01035         uint32_t local_ip = hdhomerun_control_get_local_addr(hd->cs);
01036         uint16_t local_port = hdhomerun_video_get_local_port(hd->vs);
01037         sprintf(target, "%s://%u.%u.%u.%u:%u",
01038                 protocol,
01039                 (unsigned int)(local_ip >> 24) & 0xFF, (unsigned int)(local_ip >> 16) & 0xFF,
01040                 (unsigned int)(local_ip >> 8) & 0xFF, (unsigned int)(local_ip >> 0) & 0xFF,
01041                 (unsigned int)local_port
01042         );
01043 
01044         return hdhomerun_device_set_tuner_target(hd, target);
01045 }
01046 
01047 int hdhomerun_device_set_ir_target(struct hdhomerun_device_t *hd, const char *target)
01048 {
01049         if (!hd->cs) {
01050                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_ir_target: device not set\n");
01051                 return -1;
01052         }
01053 
01054         return hdhomerun_control_set(hd->cs, "/ir/target", target, NULL, NULL);
01055 }
01056 
01057 int hdhomerun_device_set_lineup_location(struct hdhomerun_device_t *hd, const char *location)
01058 {
01059         if (!hd->cs) {
01060                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_lineup_location: device not set\n");
01061                 return -1;
01062         }
01063 
01064         return hdhomerun_control_set(hd->cs, "/lineup/location", location, NULL, NULL);
01065 }
01066 
01067 int hdhomerun_device_set_sys_dvbc_modulation(struct hdhomerun_device_t *hd, const char *modulation_list)
01068 {
01069         if (!hd->cs) {
01070                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_sys_dvbc_modulation: device not set\n");
01071                 return -1;
01072         }
01073 
01074         return hdhomerun_control_set(hd->cs, "/sys/dvbc_modulation", modulation_list, NULL, NULL);
01075 }
01076 
01077 int hdhomerun_device_get_var(struct hdhomerun_device_t *hd, const char *name, char **pvalue, char **perror)
01078 {
01079         if (!hd->cs) {
01080                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_var: device not set\n");
01081                 return -1;
01082         }
01083 
01084         return hdhomerun_control_get(hd->cs, name, pvalue, perror);
01085 }
01086 
01087 int hdhomerun_device_set_var(struct hdhomerun_device_t *hd, const char *name, const char *value, char **pvalue, char **perror)
01088 {
01089         if (!hd->cs) {
01090                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_set_var: device not set\n");
01091                 return -1;
01092         }
01093 
01094         return hdhomerun_control_set_with_lockkey(hd->cs, name, value, hd->lockkey, pvalue, perror);
01095 }
01096 
01097 int hdhomerun_device_tuner_lockkey_request(struct hdhomerun_device_t *hd, char **perror)
01098 {
01099         if (hd->multicast_ip != 0) {
01100                 return 1;
01101         }
01102         if (!hd->cs) {
01103                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_tuner_lockkey_request: device not set\n");
01104                 return -1;
01105         }
01106 
01107         uint32_t new_lockkey = random_get32();
01108 
01109         char name[32];
01110         sprintf(name, "/tuner%u/lockkey", hd->tuner);
01111 
01112         char new_lockkey_str[64];
01113         sprintf(new_lockkey_str, "%u", (unsigned int)new_lockkey);
01114 
01115         int ret = hdhomerun_control_set_with_lockkey(hd->cs, name, new_lockkey_str, hd->lockkey, NULL, perror);
01116         if (ret <= 0) {
01117                 hd->lockkey = 0;
01118                 return ret;
01119         }
01120 
01121         hd->lockkey = new_lockkey;
01122         return ret;
01123 }
01124 
01125 int hdhomerun_device_tuner_lockkey_release(struct hdhomerun_device_t *hd)
01126 {
01127         if (hd->multicast_ip != 0) {
01128                 return 1;
01129         }
01130         if (!hd->cs) {
01131                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_tuner_lockkey_release: device not set\n");
01132                 return -1;
01133         }
01134 
01135         if (hd->lockkey == 0) {
01136                 return 1;
01137         }
01138 
01139         char name[32];
01140         sprintf(name, "/tuner%u/lockkey", hd->tuner);
01141         int ret = hdhomerun_control_set_with_lockkey(hd->cs, name, "none", hd->lockkey, NULL, NULL);
01142 
01143         hd->lockkey = 0;
01144         return ret;
01145 }
01146 
01147 int hdhomerun_device_tuner_lockkey_force(struct hdhomerun_device_t *hd)
01148 {
01149         if (hd->multicast_ip != 0) {
01150                 return 1;
01151         }
01152         if (!hd->cs) {
01153                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_tuner_lockkey_force: device not set\n");
01154                 return -1;
01155         }
01156 
01157         char name[32];
01158         sprintf(name, "/tuner%u/lockkey", hd->tuner);
01159         int ret = hdhomerun_control_set(hd->cs, name, "force", NULL, NULL);
01160 
01161         hd->lockkey = 0;
01162         return ret;
01163 }
01164 
01165 void hdhomerun_device_tuner_lockkey_use_value(struct hdhomerun_device_t *hd, uint32_t lockkey)
01166 {
01167         if (hd->multicast_ip != 0) {
01168                 return;
01169         }
01170 
01171         hd->lockkey = lockkey;
01172 }
01173 
01174 int hdhomerun_device_wait_for_lock(struct hdhomerun_device_t *hd, struct hdhomerun_tuner_status_t *status)
01175 {
01176         /* Delay for SS reading to be valid (signal present). */
01177         msleep_minimum(250);
01178 
01179         /* Wait for up to 2.5 seconds for lock. */
01180         uint64_t timeout = getcurrenttime() + 2500;
01181         while (1) {
01182                 /* Get status to check for lock. Quality numbers will not be valid yet. */
01183                 int ret = hdhomerun_device_get_tuner_status(hd, NULL, status);
01184                 if (ret <= 0) {
01185                         return ret;
01186                 }
01187 
01188                 if (!status->signal_present) {
01189                         return 1;
01190                 }
01191                 if (status->lock_supported || status->lock_unsupported) {
01192                         return 1;
01193                 }
01194 
01195                 if (getcurrenttime() >= timeout) {
01196                         return 1;
01197                 }
01198 
01199                 msleep_approx(250);
01200         }
01201 }
01202 
01203 int hdhomerun_device_stream_start(struct hdhomerun_device_t *hd)
01204 {
01205         hdhomerun_device_get_video_sock(hd);
01206         if (!hd->vs) {
01207                 return -1;
01208         }
01209 
01210         /* Set target. */
01211         if (hd->multicast_ip != 0) {
01212                 int ret = hdhomerun_video_join_multicast_group(hd->vs, hd->multicast_ip, 0);
01213                 if (ret <= 0) {
01214                         return ret;
01215                 }
01216         } else {
01217                 int ret = hdhomerun_device_set_tuner_target_to_local(hd, HDHOMERUN_TARGET_PROTOCOL_RTP);
01218                 if (ret == 0) {
01219                         ret = hdhomerun_device_set_tuner_target_to_local(hd, HDHOMERUN_TARGET_PROTOCOL_UDP);
01220                 }
01221                 if (ret <= 0) {
01222                         return ret;
01223                 }
01224         }
01225 
01226         /* Flush video buffer. */
01227         msleep_minimum(64);
01228         hdhomerun_video_flush(hd->vs);
01229 
01230         /* Success. */
01231         return 1;
01232 }
01233 
01234 uint8_t *hdhomerun_device_stream_recv(struct hdhomerun_device_t *hd, size_t max_size, size_t *pactual_size)
01235 {
01236         if (!hd->vs) {
01237                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_stream_recv: video not initialized\n");
01238                 return NULL;
01239         }
01240 
01241         return hdhomerun_video_recv(hd->vs, max_size, pactual_size);
01242 }
01243 
01244 void hdhomerun_device_stream_flush(struct hdhomerun_device_t *hd)
01245 {
01246         if (!hd->vs) {
01247                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_stream_flush: video not initialized\n");
01248                 return;
01249         }
01250 
01251         hdhomerun_video_flush(hd->vs);
01252 }
01253 
01254 void hdhomerun_device_stream_stop(struct hdhomerun_device_t *hd)
01255 {
01256         if (!hd->vs) {
01257                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_stream_stop: video not initialized\n");
01258                 return;
01259         }
01260 
01261         if (hd->multicast_ip != 0) {
01262                 hdhomerun_video_leave_multicast_group(hd->vs);
01263         } else {
01264                 hdhomerun_device_set_tuner_target(hd, "none");
01265         }
01266 }
01267 
01268 int hdhomerun_device_channelscan_init(struct hdhomerun_device_t *hd, const char *channelmap)
01269 {
01270         if (hd->scan) {
01271                 channelscan_destroy(hd->scan);
01272         }
01273 
01274         hd->scan = channelscan_create(hd, channelmap);
01275         if (!hd->scan) {
01276                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_channelscan_init: failed to create scan object\n");
01277                 return -1;
01278         }
01279 
01280         return 1;
01281 }
01282 
01283 int hdhomerun_device_channelscan_advance(struct hdhomerun_device_t *hd, struct hdhomerun_channelscan_result_t *result)
01284 {
01285         if (!hd->scan) {
01286                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_channelscan_advance: scan not initialized\n");
01287                 return 0;
01288         }
01289 
01290         int ret = channelscan_advance(hd->scan, result);
01291         if (ret <= 0) { /* Free scan if normal finish or fatal error */
01292                 channelscan_destroy(hd->scan);
01293                 hd->scan = NULL;
01294         }
01295 
01296         return ret;
01297 }
01298 
01299 int hdhomerun_device_channelscan_detect(struct hdhomerun_device_t *hd, struct hdhomerun_channelscan_result_t *result)
01300 {
01301         if (!hd->scan) {
01302                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_channelscan_detect: scan not initialized\n");
01303                 return 0;
01304         }
01305 
01306         int ret = channelscan_detect(hd->scan, result);
01307         if (ret < 0) { /* Free scan if fatal error */
01308                 channelscan_destroy(hd->scan);
01309                 hd->scan = NULL;
01310         }
01311 
01312         return ret;
01313 }
01314 
01315 uint8_t hdhomerun_device_channelscan_get_progress(struct hdhomerun_device_t *hd)
01316 {
01317         if (!hd->scan) {
01318                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_channelscan_get_progress: scan not initialized\n");
01319                 return 0;
01320         }
01321 
01322         return channelscan_get_progress(hd->scan);
01323 }
01324 
01325 const char *hdhomerun_device_get_model_str(struct hdhomerun_device_t *hd)
01326 {
01327         if (*hd->model) {
01328                 return hd->model;
01329         }
01330 
01331         if (!hd->cs) {
01332                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_model_str: device not set\n");
01333                 return NULL;
01334         }
01335 
01336         char *model_str;
01337         int ret = hdhomerun_control_get(hd->cs, "/sys/model", &model_str, NULL);
01338         if (ret < 0) {
01339                 return NULL;
01340         }
01341         if (ret == 0) {
01342                 strncpy(hd->model, "hdhomerun_atsc", sizeof(hd->model) - 1);
01343                 hd->model[sizeof(hd->model) - 1] = 0;
01344                 return hd->model;
01345         }
01346 
01347         strncpy(hd->model, model_str, sizeof(hd->model) - 1);
01348         hd->model[sizeof(hd->model) - 1] = 0;
01349         return hd->model;
01350 }
01351 
01352 int hdhomerun_device_upgrade(struct hdhomerun_device_t *hd, FILE *upgrade_file)
01353 {
01354         if (!hd->cs) {
01355                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_upgrade: device not set\n");
01356                 return -1;
01357         }
01358 
01359         hdhomerun_control_set(hd->cs, "/tuner0/lockkey", "force", NULL, NULL);
01360         hdhomerun_control_set(hd->cs, "/tuner0/channel", "none", NULL, NULL);
01361 
01362         hdhomerun_control_set(hd->cs, "/tuner1/lockkey", "force", NULL, NULL);
01363         hdhomerun_control_set(hd->cs, "/tuner1/channel", "none", NULL, NULL);
01364 
01365         return hdhomerun_control_upgrade(hd->cs, upgrade_file);
01366 }
01367 
01368 void hdhomerun_device_debug_print_video_stats(struct hdhomerun_device_t *hd)
01369 {
01370         if (!hdhomerun_debug_enabled(hd->dbg)) {
01371                 return;
01372         }
01373 
01374         if (hd->cs) {
01375                 char name[32];
01376                 sprintf(name, "/tuner%u/debug", hd->tuner);
01377 
01378                 char *debug_str;
01379                 char *error_str;
01380                 int ret = hdhomerun_control_get(hd->cs, name, &debug_str, &error_str);
01381                 if (ret < 0) {
01382                         hdhomerun_debug_printf(hd->dbg, "video dev: communication error getting debug stats\n");
01383                         return;
01384                 }
01385 
01386                 if (error_str) {
01387                         hdhomerun_debug_printf(hd->dbg, "video dev: %s\n", error_str);
01388                 } else {
01389                         hdhomerun_debug_printf(hd->dbg, "video dev: %s\n", debug_str);
01390                 }
01391         }
01392 
01393         if (hd->vs) {
01394                 hdhomerun_video_debug_print_stats(hd->vs);
01395         }
01396 }
01397 
01398 void hdhomerun_device_get_video_stats(struct hdhomerun_device_t *hd, struct hdhomerun_video_stats_t *stats)
01399 {
01400         if (!hd->vs) {
01401                 hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_stream_flush: video not initialized\n");
01402                 memset(stats, 0, sizeof(struct hdhomerun_video_stats_t));
01403                 return;
01404         }
01405 
01406         hdhomerun_video_get_stats(hd->vs, stats);
01407 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends