Ticket #6672: 6672-v3.patch

File 6672-v3.patch, 221.2 KB (added by danielk, 11 years ago)

Fixes RTP bug, still has IP bug

  • libs/libmythtv/hdhomerun/hdhomerun_control.h

     
    33 *
    44 * Copyright © 2006 Silicondust Engineering Ltd. <www.silicondust.com>.
    55 *
    6  * This library is free software; you can redistribute it and/or
     6 * This library is free software; you can redistribute it and/or 
    77 * modify it under the terms of the GNU Lesser General Public
    88 * License as published by the Free Software Foundation; either
    9  * version 2.1 of the License, or (at your option) any later version.
     9 * version 3 of the License, or (at your option) any later version.
    1010 *
    1111 * This library is distributed in the hope that it will be useful,
    1212 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     
    1414 * Lesser General Public License for more details.
    1515 *
    1616 * You should have received a copy of the GNU Lesser General Public
    17  * License along with this library; if not, write to the Free Software
    18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     17 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
     18 *
     19 * As a special exception to the GNU Lesser General Public License,
     20 * you may link, statically or dynamically, an application with a
     21 * publicly distributed version of the Library to produce an
     22 * executable file containing portions of the Library, and
     23 * distribute that executable file under terms of your choice,
     24 * without any of the additional requirements listed in clause 4 of
     25 * the GNU Lesser General Public License.
     26 *
     27 * By "a publicly distributed version of the Library", we mean
     28 * either the unmodified Library as distributed by Silicondust, or a
     29 * modified version of the Library that is distributed under the
     30 * conditions defined in the GNU Lesser General Public License.
    1931 */
    2032#ifdef __cplusplus
    2133extern "C" {
     
    3143 *
    3244 * uint32_t device_id = 32-bit device id of device. Set to HDHOMERUN_DEVICE_ID_WILDCARD to match any device ID.
    3345 * uint32_t device_ip = IP address of device. Set to 0 to auto-detect.
     46 * struct hdhomerun_debug_t *dbg: Pointer to debug logging object. May be NULL.
    3447 *
    3548 * Returns a pointer to the newly created control socket.
    3649 *
    3750 * When no longer needed, the socket should be destroyed by calling hdhomerun_control_destroy.
    3851 */
    39 extern struct hdhomerun_control_sock_t *hdhomerun_control_create(uint32_t device_id, uint32_t device_ip);
    40 extern void hdhomerun_control_destroy(struct hdhomerun_control_sock_t *cs);
     52extern LIBTYPE struct hdhomerun_control_sock_t *hdhomerun_control_create(uint32_t device_id, uint32_t device_ip, struct hdhomerun_debug_t *dbg);
     53extern LIBTYPE void hdhomerun_control_destroy(struct hdhomerun_control_sock_t *cs);
    4154
    4255/*
     56 * Get the actual device id or ip of the device.
     57 *
     58 * Returns 0 if the device id cannot be determined.
     59 */
     60extern LIBTYPE uint32_t hdhomerun_control_get_device_id(struct hdhomerun_control_sock_t *cs);
     61extern LIBTYPE uint32_t hdhomerun_control_get_device_ip(struct hdhomerun_control_sock_t *cs);
     62extern LIBTYPE uint32_t hdhomerun_control_get_device_id_requested(struct hdhomerun_control_sock_t *cs);
     63extern LIBTYPE uint32_t hdhomerun_control_get_device_ip_requested(struct hdhomerun_control_sock_t *cs);
     64
     65extern LIBTYPE void hdhomerun_control_set_device(struct hdhomerun_control_sock_t *cs, uint32_t device_id, uint32_t device_ip);
     66
     67/*
    4368 * Get the local machine IP address used when communicating with the device.
    4469 *
    4570 * This function is useful for determining the IP address to use with set target commands.
    4671 *
    4772 * Returns 32-bit IP address with native endianness, or 0 on error.
    4873 */
    49 extern uint32_t hdhomerun_control_get_local_addr(struct hdhomerun_control_sock_t *cs);
     74extern LIBTYPE uint32_t hdhomerun_control_get_local_addr(struct hdhomerun_control_sock_t *cs);
    5075
    5176/*
     77 * Low-level communication.
     78 */
     79extern LIBTYPE int hdhomerun_control_send_recv(struct hdhomerun_control_sock_t *cs, struct hdhomerun_pkt_t *tx_pkt, struct hdhomerun_pkt_t *rx_pkt, uint16_t type);
     80
     81/*
    5282 * Get/set a control variable on the device.
    5383 *
    5484 * const char *name: The name of var to get/set (c-string). The supported vars is device/firmware dependant.
     
    6595 * Returns 0 if the operation was rejected (pvalue NULL, perror set).
    6696 * Returns -1 if a communication error occurs.
    6797 */
    68 extern int hdhomerun_control_get(struct hdhomerun_control_sock_t *cs, const char *name, char **pvalue, char **perror);
    69 extern int hdhomerun_control_set(struct hdhomerun_control_sock_t *cs, const char *name, const char *value, char **pvalue, char **perror);
     98extern LIBTYPE int hdhomerun_control_get(struct hdhomerun_control_sock_t *cs, const char *name, char **pvalue, char **perror);
     99extern LIBTYPE int hdhomerun_control_set(struct hdhomerun_control_sock_t *cs, const char *name, const char *value, char **pvalue, char **perror);
     100extern LIBTYPE int hdhomerun_control_set_with_lockkey(struct hdhomerun_control_sock_t *cs, const char *name, const char *value, uint32_t lockkey, char **pvalue, char **perror);
    70101
    71102/*
    72103 * Upload new firmware to the device.
     
    77108 * Returns 0 if the upload was rejected.
    78109 * Returns -1 if an error occurs.
    79110 */
    80 extern int hdhomerun_control_upgrade(struct hdhomerun_control_sock_t *cs, FILE *upgrade_file);
     111extern LIBTYPE int hdhomerun_control_upgrade(struct hdhomerun_control_sock_t *cs, FILE *upgrade_file);
    81112
    82113#ifdef __cplusplus
    83114}
  • libs/libmythtv/hdhomerun/hdhomerun.h

     
     1#ifndef __HDHOMERUN_INCLUDES__
     2#define __HDHOMERUN_INCLUDES__
    13/*
    2  * hdhomerun_device.h
     4 * hdhomerun.h
    35 *
    4  * Copyright © 2006 Silicondust Engineering Ltd. <www.silicondust.com>.
     6 * Copyright © 2006-2008 Silicondust Engineering Ltd. <www.silicondust.com>.
    57 *
    6  * This library is free software; you can redistribute it and/or
     8 * This library is free software; you can redistribute it and/or 
    79 * modify it under the terms of the GNU Lesser General Public
    810 * License as published by the Free Software Foundation; either
    9  * version 2.1 of the License, or (at your option) any later version.
     11 * version 3 of the License, or (at your option) any later version.
    1012 *
    1113 * This library is distributed in the hope that it will be useful,
    1214 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     
    1416 * Lesser General Public License for more details.
    1517 *
    1618 * You should have received a copy of the GNU Lesser General Public
    17  * License along with this library; if not, write to the Free Software
    18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     19 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
     20 *
     21 * As a special exception to the GNU Lesser General Public License,
     22 * you may link, statically or dynamically, an application with a
     23 * publicly distributed version of the Library to produce an
     24 * executable file containing portions of the Library, and
     25 * distribute that executable file under terms of your choice,
     26 * without any of the additional requirements listed in clause 4 of
     27 * the GNU Lesser General Public License.
     28 *
     29 * By "a publicly distributed version of the Library", we mean
     30 * either the unmodified Library as distributed by Silicondust, or a
     31 * modified version of the Library that is distributed under the
     32 * conditions defined in the GNU Lesser General Public License.
    1933 */
    2034
    2135#include "hdhomerun_os.h"
     36#include "hdhomerun_types.h"
    2237#include "hdhomerun_pkt.h"
     38#include "hdhomerun_debug.h"
    2339#include "hdhomerun_discover.h"
    2440#include "hdhomerun_control.h"
    2541#include "hdhomerun_video.h"
     42#include "hdhomerun_channels.h"
     43#include "hdhomerun_channelscan.h"
    2644#include "hdhomerun_device.h"
     45
     46#endif /* __HDHOMERUN_INCLUDES__ */
     47
  • libs/libmythtv/hdhomerun/hdhomerun_debug.c

     
     1/*
     2 * hdhomerun_debug.c
     3 *
     4 * Copyright © 2006 Silicondust Engineering Ltd. <www.silicondust.com>.
     5 *
     6 * This library is free software; you can redistribute it and/or
     7 * modify it under the terms of the GNU Lesser General Public
     8 * License as published by the Free Software Foundation; either
     9 * version 3 of the License, or (at your option) any later version.
     10 *
     11 * This library is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14 * Lesser General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU Lesser General Public
     17 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
     18 *
     19 * As a special exception to the GNU Lesser General Public License,
     20 * you may link, statically or dynamically, an application with a
     21 * publicly distributed version of the Library to produce an
     22 * executable file containing portions of the Library, and
     23 * distribute that executable file under terms of your choice,
     24 * without any of the additional requirements listed in clause 4 of
     25 * the GNU Lesser General Public License.
     26 *
     27 * By "a publicly distributed version of the Library", we mean
     28 * either the unmodified Library as distributed by Silicondust, or a
     29 * modified version of the Library that is distributed under the
     30 * conditions defined in the GNU Lesser General Public License.
     31 */
     32
     33/*
     34 * The debug logging includes optional support for connecting to the
     35 * Silicondust support server. This option should not be used without
     36 * being explicitly enabled by the user. Debug information should be
     37 * limited to information useful to diagnosing a problem.
     38 *  - Silicondust.
     39 */
     40
     41#include "hdhomerun.h"
     42
     43#if !defined(HDHOMERUN_DEBUG_HOST)
     44#define HDHOMERUN_DEBUG_HOST "debug.silicondust.com"
     45#endif
     46#if !defined(HDHOMERUN_DEBUG_PORT)
     47#define HDHOMERUN_DEBUG_PORT "8002"
     48#endif
     49
     50struct hdhomerun_debug_message_t
     51{
     52        struct hdhomerun_debug_message_t *next;
     53        struct hdhomerun_debug_message_t *prev;
     54        char buffer[2048];
     55};
     56
     57struct hdhomerun_debug_t
     58{
     59        pthread_t thread;
     60        volatile bool_t enabled;
     61        volatile bool_t terminate;
     62        char *prefix;
     63
     64        pthread_mutex_t print_lock;
     65        pthread_mutex_t queue_lock;
     66        pthread_mutex_t send_lock;
     67
     68        struct hdhomerun_debug_message_t *queue_head;
     69        struct hdhomerun_debug_message_t *queue_tail;
     70        uint32_t queue_depth;
     71
     72        uint64_t connect_delay;
     73
     74        char *file_name;
     75        FILE *file_fp;
     76        int sock;
     77};
     78
     79static THREAD_FUNC_PREFIX hdhomerun_debug_thread_execute(void *arg);
     80
     81struct hdhomerun_debug_t *hdhomerun_debug_create(void)
     82{
     83        struct hdhomerun_debug_t *dbg = (struct hdhomerun_debug_t *)calloc(1, sizeof(struct hdhomerun_debug_t));
     84        if (!dbg) {
     85                return NULL;
     86        }
     87
     88        dbg->sock = -1;
     89
     90        pthread_mutex_init(&dbg->print_lock, NULL);
     91        pthread_mutex_init(&dbg->queue_lock, NULL);
     92        pthread_mutex_init(&dbg->send_lock, NULL);
     93
     94        if (pthread_create(&dbg->thread, NULL, &hdhomerun_debug_thread_execute, dbg) != 0) {
     95                free(dbg);
     96                return NULL;
     97        }
     98
     99        return dbg;
     100}
     101
     102/* Send lock held by caller */
     103static void hdhomerun_debug_close_file(struct hdhomerun_debug_t *dbg)
     104{
     105        if (!dbg->file_fp) {
     106                return;
     107        }
     108
     109        fclose(dbg->file_fp);
     110        dbg->file_fp = NULL;
     111}
     112
     113/* Send lock held by caller */
     114static void hdhomerun_debug_close_sock(struct hdhomerun_debug_t *dbg)
     115{
     116        if (dbg->sock == -1) {
     117                return;
     118        }
     119
     120        close(dbg->sock);
     121        dbg->sock = -1;
     122}
     123
     124void hdhomerun_debug_destroy(struct hdhomerun_debug_t *dbg)
     125{
     126        dbg->terminate = TRUE;
     127        pthread_join(dbg->thread, NULL);
     128
     129        hdhomerun_debug_close_file(dbg);
     130        hdhomerun_debug_close_sock(dbg);
     131
     132        if (dbg->prefix) {
     133                free(dbg->prefix);
     134        }
     135
     136        free(dbg);
     137}
     138
     139void hdhomerun_debug_set_prefix(struct hdhomerun_debug_t *dbg, const char *prefix)
     140{
     141        pthread_mutex_lock(&dbg->print_lock);
     142
     143        if (dbg->prefix) {
     144                free(dbg->prefix);
     145                dbg->prefix = NULL;
     146        }
     147
     148        if (prefix) {
     149                dbg->prefix = strdup(prefix);
     150        }
     151
     152        pthread_mutex_unlock(&dbg->print_lock);
     153}
     154
     155void hdhomerun_debug_set_filename(struct hdhomerun_debug_t *dbg, const char *filename)
     156{
     157        pthread_mutex_lock(&dbg->send_lock);
     158
     159        if (!filename && !dbg->file_name) {
     160                pthread_mutex_unlock(&dbg->send_lock);
     161                return;
     162        }
     163        if (filename && dbg->file_name) {
     164                if (strcmp(filename, dbg->file_name) == 0) {
     165                        pthread_mutex_unlock(&dbg->send_lock);
     166                        return;
     167                }
     168        }
     169
     170        hdhomerun_debug_close_file(dbg);
     171        hdhomerun_debug_close_sock(dbg);
     172
     173        if (dbg->file_name) {
     174                free(dbg->file_name);
     175                dbg->file_name = NULL;
     176        }
     177        if (filename) {
     178                dbg->file_name = strdup(filename);
     179        }
     180
     181        pthread_mutex_unlock(&dbg->send_lock);
     182}
     183
     184void hdhomerun_debug_enable(struct hdhomerun_debug_t *dbg)
     185{
     186        pthread_mutex_lock(&dbg->send_lock);
     187
     188        dbg->enabled = TRUE;
     189
     190        pthread_mutex_unlock(&dbg->send_lock);
     191}
     192
     193void hdhomerun_debug_disable(struct hdhomerun_debug_t *dbg)
     194{
     195        pthread_mutex_lock(&dbg->send_lock);
     196
     197        dbg->enabled = FALSE;
     198        hdhomerun_debug_close_file(dbg);
     199        hdhomerun_debug_close_sock(dbg);
     200
     201        pthread_mutex_unlock(&dbg->send_lock);
     202}
     203
     204bool_t hdhomerun_debug_enabled(struct hdhomerun_debug_t *dbg)
     205{
     206        if (!dbg) {
     207                return FALSE;
     208        }
     209
     210        return dbg->enabled;
     211}
     212
     213void hdhomerun_debug_flush(struct hdhomerun_debug_t *dbg, uint64_t timeout)
     214{
     215        timeout = getcurrenttime() + timeout;
     216
     217        while (getcurrenttime() < timeout) {
     218                pthread_mutex_lock(&dbg->queue_lock);
     219                struct hdhomerun_debug_message_t *message = dbg->queue_tail;
     220                pthread_mutex_unlock(&dbg->queue_lock);
     221
     222                if (!message) {
     223                        return;
     224                }
     225
     226                msleep(10);
     227        }
     228}
     229
     230void hdhomerun_debug_printf(struct hdhomerun_debug_t *dbg, const char *fmt, ...)
     231{
     232        va_list args;
     233        va_start(args, fmt);
     234        hdhomerun_debug_vprintf(dbg, fmt, args);
     235        va_end(args);
     236}
     237
     238void hdhomerun_debug_vprintf(struct hdhomerun_debug_t *dbg, const char *fmt, va_list args)
     239{
     240        if (!dbg) {
     241                return;
     242        }
     243        if (!dbg->enabled) {
     244                return;
     245        }
     246
     247        struct hdhomerun_debug_message_t *message = (struct hdhomerun_debug_message_t *)malloc(sizeof(struct hdhomerun_debug_message_t));
     248        if (!message) {
     249                return;
     250        }
     251
     252        char *ptr = message->buffer;
     253        char *end = message->buffer + sizeof(message->buffer) - 2;
     254        *end = 0;
     255
     256        /*
     257         * Timestamp.
     258         */
     259        time_t current_time = time(NULL);
     260        ptr += strftime(ptr, end - ptr, "%Y%m%d-%H:%M:%S ", localtime(&current_time));
     261        if (ptr > end) {
     262                ptr = end;
     263        }
     264
     265        /*
     266         * Debug prefix.
     267         */
     268        pthread_mutex_lock(&dbg->print_lock);
     269
     270        if (dbg->prefix) {
     271                int len = snprintf(ptr, end - ptr, "%s ", dbg->prefix);
     272                len = (len <= 0) ? 0 : len;
     273                ptr += len;
     274                if (ptr > end) {
     275                        ptr = end;
     276                }
     277        }
     278
     279        pthread_mutex_unlock(&dbg->print_lock);
     280
     281        /*
     282         * Message text.
     283         */
     284        int len = vsnprintf(ptr, end - ptr, fmt, args);
     285        len = (len < 0) ? 0 : len; /* len does not include null */
     286        ptr += len;
     287        if (ptr > end) {
     288                ptr = end;
     289        }
     290
     291        /*
     292         * Force newline.
     293         */
     294        if ((ptr[-1] != '\n') && (ptr + 1 <= end)) {
     295                *ptr++ = '\n';
     296        }
     297
     298        /*
     299         * Force NULL.
     300         */
     301        if (ptr + 1 > end) {
     302                ptr = end - 1;
     303        }
     304        *ptr++ = 0;
     305
     306        /*
     307         * Enqueue.
     308         */
     309        pthread_mutex_lock(&dbg->queue_lock);
     310
     311        message->prev = NULL;
     312        message->next = dbg->queue_head;
     313        dbg->queue_head = message;
     314        if (message->next) {
     315                message->next->prev = message;
     316        } else {
     317                dbg->queue_tail = message;
     318        }
     319        dbg->queue_depth++;
     320
     321        pthread_mutex_unlock(&dbg->queue_lock);
     322}
     323
     324/* Send lock held by caller */
     325static bool_t hdhomerun_debug_output_message_file(struct hdhomerun_debug_t *dbg, struct hdhomerun_debug_message_t *message)
     326{
     327        if (!dbg->file_fp) {
     328                uint64_t current_time = getcurrenttime();
     329                if (current_time < dbg->connect_delay) {
     330                        return FALSE;
     331                }
     332                dbg->connect_delay = current_time + 30*1000;
     333
     334                dbg->file_fp = fopen(dbg->file_name, "a");
     335                if (!dbg->file_fp) {
     336                        return FALSE;
     337                }
     338        }
     339
     340        fprintf(dbg->file_fp, "%s", message->buffer);
     341        fflush(dbg->file_fp);
     342
     343        return TRUE;
     344}
     345
     346/* Send lock held by caller */
     347#if defined(__CYGWIN__)
     348static bool_t hdhomerun_debug_output_message_sock(struct hdhomerun_debug_t *dbg, struct hdhomerun_debug_message_t *message)
     349{
     350        return TRUE;
     351}
     352#else
     353static bool_t hdhomerun_debug_output_message_sock(struct hdhomerun_debug_t *dbg, struct hdhomerun_debug_message_t *message)
     354{
     355        if (dbg->sock == -1) {
     356                uint64_t current_time = getcurrenttime();
     357                if (current_time < dbg->connect_delay) {
     358                        return FALSE;
     359                }
     360                dbg->connect_delay = current_time + 30*1000;
     361
     362                dbg->sock = (int)socket(AF_INET, SOCK_STREAM, 0);
     363                if (dbg->sock == -1) {
     364                        return FALSE;
     365                }
     366
     367                struct addrinfo hints;
     368                memset(&hints, 0, sizeof(hints));
     369                hints.ai_family = AF_INET;
     370                hints.ai_socktype = SOCK_STREAM;
     371                hints.ai_protocol = IPPROTO_TCP;
     372
     373                struct addrinfo *sock_info;
     374                if (getaddrinfo(HDHOMERUN_DEBUG_HOST, HDHOMERUN_DEBUG_PORT, &hints, &sock_info) != 0) {
     375                        hdhomerun_debug_close_sock(dbg);
     376                        return FALSE;
     377                }
     378                if (connect(dbg->sock, sock_info->ai_addr, (int)sock_info->ai_addrlen) != 0) {
     379                        freeaddrinfo(sock_info);
     380                        hdhomerun_debug_close_sock(dbg);
     381                        return FALSE;
     382                }
     383                freeaddrinfo(sock_info);
     384        }
     385
     386        size_t length = strlen(message->buffer);
     387        if (send(dbg->sock, (char *)message->buffer, (int)length, 0) != length) {
     388                hdhomerun_debug_close_sock(dbg);
     389                return FALSE;
     390        }
     391
     392        return TRUE;
     393}
     394#endif
     395
     396static bool_t hdhomerun_debug_output_message(struct hdhomerun_debug_t *dbg, struct hdhomerun_debug_message_t *message)
     397{
     398        pthread_mutex_lock(&dbg->send_lock);
     399
     400        if (!dbg->enabled) {
     401                pthread_mutex_unlock(&dbg->send_lock);
     402                return TRUE;
     403        }
     404
     405        bool_t ret;
     406        if (dbg->file_name) {
     407                ret = hdhomerun_debug_output_message_file(dbg, message);
     408        } else {
     409                ret = hdhomerun_debug_output_message_sock(dbg, message);
     410        }
     411
     412        pthread_mutex_unlock(&dbg->send_lock);
     413        return ret;
     414}
     415
     416static void hdhomerun_debug_pop_and_free_message(struct hdhomerun_debug_t *dbg)
     417{
     418        pthread_mutex_lock(&dbg->queue_lock);
     419
     420        struct hdhomerun_debug_message_t *message = dbg->queue_tail;
     421        dbg->queue_tail = message->prev;
     422        if (message->prev) {
     423                message->prev->next = NULL;
     424        } else {
     425                dbg->queue_head = NULL;
     426        }
     427        dbg->queue_depth--;
     428
     429        pthread_mutex_unlock(&dbg->queue_lock);
     430
     431        free(message);
     432}
     433
     434static THREAD_FUNC_PREFIX hdhomerun_debug_thread_execute(void *arg)
     435{
     436        struct hdhomerun_debug_t *dbg = (struct hdhomerun_debug_t *)arg;
     437
     438        while (!dbg->terminate) {
     439
     440                pthread_mutex_lock(&dbg->queue_lock);
     441                struct hdhomerun_debug_message_t *message = dbg->queue_tail;
     442                uint32_t queue_depth = dbg->queue_depth;
     443                pthread_mutex_unlock(&dbg->queue_lock);
     444
     445                if (!message) {
     446                        msleep(250);
     447                        continue;
     448                }
     449
     450                if (queue_depth > 256) {
     451                        hdhomerun_debug_pop_and_free_message(dbg);
     452                        continue;
     453                }
     454
     455                if (!hdhomerun_debug_output_message(dbg, message)) {
     456                        msleep(250);
     457                        continue;
     458                }
     459
     460                hdhomerun_debug_pop_and_free_message(dbg);
     461        }
     462
     463        return 0;
     464}
  • libs/libmythtv/hdhomerun/hdhomerun_os.h

     
    11/*
    22 * hdhomerun_os.h
    33 *
    4  * Copyright © 2006 Silicondust Engineering Ltd. <www.silicondust.com>.
     4 * Copyright © 2006-2008 Silicondust Engineering Ltd. <www.silicondust.com>.
    55 *
    6  * This library is free software; you can redistribute it and/or
     6 * This library is free software; you can redistribute it and/or 
    77 * modify it under the terms of the GNU Lesser General Public
    88 * License as published by the Free Software Foundation; either
    9  * version 2.1 of the License, or (at your option) any later version.
     9 * version 3 of the License, or (at your option) any later version.
    1010 *
    1111 * This library is distributed in the hope that it will be useful,
    1212 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     
    1414 * Lesser General Public License for more details.
    1515 *
    1616 * You should have received a copy of the GNU Lesser General Public
    17  * License along with this library; if not, write to the Free Software
    18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     17 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
     18 *
     19 * As a special exception to the GNU Lesser General Public License,
     20 * you may link, statically or dynamically, an application with a
     21 * publicly distributed version of the Library to produce an
     22 * executable file containing portions of the Library, and
     23 * distribute that executable file under terms of your choice,
     24 * without any of the additional requirements listed in clause 4 of
     25 * the GNU Lesser General Public License.
     26 *
     27 * By "a publicly distributed version of the Library", we mean
     28 * either the unmodified Library as distributed by Silicondust, or a
     29 * modified version of the Library that is distributed under the
     30 * conditions defined in the GNU Lesser General Public License.
    1931 */
    2032
    21 #include <stdlib.h>
    22 #include <stdio.h>
    23 #include <string.h>
    24 
    25 #if defined(WIN32)
     33#if defined(_WIN32) || defined(_WIN64)
    2634#define __WINDOWS__
    2735#endif
    2836
    2937#if defined(__WINDOWS__)
    30 #include <windows.h>
    31 #include <sys/types.h>
    32 #include <sys/timeb.h>
     38#include "hdhomerun_os_windows.h"
    3339#else
    34 #include <unistd.h>
    35 #include <errno.h>
    36 #include <sys/types.h>
    37 #include <sys/socket.h>
    38 #include <netinet/in.h>
    39 #include <arpa/inet.h>
    40 #include <netdb.h>
    41 #include <sys/time.h>
    42 #include <sys/timeb.h>
    43 #include <fcntl.h>
     40#include "hdhomerun_os_posix.h"
    4441#endif
    4542
    46 #include <pthread.h>
    47 
    4843#if !defined(TRUE)
    4944#define TRUE 1
    5045#endif
     46
    5147#if !defined(FALSE)
    5248#define FALSE 0
    5349#endif
    54 
    55 #if defined(__WINDOWS__)
    56 
    57 typedef int bool_t;
    58 typedef unsigned __int8 uint8_t;
    59 typedef unsigned __int16 uint16_t;
    60 typedef unsigned __int32 uint32_t;
    61 typedef unsigned __int64 uint64_t;
    62 
    63 #define socklen_t int
    64 #define close closesocket
    65 #define sock_getlasterror WSAGetLastError()
    66 #define sock_getlasterror_socktimeout (WSAGetLastError() == WSAETIMEDOUT)
    67 #define atoll _atoi64
    68 #define strcasecmp _stricmp
    69 #define fseeko _fseeki64
    70 #define ftello _ftelli64
    71 #define usleep(us) Sleep((us)/1000)
    72 #define sleep(sec) Sleep((sec)*1000)
    73 
    74 static inline uint64_t getcurrenttime(void)
    75 {
    76         struct timeb tb;
    77         ftime(&tb);
    78         return ((uint64_t)tb.time * 1000) + tb.millitm;
    79 }
    80 
    81 static inline int setsocktimeout(int s, int level, int optname, uint64_t timeout)
    82 {
    83         int t = (int)timeout;
    84         return setsockopt(s, level, optname, (char *)&t, sizeof(t));
    85 }
    86 
    87 #else
    88 
    89 typedef int bool_t;
    90 
    91 #define sock_getlasterror errno
    92 #define sock_getlasterror_socktimeout (errno == EAGAIN)
    93 
    94 static inline uint64_t getcurrenttime(void)
    95 {
    96         struct timeval t;
    97         gettimeofday(&t, NULL);
    98         return ((uint64_t)t.tv_sec * 1000) + (t.tv_usec / 1000);
    99 }
    100 
    101 static inline int setsocktimeout(int s, int level, int optname, uint64_t timeout)
    102 {
    103         struct timeval t;
    104         t.tv_sec = timeout / 1000;
    105         t.tv_usec = (timeout % 1000) * 1000;
    106         return setsockopt(s, level, optname, (char *)&t, sizeof(t));
    107 }
    108 
    109 #endif
    110 
  • libs/libmythtv/hdhomerun/hdhomerun_debug.h

     
     1/*
     2 * hdhomerun_debug.h
     3 *
     4 * Copyright © 2006 Silicondust Engineering Ltd. <www.silicondust.com>.
     5 *
     6 * This library is free software; you can redistribute it and/or
     7 * modify it under the terms of the GNU Lesser General Public
     8 * License as published by the Free Software Foundation; either
     9 * version 3 of the License, or (at your option) any later version.
     10 *
     11 * This library is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14 * Lesser General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU Lesser General Public
     17 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
     18 *
     19 * As a special exception to the GNU Lesser General Public License,
     20 * you may link, statically or dynamically, an application with a
     21 * publicly distributed version of the Library to produce an
     22 * executable file containing portions of the Library, and
     23 * distribute that executable file under terms of your choice,
     24 * without any of the additional requirements listed in clause 4 of
     25 * the GNU Lesser General Public License.
     26 *
     27 * By "a publicly distributed version of the Library", we mean
     28 * either the unmodified Library as distributed by Silicondust, or a
     29 * modified version of the Library that is distributed under the
     30 * conditions defined in the GNU Lesser General Public License.
     31 */
     32
     33/*
     34 * The debug logging includes optional support for connecting to the
     35 * Silicondust support server. This option should not be used without
     36 * being explicitly enabled by the user. Debug information should be
     37 * limited to information useful to diagnosing a problem.
     38 *  - Silicondust.
     39 */
     40
     41#ifdef __cplusplus
     42extern "C" {
     43#endif
     44
     45struct hdhomerun_debug_t;
     46
     47extern LIBTYPE struct hdhomerun_debug_t *hdhomerun_debug_create(void);
     48extern LIBTYPE void hdhomerun_debug_destroy(struct hdhomerun_debug_t *dbg);
     49
     50extern LIBTYPE void hdhomerun_debug_set_prefix(struct hdhomerun_debug_t *dbg, const char *prefix);
     51extern LIBTYPE void hdhomerun_debug_set_filename(struct hdhomerun_debug_t *dbg, const char *filename);
     52extern LIBTYPE void hdhomerun_debug_enable(struct hdhomerun_debug_t *dbg);
     53extern LIBTYPE void hdhomerun_debug_disable(struct hdhomerun_debug_t *dbg);
     54extern LIBTYPE bool_t hdhomerun_debug_enabled(struct hdhomerun_debug_t *dbg);
     55
     56extern LIBTYPE void hdhomerun_debug_flush(struct hdhomerun_debug_t *dbg, uint64_t timeout);
     57
     58extern LIBTYPE void hdhomerun_debug_printf(struct hdhomerun_debug_t *dbg, const char *fmt, ...);
     59extern LIBTYPE void hdhomerun_debug_vprintf(struct hdhomerun_debug_t *dbg, const char *fmt, va_list args);
     60
     61#ifdef __cplusplus
     62}
     63#endif
  • libs/libmythtv/hdhomerun/hdhomerun_channels.c

     
     1/*
     2 * hdhomerun_channels.c
     3 *
     4 * Copyright © 2007-2008 Silicondust Engineering Ltd. <www.silicondust.com>.
     5 *
     6 * This library is free software; you can redistribute it and/or
     7 * modify it under the terms of the GNU Lesser General Public
     8 * License as published by the Free Software Foundation; either
     9 * version 3 of the License, or (at your option) any later version.
     10 *
     11 * This library is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14 * Lesser General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU Lesser General Public
     17 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
     18 *
     19 * As a special exception to the GNU Lesser General Public License,
     20 * you may link, statically or dynamically, an application with a
     21 * publicly distributed version of the Library to produce an
     22 * executable file containing portions of the Library, and
     23 * distribute that executable file under terms of your choice,
     24 * without any of the additional requirements listed in clause 4 of
     25 * the GNU Lesser General Public License.
     26 *
     27 * By "a publicly distributed version of the Library", we mean
     28 * either the unmodified Library as distributed by Silicondust, or a
     29 * modified version of the Library that is distributed under the
     30 * conditions defined in the GNU Lesser General Public License.
     31 */
     32
     33#include "hdhomerun.h"
     34
     35#define FREQUENCY_RESOLUTION 62500
     36
     37struct hdhomerun_channel_entry_t {
     38        struct hdhomerun_channel_entry_t *next;
     39        struct hdhomerun_channel_entry_t *prev;
     40        uint32_t frequency;
     41        uint8_t channel_number;
     42        char name[16];
     43};
     44
     45struct hdhomerun_channel_list_t {
     46        struct hdhomerun_channel_entry_t *head;
     47        struct hdhomerun_channel_entry_t *tail;
     48};
     49
     50struct hdhomerun_channelmap_range_t {
     51        uint8_t channel_range_start;
     52        uint8_t channel_range_end;
     53        uint32_t frequency;
     54        uint32_t spacing;
     55};
     56
     57struct hdhomerun_channelmap_record_t {
     58        const char *channelmap_prefix;
     59        const char *channelmap;
     60        const struct hdhomerun_channelmap_range_t *range_list;
     61        const char *channelmap_scan_group;
     62        const char *countrycodes;
     63};
     64
     65/* AU antenna channels. Channels {0, 1, 2, 6, 7, 8, 9, 9A} are numbered {2, 3, 4, 5, 6, 7, 8, 9} by the HDHomeRun. */
     66static const struct hdhomerun_channelmap_range_t hdhomerun_channelmap_range_au_bcast[] = {
     67        {  2,   2,  48500000, 7000000},
     68        {  3,   4,  59500000, 7000000},
     69        {  5,  12, 177500000, 7000000},
     70        { 28,  69, 529500000, 7000000},
     71        {  0,   0,         0,       0}
     72};
     73
     74/* AU cable channels. TBD. */
     75static const struct hdhomerun_channelmap_range_t hdhomerun_channelmap_range_au_cable[] = {
     76        {  0,   0,         0,       0}
     77};
     78
     79/* EU antenna channels. */
     80static const struct hdhomerun_channelmap_range_t hdhomerun_channelmap_range_eu_bcast[] = {
     81        {  2,   4,  50500000, 7000000},
     82        {  5,  12, 177500000, 7000000},
     83        { 21,  69, 474000000, 8000000},
     84        {  0,   0,         0,       0}
     85};
     86
     87/* EU cable channels. Channels do not have simple numbers - the HDHomeRun uses its own numbering scheme (subject to change). */
     88static const struct hdhomerun_channelmap_range_t hdhomerun_channelmap_range_eu_cable[] = {
     89        {  6,   7, 113000000, 8000000},
     90        {  9, 100, 138000000, 8000000},
     91        {  0,   0,         0,       0}
     92};
     93
     94/* US antenna channels. */
     95static const struct hdhomerun_channelmap_range_t hdhomerun_channelmap_range_us_bcast[] = {
     96        {  2,   4,  57000000, 6000000},
     97        {  5,   6,  79000000, 6000000},
     98        {  7,  13, 177000000, 6000000},
     99        { 14,  69, 473000000, 6000000},
     100        {  0,   0,         0,       0}
     101};
     102
     103/* US cable channels. */
     104static const struct hdhomerun_channelmap_range_t hdhomerun_channelmap_range_us_cable[] = {
     105        {  2,   4,  57000000, 6000000},
     106        {  5,   6,  79000000, 6000000},
     107        {  7,  13, 177000000, 6000000},
     108        { 14,  22, 123000000, 6000000},
     109        { 23,  94, 219000000, 6000000},
     110        { 95,  99,  93000000, 6000000},
     111        {100, 135, 651000000, 6000000},
     112        {  0,   0,         0,       0}
     113};
     114
     115/* US cable channels (HRC). */
     116static const struct hdhomerun_channelmap_range_t hdhomerun_channelmap_range_us_hrc[] = {
     117        {  2,   4,  55752700, 6000300},
     118        {  5,   6,  79753900, 6000300},
     119        {  7,  13, 175758700, 6000300},
     120        { 14,  22, 121756000, 6000300},
     121        { 23,  94, 217760800, 6000300},
     122        { 95,  99,  91754500, 6000300},
     123        {100, 135, 649782400, 6000300},
     124        {  0,   0,         0,       0}
     125};
     126
     127/* US cable channels (IRC). */
     128static const struct hdhomerun_channelmap_range_t hdhomerun_channelmap_range_us_irc[] = {
     129        {  2,   4,  57012500, 6000000},
     130        {  5,   6,  81012500, 6000000},
     131        {  7,  13, 177012500, 6000000},
     132        { 14,  22, 123012500, 6000000},
     133        { 23,  41, 219012500, 6000000},
     134        { 42,  42, 333025000, 6000000},
     135        { 43,  94, 339012500, 6000000},
     136        { 95,  97,  93012500, 6000000},
     137        { 98,  99, 111025000, 6000000},
     138        {100, 135, 651012500, 6000000},
     139        {  0,   0,         0,       0}
     140};
     141
     142static const struct hdhomerun_channelmap_record_t hdhomerun_channelmap_table[] = {
     143        {"au", "au-bcast", hdhomerun_channelmap_range_au_bcast, "au-bcast",               "AU"},
     144        {"au", "au-cable", hdhomerun_channelmap_range_au_cable, "au-cable",               "AU"},
     145        {"eu", "eu-bcast", hdhomerun_channelmap_range_eu_bcast, "eu-bcast",               "EU"},
     146        {"eu", "eu-cable", hdhomerun_channelmap_range_eu_cable, "eu-cable",               "EU"},
     147        {"tw", "tw-bcast", hdhomerun_channelmap_range_us_bcast, "tw-bcast",               "TW"},
     148        {"tw", "tw-cable", hdhomerun_channelmap_range_us_cable, "tw-cable",               "TW"},
     149        {"us", "us-bcast", hdhomerun_channelmap_range_us_bcast, "us-bcast",               "CA US"},
     150        {"us", "us-cable", hdhomerun_channelmap_range_us_cable, "us-cable us-hrc us-irc", "CA US"},
     151        {"us", "us-hrc",   hdhomerun_channelmap_range_us_hrc  , "us-cable us-hrc us-irc", "CA US"},
     152        {"us", "us-irc",   hdhomerun_channelmap_range_us_irc,   "us-cable us-hrc us-irc", "CA US"},
     153        {NULL, NULL,       NULL,                                NULL,                     NULL}
     154};
     155
     156const char *hdhomerun_channelmap_convert_countrycode_to_channelmap_prefix(const char *countrycode)
     157{
     158        const struct hdhomerun_channelmap_record_t *record = hdhomerun_channelmap_table;
     159        while (record->channelmap) {
     160                if (strstr(record->countrycodes, countrycode)) {
     161                        return record->channelmap_prefix;
     162                }
     163                record++;
     164        }
     165
     166        return "eu";
     167}
     168
     169const char *hdhomerun_channelmap_get_channelmap_scan_group(const char *channelmap)
     170{
     171        const struct hdhomerun_channelmap_record_t *record = hdhomerun_channelmap_table;
     172        while (record->channelmap) {
     173                if (strstr(channelmap, record->channelmap)) {
     174                        return record->channelmap_scan_group;
     175                }
     176                record++;
     177        }
     178
     179        return NULL;
     180}
     181
     182uint8_t hdhomerun_channel_entry_channel_number(struct hdhomerun_channel_entry_t *entry)
     183{
     184        return entry->channel_number;
     185}
     186
     187uint32_t hdhomerun_channel_entry_frequency(struct hdhomerun_channel_entry_t *entry)
     188{
     189        return entry->frequency;
     190}
     191
     192const char *hdhomerun_channel_entry_name(struct hdhomerun_channel_entry_t *entry)
     193{
     194        return entry->name;
     195}
     196
     197struct hdhomerun_channel_entry_t *hdhomerun_channel_list_first(struct hdhomerun_channel_list_t *channel_list)
     198{
     199        return channel_list->head;
     200}
     201
     202struct hdhomerun_channel_entry_t *hdhomerun_channel_list_last(struct hdhomerun_channel_list_t *channel_list)
     203{
     204        return channel_list->tail;
     205}
     206
     207struct hdhomerun_channel_entry_t *hdhomerun_channel_list_next(struct hdhomerun_channel_list_t *channel_list, struct hdhomerun_channel_entry_t *entry)
     208{
     209        return entry->next;
     210}
     211
     212struct hdhomerun_channel_entry_t *hdhomerun_channel_list_prev(struct hdhomerun_channel_list_t *channel_list, struct hdhomerun_channel_entry_t *entry)
     213{
     214        return entry->prev;
     215}
     216
     217uint32_t hdhomerun_channel_list_total_count(struct hdhomerun_channel_list_t *channel_list)
     218{
     219        uint32_t count = 0;
     220
     221        struct hdhomerun_channel_entry_t *entry = hdhomerun_channel_list_first(channel_list);
     222        while (entry) {
     223                count++;
     224                entry = hdhomerun_channel_list_next(channel_list, entry);
     225        }
     226
     227        return count;
     228}
     229
     230uint32_t hdhomerun_channel_list_frequency_count(struct hdhomerun_channel_list_t *channel_list)
     231{
     232        uint32_t count = 0;
     233        uint32_t last_frequency = 0;
     234
     235        struct hdhomerun_channel_entry_t *entry = hdhomerun_channel_list_first(channel_list);
     236        while (entry) {
     237                if (entry->frequency != last_frequency) {
     238                        last_frequency = entry->frequency;
     239                        count++;
     240                }
     241
     242                entry = hdhomerun_channel_list_next(channel_list, entry);
     243        }
     244
     245        return count;
     246}
     247
     248uint32_t hdhomerun_channel_frequency_truncate(uint32_t frequency)
     249{
     250        return (frequency / FREQUENCY_RESOLUTION) * FREQUENCY_RESOLUTION;
     251}
     252
     253uint32_t hdhomerun_channel_number_to_frequency(struct hdhomerun_channel_list_t *channel_list, uint8_t channel_number)
     254{
     255        struct hdhomerun_channel_entry_t *entry = hdhomerun_channel_list_first(channel_list);
     256        while (entry) {
     257                if (entry->channel_number == channel_number) {
     258                        return entry->frequency;
     259                }
     260
     261                entry = hdhomerun_channel_list_next(channel_list, entry);
     262        }
     263
     264        return 0;
     265}
     266
     267uint8_t hdhomerun_channel_frequency_to_number(struct hdhomerun_channel_list_t *channel_list, uint32_t frequency)
     268{
     269        frequency = hdhomerun_channel_frequency_truncate(frequency);
     270
     271        struct hdhomerun_channel_entry_t *entry = hdhomerun_channel_list_first(channel_list);
     272        while (entry) {
     273                if (entry->frequency == frequency) {
     274                        return entry->channel_number;
     275                }
     276                if (entry->frequency > frequency) {
     277                        return 0;
     278                }
     279
     280                entry = hdhomerun_channel_list_next(channel_list, entry);
     281        }
     282
     283        return 0;
     284}
     285
     286static void hdhomerun_channel_list_build_insert(struct hdhomerun_channel_list_t *channel_list, struct hdhomerun_channel_entry_t *entry)
     287{
     288        struct hdhomerun_channel_entry_t *prev = NULL;
     289        struct hdhomerun_channel_entry_t *next = channel_list->head;
     290
     291        while (next) {
     292                if (next->frequency > entry->frequency) {
     293                        break;
     294                }
     295
     296                prev = next;
     297                next = next->next;
     298        }
     299
     300        entry->prev = prev;
     301        entry->next = next;
     302
     303        if (prev) {
     304                prev->next = entry;
     305        } else {
     306                channel_list->head = entry;
     307        }
     308
     309        if (next) {
     310                next->prev = entry;
     311        } else {
     312                channel_list->tail = entry;
     313        }
     314}
     315
     316static void hdhomerun_channel_list_build_range(struct hdhomerun_channel_list_t *channel_list, const char *channelmap, const struct hdhomerun_channelmap_range_t *range)
     317{
     318        uint8_t channel_number;
     319        for (channel_number = range->channel_range_start; channel_number <= range->channel_range_end; channel_number++) {
     320                struct hdhomerun_channel_entry_t *entry = (struct hdhomerun_channel_entry_t *)calloc(1, sizeof(struct hdhomerun_channel_entry_t));
     321                if (!entry) {
     322                        return;
     323                }
     324
     325                entry->channel_number = channel_number;
     326                entry->frequency = range->frequency + ((uint32_t)(channel_number - range->channel_range_start) * range->spacing);
     327                entry->frequency = hdhomerun_channel_frequency_truncate(entry->frequency);
     328                sprintf(entry->name, "%s:%u", channelmap, entry->channel_number);
     329
     330                hdhomerun_channel_list_build_insert(channel_list, entry);
     331        }
     332}
     333
     334static void hdhomerun_channel_list_build_ranges(struct hdhomerun_channel_list_t *channel_list, const struct hdhomerun_channelmap_record_t *record)
     335{
     336        const struct hdhomerun_channelmap_range_t *range = record->range_list;
     337        while (range->frequency) {
     338                hdhomerun_channel_list_build_range(channel_list, record->channelmap, range);
     339                range++;
     340        }
     341}
     342
     343void hdhomerun_channel_list_destroy(struct hdhomerun_channel_list_t *channel_list)
     344{
     345        while (channel_list->head) {
     346                struct hdhomerun_channel_entry_t *entry = channel_list->head;
     347                channel_list->head = entry->next;
     348                free(entry);
     349        }
     350
     351        free(channel_list);
     352}
     353
     354struct hdhomerun_channel_list_t *hdhomerun_channel_list_create(const char *channelmap)
     355{
     356        struct hdhomerun_channel_list_t *channel_list = (struct hdhomerun_channel_list_t *)calloc(1, sizeof(struct hdhomerun_channel_list_t));
     357        if (!channel_list) {
     358                return NULL;
     359        }
     360
     361        const struct hdhomerun_channelmap_record_t *record = hdhomerun_channelmap_table;
     362        while (record->channelmap) {
     363                if (!strstr(channelmap, record->channelmap)) {
     364                        record++;
     365                        continue;
     366                }
     367
     368                hdhomerun_channel_list_build_ranges(channel_list, record);
     369                record++;
     370        }
     371
     372        if (!channel_list->head) {
     373                free(channel_list);
     374                return NULL;
     375        }
     376
     377        return channel_list;
     378}
  • libs/libmythtv/hdhomerun/hdhomerun_pkt.c

     
    33 *
    44 * Copyright © 2005-2006 Silicondust Engineering Ltd. <www.silicondust.com>.
    55 *
    6  * This library is free software; you can redistribute it and/or
     6 * This library is free software; you can redistribute it and/or 
    77 * modify it under the terms of the GNU Lesser General Public
    88 * License as published by the Free Software Foundation; either
    9  * version 2.1 of the License, or (at your option) any later version.
     9 * version 3 of the License, or (at your option) any later version.
    1010 *
    1111 * This library is distributed in the hope that it will be useful,
    1212 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     
    1414 * Lesser General Public License for more details.
    1515 *
    1616 * You should have received a copy of the GNU Lesser General Public
    17  * License along with this library; if not, write to the Free Software
    18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     17 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
     18 *
     19 * As a special exception to the GNU Lesser General Public License,
     20 * you may link, statically or dynamically, an application with a
     21 * publicly distributed version of the Library to produce an
     22 * executable file containing portions of the Library, and
     23 * distribute that executable file under terms of your choice,
     24 * without any of the additional requirements listed in clause 4 of
     25 * the GNU Lesser General Public License.
     26 *
     27 * By "a publicly distributed version of the Library", we mean
     28 * either the unmodified Library as distributed by Silicondust, or a
     29 * modified version of the Library that is distributed under the
     30 * conditions defined in the GNU Lesser General Public License.
    1931 */
    2032
    21 #include "hdhomerun_os.h"
    22 #include "hdhomerun_pkt.h"
     33#include "hdhomerun.h"
    2334
    24 uint8_t hdhomerun_read_u8(uint8_t **pptr)
     35struct hdhomerun_pkt_t *hdhomerun_pkt_create(void)
    2536{
    26         uint8_t *ptr = *pptr;
    27         uint8_t v = *ptr++;
    28         *pptr = ptr;
     37        struct hdhomerun_pkt_t *pkt = (struct hdhomerun_pkt_t *)calloc(1, sizeof(struct hdhomerun_pkt_t));
     38        if (!pkt) {
     39                return NULL;
     40        }
     41
     42        hdhomerun_pkt_reset(pkt);
     43
     44        return pkt;
     45}
     46
     47void hdhomerun_pkt_destroy(struct hdhomerun_pkt_t *pkt)
     48{
     49        free(pkt);
     50}
     51
     52void hdhomerun_pkt_reset(struct hdhomerun_pkt_t *pkt)
     53{
     54        pkt->limit = pkt->buffer + sizeof(pkt->buffer) - 4;
     55        pkt->start = pkt->buffer + 1024;
     56        pkt->end = pkt->start;
     57        pkt->pos = pkt->start;
     58}
     59
     60static uint32_t hdhomerun_pkt_calc_crc(uint8_t *start, uint8_t *end)
     61{
     62        uint8_t *pos = start;
     63        uint32_t crc = 0xFFFFFFFF;
     64        while (pos < end) {
     65                uint8_t x = (uint8_t)(crc) ^ *pos++;
     66                crc >>= 8;
     67                if (x & 0x01) crc ^= 0x77073096;
     68                if (x & 0x02) crc ^= 0xEE0E612C;
     69                if (x & 0x04) crc ^= 0x076DC419;
     70                if (x & 0x08) crc ^= 0x0EDB8832;
     71                if (x & 0x10) crc ^= 0x1DB71064;
     72                if (x & 0x20) crc ^= 0x3B6E20C8;
     73                if (x & 0x40) crc ^= 0x76DC4190;
     74                if (x & 0x80) crc ^= 0xEDB88320;
     75        }
     76        return crc ^ 0xFFFFFFFF;
     77}
     78
     79uint8_t hdhomerun_pkt_read_u8(struct hdhomerun_pkt_t *pkt)
     80{
     81        uint8_t v = *pkt->pos++;
    2982        return v;
    3083}
    3184
    32 uint16_t hdhomerun_read_u16(uint8_t **pptr)
     85uint16_t hdhomerun_pkt_read_u16(struct hdhomerun_pkt_t *pkt)
    3386{
    34         uint8_t *ptr = *pptr;
    3587        uint16_t v;
    36         v =  (uint16_t)*ptr++ << 8;
    37         v |= (uint16_t)*ptr++ << 0;
    38         *pptr = ptr;
     88        v =  (uint16_t)*pkt->pos++ << 8;
     89        v |= (uint16_t)*pkt->pos++ << 0;
    3990        return v;
    4091}
    4192
    42 uint32_t hdhomerun_read_u32(uint8_t **pptr)
     93uint32_t hdhomerun_pkt_read_u32(struct hdhomerun_pkt_t *pkt)
    4394{
    44         uint8_t *ptr = *pptr;
    4595        uint32_t v;
    46         v =  (uint32_t)*ptr++ << 24;
    47         v |= (uint32_t)*ptr++ << 16;
    48         v |= (uint32_t)*ptr++ << 8;
    49         v |= (uint32_t)*ptr++ << 0;
    50         *pptr = ptr;
     96        v =  (uint32_t)*pkt->pos++ << 24;
     97        v |= (uint32_t)*pkt->pos++ << 16;
     98        v |= (uint32_t)*pkt->pos++ << 8;
     99        v |= (uint32_t)*pkt->pos++ << 0;
    51100        return v;
    52101}
    53102
    54 size_t hdhomerun_read_var_length(uint8_t **pptr, uint8_t *end)
     103size_t hdhomerun_pkt_read_var_length(struct hdhomerun_pkt_t *pkt)
    55104{
    56         uint8_t *ptr = *pptr;
    57105        size_t length;
    58106       
    59         if (ptr + 1 > end) {
    60                 return -1;
     107        if (pkt->pos + 1 > pkt->end) {
     108                return (size_t)-1;
    61109        }
    62110
    63         length = (size_t)*ptr++;
     111        length = (size_t)*pkt->pos++;
    64112        if (length & 0x0080) {
    65                 if (ptr + 1 > end) {
    66                         return -1;
     113                if (pkt->pos + 1 > pkt->end) {
     114                        return (size_t)-1;
    67115                }
    68116
    69117                length &= 0x007F;
    70                 length |= (size_t)*ptr++ << 7;
     118                length |= (size_t)*pkt->pos++ << 7;
    71119        }
    72120       
    73         *pptr = ptr;
    74121        return length;
    75122}
    76123
    77 int hdhomerun_read_tlv(uint8_t **pptr, uint8_t *end, uint8_t *ptag, size_t *plength, uint8_t **pvalue)
     124uint8_t *hdhomerun_pkt_read_tlv(struct hdhomerun_pkt_t *pkt, uint8_t *ptag, size_t *plength)
    78125{
    79         if (end - *pptr < 2) {
    80                 return -1;
     126        if (pkt->pos + 2 > pkt->end) {
     127                return NULL;
    81128        }
    82129       
    83         *ptag = hdhomerun_read_u8(pptr);
    84         *plength = hdhomerun_read_var_length(pptr, end);
    85         *pvalue = *pptr;
    86        
    87         if ((size_t)(end - *pptr) < *plength) {
    88                 return -1;
     130        *ptag = hdhomerun_pkt_read_u8(pkt);
     131        *plength = hdhomerun_pkt_read_var_length(pkt);
     132
     133        if (pkt->pos + *plength > pkt->end) {
     134                return NULL;
    89135        }
    90136       
    91         *pptr += *plength;
    92         return 0;
     137        return pkt->pos + *plength;
    93138}
    94139
    95 void hdhomerun_write_u8(uint8_t **pptr, uint8_t v)
     140void hdhomerun_pkt_write_u8(struct hdhomerun_pkt_t *pkt, uint8_t v)
    96141{
    97         uint8_t *ptr = *pptr;
    98         *ptr++ = v;
    99         *pptr = ptr;
    100 }
     142        *pkt->pos++ = v;
    101143
    102 void hdhomerun_write_u16(uint8_t **pptr, uint16_t v)
    103 {
    104         uint8_t *ptr = *pptr;
    105         *ptr++ = (uint8_t)(v >> 8);
    106         *ptr++ = (uint8_t)(v >> 0);
    107         *pptr = ptr;
     144        if (pkt->pos > pkt->end) {
     145                pkt->end = pkt->pos;
     146        }
    108147}
    109148
    110 void hdhomerun_write_u32(uint8_t **pptr, uint32_t v)
     149void hdhomerun_pkt_write_u16(struct hdhomerun_pkt_t *pkt, uint16_t v)
    111150{
    112         uint8_t *ptr = *pptr;
    113         *ptr++ = (uint8_t)(v >> 24);
    114         *ptr++ = (uint8_t)(v >> 16);
    115         *ptr++ = (uint8_t)(v >> 8);
    116         *ptr++ = (uint8_t)(v >> 0);
    117         *pptr = ptr;
    118 }
     151        *pkt->pos++ = (uint8_t)(v >> 8);
     152        *pkt->pos++ = (uint8_t)(v >> 0);
    119153
    120 void hdhomerun_write_var_length(uint8_t **pptr, size_t v)
    121 {
    122         uint8_t *ptr = *pptr;
    123         if (v <= 127) {
    124                 *ptr++ = (uint8_t)v;
    125         } else {
    126                 *ptr++ = (uint8_t)(v | 0x80);
    127                 *ptr++ = (uint8_t)(v >> 7);
     154        if (pkt->pos > pkt->end) {
     155                pkt->end = pkt->pos;
    128156        }
    129         *pptr = ptr;
    130157}
    131158
    132 static void hdhomerun_write_mem(uint8_t **pptr, void *mem, size_t length)
     159void hdhomerun_pkt_write_u32(struct hdhomerun_pkt_t *pkt, uint32_t v)
    133160{
    134         uint8_t *ptr = *pptr;
    135         memcpy(ptr, mem, length);
    136         ptr += length;
    137         *pptr = ptr;
    138 }
     161        *pkt->pos++ = (uint8_t)(v >> 24);
     162        *pkt->pos++ = (uint8_t)(v >> 16);
     163        *pkt->pos++ = (uint8_t)(v >> 8);
     164        *pkt->pos++ = (uint8_t)(v >> 0);
    139165
    140 static uint32_t hdhomerun_calc_crc(uint8_t *start, uint8_t *end)
    141 {
    142         uint8_t *ptr = start;
    143         uint32_t crc = 0xFFFFFFFF;
    144         while (ptr < end) {
    145                 uint8_t x = (uint8_t)(crc) ^ *ptr++;
    146                 crc >>= 8;
    147                 if (x & 0x01) crc ^= 0x77073096;
    148                 if (x & 0x02) crc ^= 0xEE0E612C;
    149                 if (x & 0x04) crc ^= 0x076DC419;
    150                 if (x & 0x08) crc ^= 0x0EDB8832;
    151                 if (x & 0x10) crc ^= 0x1DB71064;
    152                 if (x & 0x20) crc ^= 0x3B6E20C8;
    153                 if (x & 0x40) crc ^= 0x76DC4190;
    154                 if (x & 0x80) crc ^= 0xEDB88320;
     166        if (pkt->pos > pkt->end) {
     167                pkt->end = pkt->pos;
    155168        }
    156         return crc ^ 0xFFFFFFFF;
    157169}
    158170
    159 static int hdhomerun_check_crc(uint8_t *start, uint8_t *end)
     171void hdhomerun_pkt_write_var_length(struct hdhomerun_pkt_t *pkt, size_t v)
    160172{
    161         if (end - start < 8) {
    162                 return -1;
     173        if (v <= 127) {
     174                *pkt->pos++ = (uint8_t)v;
     175        } else {
     176                *pkt->pos++ = (uint8_t)(v | 0x80);
     177                *pkt->pos++ = (uint8_t)(v >> 7);
    163178        }
    164         uint8_t *ptr = end -= 4;
    165         uint32_t actual_crc = hdhomerun_calc_crc(start, ptr);
    166         uint32_t packet_crc;
    167         packet_crc =  (uint32_t)*ptr++ << 0;
    168         packet_crc |= (uint32_t)*ptr++ << 8;
    169         packet_crc |= (uint32_t)*ptr++ << 16;
    170         packet_crc |= (uint32_t)*ptr++ << 24;
    171         if (actual_crc != packet_crc) {
    172                 return -1;
     179
     180        if (pkt->pos > pkt->end) {
     181                pkt->end = pkt->pos;
    173182        }
    174         return 0;
    175183}
    176184
    177 static void hdhomerun_write_header_length(uint8_t *ptr, size_t length)
     185void hdhomerun_pkt_write_mem(struct hdhomerun_pkt_t *pkt, const void *mem, size_t length)
    178186{
    179         hdhomerun_write_u16(&ptr, (uint16_t)length);
    180 }
     187        memcpy(pkt->pos, mem, length);
     188        pkt->pos += length;
    181189
    182 void hdhomerun_write_crc(uint8_t **pptr, uint8_t *start)
    183 {
    184         uint8_t *ptr = *pptr;
    185         uint32_t crc = hdhomerun_calc_crc(start, ptr);
    186         *ptr++ = (uint8_t)(crc >> 0);
    187         *ptr++ = (uint8_t)(crc >> 8);
    188         *ptr++ = (uint8_t)(crc >> 16);
    189         *ptr++ = (uint8_t)(crc >> 24);
    190         *pptr = ptr;
     190        if (pkt->pos > pkt->end) {
     191                pkt->end = pkt->pos;
     192        }
    191193}
    192194
    193 void hdhomerun_write_discover_request(uint8_t **pptr, uint32_t device_type, uint32_t device_id)
     195int hdhomerun_pkt_open_frame(struct hdhomerun_pkt_t *pkt, uint16_t *ptype)
    194196{
    195         uint8_t *start = *pptr;
    196         hdhomerun_write_u16(pptr, HDHOMERUN_TYPE_DISCOVER_REQ);
    197         hdhomerun_write_u16(pptr, 0);
     197        pkt->pos = pkt->start;
    198198
    199         hdhomerun_write_u8(pptr, HDHOMERUN_TAG_DEVICE_TYPE);
    200         hdhomerun_write_var_length(pptr, 4);
    201         hdhomerun_write_u32(pptr, device_type);
    202         hdhomerun_write_u8(pptr, HDHOMERUN_TAG_DEVICE_ID);
    203         hdhomerun_write_var_length(pptr, 4);
    204         hdhomerun_write_u32(pptr, device_id);
     199        if (pkt->pos + 4 > pkt->end) {
     200                return 0;
     201        }
    205202
    206         hdhomerun_write_header_length(start + 2, (int)(*pptr - start - 4));
    207         hdhomerun_write_crc(pptr, start);
    208 }
     203        *ptype = hdhomerun_pkt_read_u16(pkt);
     204        size_t length = hdhomerun_pkt_read_u16(pkt);
     205        pkt->pos += length;
    209206
    210 void hdhomerun_write_get_set_request(uint8_t **pptr, const char *name, const char *value)
    211 {
    212         uint8_t *start = *pptr;
    213         hdhomerun_write_u16(pptr, HDHOMERUN_TYPE_GETSET_REQ);
    214         hdhomerun_write_u16(pptr, 0);
     207        if (pkt->pos + 4 > pkt->end) {
     208                pkt->pos = pkt->start;
     209                return 0;
     210        }
    215211
    216         int name_len = (int)strlen(name) + 1;
    217         hdhomerun_write_u8(pptr, HDHOMERUN_TAG_GETSET_NAME);
    218         hdhomerun_write_var_length(pptr, name_len);
    219         hdhomerun_write_mem(pptr, (void *)name, name_len);
     212        uint32_t calc_crc = hdhomerun_pkt_calc_crc(pkt->start, pkt->pos);
    220213
    221         if (value) {
    222                 int value_len = (int)strlen(value) + 1;
    223                 hdhomerun_write_u8(pptr, HDHOMERUN_TAG_GETSET_VALUE);
    224                 hdhomerun_write_var_length(pptr, value_len);
    225                 hdhomerun_write_mem(pptr, (void *)value, value_len);
     214        uint32_t packet_crc;
     215        packet_crc =  (uint32_t)*pkt->pos++ << 0;
     216        packet_crc |= (uint32_t)*pkt->pos++ << 8;
     217        packet_crc |= (uint32_t)*pkt->pos++ << 16;
     218        packet_crc |= (uint32_t)*pkt->pos++ << 24;
     219        if (calc_crc != packet_crc) {
     220                return -1;
    226221        }
    227222
    228         hdhomerun_write_header_length(start + 2, (int)(*pptr - start - 4));
    229         hdhomerun_write_crc(pptr, start);
     223        pkt->start += 4;
     224        pkt->end = pkt->start + length;
     225        pkt->pos = pkt->start;
     226        return 1;
    230227}
    231228
    232 void hdhomerun_write_upgrade_request(uint8_t **pptr, uint32_t sequence, void *data, size_t length)
     229void hdhomerun_pkt_seal_frame(struct hdhomerun_pkt_t *pkt, uint16_t frame_type)
    233230{
    234         uint8_t *start = *pptr;
    235         hdhomerun_write_u16(pptr, HDHOMERUN_TYPE_UPGRADE_REQ);
    236         hdhomerun_write_u16(pptr, 0);
     231        size_t length = pkt->end - pkt->start;
    237232
    238         hdhomerun_write_u32(pptr, sequence);
    239         if (length > 0) {
    240                 hdhomerun_write_mem(pptr, data, length);
    241         }
     233        pkt->start -= 4;
     234        pkt->pos = pkt->start;
     235        hdhomerun_pkt_write_u16(pkt, frame_type);
     236        hdhomerun_pkt_write_u16(pkt, (uint16_t)length);
    242237
    243         hdhomerun_write_header_length(start + 2, *pptr - start - 4);
    244         hdhomerun_write_crc(pptr, start);
    245 }
     238        uint32_t crc = hdhomerun_pkt_calc_crc(pkt->start, pkt->end);
     239        *pkt->end++ = (uint8_t)(crc >> 0);
     240        *pkt->end++ = (uint8_t)(crc >> 8);
     241        *pkt->end++ = (uint8_t)(crc >> 16);
     242        *pkt->end++ = (uint8_t)(crc >> 24);
    246243
    247 size_t hdhomerun_peek_packet_length(uint8_t *ptr)
    248 {
    249         ptr += 2;
    250         return (size_t)hdhomerun_read_u16(&ptr) + 8;
     244        pkt->pos = pkt->start;
    251245}
    252 
    253 int hdhomerun_process_packet(uint8_t **pptr, uint8_t **pend)
    254 {
    255         if (hdhomerun_check_crc(*pptr, *pend) < 0) {
    256                 return -1;
    257         }
    258         *pend -= 4;
    259        
    260         uint16_t type = hdhomerun_read_u16(pptr);
    261         uint16_t length = hdhomerun_read_u16(pptr);
    262         if ((*pend - *pptr) < length) {
    263                 return -1;
    264         }
    265         *pend = *pptr + length;
    266         return (int)type;
    267 }
    268 
  • libs/libmythtv/hdhomerun/hdhomerun_device.c

     
    11/*
    2  * hdhomerun_record.c
     2 * hdhomerun_device.c
    33 *
    4  * Copyright © 2006 Silicondust Engineering Ltd. <www.silicondust.com>.
     4 * Copyright © 2006-2008 Silicondust Engineering Ltd. <www.silicondust.com>.
    55 *
    6  * This library is free software; you can redistribute it and/or
     6 * This library is free software; you can redistribute it and/or 
    77 * modify it under the terms of the GNU Lesser General Public
    88 * License as published by the Free Software Foundation; either
    9  * version 2.1 of the License, or (at your option) any later version.
     9 * version 3 of the License, or (at your option) any later version.
    1010 *
    1111 * This library is distributed in the hope that it will be useful,
    1212 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     
    1414 * Lesser General Public License for more details.
    1515 *
    1616 * You should have received a copy of the GNU Lesser General Public
    17  * License along with this library; if not, write to the Free Software
    18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     17 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
     18 *
     19 * As a special exception to the GNU Lesser General Public License,
     20 * you may link, statically or dynamically, an application with a
     21 * publicly distributed version of the Library to produce an
     22 * executable file containing portions of the Library, and
     23 * distribute that executable file under terms of your choice,
     24 * without any of the additional requirements listed in clause 4 of
     25 * the GNU Lesser General Public License.
     26 *
     27 * By "a publicly distributed version of the Library", we mean
     28 * either the unmodified Library as distributed by Silicondust, or a
     29 * modified version of the Library that is distributed under the
     30 * conditions defined in the GNU Lesser General Public License.
    1931 */
    2032
    21 #include "hdhomerun_os.h"
    22 #include "hdhomerun_pkt.h"
    23 #include "hdhomerun_control.h"
    24 #include "hdhomerun_video.h"
    25 #include "hdhomerun_device.h"
     33#include "hdhomerun.h"
    2634
    2735struct hdhomerun_device_t {
    2836        struct hdhomerun_control_sock_t *cs;
    2937        struct hdhomerun_video_sock_t *vs;
     38        struct hdhomerun_debug_t *dbg;
     39        struct hdhomerun_channelscan_t *scan;
    3040        unsigned int tuner;
    31         char result_buffer[1024];
     41        uint32_t lockkey;
     42        char name[32];
     43        char model[32];
    3244};
    3345
    34 struct hdhomerun_device_t *hdhomerun_device_create(uint32_t device_id, uint32_t device_ip, unsigned int tuner)
     46static void hdhomerun_device_set_update(struct hdhomerun_device_t *hd)
    3547{
     48        /* Clear cached information. */
     49        *hd->model = 0;
     50
     51        /* New name. */
     52        sprintf(hd->name, "%08lX-%u", (unsigned long)hdhomerun_control_get_device_id(hd->cs), hd->tuner);
     53}
     54
     55void hdhomerun_device_set_device(struct hdhomerun_device_t *hd, uint32_t device_id, uint32_t device_ip)
     56{
     57        hdhomerun_control_set_device(hd->cs, device_id, device_ip);
     58        hdhomerun_device_set_update(hd);
     59}
     60
     61void hdhomerun_device_set_tuner(struct hdhomerun_device_t *hd, unsigned int tuner)
     62{
     63        hd->tuner = tuner;
     64        hdhomerun_device_set_update(hd);
     65}
     66
     67struct hdhomerun_device_t *hdhomerun_device_create(uint32_t device_id, uint32_t device_ip, unsigned int tuner, struct hdhomerun_debug_t *dbg)
     68{
    3669        struct hdhomerun_device_t *hd = (struct hdhomerun_device_t *)calloc(1, sizeof(struct hdhomerun_device_t));
    3770        if (!hd) {
     71                hdhomerun_debug_printf(dbg, "hdhomerun_device_create: failed to allocate device object\n");
    3872                return NULL;
    3973        }
    4074
    41         hd->tuner = tuner;
     75        hd->dbg = dbg;
    4276
    43         hd->cs = hdhomerun_control_create(device_id, device_ip);
     77        hd->cs = hdhomerun_control_create(0, 0, hd->dbg);
    4478        if (!hd->cs) {
     79                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_create: failed to create control object\n");
    4580                free(hd);
    4681                return NULL;
    4782        }
    4883
     84        hdhomerun_device_set_device(hd, device_id, device_ip);
     85        hdhomerun_device_set_tuner(hd, tuner);
     86
    4987        return hd;
    5088}
    5189
    5290void hdhomerun_device_destroy(struct hdhomerun_device_t *hd)
    5391{
     92        if (hd->scan) {
     93                channelscan_destroy(hd->scan);
     94        }
     95
    5496        if (hd->vs) {
    5597                hdhomerun_video_destroy(hd->vs);
    5698        }
     
    60102        free(hd);
    61103}
    62104
    63 void hdhomerun_device_set_tuner(struct hdhomerun_device_t *hd, unsigned int tuner)
     105static bool_t is_hex_char(char c)
    64106{
    65         hd->tuner = tuner;
     107        if ((c >= '0') && (c <= '9')) {
     108                return TRUE;
     109        }
     110        if ((c >= 'A') && (c <= 'F')) {
     111                return TRUE;
     112        }
     113        if ((c >= 'a') && (c <= 'f')) {
     114                return TRUE;
     115        }
     116        return FALSE;
    66117}
    67118
     119static struct hdhomerun_device_t *hdhomerun_device_create_from_str_device_id(const char *device_str, struct hdhomerun_debug_t *dbg)
     120{
     121        int i;
     122        const char *ptr = device_str;
     123        for (i = 0; i < 8; i++) {
     124                if (!is_hex_char(*ptr++)) {
     125                        return NULL;
     126                }
     127        }
     128
     129        if (*ptr == 0) {
     130                unsigned long device_id;
     131                if (sscanf(device_str, "%lx", &device_id) != 1) {
     132                        return NULL;
     133                }
     134                return hdhomerun_device_create((uint32_t)device_id, 0, 0, dbg);
     135        }
     136
     137        if (*ptr == '-') {
     138                unsigned long device_id;
     139                unsigned int tuner;
     140                if (sscanf(device_str, "%lx-%u", &device_id, &tuner) != 2) {
     141                        return NULL;
     142                }
     143                return hdhomerun_device_create((uint32_t)device_id, 0, tuner, dbg);
     144        }
     145
     146        return NULL;
     147}
     148
     149static struct hdhomerun_device_t *hdhomerun_device_create_from_str_ip(const char *device_str, struct hdhomerun_debug_t *dbg)
     150{
     151        unsigned long a[4];
     152        unsigned int tuner;
     153
     154        if (sscanf(device_str, "%lu.%lu.%lu.%lu-%u", &a[0], &a[1], &a[2], &a[3], &tuner) != 5) {
     155                tuner = 0;
     156                if (sscanf(device_str, "%lu.%lu.%lu.%lu", &a[0], &a[1], &a[2], &a[3]) != 4) {
     157                        return NULL;
     158                }
     159        }
     160
     161        unsigned long device_ip = (a[0] << 24) | (a[1] << 16) | (a[2] << 8) | (a[3] << 0);
     162        return hdhomerun_device_create(HDHOMERUN_DEVICE_ID_WILDCARD, (uint32_t)device_ip, tuner, dbg);
     163}
     164
     165static struct hdhomerun_device_t *hdhomerun_device_create_from_str_dns(const char *device_str, struct hdhomerun_debug_t *dbg)
     166{
     167#if defined(__CYGWIN__)
     168        return NULL;
     169#else
     170        struct addrinfo hints;
     171        memset(&hints, 0, sizeof(hints));
     172        hints.ai_family = AF_INET;
     173        hints.ai_socktype = SOCK_STREAM;
     174        hints.ai_protocol = IPPROTO_TCP;
     175
     176        struct addrinfo *sock_info;
     177        if (getaddrinfo(device_str, "65001", &hints, &sock_info) != 0) {
     178                return NULL;
     179        }
     180
     181        struct sockaddr_in *sock_addr = (struct sockaddr_in *)sock_info->ai_addr;
     182        uint32_t device_ip = ntohl(sock_addr->sin_addr.s_addr);
     183        freeaddrinfo(sock_info);
     184
     185        if (device_ip == 0) {
     186                return NULL;
     187        }
     188
     189        return hdhomerun_device_create(HDHOMERUN_DEVICE_ID_WILDCARD, (uint32_t)device_ip, 0, dbg);
     190#endif
     191}
     192
     193struct hdhomerun_device_t *hdhomerun_device_create_from_str(const char *device_str, struct hdhomerun_debug_t *dbg)
     194{
     195        struct hdhomerun_device_t *device = hdhomerun_device_create_from_str_device_id(device_str, dbg);
     196        if (device) {
     197                return device;
     198        }
     199
     200        device = hdhomerun_device_create_from_str_ip(device_str, dbg);
     201        if (device) {
     202                return device;
     203        }
     204
     205        device = hdhomerun_device_create_from_str_dns(device_str, dbg);
     206        if (device) {
     207                return device;
     208        }
     209
     210        return NULL;
     211}
     212
     213int hdhomerun_device_set_tuner_from_str(struct hdhomerun_device_t *hd, const char *tuner_str)
     214{
     215        unsigned int tuner;
     216        if (sscanf(tuner_str, "%u", &tuner) == 1) {
     217                hdhomerun_device_set_tuner(hd, tuner);
     218                return 1;
     219        }
     220        if (sscanf(tuner_str, "/tuner%u", &tuner) == 1) {
     221                hdhomerun_device_set_tuner(hd, tuner);
     222                return 1;
     223        }
     224
     225        return -1;
     226}
     227
     228uint32_t hdhomerun_device_get_device_id(struct hdhomerun_device_t *hd)
     229{
     230        return hdhomerun_control_get_device_id(hd->cs);
     231}
     232
     233uint32_t hdhomerun_device_get_device_ip(struct hdhomerun_device_t *hd)
     234{
     235        return hdhomerun_control_get_device_ip(hd->cs);
     236}
     237
     238uint32_t hdhomerun_device_get_device_id_requested(struct hdhomerun_device_t *hd)
     239{
     240        return hdhomerun_control_get_device_id_requested(hd->cs);
     241}
     242
     243uint32_t hdhomerun_device_get_device_ip_requested(struct hdhomerun_device_t *hd)
     244{
     245        return hdhomerun_control_get_device_ip_requested(hd->cs);
     246}
     247
     248unsigned int hdhomerun_device_get_tuner(struct hdhomerun_device_t *hd)
     249{
     250        return hd->tuner;
     251}
     252
    68253struct hdhomerun_control_sock_t *hdhomerun_device_get_control_sock(struct hdhomerun_device_t *hd)
    69254{
    70255        return hd->cs;
     
    72257
    73258struct hdhomerun_video_sock_t *hdhomerun_device_get_video_sock(struct hdhomerun_device_t *hd)
    74259{
     260        if (hd->vs) {
     261                return hd->vs;
     262        }
     263
     264        hd->vs = hdhomerun_video_create(0, VIDEO_DATA_BUFFER_SIZE_1S * 2, hd->dbg);
    75265        if (!hd->vs) {
    76                 hd->vs = hdhomerun_video_create(0, VIDEO_DATA_BUFFER_SIZE_1S);
     266                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_video_sock: failed to create video object\n");
     267                return NULL;
    77268        }
     269
    78270        return hd->vs;
    79271}
    80272
     
    96288        return (uint32_t)value;
    97289}
    98290
    99 int hdhomerun_device_get_tuner_status(struct hdhomerun_device_t *hd, struct hdhomerun_tuner_status_t *status)
     291static bool_t hdhomerun_device_get_tuner_status_lock_is_bcast(struct hdhomerun_tuner_status_t *status)
    100292{
     293        if (strcmp(status->lock_str, "8vsb") == 0) {
     294                return TRUE;
     295        }
     296        if (strncmp(status->lock_str, "t8", 2) == 0) {
     297                return TRUE;
     298        }
     299        if (strncmp(status->lock_str, "t7", 2) == 0) {
     300                return TRUE;
     301        }
     302        if (strncmp(status->lock_str, "t6", 2) == 0) {
     303                return TRUE;
     304        }
     305
     306        return FALSE;
     307}
     308
     309uint32_t hdhomerun_device_get_tuner_status_ss_color(struct hdhomerun_tuner_status_t *status)
     310{
     311        unsigned int ss_yellow_min;
     312        unsigned int ss_green_min;
     313
     314        if (!status->lock_supported) {
     315                return HDHOMERUN_STATUS_COLOR_NEUTRAL;
     316        }
     317
     318        if (hdhomerun_device_get_tuner_status_lock_is_bcast(status)) {
     319                ss_yellow_min = 50;     /* -30dBmV */
     320                ss_green_min = 75;      /* -15dBmV */
     321        } else {
     322                ss_yellow_min = 80;     /* -12dBmV */
     323                ss_green_min = 90;      /* -6dBmV */
     324        }
     325
     326        if (status->signal_strength >= ss_green_min) {
     327                return HDHOMERUN_STATUS_COLOR_GREEN;
     328        }
     329        if (status->signal_strength >= ss_yellow_min) {
     330                return HDHOMERUN_STATUS_COLOR_YELLOW;
     331        }
     332
     333        return HDHOMERUN_STATUS_COLOR_RED;
     334}
     335
     336uint32_t hdhomerun_device_get_tuner_status_snq_color(struct hdhomerun_tuner_status_t *status)
     337{
     338        if (status->signal_to_noise_quality >= 70) {
     339                return HDHOMERUN_STATUS_COLOR_GREEN;
     340        }
     341        if (status->signal_to_noise_quality >= 50) {
     342                return HDHOMERUN_STATUS_COLOR_YELLOW;
     343        }
     344
     345        return HDHOMERUN_STATUS_COLOR_RED;
     346}
     347
     348uint32_t hdhomerun_device_get_tuner_status_seq_color(struct hdhomerun_tuner_status_t *status)
     349{
     350        if (status->symbol_error_quality >= 100) {
     351                return HDHOMERUN_STATUS_COLOR_GREEN;
     352        }
     353
     354        return HDHOMERUN_STATUS_COLOR_RED;
     355}
     356
     357int hdhomerun_device_get_tuner_status(struct hdhomerun_device_t *hd, char **pstatus_str, struct hdhomerun_tuner_status_t *status)
     358{
    101359        memset(status, 0, sizeof(struct hdhomerun_tuner_status_t));
    102360
    103361        char name[32];
     
    109367                return ret;
    110368        }
    111369
     370        if (pstatus_str) {
     371                *pstatus_str = status_str;
     372        }
     373
    112374        char *channel = strstr(status_str, "ch=");
    113375        if (channel) {
    114                 sscanf(channel + 3, "%s", status->channel);
     376                sscanf(channel + 3, "%31s", status->channel);
    115377        }
    116378
     379        char *lock = strstr(status_str, "lock=");
     380        if (lock) {
     381                sscanf(lock + 5, "%31s", status->lock_str);
     382        }
     383
    117384        status->signal_strength = (unsigned int)hdhomerun_device_get_status_parse(status_str, "ss=");
    118385        status->signal_to_noise_quality = (unsigned int)hdhomerun_device_get_status_parse(status_str, "snq=");
    119386        status->symbol_error_quality = (unsigned int)hdhomerun_device_get_status_parse(status_str, "seq=");
    120387        status->raw_bits_per_second = hdhomerun_device_get_status_parse(status_str, "bps=");
    121388        status->packets_per_second = hdhomerun_device_get_status_parse(status_str, "pps=");
    122389
     390        status->signal_present = status->signal_strength >= 45;
     391
     392        if (strcmp(status->lock_str, "none") != 0) {
     393                if (status->lock_str[0] == '(') {
     394                        status->lock_unsupported = TRUE;
     395                } else {
     396                        status->lock_supported = TRUE;
     397                }
     398        }
     399
    123400        return 1;
    124401}
    125402
     
    151428        return hdhomerun_control_get(hd->cs, name, pfilter, NULL);
    152429}
    153430
    154 int hdhomerun_device_get_tuner_program(struct hdhomerun_device_t *hd, uint16_t *pprogram_number)
     431int hdhomerun_device_get_tuner_program(struct hdhomerun_device_t *hd, char **pprogram)
    155432{
    156433        char name[32];
    157434        sprintf(name, "/tuner%u/program", hd->tuner);
     435        return hdhomerun_control_get(hd->cs, name, pprogram, NULL);
     436}
    158437
    159         char *program_str;
    160         int ret = hdhomerun_control_get(hd->cs, name, &program_str, NULL);
     438int hdhomerun_device_get_tuner_target(struct hdhomerun_device_t *hd, char **ptarget)
     439{
     440        char name[32];
     441        sprintf(name, "/tuner%u/target", hd->tuner);
     442        return hdhomerun_control_get(hd->cs, name, ptarget, NULL);
     443}
     444
     445int hdhomerun_device_get_tuner_plotsample(struct hdhomerun_device_t *hd, struct hdhomerun_plotsample_t **psamples, size_t *pcount)
     446{
     447        char name[32];
     448        sprintf(name, "/tuner%u/plotsample", hd->tuner);
     449
     450        char *result;
     451        int ret = hdhomerun_control_get(hd->cs, name, &result, NULL);
    161452        if (ret <= 0) {
    162453                return ret;
    163454        }
    164455
    165         *pprogram_number = (uint16_t)atol(program_str);
     456        struct hdhomerun_plotsample_t *samples = (struct hdhomerun_plotsample_t *)result;
     457        *psamples = samples;
     458        size_t count = 0;
     459
     460        while (1) {
     461                char *ptr = strchr(result, ' ');
     462                if (!ptr) {
     463                        break;
     464                }
     465                *ptr++ = 0;
     466
     467                unsigned long raw;
     468                if (sscanf(result, "%lx", &raw) != 1) {
     469                        break;
     470                }
     471
     472                uint16_t real = (raw >> 12) & 0x0FFF;
     473                if (real & 0x0800) {
     474                        real |= 0xF000;
     475                }
     476
     477                uint16_t imag = (raw >> 0) & 0x0FFF;
     478                if (imag & 0x0800) {
     479                        imag |= 0xF000;
     480                }
     481
     482                samples->real = (int16_t)real;
     483                samples->imag = (int16_t)imag;
     484                samples++;
     485                count++;
     486
     487                result = ptr;
     488        }
     489
     490        *pcount = count;
    166491        return 1;
    167492}
    168493
    169 int hdhomerun_device_get_tuner_target(struct hdhomerun_device_t *hd, char **ptarget)
     494int hdhomerun_device_get_tuner_lockkey_owner(struct hdhomerun_device_t *hd, char **powner)
    170495{
    171496        char name[32];
    172         sprintf(name, "/tuner%u/target", hd->tuner);
    173         return hdhomerun_control_get(hd->cs, name, ptarget, NULL);
     497        sprintf(name, "/tuner%u/lockkey", hd->tuner);
     498        return hdhomerun_control_get(hd->cs, name, powner, NULL);
    174499}
    175500
    176501int hdhomerun_device_get_ir_target(struct hdhomerun_device_t *hd, char **ptarget)
     
    178503        return hdhomerun_control_get(hd->cs, "/ir/target", ptarget, NULL);
    179504}
    180505
     506int hdhomerun_device_get_lineup_location(struct hdhomerun_device_t *hd, char **plocation)
     507{
     508        return hdhomerun_control_get(hd->cs, "/lineup/location", plocation, NULL);
     509}
     510
    181511int hdhomerun_device_get_version(struct hdhomerun_device_t *hd, char **pversion_str, uint32_t *pversion_num)
    182512{
    183513        char *version_str;
     
    206536{
    207537        char name[32];
    208538        sprintf(name, "/tuner%u/channel", hd->tuner);
    209         return hdhomerun_control_set(hd->cs, name, channel, NULL, NULL);
     539        return hdhomerun_control_set_with_lockkey(hd->cs, name, channel, hd->lockkey, NULL, NULL);
    210540}
    211541
    212542int hdhomerun_device_set_tuner_channelmap(struct hdhomerun_device_t *hd, const char *channelmap)
    213543{
    214544        char name[32];
    215545        sprintf(name, "/tuner%u/channelmap", hd->tuner);
    216         return hdhomerun_control_set(hd->cs, name, channelmap, NULL, NULL);
     546        return hdhomerun_control_set_with_lockkey(hd->cs, name, channelmap, hd->lockkey, NULL, NULL);
    217547}
    218548
    219549int hdhomerun_device_set_tuner_filter(struct hdhomerun_device_t *hd, const char *filter)
    220550{
    221551        char name[32];
    222552        sprintf(name, "/tuner%u/filter", hd->tuner);
    223         return hdhomerun_control_set(hd->cs, name, filter, NULL, NULL);
     553        return hdhomerun_control_set_with_lockkey(hd->cs, name, filter, hd->lockkey, NULL, NULL);
    224554}
    225555
    226 int hdhomerun_device_set_tuner_program(struct hdhomerun_device_t *hd, uint16_t program_number)
     556static int hdhomerun_device_set_tuner_filter_by_array_append(char **pptr, char *end, uint16_t range_begin, uint16_t range_end)
    227557{
    228         char name[32], value[32];
     558        char *ptr = *pptr;
     559
     560        size_t available = end - ptr;
     561        size_t required;
     562
     563        if (range_begin == range_end) {
     564                required = snprintf(ptr, available, "0x%04x ", range_begin) + 1;
     565        } else {
     566                required = snprintf(ptr, available, "0x%04x-0x%04x ", range_begin, range_end) + 1;
     567        }
     568
     569        if (required > available) {
     570                return FALSE;
     571        }
     572
     573        *pptr = strchr(ptr, 0);
     574        return TRUE;
     575}
     576
     577int hdhomerun_device_set_tuner_filter_by_array(struct hdhomerun_device_t *hd, unsigned char filter_array[0x2000])
     578{
     579        char filter[1024];
     580        char *ptr = filter;
     581        char *end = filter + sizeof(filter);
     582
     583        uint16_t range_begin = 0xFFFF;
     584        uint16_t range_end = 0xFFFF;
     585
     586        uint16_t i;
     587        for (i = 0; i <= 0x1FFF; i++) {
     588                if (!filter_array[i]) {
     589                        if (range_begin == 0xFFFF) {
     590                                continue;
     591                        }
     592                        if (!hdhomerun_device_set_tuner_filter_by_array_append(&ptr, end, range_begin, range_end)) {
     593                                return 0;
     594                        }
     595                        range_begin = 0xFFFF;
     596                        range_end = 0xFFFF;
     597                        continue;
     598                }
     599
     600                if (range_begin == 0xFFFF) {
     601                        range_begin = i;
     602                        range_end = i;
     603                        continue;
     604                }
     605
     606                range_end = i;
     607        }
     608
     609        if (range_begin != 0xFFFF) {
     610                if (!hdhomerun_device_set_tuner_filter_by_array_append(&ptr, end, range_begin, range_end)) {
     611                        return 0;
     612                }
     613        }
     614
     615        /* Remove trailing space. */
     616        if (ptr > filter) {
     617                ptr--;
     618        }
     619        *ptr = 0;
     620
     621        return hdhomerun_device_set_tuner_filter(hd, filter);
     622}
     623
     624int hdhomerun_device_set_tuner_program(struct hdhomerun_device_t *hd, const char *program)
     625{
     626        char name[32];
    229627        sprintf(name, "/tuner%u/program", hd->tuner);
    230         sprintf(value, "%u", program_number);
    231         return hdhomerun_control_set(hd->cs, name, value, NULL, NULL);
     628        return hdhomerun_control_set_with_lockkey(hd->cs, name, program, hd->lockkey, NULL, NULL);
    232629}
    233630
    234 int hdhomerun_device_set_tuner_target(struct hdhomerun_device_t *hd, char *target)
     631int hdhomerun_device_set_tuner_target(struct hdhomerun_device_t *hd, const char *target)
    235632{
    236633        char name[32];
    237634        sprintf(name, "/tuner%u/target", hd->tuner);
    238         return hdhomerun_control_set(hd->cs, name, target, NULL, NULL);
     635        return hdhomerun_control_set_with_lockkey(hd->cs, name, target, hd->lockkey, NULL, NULL);
    239636}
    240637
    241 static int hdhomerun_device_set_tuner_target_to_local(struct hdhomerun_device_t *hd)
     638int hdhomerun_device_set_tuner_target_to_local_protocol(struct hdhomerun_device_t *hd, const char *protocol)
    242639{
     640        /* Create video socket. */
     641        hdhomerun_device_get_video_sock(hd);
     642        if (!hd->vs) {
     643                return -1;
     644        }
     645
     646        /* Set target. */
    243647        char target[64];
    244648        uint32_t local_ip = hdhomerun_control_get_local_addr(hd->cs);
    245649        uint16_t local_port = hdhomerun_video_get_local_port(hd->vs);
    246         sprintf(target, "%u.%u.%u.%u:%u",
     650        sprintf(target, "%s://%u.%u.%u.%u:%u",
     651                protocol,
    247652                (unsigned int)(local_ip >> 24) & 0xFF, (unsigned int)(local_ip >> 16) & 0xFF,
    248653                (unsigned int)(local_ip >> 8) & 0xFF, (unsigned int)(local_ip >> 0) & 0xFF,
    249654                (unsigned int)local_port
     
    252657        return hdhomerun_device_set_tuner_target(hd, target);
    253658}
    254659
     660int hdhomerun_device_set_tuner_target_to_local(struct hdhomerun_device_t *hd)
     661{
     662        return hdhomerun_device_set_tuner_target_to_local_protocol(hd, HDHOMERUN_TARGET_PROTOCOL_UDP);
     663}
     664
    255665int hdhomerun_device_set_ir_target(struct hdhomerun_device_t *hd, const char *target)
    256666{
    257667        return hdhomerun_control_set(hd->cs, "/ir/target", target, NULL, NULL);
    258668}
    259669
     670int hdhomerun_device_set_lineup_location(struct hdhomerun_device_t *hd, const char *location)
     671{
     672        return hdhomerun_control_set(hd->cs, "/lineup/location", location, NULL, NULL);
     673}
     674
    260675int hdhomerun_device_get_var(struct hdhomerun_device_t *hd, const char *name, char **pvalue, char **perror)
    261676{
    262677        return hdhomerun_control_get(hd->cs, name, pvalue, perror);
     
    264679
    265680int hdhomerun_device_set_var(struct hdhomerun_device_t *hd, const char *name, const char *value, char **pvalue, char **perror)
    266681{
    267         return hdhomerun_control_set(hd->cs, name, value, pvalue, perror);
     682        return hdhomerun_control_set_with_lockkey(hd->cs, name, value, hd->lockkey, pvalue, perror);
    268683}
    269684
    270 int hdhomerun_device_stream_start(struct hdhomerun_device_t *hd)
     685int hdhomerun_device_tuner_lockkey_request(struct hdhomerun_device_t *hd, char **perror)
    271686{
    272         /* Create video socket. */
    273         hdhomerun_device_get_video_sock(hd);
    274         if (!hd->vs) {
    275                 return -1;
     687        uint32_t new_lockkey = (uint32_t)getcurrenttime();
     688
     689        char name[32];
     690        sprintf(name, "/tuner%u/lockkey", hd->tuner);
     691
     692        char new_lockkey_str[64];
     693        sprintf(new_lockkey_str, "%u", (unsigned int)new_lockkey);
     694
     695        int ret = hdhomerun_control_set_with_lockkey(hd->cs, name, new_lockkey_str, hd->lockkey, NULL, perror);
     696        if (ret <= 0) {
     697                hd->lockkey = 0;
     698                return ret;
    276699        }
    277700
     701        hd->lockkey = new_lockkey;
     702        return ret;
     703}
     704
     705int hdhomerun_device_tuner_lockkey_release(struct hdhomerun_device_t *hd)
     706{
     707        if (hd->lockkey == 0) {
     708                return 1;
     709        }
     710
     711        char name[32];
     712        sprintf(name, "/tuner%u/lockkey", hd->tuner);
     713        int ret = hdhomerun_control_set_with_lockkey(hd->cs, name, "none", hd->lockkey, NULL, NULL);
     714
     715        hd->lockkey = 0;
     716        return ret;
     717}
     718
     719int hdhomerun_device_tuner_lockkey_force(struct hdhomerun_device_t *hd)
     720{
     721        char name[32];
     722        sprintf(name, "/tuner%u/lockkey", hd->tuner);
     723        int ret = hdhomerun_control_set(hd->cs, name, "force", NULL, NULL);
     724
     725        hd->lockkey = 0;
     726        return ret;
     727}
     728
     729void hdhomerun_device_tuner_lockkey_use_value(struct hdhomerun_device_t *hd, uint32_t lockkey)
     730{
     731        hd->lockkey = lockkey;
     732}
     733
     734int hdhomerun_device_wait_for_lock(struct hdhomerun_device_t *hd, struct hdhomerun_tuner_status_t *status)
     735{
     736        /* Delay for SS reading to be valid (signal present). */
     737        msleep(250);
     738
     739        /* Wait for up to 2.5 seconds for lock. */
     740        uint64_t timeout = getcurrenttime() + 2500;
     741        while (1) {
     742                /* Get status to check for lock. Quality numbers will not be valid yet. */
     743                int ret = hdhomerun_device_get_tuner_status(hd, NULL, status);
     744                if (ret <= 0) {
     745                        return ret;
     746                }
     747
     748                if (!status->signal_present) {
     749                        return 1;
     750                }
     751                if (status->lock_supported || status->lock_unsupported) {
     752                        return 1;
     753                }
     754
     755                if (getcurrenttime() >= timeout) {
     756                        return 1;
     757                }
     758
     759                msleep(250);
     760        }
     761}
     762
     763int hdhomerun_device_stream_start(struct hdhomerun_device_t *hd)
     764{
    278765        /* Set target. */
    279         int ret = hdhomerun_device_set_tuner_target_to_local(hd);
     766        int ret = hdhomerun_device_stream_refresh_target(hd);
    280767        if (ret <= 0) {
    281768                return ret;
    282769        }
    283770
    284771        /* Flush video buffer. */
    285         usleep(64000);
     772        msleep(64);
    286773        hdhomerun_video_flush(hd->vs);
    287774
    288775        /* Success. */
    289776        return 1;
    290777}
    291778
     779int hdhomerun_device_stream_refresh_target(struct hdhomerun_device_t *hd)
     780{
     781        int ret = hdhomerun_device_set_tuner_target_to_local_protocol(hd, HDHOMERUN_TARGET_PROTOCOL_RTP);
     782        if (ret <= 0)
     783                ret = hdhomerun_device_set_tuner_target_to_local_protocol(hd, HDHOMERUN_TARGET_PROTOCOL_UDP);
     784        return ret;
     785}
     786
    292787uint8_t *hdhomerun_device_stream_recv(struct hdhomerun_device_t *hd, size_t max_size, size_t *pactual_size)
    293788{
     789        if (!hd->vs) {
     790                return NULL;
     791        }
    294792        return hdhomerun_video_recv(hd->vs, max_size, pactual_size);
    295793}
    296794
     795void hdhomerun_device_stream_flush(struct hdhomerun_device_t *hd)
     796{
     797        hdhomerun_video_flush(hd->vs);
     798}
     799
    297800void hdhomerun_device_stream_stop(struct hdhomerun_device_t *hd)
    298801{
    299802        hdhomerun_device_set_tuner_target(hd, "none");
    300803}
    301804
     805int hdhomerun_device_channelscan_init(struct hdhomerun_device_t *hd, const char *channelmap)
     806{
     807        if (hd->scan) {
     808                channelscan_destroy(hd->scan);
     809        }
     810
     811        hd->scan = channelscan_create(hd, channelmap);
     812        if (!hd->scan) {
     813                return -1;
     814        }
     815
     816        return 1;
     817}
     818
     819int hdhomerun_device_channelscan_advance(struct hdhomerun_device_t *hd, struct hdhomerun_channelscan_result_t *result)
     820{
     821        if (!hd->scan) {
     822                return 0;
     823        }
     824
     825        int ret = channelscan_advance(hd->scan, result);
     826        if (ret <= 0) {
     827                channelscan_destroy(hd->scan);
     828                hd->scan = NULL;
     829        }
     830
     831        return ret;
     832}
     833
     834int hdhomerun_device_channelscan_detect(struct hdhomerun_device_t *hd, struct hdhomerun_channelscan_result_t *result)
     835{
     836        if (!hd->scan) {
     837                return 0;
     838        }
     839
     840        int ret = channelscan_detect(hd->scan, result);
     841        if (ret <= 0) {
     842                channelscan_destroy(hd->scan);
     843                hd->scan = NULL;
     844        }
     845
     846        return ret;
     847}
     848
     849uint8_t hdhomerun_device_channelscan_get_progress(struct hdhomerun_device_t *hd)
     850{
     851        if (!hd->scan) {
     852                return 0;
     853        }
     854
     855        return channelscan_get_progress(hd->scan);
     856}
     857
    302858int hdhomerun_device_firmware_version_check(struct hdhomerun_device_t *hd, uint32_t features)
    303859{
    304860        uint32_t version;
     
    306862                return -1;
    307863        }
    308864
    309         if (version >= 20061213) {
    310                 return 1;
     865        if (version < 20070219) {
     866                return 0;
    311867        }
    312868
    313         return 0;
     869        return 1;
    314870}
    315871
     872const char *hdhomerun_device_get_model_str(struct hdhomerun_device_t *hd)
     873{
     874        if (*hd->model) {
     875                return hd->model;
     876        }
     877
     878        char *model_str;
     879        int ret = hdhomerun_control_get(hd->cs, "/sys/model", &model_str, NULL);
     880        if (ret < 0) {
     881                return NULL;
     882        }
     883        if (ret == 0) {
     884                model_str = "hdhomerun_atsc";
     885        }
     886
     887        strncpy(hd->model, model_str, sizeof(hd->model) - 1);
     888        hd->model[sizeof(hd->model) - 1] = 0;
     889
     890        return hd->model;
     891}
     892
    316893int hdhomerun_device_upgrade(struct hdhomerun_device_t *hd, FILE *upgrade_file)
    317894{
     895        hdhomerun_control_set(hd->cs, "/tuner0/lockkey", "force", NULL, NULL);
    318896        hdhomerun_control_set(hd->cs, "/tuner0/channel", "none", NULL, NULL);
     897
     898        hdhomerun_control_set(hd->cs, "/tuner1/lockkey", "force", NULL, NULL);
    319899        hdhomerun_control_set(hd->cs, "/tuner1/channel", "none", NULL, NULL);
     900
    320901        return hdhomerun_control_upgrade(hd->cs, upgrade_file);
    321902}
     903
     904void hdhomerun_device_debug_print_video_stats(struct hdhomerun_device_t *hd)
     905{
     906        if (!hdhomerun_debug_enabled(hd->dbg)) {
     907                return;
     908        }
     909
     910        char name[32];
     911        sprintf(name, "/tuner%u/debug", hd->tuner);
     912
     913        char *debug_str;
     914        char *error_str;
     915        int ret = hdhomerun_control_get(hd->cs, name, &debug_str, &error_str);
     916        if (ret < 0) {
     917                hdhomerun_debug_printf(hd->dbg, "video dev: communication error getting debug stats\n");
     918                return;
     919        }
     920
     921        if (error_str) {
     922                hdhomerun_debug_printf(hd->dbg, "video dev: %s\n", error_str);
     923        } else {
     924                hdhomerun_debug_printf(hd->dbg, "video dev: %s\n", debug_str);
     925        }
     926
     927        if (hd->vs) {
     928                hdhomerun_video_debug_print_stats(hd->vs);
     929        }
     930}
     931
     932void hdhomerun_device_get_video_stats(struct hdhomerun_device_t *hd, struct hdhomerun_video_stats_t *stats)
     933{
     934        hdhomerun_video_get_stats(hd->vs, stats);
     935}
  • libs/libmythtv/hdhomerun/hdhomerun_channels.h

     
     1/*
     2 * hdhomerun_channels.h
     3 *
     4 * Copyright © 2007-2008 Silicondust Engineering Ltd. <www.silicondust.com>.
     5 *
     6 * This library is free software; you can redistribute it and/or
     7 * modify it under the terms of the GNU Lesser General Public
     8 * License as published by the Free Software Foundation; either
     9 * version 3 of the License, or (at your option) any later version.
     10 *
     11 * This library is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14 * Lesser General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU Lesser General Public
     17 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
     18 *
     19 * As a special exception to the GNU Lesser General Public License,
     20 * you may link, statically or dynamically, an application with a
     21 * publicly distributed version of the Library to produce an
     22 * executable file containing portions of the Library, and
     23 * distribute that executable file under terms of your choice,
     24 * without any of the additional requirements listed in clause 4 of
     25 * the GNU Lesser General Public License.
     26 *
     27 * By "a publicly distributed version of the Library", we mean
     28 * either the unmodified Library as distributed by Silicondust, or a
     29 * modified version of the Library that is distributed under the
     30 * conditions defined in the GNU Lesser General Public License.
     31 */
     32
     33#ifdef __cplusplus
     34extern "C" {
     35#endif
     36
     37struct hdhomerun_channel_entry_t;
     38struct hdhomerun_channel_list_t;
     39
     40extern LIBTYPE const char *hdhomerun_channelmap_convert_countrycode_to_channelmap_prefix(const char *countrycode);
     41extern LIBTYPE const char *hdhomerun_channelmap_get_channelmap_scan_group(const char *channelmap);
     42
     43extern LIBTYPE uint8_t hdhomerun_channel_entry_channel_number(struct hdhomerun_channel_entry_t *entry);
     44extern LIBTYPE uint32_t hdhomerun_channel_entry_frequency(struct hdhomerun_channel_entry_t *entry);
     45extern LIBTYPE const char *hdhomerun_channel_entry_name(struct hdhomerun_channel_entry_t *entry);
     46
     47extern LIBTYPE struct hdhomerun_channel_list_t *hdhomerun_channel_list_create(const char *channelmap);
     48extern LIBTYPE void hdhomerun_channel_list_destroy(struct hdhomerun_channel_list_t *channel_list);
     49
     50extern LIBTYPE struct hdhomerun_channel_entry_t *hdhomerun_channel_list_first(struct hdhomerun_channel_list_t *channel_list);
     51extern LIBTYPE struct hdhomerun_channel_entry_t *hdhomerun_channel_list_last(struct hdhomerun_channel_list_t *channel_list);
     52extern LIBTYPE struct hdhomerun_channel_entry_t *hdhomerun_channel_list_next(struct hdhomerun_channel_list_t *channel_list, struct hdhomerun_channel_entry_t *entry);
     53extern LIBTYPE struct hdhomerun_channel_entry_t *hdhomerun_channel_list_prev(struct hdhomerun_channel_list_t *channel_list, struct hdhomerun_channel_entry_t *entry);
     54extern LIBTYPE uint32_t hdhomerun_channel_list_total_count(struct hdhomerun_channel_list_t *channel_list);
     55extern LIBTYPE uint32_t hdhomerun_channel_list_frequency_count(struct hdhomerun_channel_list_t *channel_list);
     56
     57extern LIBTYPE uint32_t hdhomerun_channel_frequency_truncate(uint32_t frequency);
     58extern LIBTYPE uint32_t hdhomerun_channel_number_to_frequency(struct hdhomerun_channel_list_t *channel_list, uint8_t channel_number);
     59extern LIBTYPE uint8_t hdhomerun_channel_frequency_to_number(struct hdhomerun_channel_list_t *channel_list, uint32_t frequency);
     60
     61#ifdef __cplusplus
     62}
     63#endif
  • libs/libmythtv/hdhomerun/hdhomerun_os_windows.h

     
     1/*
     2 * hdhomerun_os_windows.h
     3 *
     4 * Copyright © 2006-2008 Silicondust Engineering Ltd. <www.silicondust.com>.
     5 *
     6 * This library is free software; you can redistribute it and/or
     7 * modify it under the terms of the GNU Lesser General Public
     8 * License as published by the Free Software Foundation; either
     9 * version 3 of the License, or (at your option) any later version.
     10 *
     11 * This library is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14 * Lesser General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU Lesser General Public
     17 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
     18 *
     19 * As a special exception to the GNU Lesser General Public License,
     20 * you may link, statically or dynamically, an application with a
     21 * publicly distributed version of the Library to produce an
     22 * executable file containing portions of the Library, and
     23 * distribute that executable file under terms of your choice,
     24 * without any of the additional requirements listed in clause 4 of
     25 * the GNU Lesser General Public License.
     26 *
     27 * By "a publicly distributed version of the Library", we mean
     28 * either the unmodified Library as distributed by Silicondust, or a
     29 * modified version of the Library that is distributed under the
     30 * conditions defined in the GNU Lesser General Public License.
     31 */
     32
     33#define _WINSOCKAPI_
     34#include <windows.h>
     35#include <winsock2.h>
     36#include <ws2tcpip.h>
     37#include <wspiapi.h>
     38#include <stdlib.h>
     39#include <stdio.h>
     40#include <stdarg.h>
     41#include <string.h>
     42#include <signal.h>
     43#include <time.h>
     44#include <sys/types.h>
     45#include <sys/timeb.h>
     46
     47#if defined(DLL_IMPORT)
     48#define LIBTYPE __declspec( dllexport )
     49#elif  defined(DLL_EXPORT)
     50#define LIBTYPE __declspec( dllimport )
     51#else
     52#define LIBTYPE
     53#endif
     54
     55typedef int bool_t;
     56typedef signed __int8 int8_t;
     57typedef signed __int16 int16_t;
     58typedef signed __int32 int32_t;
     59typedef signed __int64 int64_t;
     60typedef unsigned __int8 uint8_t;
     61typedef unsigned __int16 uint16_t;
     62typedef unsigned __int32 uint32_t;
     63typedef unsigned __int64 uint64_t;
     64typedef HANDLE pthread_t;
     65typedef HANDLE pthread_mutex_t;
     66
     67#define socklen_t int
     68#define close closesocket
     69#define sock_getlasterror WSAGetLastError()
     70#define sock_getlasterror_socktimeout (WSAGetLastError() == WSAETIMEDOUT)
     71#define va_copy(x, y) x = y
     72#define atoll _atoi64
     73#define strdup _strdup
     74#define strcasecmp _stricmp
     75#define snprintf _snprintf
     76#define fseeko _fseeki64
     77#define ftello _ftelli64
     78#define THREAD_FUNC_PREFIX DWORD WINAPI
     79#define SIGPIPE SIGABRT
     80
     81static inline int msleep(unsigned int ms)
     82{
     83        Sleep(ms);
     84        return 0;
     85}
     86
     87static inline int sleep(unsigned int sec)
     88{
     89        Sleep(sec * 1000);
     90        return 0;
     91}
     92
     93static inline uint64_t getcurrenttime(void)
     94{
     95        struct timeb tb;
     96        ftime(&tb);
     97        return ((uint64_t)tb.time * 1000) + tb.millitm;
     98}
     99
     100static inline int setsocktimeout(int s, int level, int optname, uint64_t timeout)
     101{
     102        int t = (int)timeout;
     103        return setsockopt(s, level, optname, (char *)&t, sizeof(t));
     104}
     105
     106static inline int pthread_create(pthread_t *tid, void *attr, LPTHREAD_START_ROUTINE start, void *arg)
     107{
     108        *tid = CreateThread(NULL, 0, start, arg, 0, NULL);
     109        if (!*tid) {
     110                return (int)GetLastError();
     111        }
     112        return 0;
     113}
     114
     115static inline int pthread_join(pthread_t tid, void **value_ptr)
     116{
     117        while (1) {
     118                DWORD ExitCode = 0;
     119                if (!GetExitCodeThread(tid, &ExitCode)) {
     120                        return (int)GetLastError();
     121                }
     122                if (ExitCode != STILL_ACTIVE) {
     123                        return 0;
     124                }
     125        }
     126}
     127
     128static inline void pthread_mutex_init(pthread_mutex_t *mutex, void *attr)
     129{
     130        *mutex = CreateMutex(NULL, FALSE, NULL);
     131}
     132
     133static inline void pthread_mutex_lock(pthread_mutex_t *mutex)
     134{
     135        WaitForSingleObject(*mutex, INFINITE);
     136}
     137
     138static inline void pthread_mutex_unlock(pthread_mutex_t *mutex)
     139{
     140        ReleaseMutex(*mutex);
     141}
     142
     143/*
     144 * The console output format should be set to UTF-8, however in XP and Vista this breaks batch file processing.
     145 * Attempting to restore on exit fails to restore if the program is terminated by the user.
     146 * Solution - set the output format each printf.
     147 */
     148static inline void console_vprintf(const char *fmt, va_list ap)
     149{
     150        UINT cp = GetConsoleOutputCP();
     151        SetConsoleOutputCP(CP_UTF8);
     152        vprintf(fmt, ap);
     153        SetConsoleOutputCP(cp);
     154}
     155
     156static inline void console_printf(const char *fmt, ...)
     157{
     158        va_list ap;
     159        va_start(ap, fmt);
     160        console_vprintf(fmt, ap);
     161        va_end(ap);
     162}
  • libs/libmythtv/hdhomerun/hdhomerun_pkt.h

     
    33 *
    44 * Copyright © 2005-2006 Silicondust Engineering Ltd. <www.silicondust.com>.
    55 *
    6  * This library is free software; you can redistribute it and/or
     6 * This library is free software; you can redistribute it and/or 
    77 * modify it under the terms of the GNU Lesser General Public
    88 * License as published by the Free Software Foundation; either
    9  * version 2.1 of the License, or (at your option) any later version.
     9 * version 3 of the License, or (at your option) any later version.
    1010 *
    1111 * This library is distributed in the hope that it will be useful,
    1212 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     
    1414 * Lesser General Public License for more details.
    1515 *
    1616 * You should have received a copy of the GNU Lesser General Public
    17  * License along with this library; if not, write to the Free Software
    18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     17 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
     18 *
     19 * As a special exception to the GNU Lesser General Public License,
     20 * you may link, statically or dynamically, an application with a
     21 * publicly distributed version of the Library to produce an
     22 * executable file containing portions of the Library, and
     23 * distribute that executable file under terms of your choice,
     24 * without any of the additional requirements listed in clause 4 of
     25 * the GNU Lesser General Public License.
     26 *
     27 * By "a publicly distributed version of the Library", we mean
     28 * either the unmodified Library as distributed by Silicondust, or a
     29 * modified version of the Library that is distributed under the
     30 * conditions defined in the GNU Lesser General Public License.
    1931 */
    2032#ifdef __cplusplus
    2133extern "C" {
     
    110122#define HDHOMERUN_DISCOVER_UDP_PORT 65001
    111123#define HDHOMERUN_CONTROL_TCP_PORT 65001
    112124
     125#define HDHOMERUN_MAX_PACKET_SIZE 1460
     126#define HDHOMERUN_MAX_PAYLOAD_SIZE 1452
     127
    113128#define HDHOMERUN_TYPE_DISCOVER_REQ 0x0002
    114129#define HDHOMERUN_TYPE_DISCOVER_RPY 0x0003
    115130#define HDHOMERUN_TYPE_GETSET_REQ 0x0004
     
    121136#define HDHOMERUN_TAG_DEVICE_ID 0x02
    122137#define HDHOMERUN_TAG_GETSET_NAME 0x03
    123138#define HDHOMERUN_TAG_GETSET_VALUE 0x04
     139#define HDHOMERUN_TAG_GETSET_LOCKKEY 0x15
    124140#define HDHOMERUN_TAG_ERROR_MESSAGE 0x05
    125141
    126142#define HDHOMERUN_DEVICE_TYPE_WILDCARD 0xFFFFFFFF
     
    129145
    130146#define HDHOMERUN_MIN_PEEK_LENGTH 4
    131147
    132 extern uint8_t hdhomerun_read_u8(uint8_t **pptr);
    133 extern uint16_t hdhomerun_read_u16(uint8_t **pptr);
    134 extern uint32_t hdhomerun_read_u32(uint8_t **pptr);
    135 extern size_t hdhomerun_read_var_length(uint8_t **pptr, uint8_t *end);
    136 extern void hdhomerun_write_u8(uint8_t **pptr, uint8_t v);
    137 extern void hdhomerun_write_u16(uint8_t **pptr, uint16_t v);
    138 extern void hdhomerun_write_u32(uint8_t **pptr, uint32_t v);
    139 extern void hdhomerun_write_var_length(uint8_t **pptr, size_t v);
    140 extern void hdhomerun_write_crc(uint8_t **pptr, uint8_t *start);
     148struct hdhomerun_pkt_t {
     149        uint8_t *pos;
     150        uint8_t *start;
     151        uint8_t *end;
     152        uint8_t *limit;
     153        uint8_t buffer[3074];
     154};
    141155
    142 extern size_t hdhomerun_peek_packet_length(uint8_t *ptr);
    143 extern int hdhomerun_process_packet(uint8_t **pptr, uint8_t **pend);
    144 extern int hdhomerun_read_tlv(uint8_t **pptr, uint8_t *end, uint8_t *ptag, size_t *plength, uint8_t **pvalue);
     156extern LIBTYPE struct hdhomerun_pkt_t *hdhomerun_pkt_create(void);
     157extern LIBTYPE void hdhomerun_pkt_destroy(struct hdhomerun_pkt_t *pkt);
     158extern LIBTYPE void hdhomerun_pkt_reset(struct hdhomerun_pkt_t *pkt);
    145159
    146 extern void hdhomerun_write_discover_request(uint8_t **pptr, uint32_t device_type, uint32_t device_id);
    147 extern void hdhomerun_write_get_set_request(uint8_t **pptr, const char *name, const char *value);
    148 extern void hdhomerun_write_upgrade_request(uint8_t **pptr, uint32_t sequence, void *data, size_t length);
     160extern LIBTYPE uint8_t hdhomerun_pkt_read_u8(struct hdhomerun_pkt_t *pkt);
     161extern LIBTYPE uint16_t hdhomerun_pkt_read_u16(struct hdhomerun_pkt_t *pkt);
     162extern LIBTYPE uint32_t hdhomerun_pkt_read_u32(struct hdhomerun_pkt_t *pkt);
     163extern LIBTYPE size_t hdhomerun_pkt_read_var_length(struct hdhomerun_pkt_t *pkt);
     164extern LIBTYPE uint8_t *hdhomerun_pkt_read_tlv(struct hdhomerun_pkt_t *pkt, uint8_t *ptag, size_t *plength);
    149165
     166extern LIBTYPE void hdhomerun_pkt_write_u8(struct hdhomerun_pkt_t *pkt, uint8_t v);
     167extern LIBTYPE void hdhomerun_pkt_write_u16(struct hdhomerun_pkt_t *pkt, uint16_t v);
     168extern LIBTYPE void hdhomerun_pkt_write_u32(struct hdhomerun_pkt_t *pkt, uint32_t v);
     169extern LIBTYPE void hdhomerun_pkt_write_var_length(struct hdhomerun_pkt_t *pkt, size_t v);
     170extern LIBTYPE void hdhomerun_pkt_write_mem(struct hdhomerun_pkt_t *pkt, const void *mem, size_t length);
     171
     172extern LIBTYPE bool_t hdhomerun_pkt_open_frame(struct hdhomerun_pkt_t *pkt, uint16_t *ptype);
     173extern LIBTYPE void hdhomerun_pkt_seal_frame(struct hdhomerun_pkt_t *pkt, uint16_t frame_type);
     174
    150175#ifdef __cplusplus
    151176}
    152177#endif
    153 
  • libs/libmythtv/hdhomerun/hdhomerun_device.h

     
    11/*
    22 * hdhomerun_device.h
    33 *
    4  * Copyright © 2006 Silicondust Engineering Ltd. <www.silicondust.com>.
     4 * Copyright © 2006-2008 Silicondust Engineering Ltd. <www.silicondust.com>.
    55 *
    6  * This library is free software; you can redistribute it and/or
     6 * This library is free software; you can redistribute it and/or 
    77 * modify it under the terms of the GNU Lesser General Public
    88 * License as published by the Free Software Foundation; either
    9  * version 2.1 of the License, or (at your option) any later version.
     9 * version 3 of the License, or (at your option) any later version.
    1010 *
    1111 * This library is distributed in the hope that it will be useful,
    1212 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     
    1414 * Lesser General Public License for more details.
    1515 *
    1616 * You should have received a copy of the GNU Lesser General Public
    17  * License along with this library; if not, write to the Free Software
    18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     17 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
     18 *
     19 * As a special exception to the GNU Lesser General Public License,
     20 * you may link, statically or dynamically, an application with a
     21 * publicly distributed version of the Library to produce an
     22 * executable file containing portions of the Library, and
     23 * distribute that executable file under terms of your choice,
     24 * without any of the additional requirements listed in clause 4 of
     25 * the GNU Lesser General Public License.
     26 *
     27 * By "a publicly distributed version of the Library", we mean
     28 * either the unmodified Library as distributed by Silicondust, or a
     29 * modified version of the Library that is distributed under the
     30 * conditions defined in the GNU Lesser General Public License.
    1931 */
    2032
    2133#ifdef __cplusplus
     
    2638#define HDHOMERUN_DEVICE_MAX_LOCK_TO_DATA_TIME 2000
    2739#define HDHOMERUN_DEVICE_MAX_TUNE_TO_DATA_TIME (HDHOMERUN_DEVICE_MAX_TUNE_TO_LOCK_TIME + HDHOMERUN_DEVICE_MAX_LOCK_TO_DATA_TIME)
    2840
    29 struct hdhomerun_device_t;
     41#define HDHOMERUN_STATUS_COLOR_NEUTRAL  0xFFFFFFFF
     42#define HDHOMERUN_STATUS_COLOR_RED              0xFFFF0000
     43#define HDHOMERUN_STATUS_COLOR_YELLOW   0xFFFFFF00
     44#define HDHOMERUN_STATUS_COLOR_GREEN    0xFF00C000
    3045
    31 struct hdhomerun_tuner_status_t {
    32         char channel[32];
    33         unsigned int signal_strength;
    34         unsigned int signal_to_noise_quality;
    35         unsigned int symbol_error_quality;
    36         uint32_t raw_bits_per_second;
    37         uint32_t packets_per_second;
    38 };
     46#define HDHOMERUN_TARGET_PROTOCOL_UDP "udp"
     47#define HDHOMERUN_TARGET_PROTOCOL_RTP "rtp"
    3948
    4049/*
    4150 * Create a device object.
     
    5362 * uint32_t device_id = 32-bit device id of device. Set to HDHOMERUN_DEVICE_ID_WILDCARD to match any device ID.
    5463 * uint32_t device_ip = IP address of device. Set to 0 to auto-detect.
    5564 * unsigned int tuner = tuner index (0 or 1). Can be changed later by calling hdhomerun_device_set_tuner.
     65 * struct hdhomerun_debug_t *dbg: Pointer to debug logging object. May be NULL.
    5666 *
    5767 * Returns a pointer to the newly created device object.
    5868 *
    5969 * When no longer needed, the socket should be destroyed by calling hdhomerun_device_destroy.
     70 *
     71 * The hdhomerun_device_create_from_str function creates a device object from the given device_str.
     72 * The device_str parameter can be any of the following forms:
     73 *     <device id>
     74 *     <device id>-<tuner index>
     75 *     <ip address>
     76 * If the tuner index is not included in the device_str then it is set to zero.
     77 * Use hdhomerun_device_set_tuner or hdhomerun_device_set_tuner_from_str to set the tuner.
     78 *
     79 * The hdhomerun_device_set_tuner_from_str function sets the tuner from the given tuner_str.
     80 * The tuner_str parameter can be any of the following forms:
     81 *     <tuner index>
     82 *     /tuner<tuner index>
    6083 */
    61 extern struct hdhomerun_device_t *hdhomerun_device_create(uint32_t device_id, uint32_t device_ip, unsigned int tuner);
    62 extern void hdhomerun_device_destroy(struct hdhomerun_device_t *hd);
    63 extern void hdhomerun_device_set_tuner(struct hdhomerun_device_t *hd, unsigned int tuner);
     84extern LIBTYPE struct hdhomerun_device_t *hdhomerun_device_create(uint32_t device_id, uint32_t device_ip, unsigned int tuner, struct hdhomerun_debug_t *dbg);
     85extern LIBTYPE struct hdhomerun_device_t *hdhomerun_device_create_from_str(const char *device_str, struct hdhomerun_debug_t *dbg);
     86extern LIBTYPE void hdhomerun_device_destroy(struct hdhomerun_device_t *hd);
    6487
    6588/*
     89 * Get the device id, ip, or tuner of the device instance.
     90 */
     91extern LIBTYPE uint32_t hdhomerun_device_get_device_id(struct hdhomerun_device_t *hd);
     92extern LIBTYPE uint32_t hdhomerun_device_get_device_ip(struct hdhomerun_device_t *hd);
     93extern LIBTYPE uint32_t hdhomerun_device_get_device_id_requested(struct hdhomerun_device_t *hd);
     94extern LIBTYPE uint32_t hdhomerun_device_get_device_ip_requested(struct hdhomerun_device_t *hd);
     95extern LIBTYPE unsigned int hdhomerun_device_get_tuner(struct hdhomerun_device_t *hd);
     96
     97extern LIBTYPE void hdhomerun_device_set_device(struct hdhomerun_device_t *hd, uint32_t device_id, uint32_t device_ip);
     98extern LIBTYPE void hdhomerun_device_set_tuner(struct hdhomerun_device_t *hd, unsigned int tuner);
     99extern LIBTYPE int hdhomerun_device_set_tuner_from_str(struct hdhomerun_device_t *hd, const char *tuner_str);
     100
     101/*
    66102 * Get the local machine IP address used when communicating with the device.
    67103 *
    68104 * This function is useful for determining the IP address to use with set target commands.
    69105 *
    70106 * Returns 32-bit IP address with native endianness, or 0 on error.
    71107 */
    72 extern uint32_t hdhomerun_device_get_local_machine_addr(struct hdhomerun_device_t *hd);
     108extern LIBTYPE uint32_t hdhomerun_device_get_local_machine_addr(struct hdhomerun_device_t *hd);
    73109
    74110/*
    75111 * Get operations.
     
    82118 * Returns 0 if the operation was rejected.
    83119 * Returns -1 if a communication error occurred.
    84120 */
    85 extern int hdhomerun_device_get_tuner_status(struct hdhomerun_device_t *hd, struct hdhomerun_tuner_status_t *status);
    86 extern int hdhomerun_device_get_tuner_streaminfo(struct hdhomerun_device_t *hd, char **pstreaminfo);
    87 extern int hdhomerun_device_get_tuner_channel(struct hdhomerun_device_t *hd, char **pchannel);
    88 extern int hdhomerun_device_get_tuner_channelmap(struct hdhomerun_device_t *hd, char **pchannelmap);
    89 extern int hdhomerun_device_get_tuner_filter(struct hdhomerun_device_t *hd, char **pfilter);
    90 extern int hdhomerun_device_get_tuner_program(struct hdhomerun_device_t *hd, uint16_t *pprogram_number);
    91 extern int hdhomerun_device_get_tuner_target(struct hdhomerun_device_t *hd, char **ptarget);
    92 extern int hdhomerun_device_get_ir_target(struct hdhomerun_device_t *hd, char **ptarget);
    93 extern int hdhomerun_device_get_version(struct hdhomerun_device_t *hd, char **pversion_str, uint32_t *pversion_num);
     121extern LIBTYPE int hdhomerun_device_get_tuner_status(struct hdhomerun_device_t *hd, char **pstatus_str, struct hdhomerun_tuner_status_t *status);
     122extern LIBTYPE int hdhomerun_device_get_tuner_streaminfo(struct hdhomerun_device_t *hd, char **pstreaminfo);
     123extern LIBTYPE int hdhomerun_device_get_tuner_channel(struct hdhomerun_device_t *hd, char **pchannel);
     124extern LIBTYPE int hdhomerun_device_get_tuner_channelmap(struct hdhomerun_device_t *hd, char **pchannelmap);
     125extern LIBTYPE int hdhomerun_device_get_tuner_filter(struct hdhomerun_device_t *hd, char **pfilter);
     126extern LIBTYPE int hdhomerun_device_get_tuner_program(struct hdhomerun_device_t *hd, char **pprogram);
     127extern LIBTYPE int hdhomerun_device_get_tuner_target(struct hdhomerun_device_t *hd, char **ptarget);
     128extern LIBTYPE int hdhomerun_device_get_tuner_plotsample(struct hdhomerun_device_t *hd, struct hdhomerun_plotsample_t **psamples, size_t *pcount);
     129extern LIBTYPE int hdhomerun_device_get_tuner_lockkey_owner(struct hdhomerun_device_t *hd, char **powner);
     130extern LIBTYPE int hdhomerun_device_get_ir_target(struct hdhomerun_device_t *hd, char **ptarget);
     131extern LIBTYPE int hdhomerun_device_get_lineup_location(struct hdhomerun_device_t *hd, char **plocation);
     132extern LIBTYPE int hdhomerun_device_get_version(struct hdhomerun_device_t *hd, char **pversion_str, uint32_t *pversion_num);
    94133
     134extern LIBTYPE uint32_t hdhomerun_device_get_tuner_status_ss_color(struct hdhomerun_tuner_status_t *status);
     135extern LIBTYPE uint32_t hdhomerun_device_get_tuner_status_snq_color(struct hdhomerun_tuner_status_t *status);
     136extern LIBTYPE uint32_t hdhomerun_device_get_tuner_status_seq_color(struct hdhomerun_tuner_status_t *status);
     137
     138extern LIBTYPE const char *hdhomerun_device_get_model_str(struct hdhomerun_device_t *hd);
     139
    95140/*
    96141 * Set operations.
    97142 *
     
    101146 * Returns 0 if the operation was rejected.
    102147 * Returns -1 if a communication error occurred.
    103148 */
    104 extern int hdhomerun_device_set_tuner_channel(struct hdhomerun_device_t *hd, const char *channel);
    105 extern int hdhomerun_device_set_tuner_channelmap(struct hdhomerun_device_t *hd, const char *channelmap);
    106 extern int hdhomerun_device_set_tuner_filter(struct hdhomerun_device_t *hd, const char *filter);
    107 extern int hdhomerun_device_set_tuner_program(struct hdhomerun_device_t *hd, uint16_t program_number);
    108 extern int hdhomerun_device_set_tuner_target(struct hdhomerun_device_t *hd, char *target);
    109 extern int hdhomerun_device_set_ir_target(struct hdhomerun_device_t *hd, const char *target);
     149extern LIBTYPE int hdhomerun_device_set_tuner_channel(struct hdhomerun_device_t *hd, const char *channel);
     150extern LIBTYPE int hdhomerun_device_set_tuner_channelmap(struct hdhomerun_device_t *hd, const char *channelmap);
     151extern LIBTYPE int hdhomerun_device_set_tuner_filter(struct hdhomerun_device_t *hd, const char *filter);
     152extern LIBTYPE int hdhomerun_device_set_tuner_filter_by_array(struct hdhomerun_device_t *hd, unsigned char filter_array[0x2000]);
     153extern LIBTYPE int hdhomerun_device_set_tuner_program(struct hdhomerun_device_t *hd, const char *program);
     154extern LIBTYPE int hdhomerun_device_set_tuner_target(struct hdhomerun_device_t *hd, const char *target);
     155extern LIBTYPE int hdhomerun_device_set_tuner_target_to_local_protocol(struct hdhomerun_device_t *hd, const char *protocol);
     156extern LIBTYPE int hdhomerun_device_set_tuner_target_to_local(struct hdhomerun_device_t *hd);
     157extern LIBTYPE int hdhomerun_device_set_ir_target(struct hdhomerun_device_t *hd, const char *target);
     158extern LIBTYPE int hdhomerun_device_set_lineup_location(struct hdhomerun_device_t *hd, const char *location);
    110159
    111160/*
    112161 * Get/set a named control variable on the device.
     
    125174 * Returns 0 if the operation was rejected (pvalue NULL, perror set).
    126175 * Returns -1 if a communication error occurs.
    127176 */
    128 extern int hdhomerun_device_get_var(struct hdhomerun_device_t *hd, const char *name, char **pvalue, char **perror);
    129 extern int hdhomerun_device_set_var(struct hdhomerun_device_t *hd, const char *name, const char *value, char **pvalue, char **perror);
     177extern LIBTYPE int hdhomerun_device_get_var(struct hdhomerun_device_t *hd, const char *name, char **pvalue, char **perror);
     178extern LIBTYPE int hdhomerun_device_set_var(struct hdhomerun_device_t *hd, const char *name, const char *value, char **pvalue, char **perror);
    130179
    131180/*
     181 * Tuner locking.
     182 *
     183 * The hdhomerun_device_tuner_lockkey_request function is used to obtain a lock
     184 * or to verify that the hdhomerun_device object still holds the lock.
     185 * Returns 1 if the lock request was successful and the lock was obtained.
     186 * Returns 0 if the lock request was rejected.
     187 * Returns -1 if a communication error occurs.
     188 *
     189 * The hdhomerun_device_tuner_lockkey_release function is used to release a
     190 * previously held lock. If locking is used then this function must be called
     191 * before destroying the hdhomerun_device object.
     192 */
     193extern LIBTYPE int hdhomerun_device_tuner_lockkey_request(struct hdhomerun_device_t *hd, char **perror);
     194extern LIBTYPE int hdhomerun_device_tuner_lockkey_release(struct hdhomerun_device_t *hd);
     195extern LIBTYPE int hdhomerun_device_tuner_lockkey_force(struct hdhomerun_device_t *hd);
     196
     197/*
     198 * Intended only for non persistent connections; eg, hdhomerun_config.
     199 */
     200extern LIBTYPE void hdhomerun_device_tuner_lockkey_use_value(struct hdhomerun_device_t *hd, uint32_t lockkey);
     201
     202/*
     203 * Wait for tuner lock after channel change.
     204 *
     205 * The hdhomerun_device_wait_for_lock function is used to detect/wait for a lock vs no lock indication
     206 * after a channel change.
     207 *
     208 * It will return quickly if a lock is aquired.
     209 * It will return quickly if there is no signal detected.
     210 * Worst case it will time out after 1.5 seconds - the case where there is signal but no lock.
     211 */
     212extern LIBTYPE int hdhomerun_device_wait_for_lock(struct hdhomerun_device_t *hd, struct hdhomerun_tuner_status_t *status);
     213
     214/*
    132215 * Stream a filtered program or the unfiltered stream.
    133216 *
    134217 * The hdhomerun_device_stream_start function initializes the process and tells the device to start streamin data.
     
    144227 *
    145228 * The hdhomerun_device_stream_stop function tells the device to stop streaming data.
    146229 */
    147 extern int hdhomerun_device_stream_start(struct hdhomerun_device_t *hd);
    148 extern uint8_t *hdhomerun_device_stream_recv(struct hdhomerun_device_t *hd, size_t max_size, size_t *pactual_size);
    149 extern void hdhomerun_device_stream_stop(struct hdhomerun_device_t *hd);
     230extern LIBTYPE int hdhomerun_device_stream_start(struct hdhomerun_device_t *hd);
     231extern LIBTYPE int hdhomerun_device_stream_refresh_target(struct hdhomerun_device_t *hd);
     232extern LIBTYPE uint8_t *hdhomerun_device_stream_recv(struct hdhomerun_device_t *hd, size_t max_size, size_t *pactual_size);
     233extern LIBTYPE void hdhomerun_device_stream_flush(struct hdhomerun_device_t *hd);
     234extern LIBTYPE void hdhomerun_device_stream_stop(struct hdhomerun_device_t *hd);
    150235
    151236/*
     237 * Channel scan API.
     238 */
     239extern LIBTYPE int hdhomerun_device_channelscan_init(struct hdhomerun_device_t *hd, const char *channelmap);
     240extern LIBTYPE int hdhomerun_device_channelscan_advance(struct hdhomerun_device_t *hd, struct hdhomerun_channelscan_result_t *result);
     241extern LIBTYPE int hdhomerun_device_channelscan_detect(struct hdhomerun_device_t *hd, struct hdhomerun_channelscan_result_t *result);
     242extern LIBTYPE uint8_t hdhomerun_device_channelscan_get_progress(struct hdhomerun_device_t *hd);
     243
     244/*
    152245 * Check that the device is running the recommended firmware.
    153246 *
    154247 * uint32_t features: Reserved for future use. Set to zero.
     
    157250 * Returns 0 if th firmware does not meet the minimum requriements for all operations.
    158251 * Returns -1 if an error occurs.
    159252 */
    160 extern int hdhomerun_device_firmware_version_check(struct hdhomerun_device_t *hd, uint32_t features);
     253extern LIBTYPE int hdhomerun_device_firmware_version_check(struct hdhomerun_device_t *hd, uint32_t features);
    161254
    162255/*
    163256 * Upload new firmware to the device.
     
    168261 * Returns 0 if the upload was rejected.
    169262 * Returns -1 if an error occurs.
    170263 */
    171 extern int hdhomerun_device_upgrade(struct hdhomerun_device_t *hd, FILE *upgrade_file);
     264extern LIBTYPE int hdhomerun_device_upgrade(struct hdhomerun_device_t *hd, FILE *upgrade_file);
    172265
    173266/*
    174267 * Low level accessor functions.
    175268 */
    176 extern struct hdhomerun_control_sock_t *hdhomerun_device_get_control_sock(struct hdhomerun_device_t *hd);
    177 extern struct hdhomerun_video_sock_t *hdhomerun_device_get_video_sock(struct hdhomerun_device_t *hd);
     269extern LIBTYPE struct hdhomerun_control_sock_t *hdhomerun_device_get_control_sock(struct hdhomerun_device_t *hd);
     270extern LIBTYPE struct hdhomerun_video_sock_t *hdhomerun_device_get_video_sock(struct hdhomerun_device_t *hd);
    178271
     272/*
     273 * Debug print internal stats.
     274 */
     275extern LIBTYPE void hdhomerun_device_debug_print_video_stats(struct hdhomerun_device_t *hd);
     276extern LIBTYPE void hdhomerun_device_get_video_stats(struct hdhomerun_device_t *hd, struct hdhomerun_video_stats_t *stats);
     277
    179278#ifdef __cplusplus
    180279}
    181280#endif
  • libs/libmythtv/hdhomerun/hdhomerun_config.c

     
    11/*
    22 * hdhomerun_config.c
    33 *
    4  * Copyright © 2006 Silicondust Engineering Ltd. <www.silicondust.com>.
     4 * Copyright © 2006-2008 Silicondust Engineering Ltd. <www.silicondust.com>.
    55 *
    6  * This library is free software; you can redistribute it and/or
     6 * This library is free software; you can redistribute it and/or 
    77 * modify it under the terms of the GNU Lesser General Public
    88 * License as published by the Free Software Foundation; either
    9  * version 2.1 of the License, or (at your option) any later version.
     9 * version 3 of the License, or (at your option) any later version.
    1010 *
    1111 * This library is distributed in the hope that it will be useful,
    1212 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     
    1414 * Lesser General Public License for more details.
    1515 *
    1616 * You should have received a copy of the GNU Lesser General Public
    17  * License along with this library; if not, write to the Free Software
    18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     17 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
     18 *
     19 * As a special exception to the GNU Lesser General Public License,
     20 * you may link, statically or dynamically, an application with a
     21 * publicly distributed version of the Library to produce an
     22 * executable file containing portions of the Library, and
     23 * distribute that executable file under terms of your choice,
     24 * without any of the additional requirements listed in clause 4 of
     25 * the GNU Lesser General Public License.
     26 *
     27 * By "a publicly distributed version of the Library", we mean
     28 * either the unmodified Library as distributed by Silicondust, or a
     29 * modified version of the Library that is distributed under the
     30 * conditions defined in the GNU Lesser General Public License.
    1931 */
    2032
    2133#include "hdhomerun.h"
    2234
     35/*
     36 * The console output format should be set to UTF-8, however in XP and Vista this breaks batch file processing.
     37 * Attempting to restore on exit fails to restore if the program is terminated by the user.
     38 * Solution - set the output format each printf.
     39 */
     40#if defined(__WINDOWS__)
     41#define printf console_printf
     42#define vprintf console_vprintf
     43#endif
     44
    2345static const char *appname;
    2446
    2547struct hdhomerun_device_t *hd;
     
    3153        printf("\t%s <id> get help\n", appname);
    3254        printf("\t%s <id> get <item>\n", appname);
    3355        printf("\t%s <id> set <item> <value>\n", appname);
    34         printf("\t%s <id> scan <tuner> <starting channel>\n", appname);
     56        printf("\t%s <id> scan <tuner> [<filename>]\n", appname);
     57        printf("\t%s <id> save <tuner> <filename>\n", appname);
    3558        printf("\t%s <id> upgrade <filename>\n", appname);
    3659        return -1;
    3760}
     
    6891        return FALSE;
    6992}
    7093
    71 static int discover_print(void)
     94static uint32_t parse_ip_addr(const char *str)
    7295{
     96        unsigned long a[4];
     97        if (sscanf(str, "%lu.%lu.%lu.%lu", &a[0], &a[1], &a[2], &a[3]) != 4) {
     98                return 0;
     99        }
     100
     101        return (uint32_t)((a[0] << 24) | (a[1] << 16) | (a[2] << 8) | (a[3] << 0));
     102}
     103
     104static int discover_print(char *target_ip_str)
     105{
     106        uint32_t target_ip = 0;
     107        if (target_ip_str) {
     108                target_ip = parse_ip_addr(target_ip_str);
     109                if (target_ip == 0) {
     110                        fprintf(stderr, "invalid ip address: %s\n", target_ip_str);
     111                        return -1;
     112                }
     113        }
     114
    73115        struct hdhomerun_discover_device_t result_list[64];
    74         int count = hdhomerun_discover_find_devices(HDHOMERUN_DEVICE_TYPE_TUNER, result_list, 64);
     116        int count = hdhomerun_discover_find_devices_custom(target_ip, HDHOMERUN_DEVICE_TYPE_TUNER, HDHOMERUN_DEVICE_ID_WILDCARD, result_list, 64);
    75117        if (count < 0) {
    76118                fprintf(stderr, "error sending discover request\n");
    77119                return -1;
     
    94136        return count;
    95137}
    96138
    97 static bool_t parse_device_id_str(const char *s, uint32_t *pdevice_id, uint32_t *pdevice_ip)
    98 {
    99         unsigned long a[4];
    100         if (sscanf(s, "%lu.%lu.%lu.%lu", &a[0], &a[1], &a[2], &a[3]) == 4) {
    101                 *pdevice_id = HDHOMERUN_DEVICE_ID_WILDCARD;
    102                 *pdevice_ip = (uint32_t)((a[0] << 24) | (a[1] << 16) | (a[2] << 8) | (a[3] << 0));
    103                 return TRUE;
    104         }
    105 
    106         unsigned long device_id_raw;
    107         if (sscanf(s, "%lx", &device_id_raw) != 1) {
    108                 fprintf(stderr, "invalid device id: %s\n", s);
    109                 return FALSE;
    110         }
    111 
    112         uint32_t device_id = (uint32_t)device_id_raw;
    113         if (!hdhomerun_discover_validate_device_id(device_id)) {
    114                 fprintf(stderr, "invalid device id: %s\n", s);
    115                 return FALSE;
    116         }
    117 
    118         *pdevice_id = device_id;
    119         *pdevice_ip = 0;
    120         return TRUE;
    121 }
    122 
    123139static int cmd_get(const char *item)
    124140{
    125141        char *ret_value;
     
    138154        return 1;
    139155}
    140156
    141 static int cmd_set(const char *item, const char *value)
     157static int cmd_set_internal(const char *item, const char *value)
    142158{
    143159        char *ret_error;
    144160        if (hdhomerun_device_set_var(hd, item, value, NULL, &ret_error) < 0) {
     
    154170        return 1;
    155171}
    156172
    157 static int cmd_streaminfo(const char *tuner_str)
     173static int cmd_set(const char *item, const char *value)
    158174{
    159         fprintf(stderr, "streaminfo: use \"get /tuner<n>/streaminfo\"\n");
    160         return -1;
     175        if (strcmp(value, "-") == 0) {
     176                char *buffer = NULL;
     177                size_t pos = 0;
     178
     179                while (1) {
     180                        buffer = (char *)realloc(buffer, pos + 1024);
     181                        if (!buffer) {
     182                                fprintf(stderr, "out of memory\n");
     183                                return -1;
     184                        }
     185
     186                        size_t size = fread(buffer + pos, 1, 1024, stdin);
     187                        pos += size;
     188
     189                        if (size < 1024) {
     190                                break;
     191                        }
     192                }
     193
     194                buffer[pos] = 0;
     195
     196                int ret = cmd_set_internal(item, buffer);
     197
     198                free(buffer);
     199                return ret;
     200        }
     201
     202        return cmd_set_internal(item, value);
    161203}
    162204
    163 static int cmd_scan(const char *tuner_str, const char *start_value)
     205static void cmd_scan_printf(FILE *fp, const char *fmt, ...)
    164206{
    165         unsigned int tuner;
    166         if (sscanf(tuner_str, "%u", &tuner) != 1) {
    167                 fprintf(stderr, "invalid tuner number\n");
    168                 return -1;
     207        va_list ap;
     208        va_start(ap, fmt);
     209
     210        if (fp) {
     211                va_list apc;
     212                va_copy(apc, ap);
     213
     214                vfprintf(fp, fmt, apc);
     215                fflush(fp);
     216
     217                va_end(apc);
    169218        }
    170219
    171         hdhomerun_device_set_tuner(hd, tuner);
     220        vprintf(fmt, ap);
     221        fflush(stdout);
    172222
    173         char channel_str[64];
    174         strncpy(channel_str, start_value, sizeof(channel_str));
    175         channel_str[sizeof(channel_str) - 8] = 0;
     223        va_end(ap);
     224}
    176225
    177         char *channel_number_ptr = strrchr(channel_str, ':');
    178         if (!channel_number_ptr) {
    179                 channel_number_ptr = channel_str;
    180         } else {
    181                 channel_number_ptr++;
     226static int cmd_scan(const char *tuner_str, const char *filename)
     227{
     228        if (hdhomerun_device_set_tuner_from_str(hd, tuner_str) <= 0) {
     229                fprintf(stderr, "invalid tuner number\n");
     230                return -1;
    182231        }
    183232
    184         unsigned int channel_number = atol(channel_number_ptr);
    185         if (channel_number == 0) {
    186                 fprintf(stderr, "invalid starting channel\n");
     233        char *channelmap;
     234        if (hdhomerun_device_get_tuner_channelmap(hd, &channelmap) <= 0) {
     235                fprintf(stderr, "failed to query channelmap from device\n");
    187236                return -1;
    188237        }
    189238
    190         /* Test starting channel. */
    191         int ret = hdhomerun_device_set_tuner_channel(hd, channel_str);
    192         if (ret < 0) {
    193                 fprintf(stderr, "communication error sending request to hdhomerun device\n");
     239        const char *channelmap_scan_group = hdhomerun_channelmap_get_channelmap_scan_group(channelmap);
     240        if (!channelmap_scan_group) {
     241                fprintf(stderr, "unknown channelmap '%s'\n", channelmap);
    194242                return -1;
    195243        }
    196         if (ret == 0) {
    197                 fprintf(stderr, "invalid starting channel\n");
     244
     245        if (hdhomerun_device_channelscan_init(hd, channelmap_scan_group) <= 0) {
     246                fprintf(stderr, "failed to initialize channel scan\n");
    198247                return -1;
    199248        }
    200249
    201         while (1) {
    202                 /* Update channel value */
    203                 sprintf(channel_number_ptr, "%u", channel_number);
    204 
    205                 /* Set channel. */
    206                 ret = hdhomerun_device_set_tuner_channel(hd, channel_str);
    207                 if (ret < 0) {
    208                         fprintf(stderr, "communication error sending request to hdhomerun device\n");
     250        FILE *fp = NULL;
     251        if (filename) {
     252                fp = fopen(filename, "w");
     253                if (!fp) {
     254                        fprintf(stderr, "unable to create file: %s\n", filename);
    209255                        return -1;
    210256                }
    211                 if (ret == 0) {
    212                         return 0;
     257        }
     258
     259        int ret;
     260        while (1) {
     261                struct hdhomerun_channelscan_result_t result;
     262                ret = hdhomerun_device_channelscan_advance(hd, &result);
     263                if (ret <= 0) {
     264                        break;
    213265                }
    214266
    215                 /* Wait 1.5s for lock (qam auto is the slowest to lock). */
    216                 usleep(HDHOMERUN_DEVICE_MAX_TUNE_TO_LOCK_TIME * 1000);
     267                cmd_scan_printf(fp, "SCANNING: %lu (%s)\n",
     268                        result.frequency, result.channel_str
     269                );
    217270
    218                 /* Get status to check for signal. Quality numbers will not be valid yet. */
    219                 struct hdhomerun_tuner_status_t status;
    220                 if (hdhomerun_device_get_tuner_status(hd, &status) < 0) {
    221                         fprintf(stderr, "communication error sending request to hdhomerun device\n");
    222                         return -1;
     271                ret = hdhomerun_device_channelscan_detect(hd, &result);
     272                if (ret <= 0) {
     273                        break;
    223274                }
    224275
    225                 /* If no signal then advance to next channel. */
    226                 if (status.signal_strength == 0) {
    227                         printf("%s: no signal\n", channel_str);
    228                         channel_number++;
    229                         continue;
     276                cmd_scan_printf(fp, "LOCK: %s (ss=%u snq=%u seq=%u)\n",
     277                        result.status.lock_str, result.status.signal_strength,
     278                        result.status.signal_to_noise_quality, result.status.symbol_error_quality
     279                );
     280
     281                int i;
     282                for (i = 0; i < result.program_count; i++) {
     283                        struct hdhomerun_channelscan_program_t *program = &result.programs[i];
     284                        cmd_scan_printf(fp, "PROGRAM %s\n", program->program_str);
    230285                }
     286        }
    231287
    232                 /* Wait for 2s. */
    233                 usleep(HDHOMERUN_DEVICE_MAX_LOCK_TO_DATA_TIME * 1000);
     288        if (fp) {
     289                fclose(fp);
     290        }
     291        if (ret < 0) {
     292                fprintf(stderr, "communication error sending request to hdhomerun device\n");
     293        }
     294        return ret;
     295}
    234296
    235                 /* Get status to check quality numbers. */
    236                 if (hdhomerun_device_get_tuner_status(hd, &status) < 0) {
    237                         fprintf(stderr, "communication error sending request to hdhomerun device\n");
     297static bool_t cmd_saving = FALSE;
     298
     299static void cmd_save_abort(int arg)
     300{
     301        cmd_saving = FALSE;
     302}
     303
     304static int cmd_save(const char *tuner_str, const char *filename)
     305{
     306        if (hdhomerun_device_set_tuner_from_str(hd, tuner_str) <= 0) {
     307                fprintf(stderr, "invalid tuner number\n");
     308                return -1;
     309        }
     310
     311        FILE *fp;
     312        if (strcmp(filename, "null") == 0) {
     313                fp = NULL;
     314        } else if (strcmp(filename, "-") == 0) {
     315                fp = stdout;
     316        } else {
     317                fp = fopen(filename, "wb");
     318                if (!fp) {
     319                        fprintf(stderr, "unable to create file %s\n", filename);
    238320                        return -1;
    239321                }
    240                 if (status.signal_strength == 0) {
    241                         printf("%s: no signal\n", channel_str);
    242                         channel_number++;
     322        }
     323
     324        int ret = hdhomerun_device_stream_start(hd);
     325        if (ret <= 0) {
     326                fprintf(stderr, "unable to start stream\n");
     327                return ret;
     328        }
     329
     330        signal(SIGINT, cmd_save_abort);
     331        signal(SIGPIPE, cmd_save_abort);
     332
     333        struct hdhomerun_video_stats_t stats_old, stats_cur;
     334        hdhomerun_device_get_video_stats(hd, &stats_old);
     335
     336        uint64_t next_progress = getcurrenttime() + 1000;
     337
     338        cmd_saving = TRUE;
     339        while (cmd_saving) {
     340                uint64_t loop_start_time = getcurrenttime();
     341
     342                size_t actual_size;
     343                uint8_t *ptr = hdhomerun_device_stream_recv(hd, VIDEO_DATA_BUFFER_SIZE_1S, &actual_size);
     344                if (!ptr) {
     345                        msleep(64);
    243346                        continue;
    244347                }
    245                 printf("%s: ss=%u snq=%u seq=%u\n", channel_str, status.signal_strength, status.signal_to_noise_quality, status.symbol_error_quality);
    246348
    247                 /* Detect sub channels. */
    248                 usleep(4 * 1000000);
    249                 char *streaminfo;
    250                 if (hdhomerun_device_get_tuner_streaminfo(hd, &streaminfo) <= 0) {
    251                         channel_number++;
    252                         continue;
     349                if (fp) {
     350                        if (fwrite(ptr, 1, actual_size, fp) != actual_size) {
     351                                fprintf(stderr, "error writing output\n");
     352                                return -1;
     353                        }
    253354                }
    254                 while (1) {
    255                         char *end = strchr(streaminfo, '\n');
    256                         if (!end) {
    257                                 break;
     355
     356                if (loop_start_time >= next_progress) {
     357                        next_progress += 1000;
     358                        if (loop_start_time >= next_progress) {
     359                                next_progress = loop_start_time + 1000;
    258360                        }
    259361
    260                         *end++ = 0;
    261                         printf("program %s\n", streaminfo);
     362                        hdhomerun_device_get_video_stats(hd, &stats_cur);
    262363
    263                         streaminfo = end;
     364                        if (stats_cur.overflow_error_count > stats_old.overflow_error_count) {
     365                                fprintf(stderr, "o");
     366                        } else if (stats_cur.network_error_count > stats_old.network_error_count) {
     367                                fprintf(stderr, "n");
     368                        } else if (stats_cur.transport_error_count > stats_old.transport_error_count) {
     369                                fprintf(stderr, "t");
     370                        } else if (stats_cur.sequence_error_count > stats_old.sequence_error_count) {
     371                                fprintf(stderr, "s");
     372                        } else {
     373                                fprintf(stderr, ".");
     374                        }
     375
     376                        stats_old = stats_cur;
     377                        fflush(stderr);
    264378                }
    265379
    266                 /* Advance to next channel. */
    267                 channel_number++;
     380                int32_t delay = 64 - (int32_t)(getcurrenttime() - loop_start_time);
     381                if (delay <= 0) {
     382                        continue;
     383                }
     384
     385                msleep(delay);
    268386        }
     387
     388        if (fp) {
     389                fclose(fp);
     390        }
     391
     392        hdhomerun_device_stream_stop(hd);
     393        hdhomerun_device_get_video_stats(hd, &stats_cur);
     394
     395        fprintf(stderr, "\n");
     396        fprintf(stderr, "-- Video statistics --\n");
     397        fprintf(stderr, "%u packets received, %u overflow errors, %u network errors, %u transport errors, %u sequence errors\n",
     398                (unsigned int)stats_cur.packet_count,
     399                (unsigned int)stats_cur.overflow_error_count,
     400                (unsigned int)stats_cur.network_error_count,
     401                (unsigned int)stats_cur.transport_error_count,
     402                (unsigned int)stats_cur.sequence_error_count);
     403
     404        return 0;
    269405}
    270406
    271407static int cmd_upgrade(const char *filename)
     
    276412                return -1;
    277413        }
    278414
     415        printf("uploading firmware...\n");
    279416        if (hdhomerun_device_upgrade(hd, fp) <= 0) {
    280417                fprintf(stderr, "error sending upgrade file to hdhomerun device\n");
    281418                fclose(fp);
    282419                return -1;
    283420        }
     421        sleep(2);
    284422
    285         printf("upgrade complete\n");
     423        printf("upgrading firmware...\n");
     424        sleep(8);
     425
     426        printf("rebooting...\n");
     427        int count = 0;
     428        char *version_str;
     429        while (1) {
     430                if (hdhomerun_device_get_version(hd, &version_str, NULL) >= 0) {
     431                        break;
     432                }
     433
     434                count++;
     435                if (count > 30) {
     436                        fprintf(stderr, "error finding device after firmware upgrade\n");
     437                        fclose(fp);
     438                        return -1;
     439                }
     440
     441                sleep(1);
     442        }
     443
     444        printf("upgrade complete - now running firmware %s\n", version_str);
    286445        return 0;
    287446}
    288447
     448static int cmd_execute(void)
     449{
     450        char *ret_value;
     451        char *ret_error;
     452        if (hdhomerun_device_get_var(hd, "/sys/boot", &ret_value, &ret_error) < 0) {
     453                fprintf(stderr, "communication error sending request to hdhomerun device\n");
     454                return -1;
     455        }
     456
     457        if (ret_error) {
     458                printf("%s\n", ret_error);
     459                return 0;
     460        }
     461
     462        char *end = ret_value + strlen(ret_value);
     463        char *pos = ret_value;
     464
     465        while (1) {
     466                if (pos >= end) {
     467                        break;
     468                }
     469
     470                char *eol_r = strchr(pos, '\r');
     471                if (!eol_r) {
     472                        eol_r = end;
     473                }
     474
     475                char *eol_n = strchr(pos, '\n');
     476                if (!eol_n) {
     477                        eol_n = end;
     478                }
     479
     480                char *eol = min(eol_r, eol_n);
     481
     482                char *sep = strchr(pos, ' ');
     483                if (!sep || sep > eol) {
     484                        pos = eol + 1;
     485                        continue;
     486                }
     487
     488                *sep = 0;
     489                *eol = 0;
     490
     491                char *item = pos;
     492                char *value = sep + 1;
     493
     494                printf("set %s \"%s\"\n", item, value);
     495
     496                cmd_set_internal(item, value);
     497
     498                pos = eol + 1;
     499        }
     500
     501        return 1;
     502}
     503
    289504static int main_cmd(int argc, char *argv[])
    290505{
    291506        if (argc < 1) {
     
    294509
    295510        char *cmd = *argv++; argc--;
    296511
     512        if (contains(cmd, "key")) {
     513                if (argc < 2) {
     514                        return help();
     515                }
     516                uint32_t lockkey = strtoul(argv[0], NULL, 0);
     517                hdhomerun_device_tuner_lockkey_use_value(hd, lockkey);
     518
     519                cmd = argv[1];
     520                argv+=2; argc-=2;
     521        }
     522
    297523        if (contains(cmd, "get")) {
    298524                if (argc < 1) {
    299525                        return help();
     
    308534                return cmd_set(argv[0], argv[1]);
    309535        }
    310536
    311         if (contains(cmd, "streaminfo")) {
     537        if (contains(cmd, "scan")) {
    312538                if (argc < 1) {
    313539                        return help();
    314540                }
    315                 return cmd_streaminfo(argv[0]);
     541                if (argc < 2) {
     542                        return cmd_scan(argv[0], NULL);
     543                } else {
     544                        return cmd_scan(argv[0], argv[1]);
     545                }
    316546        }
    317547
    318         if (contains(cmd, "scan")) {
     548        if (contains(cmd, "save")) {
    319549                if (argc < 2) {
    320550                        return help();
    321551                }
    322                 return cmd_scan(argv[0], argv[1]);
     552                return cmd_save(argv[0], argv[1]);
    323553        }
    324554
    325555        if (contains(cmd, "upgrade")) {
     
    329559                return cmd_upgrade(argv[0]);
    330560        }
    331561
     562        if (contains(cmd, "execute")) {
     563                return cmd_execute();
     564        }
     565
    332566        return help();
    333567}
    334568
    335569static int main_internal(int argc, char *argv[])
    336570{
    337571#if defined(__WINDOWS__)
    338         //Start pthreads
    339         pthread_win32_process_attach_np();
    340 
    341         // Start WinSock
     572        /* Initialize network socket support. */
    342573        WORD wVersionRequested = MAKEWORD(2, 0);
    343574        WSADATA wsaData;
    344575        WSAStartup(wVersionRequested, &wsaData);
     
    357588                return help();
    358589        }
    359590        if (contains(id_str, "discover")) {
    360                 return discover_print();
     591                if (argc < 1) {
     592                        return discover_print(NULL);
     593                } else {
     594                        return discover_print(argv[0]);
     595                }
    361596        }
    362597
    363         /* Device ID. */
    364         uint32_t device_id, device_ip;
    365         if (!parse_device_id_str(id_str, &device_id, &device_ip)) {
    366                 return -1;
    367         }
    368 
    369598        /* Device object. */
    370         hd = hdhomerun_device_create(device_id, device_ip, 0);
     599        hd = hdhomerun_device_create_from_str(id_str, NULL);
    371600        if (!hd) {
    372                 fprintf(stderr, "unable to create device\n");
     601                fprintf(stderr, "invalid device id: %s\n", id_str);
    373602                return -1;
    374603        }
    375604
    376         /* Connect to device and check firmware version. */
    377         int ret = hdhomerun_device_firmware_version_check(hd, 0);
    378         if (ret < 0) {
     605        /* Device ID check. */
     606        uint32_t device_id_requested = hdhomerun_device_get_device_id_requested(hd);
     607        if (!hdhomerun_discover_validate_device_id(device_id_requested)) {
     608                fprintf(stderr, "invalid device id: %08lX\n", (unsigned long)device_id_requested);
     609        }
     610
     611        /* Connect to device and check model. */
     612        const char *model = hdhomerun_device_get_model_str(hd);
     613        if (!model) {
    379614                fprintf(stderr, "unable to connect to device\n");
    380615                hdhomerun_device_destroy(hd);
    381616                return -1;
    382617        }
    383         if (ret == 0) {
    384                 fprintf(stderr, "WARNING: firmware upgrade needed for all operations to function\n");
    385         }
    386618
    387619        /* Command. */
    388         ret = main_cmd(argc, argv);
     620        int ret = main_cmd(argc, argv);
    389621
    390622        /* Cleanup. */
    391623        hdhomerun_device_destroy(hd);
  • libs/libmythtv/hdhomerun/hdhomerun_video.c

     
    33 *
    44 * Copyright © 2006 Silicondust Engineering Ltd. <www.silicondust.com>.
    55 *
    6  * This library is free software; you can redistribute it and/or
     6 * This library is free software; you can redistribute it and/or 
    77 * modify it under the terms of the GNU Lesser General Public
    88 * License as published by the Free Software Foundation; either
    9  * version 2.1 of the License, or (at your option) any later version.
     9 * version 3 of the License, or (at your option) any later version.
    1010 *
    1111 * This library is distributed in the hope that it will be useful,
    1212 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     
    1414 * Lesser General Public License for more details.
    1515 *
    1616 * You should have received a copy of the GNU Lesser General Public
    17  * License along with this library; if not, write to the Free Software
    18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     17 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
     18 *
     19 * As a special exception to the GNU Lesser General Public License,
     20 * you may link, statically or dynamically, an application with a
     21 * publicly distributed version of the Library to produce an
     22 * executable file containing portions of the Library, and
     23 * distribute that executable file under terms of your choice,
     24 * without any of the additional requirements listed in clause 4 of
     25 * the GNU Lesser General Public License.
     26 *
     27 * By "a publicly distributed version of the Library", we mean
     28 * either the unmodified Library as distributed by Silicondust, or a
     29 * modified version of the Library that is distributed under the
     30 * conditions defined in the GNU Lesser General Public License.
    1931 */
    2032
    21 #include "hdhomerun_os.h"
    22 #include "hdhomerun_pkt.h"
    23 #include "hdhomerun_video.h"
     33#include "hdhomerun.h"
    2434
    2535struct hdhomerun_video_sock_t {
     36        pthread_mutex_t lock;
    2637        uint8_t *buffer;
    2738        size_t buffer_size;
    2839        volatile size_t head;
    2940        volatile size_t tail;
    3041        size_t advance;
    31         volatile bool_t running;
    3242        volatile bool_t terminate;
    3343        pthread_t thread;
    3444        int sock;
     45        uint32_t rtp_sequence;
     46        struct hdhomerun_debug_t *dbg;
     47        volatile uint32_t packet_count;
     48        volatile uint32_t transport_error_count;
     49        volatile uint32_t network_error_count;
     50        volatile uint32_t sequence_error_count;
     51        volatile uint32_t overflow_error_count;
     52        volatile uint8_t sequence[0x2000];
    3553};
    3654
    37 static void *hdhomerun_video_thread(void *arg);
     55static THREAD_FUNC_PREFIX hdhomerun_video_thread_execute(void *arg);
    3856
    39 static bool_t hdhomerun_video_bind_sock_internal(struct hdhomerun_video_sock_t *vs, uint16_t listen_port)
     57struct hdhomerun_video_sock_t *hdhomerun_video_create(uint16_t listen_port, size_t buffer_size, struct hdhomerun_debug_t *dbg)
    4058{
    41         struct sockaddr_in sock_addr;
    42         memset(&sock_addr, 0, sizeof(sock_addr));
    43         sock_addr.sin_family = AF_INET;
    44         sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    45         sock_addr.sin_port = htons(listen_port);
    46         if (bind(vs->sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) {
    47                 return FALSE;
    48         }
    49         return TRUE;
    50 }
    51 
    52 static bool_t hdhomerun_video_bind_sock(struct hdhomerun_video_sock_t *vs, uint16_t listen_port)
    53 {
    54         if (listen_port != 0) {
    55                 return hdhomerun_video_bind_sock_internal(vs, listen_port);
    56         }
    57 
    58 #if defined(__CYGWIN__) || defined(__WINDOWS__)
    59         /* Windows firewall silently blocks a listening port if the port number is not explicitly given. */
    60         /* Workaround - pick a random port number. The port may already be in use to try multiple port numbers. */
    61         srand((int)getcurrenttime());
    62         int retry;
    63         for (retry = 8; retry > 0; retry--) {
    64                 uint16_t listen_port = (uint16_t)((rand() % 32768) + 32768);
    65                 if (hdhomerun_video_bind_sock_internal(vs, listen_port)) {
    66                         return TRUE;
    67                 }
    68         }
    69         return FALSE;
    70 #else
    71         return hdhomerun_video_bind_sock_internal(vs, listen_port);
    72 #endif
    73 }
    74 
    75 struct hdhomerun_video_sock_t *hdhomerun_video_create(uint16_t listen_port, size_t buffer_size)
    76 {
    7759        /* Create object. */
    7860        struct hdhomerun_video_sock_t *vs = (struct hdhomerun_video_sock_t *)calloc(1, sizeof(struct hdhomerun_video_sock_t));
    7961        if (!vs) {
     62                hdhomerun_debug_printf(dbg, "hdhomerun_video_create: failed to allocate video object\n");
    8063                return NULL;
    8164        }
    8265
     66        vs->dbg = dbg;
     67        vs->sock = -1;
     68        pthread_mutex_init(&vs->lock, NULL);
     69
     70        /* Reset sequence tracking. */
     71        hdhomerun_video_flush(vs);
     72
    8373        /* Buffer size. */
    8474        vs->buffer_size = (buffer_size / VIDEO_DATA_PACKET_SIZE) * VIDEO_DATA_PACKET_SIZE;
    8575        if (vs->buffer_size == 0) {
    86                 free(vs);
    87                 return NULL;
     76                hdhomerun_debug_printf(dbg, "hdhomerun_video_create: invalid buffer size (%lu bytes)\n", (unsigned long)buffer_size);
     77                goto error;
    8878        }
    8979        vs->buffer_size += VIDEO_DATA_PACKET_SIZE;
    9080
    9181        /* Create buffer. */
    9282        vs->buffer = (uint8_t *)malloc(vs->buffer_size);
    9383        if (!vs->buffer) {
    94                 free(vs);
    95                 return NULL;
     84                hdhomerun_debug_printf(dbg, "hdhomerun_video_create: failed to allocate buffer (%lu bytes)\n", (unsigned long)vs->buffer_size);
     85                goto error;
    9686        }
    9787       
    9888        /* Create socket. */
    9989        vs->sock = (int)socket(AF_INET, SOCK_DGRAM, 0);
    10090        if (vs->sock == -1) {
    101                 free(vs->buffer);
    102                 free(vs);
    103                 return NULL;
     91                hdhomerun_debug_printf(dbg, "hdhomerun_video_create: failed to allocate socket\n");
     92                goto error;
    10493        }
    10594
    10695        /* Expand socket buffer size. */
     
    112101        setsocktimeout(vs->sock, SOL_SOCKET, SO_RCVTIMEO, 1000);
    113102
    114103        /* Bind socket. */
    115         if (!hdhomerun_video_bind_sock(vs, listen_port)) {
    116                 hdhomerun_video_destroy(vs);
    117                 return NULL;
     104        struct sockaddr_in sock_addr;
     105        memset(&sock_addr, 0, sizeof(sock_addr));
     106        sock_addr.sin_family = AF_INET;
     107        sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
     108        sock_addr.sin_port = htons(listen_port);
     109        if (bind(vs->sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) {
     110                hdhomerun_debug_printf(dbg, "hdhomerun_video_create: failed to bind socket (port %u)\n", listen_port);
     111                goto error;
    118112        }
    119113
    120114        /* Start thread. */
    121         if (pthread_create(&vs->thread, NULL, &hdhomerun_video_thread, vs) != 0) {
    122                 hdhomerun_video_destroy(vs);
    123                 return NULL;
     115        if (pthread_create(&vs->thread, NULL, &hdhomerun_video_thread_execute, vs) != 0) {
     116                hdhomerun_debug_printf(dbg, "hdhomerun_video_create: failed to start thread\n");
     117                goto error;
    124118        }
    125         vs->running = 1;
    126119
    127120        /* Success. */
    128121        return vs;
     122
     123error:
     124        if (vs->sock != -1) {
     125                close(vs->sock);
     126        }
     127        if (vs->buffer) {
     128                free(vs->buffer);
     129        }
     130        free(vs);
     131        return NULL;
    129132}
    130133
    131134void hdhomerun_video_destroy(struct hdhomerun_video_sock_t *vs)
    132135{
    133         if (vs->running) {
    134                 vs->terminate = 1;
    135                 pthread_join(vs->thread, NULL);
    136         }
     136        vs->terminate = TRUE;
     137        pthread_join(vs->thread, NULL);
     138
    137139        close(vs->sock);
    138140        free(vs->buffer);
     141
    139142        free(vs);
    140143}
    141144
     
    144147        struct sockaddr_in sock_addr;
    145148        socklen_t sockaddr_size = sizeof(sock_addr);
    146149        if (getsockname(vs->sock, (struct sockaddr*)&sock_addr, &sockaddr_size) != 0) {
     150                hdhomerun_debug_printf(vs->dbg, "hdhomerun_video_get_local_port: getsockname failed (%d)\n", sock_getlasterror);
    147151                return 0;
    148152        }
     153
    149154        return ntohs(sock_addr.sin_port);
    150155}
    151156
    152 int hdhomerun_video_get_sock(struct hdhomerun_video_sock_t *vs)
     157static void hdhomerun_video_stats_ts_pkt(struct hdhomerun_video_sock_t *vs, uint8_t *ptr)
    153158{
    154         return vs->sock;
     159        uint16_t packet_identifier = ((uint16_t)(ptr[1] & 0x1F) << 8) | (uint16_t)ptr[2];
     160        if (packet_identifier == 0x1FFF) {
     161                return;
     162        }
     163
     164        bool_t transport_error = ptr[1] >> 7;
     165        if (transport_error) {
     166                vs->transport_error_count++;
     167                vs->sequence[packet_identifier] = 0xFF;
     168                return;
     169        }
     170
     171        uint8_t continuity_counter = ptr[3] & 0x0F;
     172        uint8_t previous_sequence = vs->sequence[packet_identifier];
     173
     174        if (continuity_counter == ((previous_sequence + 1) & 0x0F)) {
     175                vs->sequence[packet_identifier] = continuity_counter;
     176                return;
     177        }
     178        if (previous_sequence == 0xFF) {
     179                vs->sequence[packet_identifier] = continuity_counter;
     180                return;
     181        }
     182        if (continuity_counter == previous_sequence) {
     183                return;
     184        }
     185
     186        vs->sequence_error_count++;
     187        vs->sequence[packet_identifier] = continuity_counter;
    155188}
    156189
    157 static void *hdhomerun_video_thread(void *arg)
     190static void hdhomerun_video_parse_rtp(struct hdhomerun_video_sock_t *vs, struct hdhomerun_pkt_t *pkt)
    158191{
     192        pkt->pos += 2;
     193        uint32_t rtp_sequence = hdhomerun_pkt_read_u16(pkt);
     194        pkt->pos += 8;
     195
     196        if (rtp_sequence != ((vs->rtp_sequence + 1) & 0xFFFF)) {
     197                if (vs->rtp_sequence != 0xFFFFFFFF) {
     198                        vs->network_error_count++;
     199
     200                        /* restart pid sequence check */
     201                        /* can't use memset bcs sequence is volatile */
     202                        int i;
     203                        for (i = 0; i < sizeof(vs->sequence) / sizeof(uint8_t) ; i++)
     204                                vs->sequence[i] = 0xFF;
     205                }
     206        }
     207
     208        vs->rtp_sequence = rtp_sequence;
     209}
     210
     211static THREAD_FUNC_PREFIX hdhomerun_video_thread_execute(void *arg)
     212{
    159213        struct hdhomerun_video_sock_t *vs = (struct hdhomerun_video_sock_t *)arg;
     214        struct hdhomerun_pkt_t pkt_inst;
    160215
    161216        while (!vs->terminate) {
    162                 size_t head = vs->head;
     217                struct hdhomerun_pkt_t *pkt = &pkt_inst;
     218                hdhomerun_pkt_reset(pkt);
    163219
    164220                /* Receive. */
    165                 int length = recv(vs->sock, (char *)vs->buffer + head, VIDEO_DATA_PACKET_SIZE, 0);
     221                int length = recv(vs->sock, (char *)pkt->end, VIDEO_RTP_DATA_PACKET_SIZE, 0);
     222                pkt->end += length;
     223
     224                if (length == VIDEO_RTP_DATA_PACKET_SIZE) {
     225                        hdhomerun_video_parse_rtp(vs, pkt);
     226                        length = (int)(pkt->end - pkt->pos);
     227                }
     228
    166229                if (length != VIDEO_DATA_PACKET_SIZE) {
    167230                        if (length > 0) {
    168231                                /* Data received but not valid - ignore. */
     
    172235                                /* Wait for more data. */
    173236                                continue;
    174237                        }
    175                         vs->terminate = 1;
     238                        vs->terminate = TRUE;
    176239                        return NULL;
    177240                }
    178241
     242                pthread_mutex_lock(&vs->lock);
     243
     244                /* Store in ring buffer. */
     245                size_t head = vs->head;
     246                uint8_t *ptr = vs->buffer + head;
     247                memcpy(ptr, pkt->pos, length);
     248
     249                /* Stats. */
     250                vs->packet_count++;
     251                hdhomerun_video_stats_ts_pkt(vs, ptr + TS_PACKET_SIZE * 0);
     252                hdhomerun_video_stats_ts_pkt(vs, ptr + TS_PACKET_SIZE * 1);
     253                hdhomerun_video_stats_ts_pkt(vs, ptr + TS_PACKET_SIZE * 2);
     254                hdhomerun_video_stats_ts_pkt(vs, ptr + TS_PACKET_SIZE * 3);
     255                hdhomerun_video_stats_ts_pkt(vs, ptr + TS_PACKET_SIZE * 4);
     256                hdhomerun_video_stats_ts_pkt(vs, ptr + TS_PACKET_SIZE * 5);
     257                hdhomerun_video_stats_ts_pkt(vs, ptr + TS_PACKET_SIZE * 6);
     258
    179259                /* Calculate new head. */
    180260                head += length;
    181261                if (head >= vs->buffer_size) {
     
    184264
    185265                /* Check for buffer overflow. */
    186266                if (head == vs->tail) {
     267                        vs->overflow_error_count++;
     268                        pthread_mutex_unlock(&vs->lock);
    187269                        continue;
    188270                }
    189271
    190272                /* Atomic update. */
    191273                vs->head = head;
     274
     275                pthread_mutex_unlock(&vs->lock);
    192276        }
    193277
    194278        return NULL;
     
    196280
    197281uint8_t *hdhomerun_video_recv(struct hdhomerun_video_sock_t *vs, size_t max_size, size_t *pactual_size)
    198282{
     283        pthread_mutex_lock(&vs->lock);
     284
    199285        size_t head = vs->head;
    200286        size_t tail = vs->tail;
    201287
     
    212298        if (head == tail) {
    213299                vs->advance = 0;
    214300                *pactual_size = 0;
     301                pthread_mutex_unlock(&vs->lock);
    215302                return NULL;
    216303        }
    217304
     
    219306        if (size == 0) {
    220307                vs->advance = 0;
    221308                *pactual_size = 0;
     309                pthread_mutex_unlock(&vs->lock);
    222310                return NULL;
    223311        }
    224312
     
    233321        }
    234322        vs->advance = size;
    235323        *pactual_size = size;
    236         return vs->buffer + tail;
     324        uint8_t *result = vs->buffer + tail;
     325
     326        pthread_mutex_unlock(&vs->lock);
     327        return result;
    237328}
    238329
    239330void hdhomerun_video_flush(struct hdhomerun_video_sock_t *vs)
    240331{
    241         /* Atomic update of tail. */
     332        pthread_mutex_lock(&vs->lock);
     333
    242334        vs->tail = vs->head;
    243335        vs->advance = 0;
     336
     337        /* can't use memset bcs sequence is volatile */
     338        int i;
     339        for (i = 0; i < sizeof(vs->sequence) / sizeof(uint8_t) ; i++)
     340                vs->sequence[i] = 0xFF;
     341
     342        vs->rtp_sequence = 0xFFFFFFFF;
     343
     344        vs->packet_count = 0;
     345        vs->transport_error_count = 0;
     346        vs->network_error_count = 0;
     347        vs->sequence_error_count = 0;
     348        vs->overflow_error_count = 0;
     349
     350        pthread_mutex_unlock(&vs->lock);
    244351}
    245352
     353void hdhomerun_video_debug_print_stats(struct hdhomerun_video_sock_t *vs)
     354{
     355        struct hdhomerun_video_stats_t stats;
     356        hdhomerun_video_get_stats(vs, &stats);
     357
     358        hdhomerun_debug_printf(vs->dbg, "video sock: pkt=%ld net=%ld te=%ld miss=%ld drop=%ld\n",
     359                stats.packet_count, stats.network_error_count,
     360                stats.transport_error_count, stats.sequence_error_count,
     361                stats.overflow_error_count
     362        );
     363}
     364
     365void hdhomerun_video_get_stats(struct hdhomerun_video_sock_t *vs, struct hdhomerun_video_stats_t *stats)
     366{
     367        memset(stats, 0, sizeof(struct hdhomerun_video_stats_t));
     368
     369        pthread_mutex_lock(&vs->lock);
     370
     371        stats->packet_count = vs->packet_count;
     372        stats->network_error_count = vs->network_error_count;
     373        stats->transport_error_count = vs->transport_error_count;
     374        stats->sequence_error_count = vs->sequence_error_count;
     375        stats->overflow_error_count = vs->overflow_error_count;
     376
     377        pthread_mutex_unlock(&vs->lock);
     378}
  • libs/libmythtv/hdhomerun/hdhomerun_os_posix.h

     
     1/*
     2 * hdhomerun_os_posix.h
     3 *
     4 * Copyright © 2006-2008 Silicondust Engineering Ltd. <www.silicondust.com>.
     5 *
     6 * This library is free software; you can redistribute it and/or
     7 * modify it under the terms of the GNU Lesser General Public
     8 * License as published by the Free Software Foundation; either
     9 * version 3 of the License, or (at your option) any later version.
     10 *
     11 * This library is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14 * Lesser General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU Lesser General Public
     17 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
     18 *
     19 * As a special exception to the GNU Lesser General Public License,
     20 * you may link, statically or dynamically, an application with a
     21 * publicly distributed version of the Library to produce an
     22 * executable file containing portions of the Library, and
     23 * distribute that executable file under terms of your choice,
     24 * without any of the additional requirements listed in clause 4 of
     25 * the GNU Lesser General Public License.
     26 *
     27 * By "a publicly distributed version of the Library", we mean
     28 * either the unmodified Library as distributed by Silicondust, or a
     29 * modified version of the Library that is distributed under the
     30 * conditions defined in the GNU Lesser General Public License.
     31 */
     32
     33#define _FILE_OFFSET_BITS 64
     34#include <stdlib.h>
     35#include <stdio.h>
     36#include <stdarg.h>
     37#include <string.h>
     38#include <unistd.h>
     39#include <errno.h>
     40#include <fcntl.h>
     41#include <sys/types.h>
     42#include <sys/socket.h>
     43#include <sys/time.h>
     44#include <sys/timeb.h>
     45#include <sys/wait.h>
     46#include <sys/signal.h>
     47#include <netinet/in.h>
     48#include <arpa/inet.h>
     49#include <netdb.h>
     50#include <pthread.h>
     51
     52typedef int bool_t;
     53
     54#define LIBTYPE
     55#define sock_getlasterror errno
     56#define sock_getlasterror_socktimeout (errno == EAGAIN)
     57#define console_vprintf vprintf
     58#define console_printf printf
     59#define THREAD_FUNC_PREFIX void *
     60
     61static inline int msleep(unsigned int ms)
     62{
     63        usleep(ms * 1000);
     64        return 0;
     65}
     66
     67static inline uint64_t getcurrenttime(void)
     68{
     69        struct timeval t;
     70        gettimeofday(&t, NULL);
     71        return ((uint64_t)t.tv_sec * 1000) + (t.tv_usec / 1000);
     72}
     73
     74static inline int setsocktimeout(int s, int level, int optname, uint64_t timeout)
     75{
     76        struct timeval t;
     77        t.tv_sec = timeout / 1000;
     78        t.tv_usec = (timeout % 1000) * 1000;
     79        return setsockopt(s, level, optname, (char *)&t, sizeof(t));
     80}
     81
     82#define min(a,b) (((a)<(b))?(a):(b))
     83#define max(a,b) (((a)>(b))?(a):(b))
     84
  • libs/libmythtv/hdhomerun/hdhomerun_types.h

     
     1/*
     2 * hdhomerun_types.h
     3 *
     4 * Copyright © 2008 Silicondust Engineering Ltd. <www.silicondust.com>.
     5 *
     6 * This library is free software; you can redistribute it and/or
     7 * modify it under the terms of the GNU Lesser General Public
     8 * License as published by the Free Software Foundation; either
     9 * version 3 of the License, or (at your option) any later version.
     10 *
     11 * This library is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14 * Lesser General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU Lesser General Public
     17 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
     18 *
     19 * As a special exception to the GNU Lesser General Public License,
     20 * you may link, statically or dynamically, an application with a
     21 * publicly distributed version of the Library to produce an
     22 * executable file containing portions of the Library, and
     23 * distribute that executable file under terms of your choice,
     24 * without any of the additional requirements listed in clause 4 of
     25 * the GNU Lesser General Public License.
     26 *
     27 * By "a publicly distributed version of the Library", we mean
     28 * either the unmodified Library as distributed by Silicondust, or a
     29 * modified version of the Library that is distributed under the
     30 * conditions defined in the GNU Lesser General Public License.
     31 */
     32
     33struct hdhomerun_device_t;
     34
     35struct hdhomerun_tuner_status_t {
     36        char channel[32];
     37        char lock_str[32];
     38        bool_t signal_present;
     39        bool_t lock_supported;
     40        bool_t lock_unsupported;
     41        unsigned int signal_strength;
     42        unsigned int signal_to_noise_quality;
     43        unsigned int symbol_error_quality;
     44        uint32_t raw_bits_per_second;
     45        uint32_t packets_per_second;
     46};
     47
     48struct hdhomerun_channelscan_program_t {
     49        char program_str[64];
     50        uint16_t program_number;
     51        uint16_t virtual_major;
     52        uint16_t virtual_minor;
     53        uint16_t type;
     54        char name[32];
     55};
     56
     57#define HDHOMERUN_CHANNELSCAN_MAX_PROGRAM_COUNT 64
     58
     59struct hdhomerun_channelscan_result_t {
     60        char channel_str[64];
     61        uint32_t channelmap;
     62        uint32_t frequency;
     63        struct hdhomerun_tuner_status_t status;
     64        int program_count;
     65        struct hdhomerun_channelscan_program_t programs[HDHOMERUN_CHANNELSCAN_MAX_PROGRAM_COUNT];
     66        uint32_t pat_crc;
     67};
     68
     69struct hdhomerun_plotsample_t {
     70        int16_t real;
     71        int16_t imag;
     72};
  • libs/libmythtv/hdhomerun/hdhomerun_video.h

     
    33 *
    44 * Copyright © 2006 Silicondust Engineering Ltd. <www.silicondust.com>.
    55 *
    6  * This library is free software; you can redistribute it and/or
     6 * This library is free software; you can redistribute it and/or 
    77 * modify it under the terms of the GNU Lesser General Public
    88 * License as published by the Free Software Foundation; either
    9  * version 2.1 of the License, or (at your option) any later version.
     9 * version 3 of the License, or (at your option) any later version.
    1010 *
    1111 * This library is distributed in the hope that it will be useful,
    1212 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     
    1414 * Lesser General Public License for more details.
    1515 *
    1616 * You should have received a copy of the GNU Lesser General Public
    17  * License along with this library; if not, write to the Free Software
    18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     17 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
     18 *
     19 * As a special exception to the GNU Lesser General Public License,
     20 * you may link, statically or dynamically, an application with a
     21 * publicly distributed version of the Library to produce an
     22 * executable file containing portions of the Library, and
     23 * distribute that executable file under terms of your choice,
     24 * without any of the additional requirements listed in clause 4 of
     25 * the GNU Lesser General Public License.
     26 *
     27 * By "a publicly distributed version of the Library", we mean
     28 * either the unmodified Library as distributed by Silicondust, or a
     29 * modified version of the Library that is distributed under the
     30 * conditions defined in the GNU Lesser General Public License.
    1931 */
    2032#ifdef __cplusplus
    2133extern "C" {
     
    2335
    2436struct hdhomerun_video_sock_t;
    2537
     38struct hdhomerun_video_stats_t {
     39        uint32_t packet_count;
     40        uint32_t network_error_count;
     41        uint32_t transport_error_count;
     42        uint32_t sequence_error_count;
     43        uint32_t overflow_error_count;
     44};
     45
    2646#define TS_PACKET_SIZE 188
    2747#define VIDEO_DATA_PACKET_SIZE (188 * 7)
    2848#define VIDEO_DATA_BUFFER_SIZE_1S (20000000 / 8)
    2949
     50#define VIDEO_RTP_DATA_PACKET_SIZE ((188 * 7) + 12)
     51
    3052/*
    3153 * Create a video/data socket.
    3254 *
    3355 * uint16_t listen_port: Port number to listen on. Set to 0 to auto-select.
    3456 * size_t buffer_size: Size of receive buffer. For 1 second of buffer use VIDEO_DATA_BUFFER_SIZE_1S.
     57 * struct hdhomerun_debug_t *dbg: Pointer to debug logging object. May be NULL.
    3558 *
    3659 * Returns a pointer to the newly created control socket.
    3760 *
    3861 * When no longer needed, the socket should be destroyed by calling hdhomerun_control_destroy.
    3962 */
    40 extern struct hdhomerun_video_sock_t *hdhomerun_video_create(uint16_t listen_port, size_t buffer_size);
    41 extern void hdhomerun_video_destroy(struct hdhomerun_video_sock_t *vs);
     63extern LIBTYPE struct hdhomerun_video_sock_t *hdhomerun_video_create(uint16_t listen_port, size_t buffer_size, struct hdhomerun_debug_t *dbg);
     64extern LIBTYPE void hdhomerun_video_destroy(struct hdhomerun_video_sock_t *vs);
    4265
    4366/*
    4467 * Get the port the socket is listening on.
    4568 *
    4669 * Returns 16-bit port with native endianness, or 0 on error.
    4770 */
    48 extern uint16_t hdhomerun_video_get_local_port(struct hdhomerun_video_sock_t *vs);
     71extern LIBTYPE uint16_t hdhomerun_video_get_local_port(struct hdhomerun_video_sock_t *vs);
    4972
    5073/*
    51  * Get the low-level socket handle.
    52  */
    53 extern int hdhomerun_video_get_sock(struct hdhomerun_video_sock_t *vs);
    54 
    55 /*
    5674 * Read data from buffer.
    5775 *
    5876 * size_t max_size: The maximum amount of data to be returned.
     
    6987 * The buffer is implemented as a ring buffer. It is possible for this function to return a small
    7088 * amount of data when more is available due to the wrap-around case.
    7189 */
    72 extern uint8_t *hdhomerun_video_recv(struct hdhomerun_video_sock_t *vs, size_t max_size, size_t *pactual_size);
     90extern LIBTYPE uint8_t *hdhomerun_video_recv(struct hdhomerun_video_sock_t *vs, size_t max_size, size_t *pactual_size);
    7391
    7492/*
    7593 * Flush the buffer.
    7694 */
    77 extern void hdhomerun_video_flush(struct hdhomerun_video_sock_t *vs);
     95extern LIBTYPE void hdhomerun_video_flush(struct hdhomerun_video_sock_t *vs);
    7896
     97/*
     98 * Debug print internal stats.
     99 */
     100extern LIBTYPE void hdhomerun_video_debug_print_stats(struct hdhomerun_video_sock_t *vs);
     101extern LIBTYPE void hdhomerun_video_get_stats(struct hdhomerun_video_sock_t *vs, struct hdhomerun_video_stats_t *stats);
     102
    79103#ifdef __cplusplus
    80104}
    81105#endif
  • libs/libmythtv/hdhomerun/hdhomerun_channelscan.c

     
     1/*
     2 * hdhomerun_channelscan.c
     3 *
     4 * Copyright © 2007-2008 Silicondust Engineering Ltd. <www.silicondust.com>.
     5 *
     6 * This library is free software; you can redistribute it and/or
     7 * modify it under the terms of the GNU Lesser General Public
     8 * License as published by the Free Software Foundation; either
     9 * version 3 of the License, or (at your option) any later version.
     10 *
     11 * This library is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14 * Lesser General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU Lesser General Public
     17 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
     18 *
     19 * As a special exception to the GNU Lesser General Public License,
     20 * you may link, statically or dynamically, an application with a
     21 * publicly distributed version of the Library to produce an
     22 * executable file containing portions of the Library, and
     23 * distribute that executable file under terms of your choice,
     24 * without any of the additional requirements listed in clause 4 of
     25 * the GNU Lesser General Public License.
     26 *
     27 * By "a publicly distributed version of the Library", we mean
     28 * either the unmodified Library as distributed by Silicondust, or a
     29 * modified version of the Library that is distributed under the
     30 * conditions defined in the GNU Lesser General Public License.
     31 */
     32
     33#include "hdhomerun.h"
     34
     35struct hdhomerun_channelscan_t {
     36        struct hdhomerun_device_t *hd;
     37        uint32_t scanned_channels;
     38        struct hdhomerun_channel_list_t *channel_list; 
     39        struct hdhomerun_channel_entry_t *next_channel;
     40};
     41
     42struct hdhomerun_channelscan_t *channelscan_create(struct hdhomerun_device_t *hd, const char *channelmap)
     43{
     44        struct hdhomerun_channelscan_t *scan = (struct hdhomerun_channelscan_t *)calloc(1, sizeof(struct hdhomerun_channelscan_t));
     45        if (!scan) {
     46                return NULL;
     47        }
     48
     49        scan->hd = hd;
     50
     51        scan->channel_list = hdhomerun_channel_list_create(channelmap);
     52        if (!scan->channel_list) {
     53                free(scan);
     54                return NULL;
     55        }
     56
     57        scan->next_channel = hdhomerun_channel_list_last(scan->channel_list);
     58        return scan;
     59}
     60
     61void channelscan_destroy(struct hdhomerun_channelscan_t *scan)
     62{
     63        free(scan);
     64}
     65
     66static int channelscan_find_lock(struct hdhomerun_channelscan_t *scan, uint32_t frequency, struct hdhomerun_channelscan_result_t *result)
     67{
     68        /* Set channel. */
     69        char channel_str[64];
     70        sprintf(channel_str, "auto:%ld", (unsigned long)frequency);
     71
     72        int ret = hdhomerun_device_set_tuner_channel(scan->hd, channel_str);
     73        if (ret <= 0) {
     74                return ret;
     75        }
     76
     77        /* Wait for lock. */
     78        ret = hdhomerun_device_wait_for_lock(scan->hd, &result->status);
     79        if (ret <= 0) {
     80                return ret;
     81        }
     82        if (!result->status.lock_supported) {
     83                return 1;
     84        }
     85
     86        /* Wait for symbol quality = 100%. */
     87        uint64_t timeout = getcurrenttime() + 5000;
     88        while (1) {
     89                ret = hdhomerun_device_get_tuner_status(scan->hd, NULL, &result->status);
     90                if (ret <= 0) {
     91                        return ret;
     92                }
     93
     94                if (result->status.symbol_error_quality == 100) {
     95                        return 1;
     96                }
     97
     98                if (getcurrenttime() >= timeout) {
     99                        return 1;
     100                }
     101
     102                msleep(250);
     103        }
     104}
     105
     106static void channelscan_extract_name(struct hdhomerun_channelscan_program_t *program, const char *line)
     107{
     108        /* Find start of name. */
     109        const char *start = strchr(line, ' ');
     110        if (!start) {
     111                return;
     112        }
     113        start++;
     114
     115        start = strchr(start, ' ');
     116        if (!start) {
     117                return;
     118        }
     119        start++;
     120
     121        /* Find end of name. */
     122        const char *end = strstr(start, " (");
     123        if (!end) {
     124                end = strchr(line, 0);
     125        }
     126
     127        if (end <= start) {
     128                return;
     129        }
     130
     131        /* Extract name. */
     132        size_t length = (size_t)(end - start);
     133        if (length > sizeof(program->name) - 1) {
     134                length = sizeof(program->name) - 1;
     135        }
     136
     137        strncpy(program->name, start, length);
     138        program->name[length] = 0;
     139}
     140
     141static int channelscan_detect_programs(struct hdhomerun_channelscan_t *scan, struct hdhomerun_channelscan_result_t *result, bool_t *pchanged, bool_t *pincomplete)
     142{
     143        *pchanged = FALSE;
     144        *pincomplete = FALSE;
     145
     146        char *streaminfo;
     147        int ret = hdhomerun_device_get_tuner_streaminfo(scan->hd, &streaminfo);
     148        if (ret <= 0) {
     149                return ret;
     150        }
     151
     152        char *line = streaminfo;
     153        int program_count = 0;
     154
     155        while (1) {
     156                char *end = strchr(line, '\n');
     157                if (!end) {
     158                        break;
     159                }
     160
     161                *end = 0;
     162
     163                unsigned long pat_crc;
     164                if (sscanf(line, "crc=0x%lx", &pat_crc) == 1) {
     165                        result->pat_crc = pat_crc;
     166                        continue;
     167                }
     168
     169                struct hdhomerun_channelscan_program_t program;
     170                memset(&program, 0, sizeof(program));
     171
     172                strncpy(program.program_str, line, sizeof(program.program_str));
     173                program.program_str[sizeof(program.program_str) - 1] = 0;
     174
     175                unsigned int program_number;
     176                unsigned int virtual_major, virtual_minor;
     177                if (sscanf(line, "%u: %u.%u", &program_number, &virtual_major, &virtual_minor) != 3) {
     178                        if (sscanf(line, "%u: %u", &program_number, &virtual_major) != 2) {
     179                                continue;
     180                        }
     181                        virtual_minor = 0;
     182                }
     183
     184                program.program_number = program_number;
     185                program.virtual_major = virtual_major;
     186                program.virtual_minor = virtual_minor;
     187
     188                channelscan_extract_name(&program, line);
     189
     190                if (strstr(line, "(control)")) {
     191                        program.type = HDHOMERUN_CHANNELSCAN_PROGRAM_CONTROL;
     192                } else if (strstr(line, "(encrypted)")) {
     193                        program.type = HDHOMERUN_CHANNELSCAN_PROGRAM_ENCRYPTED;
     194                } else if (strstr(line, "(no data)")) {
     195                        program.type = HDHOMERUN_CHANNELSCAN_PROGRAM_NODATA;
     196                        *pincomplete = TRUE;
     197                } else {
     198                        program.type = HDHOMERUN_CHANNELSCAN_PROGRAM_NORMAL;
     199                        if ((program.virtual_major == 0) || (program.name[0] == 0)) {
     200                                *pincomplete = TRUE;
     201                        }
     202                }
     203
     204                if (memcmp(&result->programs[program_count], &program, sizeof(program)) != 0) {
     205                        memcpy(&result->programs[program_count], &program, sizeof(program));
     206                        *pchanged = TRUE;
     207                }
     208
     209                program_count++;
     210                if (program_count >= HDHOMERUN_CHANNELSCAN_MAX_PROGRAM_COUNT) {
     211                        break;
     212                }
     213
     214                line = end + 1;
     215        }
     216
     217        if (program_count == 0) {
     218                *pincomplete = TRUE;
     219        }
     220        if (result->program_count != program_count) {
     221                result->program_count = program_count;
     222                *pchanged = TRUE;
     223        }
     224
     225        return 1;
     226}
     227
     228int channelscan_advance(struct hdhomerun_channelscan_t *scan, struct hdhomerun_channelscan_result_t *result)
     229{
     230        memset(result, 0, sizeof(struct hdhomerun_channelscan_result_t));
     231
     232        struct hdhomerun_channel_entry_t *entry = scan->next_channel;
     233        if (!entry) {
     234                return 0;
     235        }
     236
     237        /* Combine channels with same frequency. */
     238        result->frequency = hdhomerun_channel_entry_frequency(entry);
     239        strncpy(result->channel_str, hdhomerun_channel_entry_name(entry), sizeof(result->channel_str) - 1);
     240        result->channel_str[sizeof(result->channel_str) - 1] = 0;
     241
     242        while (1) {
     243                entry = hdhomerun_channel_list_prev(scan->channel_list, entry);
     244                if (!entry) {
     245                        scan->next_channel = NULL;
     246                        break;
     247                }
     248
     249                if (hdhomerun_channel_entry_frequency(entry) != result->frequency) {
     250                        scan->next_channel = entry;
     251                        break;
     252                }
     253
     254                char *ptr = strchr(result->channel_str, 0);
     255                sprintf(ptr, ", %s", hdhomerun_channel_entry_name(entry));
     256        }
     257
     258        return 1;
     259}
     260
     261int channelscan_detect(struct hdhomerun_channelscan_t *scan, struct hdhomerun_channelscan_result_t *result)
     262{
     263        scan->scanned_channels++;
     264
     265        /* Find lock. */
     266        int ret = channelscan_find_lock(scan, result->frequency, result);
     267        if (ret <= 0) {
     268                return ret;
     269        }
     270        if (!result->status.lock_supported) {
     271                return 1;
     272        }
     273
     274        /* Detect programs. */
     275        result->program_count = 0;
     276
     277        uint64_t timeout = getcurrenttime() + 10000;
     278        uint64_t complete_time = getcurrenttime() + 2000;
     279        while (1) {
     280                bool_t changed, incomplete;
     281                ret = channelscan_detect_programs(scan, result, &changed, &incomplete);
     282                if (ret <= 0) {
     283                        return ret;
     284                }
     285
     286                if (changed) {
     287                        complete_time = getcurrenttime() + 2000;
     288                }
     289
     290                if (!incomplete && (getcurrenttime() >= complete_time)) {
     291                        return 1;
     292                }
     293
     294                if (getcurrenttime() >= timeout) {
     295                        return 1;
     296                }
     297
     298                msleep(250);
     299        }
     300}
     301
     302uint8_t channelscan_get_progress(struct hdhomerun_channelscan_t *scan)
     303{
     304        struct hdhomerun_channel_entry_t *entry = scan->next_channel;
     305        if (!entry) {
     306                return 100;
     307        }
     308
     309        uint32_t channels_remaining = 1;
     310        uint32_t frequency = hdhomerun_channel_entry_frequency(entry);
     311
     312        while (1) {
     313                entry = hdhomerun_channel_list_prev(scan->channel_list, entry);
     314                if (!entry) {
     315                        break;
     316                }
     317
     318                if (hdhomerun_channel_entry_frequency(entry) != frequency) {
     319                        channels_remaining++;
     320                        frequency = hdhomerun_channel_entry_frequency(entry);
     321                }
     322        }
     323
     324        return scan->scanned_channels * 100 / (scan->scanned_channels + channels_remaining);
     325}
  • libs/libmythtv/hdhomerun/hdhomerun_discover.c

     
    11/*
    22 * hdhomerun_discover.c
    33 *
    4  * Copyright © 2006 Silicondust Engineering Ltd. <www.silicondust.com>.
     4 * Copyright © 2006-2007 Silicondust Engineering Ltd. <www.silicondust.com>.
    55 *
    6  * This library is free software; you can redistribute it and/or
     6 * This library is free software; you can redistribute it and/or 
    77 * modify it under the terms of the GNU Lesser General Public
    88 * License as published by the Free Software Foundation; either
    9  * version 2.1 of the License, or (at your option) any later version.
     9 * version 3 of the License, or (at your option) any later version.
    1010 *
    1111 * This library is distributed in the hope that it will be useful,
    1212 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     
    1414 * Lesser General Public License for more details.
    1515 *
    1616 * You should have received a copy of the GNU Lesser General Public
    17  * License along with this library; if not, write to the Free Software
    18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     17 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
     18 *
     19 * As a special exception to the GNU Lesser General Public License,
     20 * you may link, statically or dynamically, an application with a
     21 * publicly distributed version of the Library to produce an
     22 * executable file containing portions of the Library, and
     23 * distribute that executable file under terms of your choice,
     24 * without any of the additional requirements listed in clause 4 of
     25 * the GNU Lesser General Public License.
     26 *
     27 * By "a publicly distributed version of the Library", we mean
     28 * either the unmodified Library as distributed by Silicondust, or a
     29 * modified version of the Library that is distributed under the
     30 * conditions defined in the GNU Lesser General Public License.
    1931 */
    2032
    21 #include "hdhomerun_os.h"
    22 #include "hdhomerun_pkt.h"
    23 #include "hdhomerun_discover.h"
     33#include "hdhomerun.h"
    2434
    2535#if defined(__CYGWIN__) || defined(__WINDOWS__)
    2636#include <windows.h>
    27 #include <iptypes.h>
    2837#include <iphlpapi.h>
     38#define USE_IPHLPAPI 1
     39#else
     40#include <net/if.h>
     41#include <sys/ioctl.h>
     42#ifndef _SIZEOF_ADDR_IFREQ
     43#define _SIZEOF_ADDR_IFREQ(x) sizeof(x)
    2944#endif
     45#endif
    3046
    31 // for OSX
    32 #include <unistd.h>    // execl, pipe, sysconf
    33 #include <sys/types.h> // waitpid
    34 #include <sys/wait.h>  // waitpid
     47#include <sys/param.h>  // Defines BSD on FreeBSD and Mac OS X
     48#if defined(__linux__) || defined(__APPLE__) || defined(BSD)
     49#  include <ifaddrs.h>
     50#  define USE_IFADDRS 1
     51#  include <sys/select.h>
     52#endif
    3553
     54#define HDHOMERUN_DISOCVER_MAX_SOCK_COUNT 16
     55
    3656struct hdhomerun_discover_sock_t {
    3757        int sock;
     58        uint32_t local_ip;
     59        uint32_t subnet_mask;
    3860};
    3961
    40 static struct hdhomerun_discover_sock_t *hdhomerun_discover_create(void)
     62struct hdhomerun_discover_t {
     63        struct hdhomerun_discover_sock_t socks[HDHOMERUN_DISOCVER_MAX_SOCK_COUNT];
     64        unsigned int sock_count;
     65        struct hdhomerun_pkt_t tx_pkt;
     66        struct hdhomerun_pkt_t rx_pkt;
     67};
     68
     69static bool_t hdhomerun_discover_sock_create(struct hdhomerun_discover_t *ds, uint32_t local_ip, uint32_t subnet_mask)
    4170{
    42         struct hdhomerun_discover_sock_t *ds = (struct hdhomerun_discover_sock_t *)malloc(sizeof(struct hdhomerun_discover_sock_t));
    43         if (!ds) {
    44                 return NULL;
     71        if (ds->sock_count >= HDHOMERUN_DISOCVER_MAX_SOCK_COUNT) {
     72                return FALSE;
    4573        }
    46        
     74
    4775        /* Create socket. */
    48         ds->sock = (int)socket(AF_INET, SOCK_DGRAM, 0);
    49         if (ds->sock == -1) {
    50                 free(ds);
    51                 return NULL;
     76        int sock = (int)socket(AF_INET, SOCK_DGRAM, 0);
     77        if (sock == -1) {
     78                return FALSE;
    5279        }
    5380
    5481        /* Set timeouts. */
    55         setsocktimeout(ds->sock, SOL_SOCKET, SO_SNDTIMEO, 1000);
    56         setsocktimeout(ds->sock, SOL_SOCKET, SO_RCVTIMEO, 1000);
     82        setsocktimeout(sock, SOL_SOCKET, SO_SNDTIMEO, 1000);
     83        setsocktimeout(sock, SOL_SOCKET, SO_RCVTIMEO, 1000);
    5784
    5885        /* Allow broadcast. */
    5986        int sock_opt = 1;
    60         setsockopt(ds->sock, SOL_SOCKET, SO_BROADCAST, (char *)&sock_opt, sizeof(sock_opt));
     87        setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&sock_opt, sizeof(sock_opt));
    6188
    6289        /* Bind socket. */
    6390        struct sockaddr_in sock_addr;
    6491        memset(&sock_addr, 0, sizeof(sock_addr));
    6592        sock_addr.sin_family = AF_INET;
    66         sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
     93        sock_addr.sin_addr.s_addr = htonl(local_ip);
    6794        sock_addr.sin_port = htons(0);
    68         if (bind(ds->sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) {
    69                 close(ds->sock);
    70                 free(ds);
    71                 return NULL;
     95        if (bind(sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) {
     96                close(sock);
     97                return FALSE;
    7298        }
    7399
    74         /* Success. */
    75         return ds;
    76 }
     100        /* Write sock entry. */
     101        struct hdhomerun_discover_sock_t *dss = &ds->socks[ds->sock_count++];
     102        dss->sock = sock;
     103        dss->local_ip = local_ip;
     104        dss->subnet_mask = subnet_mask;
    77105
    78 static void hdhomerun_discover_destroy(struct hdhomerun_discover_sock_t *ds)
    79 {
    80         close(ds->sock);
    81         free(ds);
     106        return TRUE;
    82107}
    83108
    84 static int hdhomerun_discover_send_packet(struct hdhomerun_discover_sock_t *ds, uint32_t ip_addr, uint32_t device_type, uint32_t device_id)
     109#if defined(USE_IPHLPAPI)
     110static void hdhomerun_discover_sock_detect(struct hdhomerun_discover_t *ds)
    85111{
    86         uint8_t buffer[1024];
    87         uint8_t *ptr = buffer;
    88         hdhomerun_write_discover_request(&ptr, device_type, device_id);
    89 
    90         struct sockaddr_in sock_addr;
    91         memset(&sock_addr, 0, sizeof(sock_addr));
    92         sock_addr.sin_family = AF_INET;
    93         sock_addr.sin_addr.s_addr = htonl(ip_addr);
    94         sock_addr.sin_port = htons(HDHOMERUN_DISCOVER_UDP_PORT);
    95 
    96         int length = (int)(ptr - buffer);
    97         if (sendto(ds->sock, (char *)buffer, (int)length, 0, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != length) {
    98                 return -1;
    99         }
    100 
    101         return 0;
    102 }
    103 
    104 #if defined(__APPLE__)
    105 static int hdhomerun_discover_send_internal(struct hdhomerun_discover_sock_t *ds, unsigned long device_type, unsigned long device_id)
    106 {
    107     /* printf("Looking for 0x%lx with id 0x%lx\n", device_type, device_id); */
    108     int fds[2];
    109     if (pipe(fds) < 0)
    110     {
    111         printf("Pipe Failed\n");
    112         return -1;
    113     }
    114 
    115     pid_t child = fork();
    116     if (child < 0)
    117     {
    118         printf("Fork Failed\n");
    119         return -1;
    120     }
    121     else if (child == 0)
    122     {
    123         /* Child */
    124         int i = 0;
    125 
    126         /* Attach stdout to pipe */
    127         close(1);
    128         dup2(fds[1], 1);
    129 
    130         /* Close all open file descriptors except stdout/stderr */
    131         for (i = sysconf(_SC_OPEN_MAX) - 1; i > 2; i--)
    132             close(i);
    133 
    134         /* Run command */
    135         execl("/bin/sh", "sh", "-c", "ifconfig", NULL);
    136 
    137         /* Failed to exec */
    138         _exit(1); /* this exit is ok */
    139     }
    140     else
    141     {
    142         /* Parent */
    143         int send_count = 0;
    144         int status;
    145         FILE *fp;
    146         char line[1024];
    147         char adaptor[1024];
    148 
    149         close(fds[1]);
    150 
    151         if (waitpid(child, &status, 0) < 0)
    152             return -1;
    153 
    154         if (WEXITSTATUS(status))
    155             return -1;
    156 
    157         fp = fdopen(fds[0], "r");
    158         while (1)
    159         {
    160             char *ptr = NULL;
    161             int netmask, broadcast;
    162             int a,b,c,d;
    163 
    164             if (!fgets(line, sizeof(line) - 1, fp))
    165             {
    166                 break;
    167             }
    168 
    169             line[1023] = 0;
    170 
    171             /* find ": flags" */
    172             ptr = strnstr(line, ": flags", 1024 - 1);
    173             if (ptr >= line)
    174             {
    175                 /* grab adaptor before that */
    176                 strncpy(adaptor, line, ptr-line);
    177                 adaptor[ptr-line] = 0;
    178             }
    179 
    180             /* find "netmask " */
    181             ptr = strnstr(line, "netmask ", 1024 - 1);
    182             if (ptr <= line)
    183                 continue;
    184             ptr += strlen("netmask ");
    185             sscanf(ptr, "%x", &netmask);
    186 
    187             /* find "broadcast " */
    188             ptr = strnstr(ptr, "broadcast ", 1024 - 1);
    189             if (ptr <= line)
    190                 continue;
    191             ptr += strlen("broadcast ");
    192             sscanf(ptr, "%i.%i.%i.%i", &a, &b, &c, &d);
    193             broadcast = a<<24 | b<<16 | c<<8 | d;
    194             /*
    195             printf("Adaptor: '%s' 0x%08x %i.%i.%i.%i\n",
    196                    adaptor, broadcast, a,b,c,d);
    197             */
    198 
    199             /* send discover packet this adaptor */
    200             if (hdhomerun_discover_send_packet(
    201                     ds, broadcast, device_type, device_id) >= 0)
    202             {
    203                 send_count++;
    204             }
    205         }
    206 
    207         fclose(fp); /* this closes fds[0] as well */
    208 
    209         /* printf("send_count: %i\n\n", send_count); */
    210         return (send_count == 0) ? -1 : 0;
    211     }
    212 }
    213 
    214 #elif defined(__CYGWIN__) || defined(__WINDOWS__)
    215 
    216 static int hdhomerun_discover_send_internal(struct hdhomerun_discover_sock_t *ds, uint32_t device_type, uint32_t device_id)
    217 {
    218112        PIP_ADAPTER_INFO pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));
    219113        ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
    220114
     
    222116        if (Ret != NO_ERROR) {
    223117                free(pAdapterInfo);
    224118                if (Ret != ERROR_BUFFER_OVERFLOW) {
    225                         return -1;
     119                        return;
    226120                }
    227121                pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen);
    228122                Ret = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen);
    229123                if (Ret != NO_ERROR) {
    230124                        free(pAdapterInfo);
    231                         return -1;
     125                        return;
    232126                }
    233127        }
    234128
    235         unsigned int send_count = 0;
    236129        PIP_ADAPTER_INFO pAdapter = pAdapterInfo;
    237130        while (pAdapter) {
    238131                IP_ADDR_STRING *pIPAddr = &pAdapter->IpAddressList;
    239132                while (pIPAddr) {
    240                         uint32_t addr = ntohl(inet_addr(pIPAddr->IpAddress.String));
     133                        uint32_t local_ip = ntohl(inet_addr(pIPAddr->IpAddress.String));
    241134                        uint32_t mask = ntohl(inet_addr(pIPAddr->IpMask.String));
    242                        
    243                         uint32_t broadcast = addr | ~mask;
    244                         if ((broadcast == 0x00000000) || (broadcast == 0xFFFFFFFF)) {
    245                                 pIPAddr = pIPAddr->Next;
    246                                 continue;
    247                         }
    248135
    249                         if (hdhomerun_discover_send_packet(ds, broadcast, device_type, device_id) < 0) {
     136                        if (local_ip == 0) {
    250137                                pIPAddr = pIPAddr->Next;
    251138                                continue;
    252139                        }
    253140
    254                         send_count++;
    255 
     141                        hdhomerun_discover_sock_create(ds, local_ip, mask);
    256142                        pIPAddr = pIPAddr->Next;
    257143                }
    258144
     
    260146        }
    261147
    262148        free(pAdapterInfo);
    263 
    264         if (send_count == 0) {
    265                 return -1;
    266         }
    267         return 0;
    268149}
    269150
    270 #elif defined(__linux__)
     151#else
    271152
    272 static int hdhomerun_discover_send_internal(struct hdhomerun_discover_sock_t *ds, uint32_t device_type, uint32_t device_id)
     153static void hdhomerun_discover_sock_detect(struct hdhomerun_discover_t *ds)
    273154{
    274         FILE *fp = fopen("/proc/net/route", "r");
    275         if (!fp) {
    276                 return -1;
     155        int fd = socket(AF_INET, SOCK_DGRAM, 0);
     156        if (fd == -1) {
     157                return;
    277158        }
    278159
    279         unsigned int send_count = 0;
    280         while (1) {
    281                 char line[256];
    282                 if (!fgets(line, sizeof(line), fp)) {
    283                         break;
    284                 }
    285                 line[255] = 0;
     160        struct ifconf ifc;
     161        uint8_t buf[8192];
     162        ifc.ifc_len = sizeof(buf);
     163        ifc.ifc_buf = (char *)buf;
    286164
    287                 uint32_t dest;
    288                 uint32_t mask;
    289                 if (sscanf(line, "%*s %x %*x %*x %*d %*d %*d %x", &dest, &mask) != 2) {
     165        memset(buf, 0, sizeof(buf));
     166
     167        if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
     168                close(fd);
     169                return;
     170        }
     171
     172        uint8_t *ptr = (uint8_t *)ifc.ifc_req;
     173        uint8_t *end = (uint8_t *)&ifc.ifc_buf[ifc.ifc_len];
     174
     175        while (ptr <= end) {
     176                struct ifreq *ifr = (struct ifreq *)ptr;
     177                ptr += _SIZEOF_ADDR_IFREQ(*ifr);
     178
     179                if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
    290180                        continue;
    291181                }
    292                 dest = ntohl(dest);
    293                 mask = ntohl(mask);
    294                
    295                 uint32_t broadcast = dest | ~mask;
    296 
    297                 if ((broadcast == 0x00000000) || (broadcast == 0xFFFFFFFF)) {
     182                struct sockaddr_in *addr_in = (struct sockaddr_in *)&(ifr->ifr_addr);
     183                uint32_t local_ip = ntohl(addr_in->sin_addr.s_addr);
     184                if (local_ip == 0) {
    298185                        continue;
    299186                }
    300187
    301                 if (hdhomerun_discover_send_packet(ds, broadcast, device_type, device_id) < 0) {
     188                if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
    302189                        continue;
    303190                }
     191                struct sockaddr_in *mask_in = (struct sockaddr_in *)&(ifr->ifr_addr);
     192                uint32_t mask = ntohl(mask_in->sin_addr.s_addr);
    304193
    305                 send_count++;
     194                hdhomerun_discover_sock_create(ds, local_ip, mask);
    306195        }
     196}
     197#endif
    307198
    308         fclose(fp);
    309         if (send_count == 0) {
    310                 return -1;
     199static struct hdhomerun_discover_t *hdhomerun_discover_create(void)
     200{
     201        struct hdhomerun_discover_t *ds = (struct hdhomerun_discover_t *)calloc(1, sizeof(struct hdhomerun_discover_t));
     202        if (!ds) {
     203                return NULL;
    311204        }
    312         return 0;
     205
     206        /* Create a routable socket. */
     207        if (!hdhomerun_discover_sock_create(ds, 0, 0)) {
     208                free(ds);
     209                return NULL;
     210        }
     211
     212        /* Detect & create local sockets. */
     213        hdhomerun_discover_sock_detect(ds);
     214
     215        /* Success. */
     216        return ds;
    313217}
    314218
    315 #else
     219static void hdhomerun_discover_destroy(struct hdhomerun_discover_t *ds)
     220{
     221        unsigned int i;
     222        for (i = 0; i < ds->sock_count; i++) {
     223                struct hdhomerun_discover_sock_t *dss = &ds->socks[i];
     224                close(dss->sock);
     225        }
    316226
    317 static int hdhomerun_discover_send_internal(struct hdhomerun_discover_sock_t *ds, uint32_t device_type, uint32_t device_id)
     227        free(ds);
     228}
     229
     230static bool_t hdhomerun_discover_send_internal(struct hdhomerun_discover_t *ds, struct hdhomerun_discover_sock_t *dss, uint32_t target_ip, uint32_t device_type, uint32_t device_id)
    318231{
    319         return -1;
     232        struct hdhomerun_pkt_t *tx_pkt = &ds->tx_pkt;
     233        hdhomerun_pkt_reset(tx_pkt);
     234
     235        hdhomerun_pkt_write_u8(tx_pkt, HDHOMERUN_TAG_DEVICE_TYPE);
     236        hdhomerun_pkt_write_var_length(tx_pkt, 4);
     237        hdhomerun_pkt_write_u32(tx_pkt, device_type);
     238        hdhomerun_pkt_write_u8(tx_pkt, HDHOMERUN_TAG_DEVICE_ID);
     239        hdhomerun_pkt_write_var_length(tx_pkt, 4);
     240        hdhomerun_pkt_write_u32(tx_pkt, device_id);
     241        hdhomerun_pkt_seal_frame(tx_pkt, HDHOMERUN_TYPE_DISCOVER_REQ);
     242
     243        struct sockaddr_in sock_addr;
     244        memset(&sock_addr, 0, sizeof(sock_addr));
     245        sock_addr.sin_family = AF_INET;
     246        sock_addr.sin_addr.s_addr = htonl(target_ip);
     247        sock_addr.sin_port = htons(HDHOMERUN_DISCOVER_UDP_PORT);
     248
     249        int length = (int)(tx_pkt->end - tx_pkt->start);
     250        if (sendto(dss->sock, (char *)tx_pkt->start, length, 0, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != length) {
     251                return FALSE;
     252        }
     253
     254        return TRUE;
    320255}
    321 #endif
    322256
    323 static int hdhomerun_discover_send(struct hdhomerun_discover_sock_t *ds, uint32_t device_type, uint32_t device_id)
     257static bool_t hdhomerun_discover_send_wildcard_ip(struct hdhomerun_discover_t *ds, uint32_t device_type, uint32_t device_id)
    324258{
    325         if (hdhomerun_discover_send_internal(ds, device_type, device_id) < 0) {
    326                 return hdhomerun_discover_send_packet(ds, 0xFFFFFFFF, device_type, device_id);
     259        bool_t result = FALSE;
     260
     261        /*
     262         * Send subnet broadcast using each local ip socket.
     263         * This will work with multiple separate 169.254.x.x interfaces.
     264         */
     265        unsigned int i;
     266        for (i = 1; i < ds->sock_count; i++) {
     267                struct hdhomerun_discover_sock_t *dss = &ds->socks[i];
     268                uint32_t target_ip = dss->local_ip | ~dss->subnet_mask;
     269                result |= hdhomerun_discover_send_internal(ds, dss, target_ip, device_type, device_id);
    327270        }
    328         return 0;
     271
     272        /*
     273         * If no local ip sockets then fall back to sending a global broadcast letting the OS choose the interface.
     274         */
     275        if (!result) {
     276                struct hdhomerun_discover_sock_t *dss = &ds->socks[0];
     277                result = hdhomerun_discover_send_internal(ds, dss, 0xFFFFFFFF, device_type, device_id);
     278        }
     279
     280        return result;
    329281}
    330282
    331 static int hdhomerun_discover_recv(struct hdhomerun_discover_sock_t *ds, struct hdhomerun_discover_device_t *result)
     283static bool_t hdhomerun_discover_send_target_ip(struct hdhomerun_discover_t *ds, uint32_t target_ip, uint32_t device_type, uint32_t device_id)
    332284{
    333         struct timeval t;
    334         t.tv_sec = 0;
    335         t.tv_usec = 250000;
     285        bool_t result = FALSE;
    336286
    337         fd_set readfds;
    338         FD_ZERO(&readfds);
    339         FD_SET(ds->sock, &readfds);
     287        /*
     288         * Send targeted packet from any local ip that is in the same subnet.
     289         * This will work with multiple separate 169.254.x.x interfaces.
     290         */
     291        unsigned int i;
     292        for (i = 1; i < ds->sock_count; i++) {
     293                struct hdhomerun_discover_sock_t *dss = &ds->socks[i];
     294                if ((target_ip & dss->subnet_mask) != (dss->local_ip & dss->subnet_mask)) {
     295                        continue;
     296                }
    340297
    341         if (select(ds->sock+1, &readfds, NULL, NULL, &t) < 0) {
    342                 return -1;
     298                result |= hdhomerun_discover_send_internal(ds, dss, target_ip, device_type, device_id);
    343299        }
    344         if (!FD_ISSET(ds->sock, &readfds)) {
    345                 return 0;
     300
     301        /*
     302         * If target IP does not match a local subnet then fall back to letting the OS choose the gateway interface.
     303         */
     304        if (!result) {
     305                struct hdhomerun_discover_sock_t *dss = &ds->socks[0];
     306                result = hdhomerun_discover_send_internal(ds, dss, target_ip, device_type, device_id);
    346307        }
    347308
    348         uint8_t buffer[1024];
     309        return result;
     310}
     311
     312static bool_t hdhomerun_discover_send(struct hdhomerun_discover_t *ds, uint32_t target_ip, uint32_t device_type, uint32_t device_id)
     313{
     314        if (target_ip != 0) {
     315                return hdhomerun_discover_send_target_ip(ds, target_ip, device_type, device_id);
     316        }
     317
     318        return hdhomerun_discover_send_wildcard_ip(ds, device_type, device_id);
     319}
     320
     321static int hdhomerun_discover_recv_internal(struct hdhomerun_discover_t *ds, struct hdhomerun_discover_sock_t *dss, struct hdhomerun_discover_device_t *result)
     322{
     323        struct hdhomerun_pkt_t *rx_pkt = &ds->rx_pkt;
     324        hdhomerun_pkt_reset(rx_pkt);
     325
    349326        struct sockaddr_in sock_addr;
     327        memset(&sock_addr, 0, sizeof(sock_addr));
    350328        socklen_t sockaddr_size = sizeof(sock_addr);
    351         int rx_length = recvfrom(ds->sock, (char *)buffer, sizeof(buffer), 0, (struct sockaddr *)&sock_addr, &sockaddr_size);
     329
     330        int rx_length = recvfrom(dss->sock, (char *)rx_pkt->end, (int)(rx_pkt->limit - rx_pkt->end), 0, (struct sockaddr *)&sock_addr, &sockaddr_size);
    352331        if (rx_length <= 0) {
    353332                /* Don't return error - windows machine on VPN can sometimes cause a sock error here but otherwise works. */
    354333                return 0;
    355334        }
    356         if (rx_length < HDHOMERUN_MIN_PEEK_LENGTH) {
    357                 return 0;
    358         }
     335        rx_pkt->end += rx_length;
    359336
    360         size_t length = hdhomerun_peek_packet_length(buffer);
    361         if (length > (size_t)rx_length) {
     337        uint16_t type;
     338        if (hdhomerun_pkt_open_frame(rx_pkt, &type) <= 0) {
    362339                return 0;
    363340        }
    364 
    365         uint8_t *ptr = buffer;
    366         uint8_t *end = buffer + length;
    367         int type = hdhomerun_process_packet(&ptr, &end);
    368341        if (type != HDHOMERUN_TYPE_DISCOVER_RPY) {
    369342                return 0;
    370343        }
     
    372345        result->ip_addr = ntohl(sock_addr.sin_addr.s_addr);
    373346        result->device_type = 0;
    374347        result->device_id = 0;
     348
    375349        while (1) {
    376350                uint8_t tag;
    377351                size_t len;
    378                 uint8_t *value;
    379                 if (hdhomerun_read_tlv(&ptr, end, &tag, &len, &value) < 0) {
     352                uint8_t *next = hdhomerun_pkt_read_tlv(rx_pkt, &tag, &len);
     353                if (!next) {
    380354                        break;
    381355                }
    382356
     
    385359                        if (len != 4) {
    386360                                break;
    387361                        }
    388                         result->device_type = hdhomerun_read_u32(&value);
     362                        result->device_type = hdhomerun_pkt_read_u32(rx_pkt);
    389363                        break;
     364
    390365                case HDHOMERUN_TAG_DEVICE_ID:
    391366                        if (len != 4) {
    392367                                break;
    393368                        }
    394                         result->device_id = hdhomerun_read_u32(&value);
     369                        result->device_id = hdhomerun_pkt_read_u32(rx_pkt);
    395370                        break;
     371
    396372                default:
    397373                        break;
    398374                }
     375
     376                rx_pkt->pos = next;
    399377        }
    400378
    401379        return 1;
    402380}
    403381
    404 static struct hdhomerun_discover_device_t *hdhomerun_discover_find_in_list(struct hdhomerun_discover_device_t result_list[], int count, uint32_t device_id)
     382static int hdhomerun_discover_recv(struct hdhomerun_discover_t *ds, struct hdhomerun_discover_device_t *result)
    405383{
     384        struct timeval t;
     385        t.tv_sec = 0;
     386        t.tv_usec = 250000;
     387
     388        fd_set readfds;
     389        FD_ZERO(&readfds);
     390        int max_sock = -1;
     391
     392        unsigned int i;
     393        for (i = 0; i < ds->sock_count; i++) {
     394                struct hdhomerun_discover_sock_t *dss = &ds->socks[i];
     395                FD_SET(dss->sock, &readfds);
     396                if (dss->sock > max_sock) {
     397                        max_sock = dss->sock;
     398                }
     399        }
     400
     401        if (select(max_sock+1, &readfds, NULL, NULL, &t) < 0) {
     402                return -1;
     403        }
     404
     405        for (i = 0; i < ds->sock_count; i++) {
     406                struct hdhomerun_discover_sock_t *dss = &ds->socks[i];
     407                if (!FD_ISSET(dss->sock, &readfds)) {
     408                        continue;
     409                }
     410
     411                if (hdhomerun_discover_recv_internal(ds, dss, result) <= 0) {
     412                        continue;
     413                }
     414
     415                return 1;
     416        }
     417
     418        return 0;
     419}
     420
     421static struct hdhomerun_discover_device_t *hdhomerun_discover_find_in_list(struct hdhomerun_discover_device_t result_list[], int count, uint32_t ip_addr)
     422{
    406423        int index;
    407424        for (index = 0; index < count; index++) {
    408425                struct hdhomerun_discover_device_t *result = &result_list[index];
    409                 if (result->device_id == device_id) {
     426                if (result->ip_addr == ip_addr) {
    410427                        return result;
    411428                }
    412429        }
     
    414431        return NULL;
    415432}
    416433
    417 static int hdhomerun_discover_find_devices_internal(struct hdhomerun_discover_sock_t *ds, uint32_t device_type, uint32_t device_id, struct hdhomerun_discover_device_t result_list[], int max_count)
     434static int hdhomerun_discover_find_devices_internal(struct hdhomerun_discover_t *ds, uint32_t target_ip, uint32_t device_type, uint32_t device_id, struct hdhomerun_discover_device_t result_list[], int max_count)
    418435{
    419436        int count = 0;
    420 
    421437        int attempt;
    422438        for (attempt = 0; attempt < 4; attempt++) {
    423                 if (hdhomerun_discover_send(ds, device_type, device_id) < 0) {
     439                if (!hdhomerun_discover_send(ds, target_ip, device_type, device_id)) {
    424440                        return -1;
    425441                }
    426442
     
    433449                                return -1;
    434450                        }
    435451                        if (ret == 0) {
    436                                 break;
     452                                continue;
    437453                        }
    438454
    439455                        /* Filter. */
     
    449465                        }
    450466
    451467                        /* Ensure not already in list. */
    452                         if (hdhomerun_discover_find_in_list(result_list, count, result->device_id)) {
     468                        if (hdhomerun_discover_find_in_list(result_list, count, result->ip_addr)) {
    453469                                continue;
    454470                        }
    455471
     
    464480        return count;
    465481}
    466482
    467 int hdhomerun_discover_find_device(uint32_t device_id, struct hdhomerun_discover_device_t *result)
     483int hdhomerun_discover_find_devices_custom(uint32_t target_ip, uint32_t device_type, uint32_t device_id, struct hdhomerun_discover_device_t result_list[], int max_count)
    468484{
    469         struct hdhomerun_discover_sock_t *ds = hdhomerun_discover_create();
     485        struct hdhomerun_discover_t *ds = hdhomerun_discover_create();
    470486        if (!ds) {
    471487                return -1;
    472488        }
    473489
    474         int ret = hdhomerun_discover_find_devices_internal(ds, HDHOMERUN_DEVICE_TYPE_WILDCARD, device_id, result, 1);
     490        int ret = hdhomerun_discover_find_devices_internal(ds, target_ip, device_type, device_id, result_list, max_count);
    475491
    476492        hdhomerun_discover_destroy(ds);
    477493        return ret;
    478494}
    479495
    480 int hdhomerun_discover_find_devices(uint32_t device_type, struct hdhomerun_discover_device_t result_list[], int max_count)
    481 {
    482         struct hdhomerun_discover_sock_t *ds = hdhomerun_discover_create();
    483         if (!ds) {
    484                 return -1;
    485         }
    486 
    487         int ret = hdhomerun_discover_find_devices_internal(ds, device_type, HDHOMERUN_DEVICE_ID_WILDCARD, result_list, max_count);
    488 
    489         hdhomerun_discover_destroy(ds);
    490         return ret;
    491 }
    492 
    493496bool_t hdhomerun_discover_validate_device_id(uint32_t device_id)
    494497{
    495498        static uint32_t lookup_table[16] = {0xA, 0x5, 0xF, 0x6, 0x7, 0xC, 0x1, 0xB, 0x9, 0x2, 0x8, 0xD, 0x4, 0x3, 0xE, 0x0};
  • libs/libmythtv/hdhomerun/hdhomerun_dhcp.c

     
     1/*
     2 * hdhomerun_dhcp.c
     3 *
     4 * Copyright © 2006-2007 Silicondust Engineering Ltd. <www.silicondust.com>.
     5 *
     6 * This library is free software; you can redistribute it and/or
     7 * modify it under the terms of the GNU Lesser General Public
     8 * License as published by the Free Software Foundation; either
     9 * version 3 of the License, or (at your option) any later version.
     10 *
     11 * This library is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14 * Lesser General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU Lesser General Public
     17 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
     18 */
     19
     20#include "hdhomerun.h"
     21#include "hdhomerun_dhcp.h"
     22
     23struct dhcp_hdr_t {
     24        uint8_t bootp_message_type;
     25        uint8_t hardware_type;
     26        uint8_t hardware_address_length;
     27        uint8_t hops;
     28        uint32_t transaction_id;
     29        uint16_t seconds_elapsed;
     30        uint16_t bootp_flags;
     31        uint32_t client_ip;
     32        uint32_t your_ip;
     33        uint32_t next_server_ip;
     34        uint32_t relay_agent_ip;
     35        uint8_t client_mac[16];
     36        uint8_t server_host_name[64];
     37        uint8_t boot_file_name[128];
     38        uint32_t magic_cookie;
     39};
     40
     41struct hdhomerun_dhcp_t {
     42        int sock;
     43        uint32_t local_address;
     44        pthread_t thread;
     45        volatile bool_t terminate;
     46};
     47
     48static THREAD_FUNC_PREFIX hdhomerun_dhcp_thread_execute(void *arg);
     49
     50struct hdhomerun_dhcp_t *hdhomerun_dhcp_create(uint32_t bind_address)
     51{
     52        if (bind_address != 0) {
     53                if ((bind_address & 0xFFFF0000) != 0xA9FE0000) {
     54                        return NULL;
     55                }
     56        }
     57
     58        /* Create socket. */
     59        int sock = (int)socket(AF_INET, SOCK_DGRAM, 0);
     60        if (sock == -1) {
     61                return NULL;
     62        }
     63
     64        /* Set timeout. */
     65        setsocktimeout(sock, SOL_SOCKET, SO_RCVTIMEO, 1000);
     66
     67        /* Allow broadcast. */
     68        int sock_opt = 1;
     69        setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&sock_opt, sizeof(sock_opt));
     70
     71        /* Allow reuse. */
     72        sock_opt = 1;
     73        setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&sock_opt, sizeof(sock_opt));
     74
     75        /* Bind socket. */
     76        struct sockaddr_in sock_addr;
     77        memset(&sock_addr, 0, sizeof(sock_addr));
     78        sock_addr.sin_family = AF_INET;
     79        sock_addr.sin_addr.s_addr = htonl(bind_address);
     80        sock_addr.sin_port = htons(67);
     81        if (bind(sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) {
     82                close(sock);
     83                return NULL;
     84        }
     85
     86        /* Allocate object. */
     87        struct hdhomerun_dhcp_t *dhcp = (struct hdhomerun_dhcp_t *)calloc(1, sizeof(struct hdhomerun_dhcp_t));
     88        if (!dhcp) {
     89                close(sock);
     90                return NULL;
     91        }
     92
     93        dhcp->sock = sock;
     94
     95        if (bind_address != 0) {
     96                dhcp->local_address = bind_address;
     97        } else {
     98                dhcp->local_address = 0xA9FEFFFF;
     99        }
     100
     101        /* Spawn thread. */
     102        if (pthread_create(&dhcp->thread, NULL, &hdhomerun_dhcp_thread_execute, dhcp) != 0) {
     103                close(sock);
     104                free(dhcp);
     105                return NULL;
     106        }
     107
     108        /* Success. */
     109        return dhcp;
     110}
     111
     112void hdhomerun_dhcp_destroy(struct hdhomerun_dhcp_t *dhcp)
     113{
     114        dhcp->terminate = TRUE;
     115        pthread_join(dhcp->thread, NULL);
     116
     117        close(dhcp->sock);
     118        free(dhcp);
     119}
     120
     121static void hdhomerun_dhcp_send(struct hdhomerun_dhcp_t *dhcp, uint8_t message_type, struct hdhomerun_pkt_t *pkt)
     122{
     123        pkt->pos = pkt->start;
     124        struct dhcp_hdr_t *hdr = (struct dhcp_hdr_t *)pkt->pos;
     125        pkt->pos += sizeof(struct dhcp_hdr_t);
     126        pkt->end = pkt->pos;
     127
     128        uint32_t remote_addr = 0xA9FE0000;
     129        remote_addr |= (uint32_t)hdr->client_mac[4] << 8;
     130        remote_addr |= (uint32_t)hdr->client_mac[5] << 0;
     131        if ((remote_addr == 0xA9FE0000) || (remote_addr == 0xA9FEFFFF)) {
     132                remote_addr = 0xA9FE8080;
     133        }
     134
     135        hdr->bootp_message_type = 0x02;
     136        hdr->your_ip = htonl(remote_addr);
     137        hdr->next_server_ip = htonl(0x00000000);
     138
     139        hdhomerun_pkt_write_u8(pkt, 53);
     140        hdhomerun_pkt_write_u8(pkt, 1);
     141        hdhomerun_pkt_write_u8(pkt, message_type);
     142
     143        hdhomerun_pkt_write_u8(pkt, 54);
     144        hdhomerun_pkt_write_u8(pkt, 4);
     145        hdhomerun_pkt_write_u32(pkt, dhcp->local_address);
     146
     147        hdhomerun_pkt_write_u8(pkt, 51);
     148        hdhomerun_pkt_write_u8(pkt, 4);
     149        hdhomerun_pkt_write_u32(pkt, 7*24*60*60);
     150
     151        hdhomerun_pkt_write_u8(pkt, 1);
     152        hdhomerun_pkt_write_u8(pkt, 4);
     153        hdhomerun_pkt_write_u32(pkt, 0xFFFF0000);
     154
     155        hdhomerun_pkt_write_u8(pkt, 0xFF);
     156
     157        while (pkt->pos < pkt->start + 300) {
     158                hdhomerun_pkt_write_u8(pkt, 0x00);
     159        }
     160
     161        struct sockaddr_in sock_addr;
     162        memset(&sock_addr, 0, sizeof(sock_addr));
     163        sock_addr.sin_family = AF_INET;
     164        sock_addr.sin_addr.s_addr = htonl(0xFFFFFFFF);
     165        sock_addr.sin_port = htons(68);
     166
     167        sendto(dhcp->sock, (char *)pkt->start, (int)(pkt->end - pkt->start), 0, (struct sockaddr *)&sock_addr, sizeof(sock_addr));
     168}
     169
     170static void hdhomerun_dhcp_recv(struct hdhomerun_dhcp_t *dhcp, struct hdhomerun_pkt_t *pkt)
     171{
     172        pkt->pos = pkt->start;
     173        struct dhcp_hdr_t *hdr = (struct dhcp_hdr_t *)pkt->pos;
     174        pkt->pos += sizeof(struct dhcp_hdr_t);
     175        if (pkt->pos > pkt->end) {
     176                return;
     177        }
     178
     179        if (ntohl(hdr->magic_cookie) != 0x63825363) {
     180                return;
     181        }
     182
     183        static uint8_t vendor[3] = {0x00, 0x18, 0xDD};
     184        if (memcmp(hdr->client_mac, vendor, 3) != 0) {
     185                return;
     186        }
     187
     188        if (pkt->pos + 3 > pkt->end) {
     189                return;
     190        }
     191        if (hdhomerun_pkt_read_u8(pkt) != 53) {
     192                return;
     193        }
     194        if (hdhomerun_pkt_read_u8(pkt) != 1) {
     195                return;
     196        }
     197        uint8_t message_type_val = hdhomerun_pkt_read_u8(pkt);
     198
     199        switch (message_type_val) {
     200        case 0x01:
     201                hdhomerun_dhcp_send(dhcp, 0x02, pkt);
     202                break;
     203        case 0x03:
     204                hdhomerun_dhcp_send(dhcp, 0x05, pkt);
     205                break;
     206        default:
     207                return;
     208        }
     209}
     210
     211static THREAD_FUNC_PREFIX hdhomerun_dhcp_thread_execute(void *arg)
     212{
     213        struct hdhomerun_dhcp_t *dhcp = (struct hdhomerun_dhcp_t *)arg;
     214        struct hdhomerun_pkt_t pkt_inst;
     215
     216        while (1) {
     217                if (dhcp->terminate) {
     218                        return NULL;
     219                }
     220
     221                struct hdhomerun_pkt_t *pkt = &pkt_inst;
     222                hdhomerun_pkt_reset(pkt);
     223
     224                int rx_length = recv(dhcp->sock, (char *)pkt->end, (int)(pkt->limit - pkt->end), 0);
     225                if (rx_length <= 0) {
     226                        if (!sock_getlasterror_socktimeout) {
     227                                sleep(1);
     228                        }
     229                        continue;
     230                }
     231                pkt->end += rx_length;
     232
     233                hdhomerun_dhcp_recv(dhcp, pkt);
     234        }
     235}
  • libs/libmythtv/hdhomerun/hdhomerun_control.c

     
    33 *
    44 * Copyright © 2006 Silicondust Engineering Ltd. <www.silicondust.com>.
    55 *
    6  * This library is free software; you can redistribute it and/or
     6 * This library is free software; you can redistribute it and/or 
    77 * modify it under the terms of the GNU Lesser General Public
    88 * License as published by the Free Software Foundation; either
    9  * version 2.1 of the License, or (at your option) any later version.
     9 * version 3 of the License, or (at your option) any later version.
    1010 *
    1111 * This library is distributed in the hope that it will be useful,
    1212 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     
    1414 * Lesser General Public License for more details.
    1515 *
    1616 * You should have received a copy of the GNU Lesser General Public
    17  * License along with this library; if not, write to the Free Software
    18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     17 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
     18 *
     19 * As a special exception to the GNU Lesser General Public License,
     20 * you may link, statically or dynamically, an application with a
     21 * publicly distributed version of the Library to produce an
     22 * executable file containing portions of the Library, and
     23 * distribute that executable file under terms of your choice,
     24 * without any of the additional requirements listed in clause 4 of
     25 * the GNU Lesser General Public License.
     26 *
     27 * By "a publicly distributed version of the Library", we mean
     28 * either the unmodified Library as distributed by Silicondust, or a
     29 * modified version of the Library that is distributed under the
     30 * conditions defined in the GNU Lesser General Public License.
    1931 */
    2032
    21 #include "hdhomerun_os.h"
    22 #include "hdhomerun_pkt.h"
    23 #include "hdhomerun_discover.h"
    24 #include "hdhomerun_control.h"
     33#include "hdhomerun.h"
    2534
     35#define HDHOMERUN_CONTROL_SEND_TIMEOUT 5000
     36#define HDHOMERUN_CONTROL_RECV_TIMEOUT 5000
     37#define HDHOMERUN_CONTROL_UPGRADE_TIMEOUT 20000
     38
    2639struct hdhomerun_control_sock_t {
    27         uint32_t device_id;
    28         uint32_t device_ip;
     40        uint32_t desired_device_id;
     41        uint32_t desired_device_ip;
     42        uint32_t actual_device_id;
     43        uint32_t actual_device_ip;
    2944        int sock;
    30         uint8_t buffer[16384];
     45        struct hdhomerun_debug_t *dbg;
     46        struct hdhomerun_pkt_t tx_pkt;
     47        struct hdhomerun_pkt_t rx_pkt;
    3148};
    3249
    33 struct hdhomerun_control_sock_t *hdhomerun_control_create(uint32_t device_id, uint32_t device_ip)
     50static void hdhomerun_control_close_sock(struct hdhomerun_control_sock_t *cs)
    3451{
    35         struct hdhomerun_control_sock_t *cs = (struct hdhomerun_control_sock_t *)malloc(sizeof(struct hdhomerun_control_sock_t));
     52        if (cs->sock == -1) {
     53                return;
     54        }
     55
     56        close(cs->sock);
     57        cs->sock = -1;
     58}
     59
     60void hdhomerun_control_set_device(struct hdhomerun_control_sock_t *cs, uint32_t device_id, uint32_t device_ip)
     61{
     62        hdhomerun_control_close_sock(cs);
     63
     64        cs->desired_device_id = device_id;
     65        cs->desired_device_ip = device_ip;
     66        cs->actual_device_id = 0;
     67        cs->actual_device_ip = 0;
     68}
     69
     70struct hdhomerun_control_sock_t *hdhomerun_control_create(uint32_t device_id, uint32_t device_ip, struct hdhomerun_debug_t *dbg)
     71{
     72        struct hdhomerun_control_sock_t *cs = (struct hdhomerun_control_sock_t *)calloc(1, sizeof(struct hdhomerun_control_sock_t));
    3673        if (!cs) {
     74                hdhomerun_debug_printf(dbg, "hdhomerun_control_create: failed to allocate control object\n");
    3775                return NULL;
    3876        }
    39        
    40         cs->device_id = device_id;
    41         cs->device_ip = device_ip;
     77
     78        cs->dbg = dbg;
    4279        cs->sock = -1;
     80        hdhomerun_control_set_device(cs, device_id, device_ip);
    4381
    4482        return cs;
    4583}
    4684
    4785void hdhomerun_control_destroy(struct hdhomerun_control_sock_t *cs)
    4886{
    49         if (cs->sock != -1) {
    50                 close(cs->sock);
    51         }
     87        hdhomerun_control_close_sock(cs);
    5288        free(cs);
    5389}
    5490
    55 static void hdhomerun_control_close_sock(struct hdhomerun_control_sock_t *cs)
    56 {
    57         close(cs->sock);
    58         cs->sock = -1;
    59 }
    60 
    6191static bool_t hdhomerun_control_connect_sock(struct hdhomerun_control_sock_t *cs)
    6292{
    6393        if (cs->sock != -1) {
    6494                return TRUE;
    6595        }
    669