Ticket #6672: mythtv-0.21-fixes-hdhomerun-update.1.patch

File mythtv-0.21-fixes-hdhomerun-update.1.patch, 251.5 KB (added by mikeb@…, 11 years ago)

replaces all previous patches

  • libs/libmythtv/hdhomerun/hdhomerun_control.h

     
    11/*
    22 * hdhomerun_control.h
    33 *
    4  * Copyright © 2006 Silicondust Engineering Ltd. <www.silicondust.com>.
     4 * Copyright © 2006 Silicondust USA Inc. <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

     
    11/*
    2  * hdhomerun_device.h
     2 * hdhomerun.h
    33 *
    4  * Copyright © 2006 Silicondust Engineering Ltd. <www.silicondust.com>.
     4 * Copyright © 2006-2008 Silicondust USA Inc. <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_os.h"
     34#include "hdhomerun_types.h"
    2235#include "hdhomerun_pkt.h"
     36#include "hdhomerun_debug.h"
    2337#include "hdhomerun_discover.h"
    2438#include "hdhomerun_control.h"
    2539#include "hdhomerun_video.h"
     40#include "hdhomerun_channels.h"
     41#include "hdhomerun_channelscan.h"
    2642#include "hdhomerun_device.h"
     43#include "hdhomerun_device_selector.h"
  • libs/libmythtv/hdhomerun/hdhomerun_debug.c

     
     1/*
     2 * hdhomerun_debug.c
     3 *
     4 * Copyright © 2006 Silicondust USA Inc. <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 USA Inc. <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 USA Inc. <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 USA Inc. <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

     
    11/*
    22 * hdhomerun_pkt.c
    33 *
    4  * Copyright © 2005-2006 Silicondust Engineering Ltd. <www.silicondust.com>.
     4 * Copyright © 2005-2006 Silicondust USA Inc. <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 USA Inc. <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;
     40        uint32_t device_id;
    3041        unsigned int tuner;
    31         char result_buffer[1024];
     42        uint32_t lockkey;
     43        char name[32];
     44        char model[32];
    3245};
    3346
    34 struct hdhomerun_device_t *hdhomerun_device_create(uint32_t device_id, uint32_t device_ip, unsigned int tuner)
     47static void hdhomerun_device_set_update(struct hdhomerun_device_t *hd)
    3548{
     49        /* Clear cached information. */
     50        *hd->model = 0;
     51
     52        /* New name. */
     53        sprintf(hd->name, "%08lX-%u", (unsigned long)hd->device_id, hd->tuner);
     54}
     55
     56void hdhomerun_device_set_device(struct hdhomerun_device_t *hd, uint32_t device_id, uint32_t device_ip)
     57{
     58        hdhomerun_control_set_device(hd->cs, device_id, device_ip);
     59
     60        if ((device_id == 0) || (device_id == HDHOMERUN_DEVICE_ID_WILDCARD)) {
     61                device_id = hdhomerun_control_get_device_id(hd->cs);
     62        }
     63
     64        hd->device_id = device_id;
     65        hdhomerun_device_set_update(hd);
     66}
     67
     68void hdhomerun_device_set_tuner(struct hdhomerun_device_t *hd, unsigned int tuner)
     69{
     70        hd->tuner = tuner;
     71        hdhomerun_device_set_update(hd);
     72}
     73
     74struct hdhomerun_device_t *hdhomerun_device_create(uint32_t device_id, uint32_t device_ip, unsigned int tuner, struct hdhomerun_debug_t *dbg)
     75{
    3676        struct hdhomerun_device_t *hd = (struct hdhomerun_device_t *)calloc(1, sizeof(struct hdhomerun_device_t));
    3777        if (!hd) {
     78                hdhomerun_debug_printf(dbg, "hdhomerun_device_create: failed to allocate device object\n");
    3879                return NULL;
    3980        }
    4081
    41         hd->tuner = tuner;
     82        hd->dbg = dbg;
    4283
    43         hd->cs = hdhomerun_control_create(device_id, device_ip);
     84        hd->cs = hdhomerun_control_create(0, 0, hd->dbg);
    4485        if (!hd->cs) {
     86                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_create: failed to create control object\n");
    4587                free(hd);
    4688                return NULL;
    4789        }
    4890
     91        hdhomerun_device_set_device(hd, device_id, device_ip);
     92        hdhomerun_device_set_tuner(hd, tuner);
     93
    4994        return hd;
    5095}
    5196
    5297void hdhomerun_device_destroy(struct hdhomerun_device_t *hd)
    5398{
     99        if (hd->scan) {
     100                channelscan_destroy(hd->scan);
     101        }
     102
    54103        if (hd->vs) {
    55104                hdhomerun_video_destroy(hd->vs);
    56105        }
     
    60109        free(hd);
    61110}
    62111
    63 void hdhomerun_device_set_tuner(struct hdhomerun_device_t *hd, unsigned int tuner)
     112static bool_t is_hex_char(char c)
    64113{
    65         hd->tuner = tuner;
     114        if ((c >= '0') && (c <= '9')) {
     115                return TRUE;
     116        }
     117        if ((c >= 'A') && (c <= 'F')) {
     118                return TRUE;
     119        }
     120        if ((c >= 'a') && (c <= 'f')) {
     121                return TRUE;
     122        }
     123        return FALSE;
    66124}
    67125
     126static struct hdhomerun_device_t *hdhomerun_device_create_from_str_device_id(const char *device_str, struct hdhomerun_debug_t *dbg)
     127{
     128        int i;
     129        const char *ptr = device_str;
     130        for (i = 0; i < 8; i++) {
     131                if (!is_hex_char(*ptr++)) {
     132                        return NULL;
     133                }
     134        }
     135
     136        if (*ptr == 0) {
     137                unsigned long device_id;
     138                if (sscanf(device_str, "%lx", &device_id) != 1) {
     139                        return NULL;
     140                }
     141                return hdhomerun_device_create((uint32_t)device_id, 0, 0, dbg);
     142        }
     143
     144        if (*ptr == '-') {
     145                unsigned long device_id;
     146                unsigned int tuner;
     147                if (sscanf(device_str, "%lx-%u", &device_id, &tuner) != 2) {
     148                        return NULL;
     149                }
     150                return hdhomerun_device_create((uint32_t)device_id, 0, tuner, dbg);
     151        }
     152
     153        return NULL;
     154}
     155
     156static struct hdhomerun_device_t *hdhomerun_device_create_from_str_ip(const char *device_str, struct hdhomerun_debug_t *dbg)
     157{
     158        unsigned long a[4];
     159        if (sscanf(device_str, "%lu.%lu.%lu.%lu", &a[0], &a[1], &a[2], &a[3]) != 4) {
     160                return NULL;
     161        }
     162
     163        unsigned long device_ip = (a[0] << 24) | (a[1] << 16) | (a[2] << 8) | (a[3] << 0);
     164        return hdhomerun_device_create(HDHOMERUN_DEVICE_ID_WILDCARD, (uint32_t)device_ip, 0, dbg);
     165}
     166
     167static struct hdhomerun_device_t *hdhomerun_device_create_from_str_dns(const char *device_str, struct hdhomerun_debug_t *dbg)
     168{
     169#if defined(__CYGWIN__)
     170        return NULL;
     171#else
     172        struct addrinfo hints;
     173        memset(&hints, 0, sizeof(hints));
     174        hints.ai_family = AF_INET;
     175        hints.ai_socktype = SOCK_STREAM;
     176        hints.ai_protocol = IPPROTO_TCP;
     177
     178        struct addrinfo *sock_info;
     179        if (getaddrinfo(device_str, "65001", &hints, &sock_info) != 0) {
     180                return NULL;
     181        }
     182
     183        struct sockaddr_in *sock_addr = (struct sockaddr_in *)sock_info->ai_addr;
     184        uint32_t device_ip = ntohl(sock_addr->sin_addr.s_addr);
     185        freeaddrinfo(sock_info);
     186
     187        if (device_ip == 0) {
     188                return NULL;
     189        }
     190
     191        return hdhomerun_device_create(HDHOMERUN_DEVICE_ID_WILDCARD, (uint32_t)device_ip, 0, dbg);
     192#endif
     193}
     194
     195struct hdhomerun_device_t *hdhomerun_device_create_from_str(const char *device_str, struct hdhomerun_debug_t *dbg)
     196{
     197        struct hdhomerun_device_t *device = hdhomerun_device_create_from_str_device_id(device_str, dbg);
     198        if (device) {
     199                return device;
     200        }
     201
     202        device = hdhomerun_device_create_from_str_ip(device_str, dbg);
     203        if (device) {
     204                return device;
     205        }
     206
     207        device = hdhomerun_device_create_from_str_dns(device_str, dbg);
     208        if (device) {
     209                return device;
     210        }
     211
     212        return NULL;
     213}
     214
     215int hdhomerun_device_set_tuner_from_str(struct hdhomerun_device_t *hd, const char *tuner_str)
     216{
     217        unsigned int tuner;
     218        if (sscanf(tuner_str, "%u", &tuner) == 1) {
     219                hdhomerun_device_set_tuner(hd, tuner);
     220                return 1;
     221        }
     222        if (sscanf(tuner_str, "/tuner%u", &tuner) == 1) {
     223                hdhomerun_device_set_tuner(hd, tuner);
     224                return 1;
     225        }
     226
     227        return -1;
     228}
     229
     230const char *hdhomerun_device_get_name(struct hdhomerun_device_t *hd)
     231{
     232        return hd->name;
     233}
     234
     235uint32_t hdhomerun_device_get_device_id(struct hdhomerun_device_t *hd)
     236{
     237        return hdhomerun_control_get_device_id(hd->cs);
     238}
     239
     240uint32_t hdhomerun_device_get_device_ip(struct hdhomerun_device_t *hd)
     241{
     242        return hdhomerun_control_get_device_ip(hd->cs);
     243}
     244
     245uint32_t hdhomerun_device_get_device_id_requested(struct hdhomerun_device_t *hd)
     246{
     247        return hdhomerun_control_get_device_id_requested(hd->cs);
     248}
     249
     250uint32_t hdhomerun_device_get_device_ip_requested(struct hdhomerun_device_t *hd)
     251{
     252        return hdhomerun_control_get_device_ip_requested(hd->cs);
     253}
     254
     255unsigned int hdhomerun_device_get_tuner(struct hdhomerun_device_t *hd)
     256{
     257        return hd->tuner;
     258}
     259
    68260struct hdhomerun_control_sock_t *hdhomerun_device_get_control_sock(struct hdhomerun_device_t *hd)
    69261{
    70262        return hd->cs;
     
    72264
    73265struct hdhomerun_video_sock_t *hdhomerun_device_get_video_sock(struct hdhomerun_device_t *hd)
    74266{
     267        if (hd->vs) {
     268                return hd->vs;
     269        }
     270
     271        hd->vs = hdhomerun_video_create(0, VIDEO_DATA_BUFFER_SIZE_1S * 2, hd->dbg);
    75272        if (!hd->vs) {
    76                 hd->vs = hdhomerun_video_create(0, VIDEO_DATA_BUFFER_SIZE_1S);
     273                hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_get_video_sock: failed to create video object\n");
     274                return NULL;
    77275        }
     276
    78277        return hd->vs;
    79278}
    80279
     
    96295        return (uint32_t)value;
    97296}
    98297
    99 int hdhomerun_device_get_tuner_status(struct hdhomerun_device_t *hd, struct hdhomerun_tuner_status_t *status)
     298static bool_t hdhomerun_device_get_tuner_status_lock_is_bcast(struct hdhomerun_tuner_status_t *status)
    100299{
     300        if (strcmp(status->lock_str, "8vsb") == 0) {
     301                return TRUE;
     302        }
     303        if (strncmp(status->lock_str, "t8", 2) == 0) {
     304                return TRUE;
     305        }
     306        if (strncmp(status->lock_str, "t7", 2) == 0) {
     307                return TRUE;
     308        }
     309        if (strncmp(status->lock_str, "t6", 2) == 0) {
     310                return TRUE;
     311        }
     312
     313        return FALSE;
     314}
     315
     316uint32_t hdhomerun_device_get_tuner_status_ss_color(struct hdhomerun_tuner_status_t *status)
     317{
     318        unsigned int ss_yellow_min;
     319        unsigned int ss_green_min;
     320
     321        if (!status->lock_supported) {
     322                return HDHOMERUN_STATUS_COLOR_NEUTRAL;
     323        }
     324
     325        if (hdhomerun_device_get_tuner_status_lock_is_bcast(status)) {
     326                ss_yellow_min = 50;     /* -30dBmV */
     327                ss_green_min = 75;      /* -15dBmV */
     328        } else {
     329                ss_yellow_min = 80;     /* -12dBmV */
     330                ss_green_min = 90;      /* -6dBmV */
     331        }
     332
     333        if (status->signal_strength >= ss_green_min) {
     334                return HDHOMERUN_STATUS_COLOR_GREEN;
     335        }
     336        if (status->signal_strength >= ss_yellow_min) {
     337                return HDHOMERUN_STATUS_COLOR_YELLOW;
     338        }
     339
     340        return HDHOMERUN_STATUS_COLOR_RED;
     341}
     342
     343uint32_t hdhomerun_device_get_tuner_status_snq_color(struct hdhomerun_tuner_status_t *status)
     344{
     345        if (status->signal_to_noise_quality >= 70) {
     346                return HDHOMERUN_STATUS_COLOR_GREEN;
     347        }
     348        if (status->signal_to_noise_quality >= 50) {
     349                return HDHOMERUN_STATUS_COLOR_YELLOW;
     350        }
     351
     352        return HDHOMERUN_STATUS_COLOR_RED;
     353}
     354
     355uint32_t hdhomerun_device_get_tuner_status_seq_color(struct hdhomerun_tuner_status_t *status)
     356{
     357        if (status->symbol_error_quality >= 100) {
     358                return HDHOMERUN_STATUS_COLOR_GREEN;
     359        }
     360
     361        return HDHOMERUN_STATUS_COLOR_RED;
     362}
     363
     364int hdhomerun_device_get_tuner_status(struct hdhomerun_device_t *hd, char **pstatus_str, struct hdhomerun_tuner_status_t *status)
     365{
    101366        memset(status, 0, sizeof(struct hdhomerun_tuner_status_t));
    102367
    103368        char name[32];
     
    109374                return ret;
    110375        }
    111376
     377        if (pstatus_str) {
     378                *pstatus_str = status_str;
     379        }
     380
    112381        char *channel = strstr(status_str, "ch=");
    113382        if (channel) {
    114                 sscanf(channel + 3, "%s", status->channel);
     383                sscanf(channel + 3, "%31s", status->channel);
    115384        }
    116385
     386        char *lock = strstr(status_str, "lock=");
     387        if (lock) {
     388                sscanf(lock + 5, "%31s", status->lock_str);
     389        }
     390
    117391        status->signal_strength = (unsigned int)hdhomerun_device_get_status_parse(status_str, "ss=");
    118392        status->signal_to_noise_quality = (unsigned int)hdhomerun_device_get_status_parse(status_str, "snq=");
    119393        status->symbol_error_quality = (unsigned int)hdhomerun_device_get_status_parse(status_str, "seq=");
    120394        status->raw_bits_per_second = hdhomerun_device_get_status_parse(status_str, "bps=");
    121395        status->packets_per_second = hdhomerun_device_get_status_parse(status_str, "pps=");
    122396
     397        status->signal_present = status->signal_strength >= 45;
     398
     399        if (strcmp(status->lock_str, "none") != 0) {
     400                if (status->lock_str[0] == '(') {
     401                        status->lock_unsupported = TRUE;
     402                } else {
     403                        status->lock_supported = TRUE;
     404                }
     405        }
     406
    123407        return 1;
    124408}
    125409
     
    151435        return hdhomerun_control_get(hd->cs, name, pfilter, NULL);
    152436}
    153437
    154 int hdhomerun_device_get_tuner_program(struct hdhomerun_device_t *hd, uint16_t *pprogram_number)
     438int hdhomerun_device_get_tuner_program(struct hdhomerun_device_t *hd, char **pprogram)
    155439{
    156440        char name[32];
    157441        sprintf(name, "/tuner%u/program", hd->tuner);
     442        return hdhomerun_control_get(hd->cs, name, pprogram, NULL);
     443}
    158444
    159         char *program_str;
    160         int ret = hdhomerun_control_get(hd->cs, name, &program_str, NULL);
     445int hdhomerun_device_get_tuner_target(struct hdhomerun_device_t *hd, char **ptarget)
     446{
     447        char name[32];
     448        sprintf(name, "/tuner%u/target", hd->tuner);
     449        return hdhomerun_control_get(hd->cs, name, ptarget, NULL);
     450}
     451
     452int hdhomerun_device_get_tuner_plotsample(struct hdhomerun_device_t *hd, struct hdhomerun_plotsample_t **psamples, size_t *pcount)
     453{
     454        char name[32];
     455        sprintf(name, "/tuner%u/plotsample", hd->tuner);
     456
     457        char *result;
     458        int ret = hdhomerun_control_get(hd->cs, name, &result, NULL);
    161459        if (ret <= 0) {
    162460                return ret;
    163461        }
    164462
    165         *pprogram_number = (uint16_t)atol(program_str);
     463        struct hdhomerun_plotsample_t *samples = (struct hdhomerun_plotsample_t *)result;
     464        *psamples = samples;
     465        size_t count = 0;
     466
     467        while (1) {
     468                char *ptr = strchr(result, ' ');
     469                if (!ptr) {
     470                        break;
     471                }
     472                *ptr++ = 0;
     473
     474                unsigned long raw;
     475                if (sscanf(result, "%lx", &raw) != 1) {
     476                        break;
     477                }
     478
     479                uint16_t real = (raw >> 12) & 0x0FFF;
     480                if (real & 0x0800) {
     481                        real |= 0xF000;
     482                }
     483
     484                uint16_t imag = (raw >> 0) & 0x0FFF;
     485                if (imag & 0x0800) {
     486                        imag |= 0xF000;
     487                }
     488
     489                samples->real = (int16_t)real;
     490                samples->imag = (int16_t)imag;
     491                samples++;
     492                count++;
     493
     494                result = ptr;
     495        }
     496
     497        *pcount = count;
    166498        return 1;
    167499}
    168500
    169 int hdhomerun_device_get_tuner_target(struct hdhomerun_device_t *hd, char **ptarget)
     501int hdhomerun_device_get_tuner_lockkey_owner(struct hdhomerun_device_t *hd, char **powner)
    170502{
    171503        char name[32];
    172         sprintf(name, "/tuner%u/target", hd->tuner);
    173         return hdhomerun_control_get(hd->cs, name, ptarget, NULL);
     504        sprintf(name, "/tuner%u/lockkey", hd->tuner);
     505        return hdhomerun_control_get(hd->cs, name, powner, NULL);
    174506}
    175507
    176508int hdhomerun_device_get_ir_target(struct hdhomerun_device_t *hd, char **ptarget)
     
    178510        return hdhomerun_control_get(hd->cs, "/ir/target", ptarget, NULL);
    179511}
    180512
     513int hdhomerun_device_get_lineup_location(struct hdhomerun_device_t *hd, char **plocation)
     514{
     515        return hdhomerun_control_get(hd->cs, "/lineup/location", plocation, NULL);
     516}
     517
    181518int hdhomerun_device_get_version(struct hdhomerun_device_t *hd, char **pversion_str, uint32_t *pversion_num)
    182519{
    183520        char *version_str;
     
    206543{
    207544        char name[32];
    208545        sprintf(name, "/tuner%u/channel", hd->tuner);
    209         return hdhomerun_control_set(hd->cs, name, channel, NULL, NULL);
     546        return hdhomerun_control_set_with_lockkey(hd->cs, name, channel, hd->lockkey, NULL, NULL);
    210547}
    211548
    212549int hdhomerun_device_set_tuner_channelmap(struct hdhomerun_device_t *hd, const char *channelmap)
    213550{
    214551        char name[32];
    215552        sprintf(name, "/tuner%u/channelmap", hd->tuner);
    216         return hdhomerun_control_set(hd->cs, name, channelmap, NULL, NULL);
     553        return hdhomerun_control_set_with_lockkey(hd->cs, name, channelmap, hd->lockkey, NULL, NULL);
    217554}
    218555
    219556int hdhomerun_device_set_tuner_filter(struct hdhomerun_device_t *hd, const char *filter)
    220557{
    221558        char name[32];
    222559        sprintf(name, "/tuner%u/filter", hd->tuner);
    223         return hdhomerun_control_set(hd->cs, name, filter, NULL, NULL);
     560        return hdhomerun_control_set_with_lockkey(hd->cs, name, filter, hd->lockkey, NULL, NULL);
    224561}
    225562
    226 int hdhomerun_device_set_tuner_program(struct hdhomerun_device_t *hd, uint16_t program_number)
     563static int hdhomerun_device_set_tuner_filter_by_array_append(char **pptr, char *end, uint16_t range_begin, uint16_t range_end)
    227564{
    228         char name[32], value[32];
     565        char *ptr = *pptr;
     566
     567        size_t available = end - ptr;
     568        size_t required;
     569
     570        if (range_begin == range_end) {
     571                required = snprintf(ptr, available, "0x%04x ", range_begin) + 1;
     572        } else {
     573                required = snprintf(ptr, available, "0x%04x-0x%04x ", range_begin, range_end) + 1;
     574        }
     575
     576        if (required > available) {
     577                return FALSE;
     578        }
     579
     580        *pptr = strchr(ptr, 0);
     581        return TRUE;
     582}
     583
     584int hdhomerun_device_set_tuner_filter_by_array(struct hdhomerun_device_t *hd, unsigned char filter_array[0x2000])
     585{
     586        char filter[1024];
     587        char *ptr = filter;
     588        char *end = filter + sizeof(filter);
     589
     590        uint16_t range_begin = 0xFFFF;
     591        uint16_t range_end = 0xFFFF;
     592
     593        uint16_t i;
     594        for (i = 0; i <= 0x1FFF; i++) {
     595                if (!filter_array[i]) {
     596                        if (range_begin == 0xFFFF) {
     597                                continue;
     598                        }
     599                        if (!hdhomerun_device_set_tuner_filter_by_array_append(&ptr, end, range_begin, range_end)) {
     600                                return 0;
     601                        }
     602                        range_begin = 0xFFFF;
     603                        range_end = 0xFFFF;
     604                        continue;
     605                }
     606
     607                if (range_begin == 0xFFFF) {
     608                        range_begin = i;
     609                        range_end = i;
     610                        continue;
     611                }
     612
     613                range_end = i;
     614        }
     615
     616        if (range_begin != 0xFFFF) {
     617                if (!hdhomerun_device_set_tuner_filter_by_array_append(&ptr, end, range_begin, range_end)) {
     618                        return 0;
     619                }
     620        }
     621
     622        /* Remove trailing space. */
     623        if (ptr > filter) {
     624                ptr--;
     625        }
     626        *ptr = 0;
     627
     628        return hdhomerun_device_set_tuner_filter(hd, filter);
     629}
     630
     631int hdhomerun_device_set_tuner_program(struct hdhomerun_device_t *hd, const char *program)
     632{
     633        char name[32];
    229634        sprintf(name, "/tuner%u/program", hd->tuner);
    230         sprintf(value, "%u", program_number);
    231         return hdhomerun_control_set(hd->cs, name, value, NULL, NULL);
     635        return hdhomerun_control_set_with_lockkey(hd->cs, name, program, hd->lockkey, NULL, NULL);
    232636}
    233637
    234 int hdhomerun_device_set_tuner_target(struct hdhomerun_device_t *hd, char *target)
     638int hdhomerun_device_set_tuner_target(struct hdhomerun_device_t *hd, const char *target)
    235639{
    236640        char name[32];
    237641        sprintf(name, "/tuner%u/target", hd->tuner);
    238         return hdhomerun_control_set(hd->cs, name, target, NULL, NULL);
     642        return hdhomerun_control_set_with_lockkey(hd->cs, name, target, hd->lockkey, NULL, NULL);
    239643}
    240644
    241 static int hdhomerun_device_set_tuner_target_to_local(struct hdhomerun_device_t *hd)
     645int hdhomerun_device_set_tuner_target_to_local_protocol(struct hdhomerun_device_t *hd, const char *protocol)
    242646{
     647        /* Create video socket. */
     648        hdhomerun_device_get_video_sock(hd);
     649        if (!hd->vs) {
     650                return -1;
     651        }
     652
     653        /* Set target. */
    243654        char target[64];
    244655        uint32_t local_ip = hdhomerun_control_get_local_addr(hd->cs);
    245656        uint16_t local_port = hdhomerun_video_get_local_port(hd->vs);
    246         sprintf(target, "%u.%u.%u.%u:%u",
     657        sprintf(target, "%s://%u.%u.%u.%u:%u",
     658                protocol,
    247659                (unsigned int)(local_ip >> 24) & 0xFF, (unsigned int)(local_ip >> 16) & 0xFF,
    248660                (unsigned int)(local_ip >> 8) & 0xFF, (unsigned int)(local_ip >> 0) & 0xFF,
    249661                (unsigned int)local_port
     
    252664        return hdhomerun_device_set_tuner_target(hd, target);
    253665}
    254666
     667int hdhomerun_device_set_tuner_target_to_local(struct hdhomerun_device_t *hd)
     668{
     669        return hdhomerun_device_set_tuner_target_to_local_protocol(hd, HDHOMERUN_TARGET_PROTOCOL_UDP);
     670}
     671
    255672int hdhomerun_device_set_ir_target(struct hdhomerun_device_t *hd, const char *target)
    256673{
    257674        return hdhomerun_control_set(hd->cs, "/ir/target", target, NULL, NULL);
    258675}
    259676
     677int hdhomerun_device_set_lineup_location(struct hdhomerun_device_t *hd, const char *location)
     678{
     679        return hdhomerun_control_set(hd->cs, "/lineup/location", location, NULL, NULL);
     680}
     681
    260682int hdhomerun_device_get_var(struct hdhomerun_device_t *hd, const char *name, char **pvalue, char **perror)
    261683{
    262684        return hdhomerun_control_get(hd->cs, name, pvalue, perror);
     
    264686
    265687int hdhomerun_device_set_var(struct hdhomerun_device_t *hd, const char *name, const char *value, char **pvalue, char **perror)
    266688{
    267         return hdhomerun_control_set(hd->cs, name, value, pvalue, perror);
     689        return hdhomerun_control_set_with_lockkey(hd->cs, name, value, hd->lockkey, pvalue, perror);
    268690}
    269691
    270 int hdhomerun_device_stream_start(struct hdhomerun_device_t *hd)
     692int hdhomerun_device_tuner_lockkey_request(struct hdhomerun_device_t *hd, char **perror)
    271693{
    272         /* Create video socket. */
    273         hdhomerun_device_get_video_sock(hd);
    274         if (!hd->vs) {
    275                 return -1;
     694        uint32_t new_lockkey = (uint32_t)getcurrenttime();
     695
     696        char name[32];
     697        sprintf(name, "/tuner%u/lockkey", hd->tuner);
     698
     699        char new_lockkey_str[64];
     700        sprintf(new_lockkey_str, "%u", (unsigned int)new_lockkey);
     701
     702        int ret = hdhomerun_control_set_with_lockkey(hd->cs, name, new_lockkey_str, hd->lockkey, NULL, perror);
     703        if (ret <= 0) {
     704                hd->lockkey = 0;
     705                return ret;
    276706        }
    277707
     708        hd->lockkey = new_lockkey;
     709        return ret;
     710}
     711
     712int hdhomerun_device_tuner_lockkey_release(struct hdhomerun_device_t *hd)
     713{
     714        if (hd->lockkey == 0) {
     715                return 1;
     716        }
     717
     718        char name[32];
     719        sprintf(name, "/tuner%u/lockkey", hd->tuner);
     720        int ret = hdhomerun_control_set_with_lockkey(hd->cs, name, "none", hd->lockkey, NULL, NULL);
     721
     722        hd->lockkey = 0;
     723        return ret;
     724}
     725
     726int hdhomerun_device_tuner_lockkey_force(struct hdhomerun_device_t *hd)
     727{
     728        char name[32];
     729        sprintf(name, "/tuner%u/lockkey", hd->tuner);
     730        int ret = hdhomerun_control_set(hd->cs, name, "force", NULL, NULL);
     731
     732        hd->lockkey = 0;
     733        return ret;
     734}
     735
     736void hdhomerun_device_tuner_lockkey_use_value(struct hdhomerun_device_t *hd, uint32_t lockkey)
     737{
     738        hd->lockkey = lockkey;
     739}
     740
     741int hdhomerun_device_wait_for_lock(struct hdhomerun_device_t *hd, struct hdhomerun_tuner_status_t *status)
     742{
     743        /* Delay for SS reading to be valid (signal present). */
     744        msleep(250);
     745
     746        /* Wait for up to 2.5 seconds for lock. */
     747        uint64_t timeout = getcurrenttime() + 2500;
     748        while (1) {
     749                /* Get status to check for lock. Quality numbers will not be valid yet. */
     750                int ret = hdhomerun_device_get_tuner_status(hd, NULL, status);
     751                if (ret <= 0) {
     752                        return ret;
     753                }
     754
     755                if (!status->signal_present) {
     756                        return 1;
     757                }
     758                if (status->lock_supported || status->lock_unsupported) {
     759                        return 1;
     760                }
     761
     762                if (getcurrenttime() >= timeout) {
     763                        return 1;
     764                }
     765
     766                msleep(250);
     767        }
     768}
     769
     770int hdhomerun_device_stream_start(struct hdhomerun_device_t *hd)
     771{
    278772        /* Set target. */
    279         int ret = hdhomerun_device_set_tuner_target_to_local(hd);
     773        int ret = hdhomerun_device_stream_refresh_target(hd);
    280774        if (ret <= 0) {
    281775                return ret;
    282776        }
    283777
    284778        /* Flush video buffer. */
    285         usleep(64000);
     779        msleep(64);
    286780        hdhomerun_video_flush(hd->vs);
    287781
    288782        /* Success. */
    289783        return 1;
    290784}
    291785
     786int hdhomerun_device_stream_refresh_target(struct hdhomerun_device_t *hd)
     787{
     788        int ret = hdhomerun_device_set_tuner_target_to_local_protocol(hd, HDHOMERUN_TARGET_PROTOCOL_RTP);
     789        if (ret == 0) {
     790                ret = hdhomerun_device_set_tuner_target_to_local_protocol(hd, HDHOMERUN_TARGET_PROTOCOL_UDP);
     791        }
     792        return ret;
     793}
     794
    292795uint8_t *hdhomerun_device_stream_recv(struct hdhomerun_device_t *hd, size_t max_size, size_t *pactual_size)
    293796{
     797        if (!hd->vs) {
     798                return NULL;
     799        }
    294800        return hdhomerun_video_recv(hd->vs, max_size, pactual_size);
    295801}
    296802
     803void hdhomerun_device_stream_flush(struct hdhomerun_device_t *hd)
     804{
     805        hdhomerun_video_flush(hd->vs);
     806}
     807
    297808void hdhomerun_device_stream_stop(struct hdhomerun_device_t *hd)
    298809{
    299810        hdhomerun_device_set_tuner_target(hd, "none");
    300811}
    301812
     813int hdhomerun_device_channelscan_init(struct hdhomerun_device_t *hd, const char *channelmap)
     814{
     815        if (hd->scan) {
     816                channelscan_destroy(hd->scan);
     817        }
     818
     819        hd->scan = channelscan_create(hd, channelmap);
     820        if (!hd->scan) {
     821                return -1;
     822        }
     823
     824        return 1;
     825}
     826
     827int hdhomerun_device_channelscan_advance(struct hdhomerun_device_t *hd, struct hdhomerun_channelscan_result_t *result)
     828{
     829        if (!hd->scan) {
     830                return 0;
     831        }
     832
     833        int ret = channelscan_advance(hd->scan, result);
     834        if (ret <= 0) {
     835                channelscan_destroy(hd->scan);
     836                hd->scan = NULL;
     837        }
     838
     839        return ret;
     840}
     841
     842int hdhomerun_device_channelscan_detect(struct hdhomerun_device_t *hd, struct hdhomerun_channelscan_result_t *result)
     843{
     844        if (!hd->scan) {
     845                return 0;
     846        }
     847
     848        int ret = channelscan_detect(hd->scan, result);
     849        if (ret <= 0) {
     850                channelscan_destroy(hd->scan);
     851                hd->scan = NULL;
     852        }
     853
     854        return ret;
     855}
     856
     857uint8_t hdhomerun_device_channelscan_get_progress(struct hdhomerun_device_t *hd)
     858{
     859        if (!hd->scan) {
     860                return 0;
     861        }
     862
     863        return channelscan_get_progress(hd->scan);
     864}
     865
    302866int hdhomerun_device_firmware_version_check(struct hdhomerun_device_t *hd, uint32_t features)
    303867{
    304868        uint32_t version;
     
    306870                return -1;
    307871        }
    308872
    309         if (version >= 20061213) {
    310                 return 1;
     873        if (version < 20070219) {
     874                return 0;
    311875        }
    312876
    313         return 0;
     877        return 1;
    314878}
    315879
     880const char *hdhomerun_device_get_model_str(struct hdhomerun_device_t *hd)
     881{
     882        if (*hd->model) {
     883                return hd->model;
     884        }
     885
     886        char *model_str;
     887        int ret = hdhomerun_control_get(hd->cs, "/sys/model", &model_str, NULL);
     888        if (ret < 0) {
     889                return NULL;
     890        }
     891        if (ret == 0) {
     892                model_str = "hdhomerun_atsc";
     893        }
     894
     895        strncpy(hd->model, model_str, sizeof(hd->model) - 1);
     896        hd->model[sizeof(hd->model) - 1] = 0;
     897
     898        return hd->model;
     899}
     900
    316901int hdhomerun_device_upgrade(struct hdhomerun_device_t *hd, FILE *upgrade_file)
    317902{
     903        hdhomerun_control_set(hd->cs, "/tuner0/lockkey", "force", NULL, NULL);
    318904        hdhomerun_control_set(hd->cs, "/tuner0/channel", "none", NULL, NULL);
     905
     906        hdhomerun_control_set(hd->cs, "/tuner1/lockkey", "force", NULL, NULL);
    319907        hdhomerun_control_set(hd->cs, "/tuner1/channel", "none", NULL, NULL);
     908
    320909        return hdhomerun_control_upgrade(hd->cs, upgrade_file);
    321910}
     911
     912void hdhomerun_device_debug_print_video_stats(struct hdhomerun_device_t *hd)
     913{
     914        if (!hdhomerun_debug_enabled(hd->dbg)) {
     915                return;
     916        }
     917
     918        char name[32];
     919        sprintf(name, "/tuner%u/debug", hd->tuner);
     920
     921        char *debug_str;
     922        char *error_str;
     923        int ret = hdhomerun_control_get(hd->cs, name, &debug_str, &error_str);
     924        if (ret < 0) {
     925                hdhomerun_debug_printf(hd->dbg, "video dev: communication error getting debug stats\n");
     926                return;
     927        }
     928
     929        if (error_str) {
     930                hdhomerun_debug_printf(hd->dbg, "video dev: %s\n", error_str);
     931        } else {
     932                hdhomerun_debug_printf(hd->dbg, "video dev: %s\n", debug_str);
     933        }
     934
     935        if (hd->vs) {
     936                hdhomerun_video_debug_print_stats(hd->vs);
     937        }
     938}
     939
     940void hdhomerun_device_get_video_stats(struct hdhomerun_device_t *hd, struct hdhomerun_video_stats_t *stats)
     941{
     942        hdhomerun_video_get_stats(hd->vs, stats);
     943}
  • libs/libmythtv/hdhomerun/hdhomerun_channels.h

     
     1/*
     2 * hdhomerun_channels.h
     3 *
     4 * Copyright © 2007-2008 Silicondust USA Inc. <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 USA Inc. <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

     
    11/*
    22 * hdhomerun_pkt.h
    33 *
    4  * Copyright © 2005-2006 Silicondust Engineering Ltd. <www.silicondust.com>.
     4 * Copyright © 2005-2006 Silicondust USA Inc. <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 USA Inc. <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_TARGET_PROTOCOL_UDP "udp"
     42#define HDHOMERUN_TARGET_PROTOCOL_RTP "rtp"
    3043
    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 };
    39 
    4044/*
    4145 * Create a device object.
    4246 *
     
    4549 *
    4650 * For example, a threaded application that streams video from 4 tuners (2 HDHomeRun devices) and has
    4751 * GUI feedback to the user of the selected tuner might use 5 device objects: 4 for streaming video
    48  * (one per thread) and one for the GUI display that can just between tuners.
     52 * (one per thread) and one for the GUI display that can switch between tuners.
    4953 *
    50  * This function will not attempt to connect to the device.
    51  * The connection will be established when first used.
     54 * This function will not attempt to connect to the device. The connection will be established when first used.
    5255 *
    5356 * uint32_t device_id = 32-bit device id of device. Set to HDHOMERUN_DEVICE_ID_WILDCARD to match any device ID.
    5457 * uint32_t device_ip = IP address of device. Set to 0 to auto-detect.
    5558 * unsigned int tuner = tuner index (0 or 1). Can be changed later by calling hdhomerun_device_set_tuner.
     59 * struct hdhomerun_debug_t *dbg: Pointer to debug logging object. May be NULL.
    5660 *
    5761 * Returns a pointer to the newly created device object.
    5862 *
    5963 * When no longer needed, the socket should be destroyed by calling hdhomerun_device_destroy.
     64 *
     65 * The hdhomerun_device_create_from_str function creates a device object from the given device_str.
     66 * The device_str parameter can be any of the following forms:
     67 *     <device id>
     68 *     <device id>-<tuner index>
     69 *     <ip address>
     70 * If the tuner index is not included in the device_str then it is set to zero. Use hdhomerun_device_set_tuner
     71 * or hdhomerun_device_set_tuner_from_str to set the tuner.
     72 *
     73 * The hdhomerun_device_set_tuner_from_str function sets the tuner from the given tuner_str.
     74 * The tuner_str parameter can be any of the following forms:
     75 *     <tuner index>
     76 *     /tuner<tuner index>
    6077 */
    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);
     78extern LIBTYPE struct hdhomerun_device_t *hdhomerun_device_create(uint32_t device_id, uint32_t device_ip, unsigned int tuner, struct hdhomerun_debug_t *dbg);
     79extern LIBTYPE struct hdhomerun_device_t *hdhomerun_device_create_from_str(const char *device_str, struct hdhomerun_debug_t *dbg);
     80extern LIBTYPE void hdhomerun_device_destroy(struct hdhomerun_device_t *hd);
    6481
    6582/*
     83 * Get the device id, ip, or tuner of the device instance.
     84 */
     85extern LIBTYPE const char *hdhomerun_device_get_name(struct hdhomerun_device_t *hd);
     86extern LIBTYPE uint32_t hdhomerun_device_get_device_id(struct hdhomerun_device_t *hd);
     87extern LIBTYPE uint32_t hdhomerun_device_get_device_ip(struct hdhomerun_device_t *hd);
     88extern LIBTYPE uint32_t hdhomerun_device_get_device_id_requested(struct hdhomerun_device_t *hd);
     89extern LIBTYPE uint32_t hdhomerun_device_get_device_ip_requested(struct hdhomerun_device_t *hd);
     90extern LIBTYPE unsigned int hdhomerun_device_get_tuner(struct hdhomerun_device_t *hd);
     91
     92extern LIBTYPE void hdhomerun_device_set_device(struct hdhomerun_device_t *hd, uint32_t device_id, uint32_t device_ip);
     93extern LIBTYPE void hdhomerun_device_set_tuner(struct hdhomerun_device_t *hd, unsigned int tuner);
     94extern LIBTYPE int hdhomerun_device_set_tuner_from_str(struct hdhomerun_device_t *hd, const char *tuner_str);
     95
     96/*
    6697 * Get the local machine IP address used when communicating with the device.
    6798 *
    6899 * This function is useful for determining the IP address to use with set target commands.
    69100 *
    70101 * Returns 32-bit IP address with native endianness, or 0 on error.
    71102 */
    72 extern uint32_t hdhomerun_device_get_local_machine_addr(struct hdhomerun_device_t *hd);
     103extern LIBTYPE uint32_t hdhomerun_device_get_local_machine_addr(struct hdhomerun_device_t *hd);
    73104
    74105/*
    75106 * Get operations.
     
    82113 * Returns 0 if the operation was rejected.
    83114 * Returns -1 if a communication error occurred.
    84115 */
    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);
     116extern LIBTYPE int hdhomerun_device_get_tuner_status(struct hdhomerun_device_t *hd, char **pstatus_str, struct hdhomerun_tuner_status_t *status);
     117extern LIBTYPE int hdhomerun_device_get_tuner_streaminfo(struct hdhomerun_device_t *hd, char **pstreaminfo);
     118extern LIBTYPE int hdhomerun_device_get_tuner_channel(struct hdhomerun_device_t *hd, char **pchannel);
     119extern LIBTYPE int hdhomerun_device_get_tuner_channelmap(struct hdhomerun_device_t *hd, char **pchannelmap);
     120extern LIBTYPE int hdhomerun_device_get_tuner_filter(struct hdhomerun_device_t *hd, char **pfilter);
     121extern LIBTYPE int hdhomerun_device_get_tuner_program(struct hdhomerun_device_t *hd, char **pprogram);
     122extern LIBTYPE int hdhomerun_device_get_tuner_target(struct hdhomerun_device_t *hd, char **ptarget);
     123extern LIBTYPE int hdhomerun_device_get_tuner_plotsample(struct hdhomerun_device_t *hd, struct hdhomerun_plotsample_t **psamples, size_t *pcount);
     124extern LIBTYPE int hdhomerun_device_get_tuner_lockkey_owner(struct hdhomerun_device_t *hd, char **powner);
     125extern LIBTYPE int hdhomerun_device_get_ir_target(struct hdhomerun_device_t *hd, char **ptarget);
     126extern LIBTYPE int hdhomerun_device_get_lineup_location(struct hdhomerun_device_t *hd, char **plocation);
     127extern LIBTYPE int hdhomerun_device_get_version(struct hdhomerun_device_t *hd, char **pversion_str, uint32_t *pversion_num);
    94128
     129extern LIBTYPE uint32_t hdhomerun_device_get_tuner_status_ss_color(struct hdhomerun_tuner_status_t *status);
     130extern LIBTYPE uint32_t hdhomerun_device_get_tuner_status_snq_color(struct hdhomerun_tuner_status_t *status);
     131extern LIBTYPE uint32_t hdhomerun_device_get_tuner_status_seq_color(struct hdhomerun_tuner_status_t *status);
     132
     133extern LIBTYPE const char *hdhomerun_device_get_model_str(struct hdhomerun_device_t *hd);
     134
    95135/*
    96136 * Set operations.
    97137 *
     
    101141 * Returns 0 if the operation was rejected.
    102142 * Returns -1 if a communication error occurred.
    103143 */
    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);
     144extern LIBTYPE int hdhomerun_device_set_tuner_channel(struct hdhomerun_device_t *hd, const char *channel);
     145extern LIBTYPE int hdhomerun_device_set_tuner_channelmap(struct hdhomerun_device_t *hd, const char *channelmap);
     146extern LIBTYPE int hdhomerun_device_set_tuner_filter(struct hdhomerun_device_t *hd, const char *filter);
     147extern LIBTYPE int hdhomerun_device_set_tuner_filter_by_array(struct hdhomerun_device_t *hd, unsigned char filter_array[0x2000]);
     148extern LIBTYPE int hdhomerun_device_set_tuner_program(struct hdhomerun_device_t *hd, const char *program);
     149extern LIBTYPE int hdhomerun_device_set_tuner_target(struct hdhomerun_device_t *hd, const char *target);
     150extern LIBTYPE int hdhomerun_device_set_tuner_target_to_local_protocol(struct hdhomerun_device_t *hd, const char *protocol);
     151extern LIBTYPE int hdhomerun_device_set_tuner_target_to_local(struct hdhomerun_device_t *hd);
     152extern LIBTYPE int hdhomerun_device_set_ir_target(struct hdhomerun_device_t *hd, const char *target);
     153extern LIBTYPE int hdhomerun_device_set_lineup_location(struct hdhomerun_device_t *hd, const char *location);
    110154
    111155/*
    112156 * Get/set a named control variable on the device.
     
    125169 * Returns 0 if the operation was rejected (pvalue NULL, perror set).
    126170 * Returns -1 if a communication error occurs.
    127171 */
    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);
     172extern LIBTYPE int hdhomerun_device_get_var(struct hdhomerun_device_t *hd, const char *name, char **pvalue, char **perror);
     173extern LIBTYPE int hdhomerun_device_set_var(struct hdhomerun_device_t *hd, const char *name, const char *value, char **pvalue, char **perror);
    130174
    131175/*
     176 * Tuner locking.
     177 *
     178 * The hdhomerun_device_tuner_lockkey_request function is used to obtain a lock
     179 * or to verify that the hdhomerun_device object still holds the lock.
     180 * Returns 1 if the lock request was successful and the lock was obtained.
     181 * Returns 0 if the lock request was rejected.
     182 * Returns -1 if a communication error occurs.
     183 *
     184 * The hdhomerun_device_tuner_lockkey_release function is used to release a
     185 * previously held lock. If locking is used then this function must be called
     186 * before destroying the hdhomerun_device object.
     187 */
     188extern LIBTYPE int hdhomerun_device_tuner_lockkey_request(struct hdhomerun_device_t *hd, char **perror);
     189extern LIBTYPE int hdhomerun_device_tuner_lockkey_release(struct hdhomerun_device_t *hd);
     190extern LIBTYPE int hdhomerun_device_tuner_lockkey_force(struct hdhomerun_device_t *hd);
     191
     192/*
     193 * Intended only for non persistent connections; eg, hdhomerun_config.
     194 */
     195extern LIBTYPE void hdhomerun_device_tuner_lockkey_use_value(struct hdhomerun_device_t *hd, uint32_t lockkey);
     196
     197/*
     198 * Wait for tuner lock after channel change.
     199 *
     200 * The hdhomerun_device_wait_for_lock function is used to detect/wait for a lock vs no lock indication
     201 * after a channel change.
     202 *
     203 * It will return quickly if a lock is aquired.
     204 * It will return quickly if there is no signal detected.
     205 * Worst case it will time out after 1.5 seconds - the case where there is signal but no lock.
     206 */
     207extern LIBTYPE int hdhomerun_device_wait_for_lock(struct hdhomerun_device_t *hd, struct hdhomerun_tuner_status_t *status);
     208
     209/*
    132210 * Stream a filtered program or the unfiltered stream.
    133211 *
    134212 * The hdhomerun_device_stream_start function initializes the process and tells the device to start streamin data.
     
    144222 *
    145223 * The hdhomerun_device_stream_stop function tells the device to stop streaming data.
    146224 */
    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);
     225extern LIBTYPE int hdhomerun_device_stream_start(struct hdhomerun_device_t *hd);
     226extern LIBTYPE int hdhomerun_device_stream_refresh_target(struct hdhomerun_device_t *hd);
     227extern LIBTYPE uint8_t *hdhomerun_device_stream_recv(struct hdhomerun_device_t *hd, size_t max_size, size_t *pactual_size);
     228extern LIBTYPE void hdhomerun_device_stream_flush(struct hdhomerun_device_t *hd);
     229extern LIBTYPE void hdhomerun_device_stream_stop(struct hdhomerun_device_t *hd);
    150230
    151231/*
     232 * Channel scan API.
     233 */
     234extern LIBTYPE int hdhomerun_device_channelscan_init(struct hdhomerun_device_t *hd, const char *channelmap);
     235extern LIBTYPE int hdhomerun_device_channelscan_advance(struct hdhomerun_device_t *hd, struct hdhomerun_channelscan_result_t *result);
     236extern LIBTYPE int hdhomerun_device_channelscan_detect(struct hdhomerun_device_t *hd, struct hdhomerun_channelscan_result_t *result);
     237extern LIBTYPE uint8_t hdhomerun_device_channelscan_get_progress(struct hdhomerun_device_t *hd);
     238
     239/*
    152240 * Check that the device is running the recommended firmware.
    153241 *
    154242 * uint32_t features: Reserved for future use. Set to zero.
     
    157245 * Returns 0 if th firmware does not meet the minimum requriements for all operations.
    158246 * Returns -1 if an error occurs.
    159247 */
    160 extern int hdhomerun_device_firmware_version_check(struct hdhomerun_device_t *hd, uint32_t features);
     248extern LIBTYPE int hdhomerun_device_firmware_version_check(struct hdhomerun_device_t *hd, uint32_t features);
    161249
    162250/*
    163251 * Upload new firmware to the device.
     
    168256 * Returns 0 if the upload was rejected.
    169257 * Returns -1 if an error occurs.
    170258 */
    171 extern int hdhomerun_device_upgrade(struct hdhomerun_device_t *hd, FILE *upgrade_file);
     259extern LIBTYPE int hdhomerun_device_upgrade(struct hdhomerun_device_t *hd, FILE *upgrade_file);
    172260
    173261/*
    174262 * Low level accessor functions.
    175263 */
    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);
     264extern LIBTYPE struct hdhomerun_control_sock_t *hdhomerun_device_get_control_sock(struct hdhomerun_device_t *hd);
     265extern LIBTYPE struct hdhomerun_video_sock_t *hdhomerun_device_get_video_sock(struct hdhomerun_device_t *hd);
    178266
     267/*
     268 * Debug print internal stats.
     269 */
     270extern LIBTYPE void hdhomerun_device_debug_print_video_stats(struct hdhomerun_device_t *hd);
     271extern LIBTYPE void hdhomerun_device_get_video_stats(struct hdhomerun_device_t *hd, struct hdhomerun_video_stats_t *stats);
     272
    179273#ifdef __cplusplus
    180274}
    181275#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 USA Inc. <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 bool_t sigabort = FALSE;
     206
     207static void signal_abort(int arg)
    164208{
    165         unsigned int tuner;
    166         if (sscanf(tuner_str, "%u", &tuner) != 1) {
    167                 fprintf(stderr, "invalid tuner number\n");
    168                 return -1;
     209        sigabort = TRUE;
     210}
     211
     212static void cmd_scan_printf(FILE *fp, const char *fmt, ...)
     213{
     214        va_list ap;
     215        va_start(ap, fmt);
     216
     217        if (fp) {
     218                va_list apc;
     219                va_copy(apc, ap);
     220
     221                vfprintf(fp, fmt, apc);
     222                fflush(fp);
     223
     224                va_end(apc);
    169225        }
    170226
    171         hdhomerun_device_set_tuner(hd, tuner);
     227        vprintf(fmt, ap);
     228        fflush(stdout);
    172229
    173         char channel_str[64];
    174         strncpy(channel_str, start_value, sizeof(channel_str));
    175         channel_str[sizeof(channel_str) - 8] = 0;
     230        va_end(ap);
     231}
    176232
    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++;
     233static int cmd_scan(const char *tuner_str, const char *filename)
     234{
     235        if (hdhomerun_device_set_tuner_from_str(hd, tuner_str) <= 0) {
     236                fprintf(stderr, "invalid tuner number\n");
     237                return -1;
    182238        }
    183239
    184         unsigned int channel_number = atol(channel_number_ptr);
    185         if (channel_number == 0) {
    186                 fprintf(stderr, "invalid starting channel\n");
     240        char *ret_error;
     241        if (hdhomerun_device_tuner_lockkey_request(hd, &ret_error) <= 0) {
     242                fprintf(stderr, "failed to lock tuner\n");
     243                if (ret_error) {
     244                        fprintf(stderr, "%s\n", ret_error);
     245                }
    187246                return -1;
    188247        }
    189248
    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");
     249        hdhomerun_device_set_tuner_target(hd, "none");
     250
     251        char *channelmap;
     252        if (hdhomerun_device_get_tuner_channelmap(hd, &channelmap) <= 0) {
     253                fprintf(stderr, "failed to query channelmap from device\n");
    194254                return -1;
    195255        }
    196         if (ret == 0) {
    197                 fprintf(stderr, "invalid starting channel\n");
     256
     257        const char *channelmap_scan_group = hdhomerun_channelmap_get_channelmap_scan_group(channelmap);
     258        if (!channelmap_scan_group) {
     259                fprintf(stderr, "unknown channelmap '%s'\n", channelmap);
    198260                return -1;
    199261        }
    200262
    201         while (1) {
    202                 /* Update channel value */
    203                 sprintf(channel_number_ptr, "%u", channel_number);
     263        if (hdhomerun_device_channelscan_init(hd, channelmap_scan_group) <= 0) {
     264                fprintf(stderr, "failed to initialize channel scan\n");
     265                return -1;
     266        }
    204267
    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");
     268        FILE *fp = NULL;
     269        if (filename) {
     270                fp = fopen(filename, "w");
     271                if (!fp) {
     272                        fprintf(stderr, "unable to create file: %s\n", filename);
    209273                        return -1;
    210274                }
    211                 if (ret == 0) {
    212                         return 0;
     275        }
     276
     277        signal(SIGINT, signal_abort);
     278        signal(SIGPIPE, signal_abort);
     279
     280        int ret = 0;
     281        while (!sigabort) {
     282                struct hdhomerun_channelscan_result_t result;
     283                ret = hdhomerun_device_channelscan_advance(hd, &result);
     284                if (ret <= 0) {
     285                        break;
    213286                }
    214287
    215                 /* Wait 1.5s for lock (qam auto is the slowest to lock). */
    216                 usleep(HDHOMERUN_DEVICE_MAX_TUNE_TO_LOCK_TIME * 1000);
     288                cmd_scan_printf(fp, "SCANNING: %lu (%s)\n",
     289                        result.frequency, result.channel_str
     290                );
    217291
    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;
     292                ret = hdhomerun_device_channelscan_detect(hd, &result);
     293                if (ret <= 0) {
     294                        break;
    223295                }
    224296
    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;
     297                cmd_scan_printf(fp, "LOCK: %s (ss=%u snq=%u seq=%u)\n",
     298                        result.status.lock_str, result.status.signal_strength,
     299                        result.status.signal_to_noise_quality, result.status.symbol_error_quality
     300                );
     301
     302                if (result.transport_stream_id_detected) {
     303                        cmd_scan_printf(fp, "TSID: 0x%04X\n", result.transport_stream_id);
    230304                }
    231305
    232                 /* Wait for 2s. */
    233                 usleep(HDHOMERUN_DEVICE_MAX_LOCK_TO_DATA_TIME * 1000);
     306                int i;
     307                for (i = 0; i < result.program_count; i++) {
     308                        struct hdhomerun_channelscan_program_t *program = &result.programs[i];
     309                        cmd_scan_printf(fp, "PROGRAM %s\n", program->program_str);
     310                }
     311        }
    234312
    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");
     313        hdhomerun_device_tuner_lockkey_release(hd);
     314
     315        if (fp) {
     316                fclose(fp);
     317        }
     318        if (ret < 0) {
     319                fprintf(stderr, "communication error sending request to hdhomerun device\n");
     320        }
     321        return ret;
     322}
     323
     324static int cmd_save(const char *tuner_str, const char *filename)
     325{
     326        if (hdhomerun_device_set_tuner_from_str(hd, tuner_str) <= 0) {
     327                fprintf(stderr, "invalid tuner number\n");
     328                return -1;
     329        }
     330
     331        FILE *fp;
     332        if (strcmp(filename, "null") == 0) {
     333                fp = NULL;
     334        } else if (strcmp(filename, "-") == 0) {
     335                fp = stdout;
     336        } else {
     337                fp = fopen(filename, "wb");
     338                if (!fp) {
     339                        fprintf(stderr, "unable to create file %s\n", filename);
    238340                        return -1;
    239341                }
    240                 if (status.signal_strength == 0) {
    241                         printf("%s: no signal\n", channel_str);
    242                         channel_number++;
    243                         continue;
     342        }
     343
     344        int ret = hdhomerun_device_stream_start(hd);
     345        if (ret <= 0) {
     346                fprintf(stderr, "unable to start stream\n");
     347                if (fp && fp != stdout) {
     348                        fclose(fp);
    244349                }
    245                 printf("%s: ss=%u snq=%u seq=%u\n", channel_str, status.signal_strength, status.signal_to_noise_quality, status.symbol_error_quality);
     350                return ret;
     351        }
    246352
    247                 /* Detect sub channels. */
    248                 usleep(4 * 1000000);
    249                 char *streaminfo;
    250                 if (hdhomerun_device_get_tuner_streaminfo(hd, &streaminfo) <= 0) {
    251                         channel_number++;
     353        signal(SIGINT, signal_abort);
     354        signal(SIGPIPE, signal_abort);
     355
     356        struct hdhomerun_video_stats_t stats_old, stats_cur;
     357        hdhomerun_device_get_video_stats(hd, &stats_old);
     358
     359        uint64_t next_progress = getcurrenttime() + 1000;
     360
     361        while (!sigabort) {
     362                uint64_t loop_start_time = getcurrenttime();
     363
     364                size_t actual_size;
     365                uint8_t *ptr = hdhomerun_device_stream_recv(hd, VIDEO_DATA_BUFFER_SIZE_1S, &actual_size);
     366                if (!ptr) {
     367                        msleep(64);
    252368                        continue;
    253369                }
    254                 while (1) {
    255                         char *end = strchr(streaminfo, '\n');
    256                         if (!end) {
    257                                 break;
     370
     371                if (fp) {
     372                        if (fwrite(ptr, 1, actual_size, fp) != actual_size) {
     373                                fprintf(stderr, "error writing output\n");
     374                                return -1;
    258375                        }
     376                }
    259377
    260                         *end++ = 0;
    261                         printf("program %s\n", streaminfo);
     378                if (loop_start_time >= next_progress) {
     379                        next_progress += 1000;
     380                        if (loop_start_time >= next_progress) {
     381                                next_progress = loop_start_time + 1000;
     382                        }
    262383
    263                         streaminfo = end;
     384                        hdhomerun_device_get_video_stats(hd, &stats_cur);
     385
     386                        if (stats_cur.overflow_error_count > stats_old.overflow_error_count) {
     387                                fprintf(stderr, "o");
     388                        } else if (stats_cur.network_error_count > stats_old.network_error_count) {
     389                                fprintf(stderr, "n");
     390                        } else if (stats_cur.transport_error_count > stats_old.transport_error_count) {
     391                                fprintf(stderr, "t");
     392                        } else if (stats_cur.sequence_error_count > stats_old.sequence_error_count) {
     393                                fprintf(stderr, "s");
     394                        } else {
     395                                fprintf(stderr, ".");
     396                        }
     397
     398                        stats_old = stats_cur;
     399                        fflush(stderr);
    264400                }
    265401
    266                 /* Advance to next channel. */
    267                 channel_number++;
     402                int32_t delay = 64 - (int32_t)(getcurrenttime() - loop_start_time);
     403                if (delay <= 0) {
     404                        continue;
     405                }
     406
     407                msleep(delay);
    268408        }
     409
     410        if (fp) {
     411                fclose(fp);
     412        }
     413
     414        hdhomerun_device_stream_stop(hd);
     415        hdhomerun_device_get_video_stats(hd, &stats_cur);
     416
     417        fprintf(stderr, "\n");
     418        fprintf(stderr, "-- Video statistics --\n");
     419        fprintf(stderr, "%u packets received, %u overflow errors, %u network errors, %u transport errors, %u sequence errors\n",
     420                (unsigned int)stats_cur.packet_count,
     421                (unsigned int)stats_cur.overflow_error_count,
     422                (unsigned int)stats_cur.network_error_count,
     423                (unsigned int)stats_cur.transport_error_count,
     424                (unsigned int)stats_cur.sequence_error_count);
     425
     426        return 0;
    269427}
    270428
    271429static int cmd_upgrade(const char *filename)
     
    276434                return -1;
    277435        }
    278436
     437        printf("uploading firmware...\n");
    279438        if (hdhomerun_device_upgrade(hd, fp) <= 0) {
    280439                fprintf(stderr, "error sending upgrade file to hdhomerun device\n");
    281440                fclose(fp);
    282441                return -1;
    283442        }
     443        sleep(2);
    284444
    285         printf("upgrade complete\n");
     445        printf("upgrading firmware...\n");
     446        sleep(8);
     447
     448        printf("rebooting...\n");
     449        int count = 0;
     450        char *version_str;
     451        while (1) {
     452                if (hdhomerun_device_get_version(hd, &version_str, NULL) >= 0) {
     453                        break;
     454                }
     455
     456                count++;
     457                if (count > 30) {
     458                        fprintf(stderr, "error finding device after firmware upgrade\n");
     459                        fclose(fp);
     460                        return -1;
     461                }
     462
     463                sleep(1);
     464        }
     465
     466        printf("upgrade complete - now running firmware %s\n", version_str);
    286467        return 0;
    287468}
    288469
     470static int cmd_execute(void)
     471{
     472        char *ret_value;
     473        char *ret_error;
     474        if (hdhomerun_device_get_var(hd, "/sys/boot", &ret_value, &ret_error) < 0) {
     475                fprintf(stderr, "communication error sending request to hdhomerun device\n");
     476                return -1;
     477        }
     478
     479        if (ret_error) {
     480                printf("%s\n", ret_error);
     481                return 0;
     482        }
     483
     484        char *end = ret_value + strlen(ret_value);
     485        char *pos = ret_value;
     486
     487        while (1) {
     488                if (pos >= end) {
     489                        break;
     490                }
     491
     492                char *eol_r = strchr(pos, '\r');
     493                if (!eol_r) {
     494                        eol_r = end;
     495                }
     496
     497                char *eol_n = strchr(pos, '\n');
     498                if (!eol_n) {
     499                        eol_n = end;
     500                }
     501
     502                char *eol = eol_r;
     503                if (eol_n < eol) {
     504                        eol = eol_n;
     505                }
     506
     507                char *sep = strchr(pos, ' ');
     508                if (!sep || sep > eol) {
     509                        pos = eol + 1;
     510                        continue;
     511                }
     512
     513                *sep = 0;
     514                *eol = 0;
     515
     516                char *item = pos;
     517                char *value = sep + 1;
     518
     519                printf("set %s \"%s\"\n", item, value);
     520
     521                cmd_set_internal(item, value);
     522
     523                pos = eol + 1;
     524        }
     525
     526        return 1;
     527}
     528
    289529static int main_cmd(int argc, char *argv[])
    290530{
    291531        if (argc < 1) {
     
    294534
    295535        char *cmd = *argv++; argc--;
    296536
     537        if (contains(cmd, "key")) {
     538                if (argc < 2) {
     539                        return help();
     540                }
     541                uint32_t lockkey = strtoul(argv[0], NULL, 0);
     542                hdhomerun_device_tuner_lockkey_use_value(hd, lockkey);
     543
     544                cmd = argv[1];
     545                argv+=2; argc-=2;
     546        }
     547
    297548        if (contains(cmd, "get")) {
    298549                if (argc < 1) {
    299550                        return help();
     
    308559                return cmd_set(argv[0], argv[1]);
    309560        }
    310561
    311         if (contains(cmd, "streaminfo")) {
     562        if (contains(cmd, "scan")) {
    312563                if (argc < 1) {
    313564                        return help();
    314565                }
    315                 return cmd_streaminfo(argv[0]);
     566                if (argc < 2) {
     567                        return cmd_scan(argv[0], NULL);
     568                } else {
     569                        return cmd_scan(argv[0], argv[1]);
     570                }
    316571        }
    317572
    318         if (contains(cmd, "scan")) {
     573        if (contains(cmd, "save")) {
    319574                if (argc < 2) {
    320575                        return help();
    321576                }
    322                 return cmd_scan(argv[0], argv[1]);
     577                return cmd_save(argv[0], argv[1]);
    323578        }
    324579
    325580        if (contains(cmd, "upgrade")) {
     
    329584                return cmd_upgrade(argv[0]);
    330585        }
    331586
     587        if (contains(cmd, "execute")) {
     588                return cmd_execute();
     589        }
     590
    332591        return help();
    333592}
    334593
    335594static int main_internal(int argc, char *argv[])
    336595{
    337596#if defined(__WINDOWS__)
    338         //Start pthreads
    339         pthread_win32_process_attach_np();
    340 
    341         // Start WinSock
     597        /* Initialize network socket support. */
    342598        WORD wVersionRequested = MAKEWORD(2, 0);
    343599        WSADATA wsaData;
    344600        WSAStartup(wVersionRequested, &wsaData);
     
    357613                return help();
    358614        }
    359615        if (contains(id_str, "discover")) {
    360                 return discover_print();
     616                if (argc < 1) {
     617                        return discover_print(NULL);
     618                } else {
     619                        return discover_print(argv[0]);
     620                }
    361621        }
    362622
    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 
    369623        /* Device object. */
    370         hd = hdhomerun_device_create(device_id, device_ip, 0);
     624        hd = hdhomerun_device_create_from_str(id_str, NULL);
    371625        if (!hd) {
    372                 fprintf(stderr, "unable to create device\n");
     626                fprintf(stderr, "invalid device id: %s\n", id_str);
    373627                return -1;
    374628        }
    375629
    376         /* Connect to device and check firmware version. */
    377         int ret = hdhomerun_device_firmware_version_check(hd, 0);
    378         if (ret < 0) {
     630        /* Device ID check. */
     631        uint32_t device_id_requested = hdhomerun_device_get_device_id_requested(hd);
     632        if (!hdhomerun_discover_validate_device_id(device_id_requested)) {
     633                fprintf(stderr, "invalid device id: %08lX\n", (unsigned long)device_id_requested);
     634        }
     635
     636        /* Connect to device and check model. */
     637        const char *model = hdhomerun_device_get_model_str(hd);
     638        if (!model) {
    379639                fprintf(stderr, "unable to connect to device\n");
    380640                hdhomerun_device_destroy(hd);
    381641                return -1;
    382642        }
    383         if (ret == 0) {
    384                 fprintf(stderr, "WARNING: firmware upgrade needed for all operations to function\n");
    385         }
    386643
    387644        /* Command. */
    388         ret = main_cmd(argc, argv);
     645        int ret = main_cmd(argc, argv);
    389646
    390647        /* Cleanup. */
    391648        hdhomerun_device_destroy(hd);
  • libs/libmythtv/hdhomerun/hdhomerun_video.c

     
    11/*
    22 * hdhomerun_video.c
    33 *
    4  * Copyright © 2006 Silicondust Engineering Ltd. <www.silicondust.com>.
     4 * Copyright © 2006 Silicondust USA Inc. <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                        memset((void *)vs->sequence, 0xFF, sizeof(vs->sequence));
     202                }
     203        }
     204
     205        vs->rtp_sequence = rtp_sequence;
     206}
     207
     208static THREAD_FUNC_PREFIX hdhomerun_video_thread_execute(void *arg)
     209{
    159210        struct hdhomerun_video_sock_t *vs = (struct hdhomerun_video_sock_t *)arg;
     211        struct hdhomerun_pkt_t pkt_inst;
    160212
    161213        while (!vs->terminate) {
    162                 size_t head = vs->head;
     214                struct hdhomerun_pkt_t *pkt = &pkt_inst;
     215                hdhomerun_pkt_reset(pkt);
    163216
    164217                /* Receive. */
    165                 int length = recv(vs->sock, (char *)vs->buffer + head, VIDEO_DATA_PACKET_SIZE, 0);
     218                int length = recv(vs->sock, (char *)pkt->end, VIDEO_RTP_DATA_PACKET_SIZE, 0);
     219                pkt->end += length;
     220
     221                if (length == VIDEO_RTP_DATA_PACKET_SIZE) {
     222                        hdhomerun_video_parse_rtp(vs, pkt);
     223                        length = (int)(pkt->end - pkt->pos);
     224                }
     225
    166226                if (length != VIDEO_DATA_PACKET_SIZE) {
    167227                        if (length > 0) {
    168228                                /* Data received but not valid - ignore. */
     
    172232                                /* Wait for more data. */
    173233                                continue;
    174234                        }
    175                         vs->terminate = 1;
     235                        vs->terminate = TRUE;
    176236                        return NULL;
    177237                }
    178238
     239                pthread_mutex_lock(&vs->lock);
     240
     241                /* Store in ring buffer. */
     242                size_t head = vs->head;
     243                uint8_t *ptr = vs->buffer + head;
     244                memcpy(ptr, pkt->pos, length);
     245
     246                /* Stats. */
     247                vs->packet_count++;
     248                hdhomerun_video_stats_ts_pkt(vs, ptr + TS_PACKET_SIZE * 0);
     249                hdhomerun_video_stats_ts_pkt(vs, ptr + TS_PACKET_SIZE * 1);
     250                hdhomerun_video_stats_ts_pkt(vs, ptr + TS_PACKET_SIZE * 2);
     251                hdhomerun_video_stats_ts_pkt(vs, ptr + TS_PACKET_SIZE * 3);
     252                hdhomerun_video_stats_ts_pkt(vs, ptr + TS_PACKET_SIZE * 4);
     253                hdhomerun_video_stats_ts_pkt(vs, ptr + TS_PACKET_SIZE * 5);
     254                hdhomerun_video_stats_ts_pkt(vs, ptr + TS_PACKET_SIZE * 6);
     255
    179256                /* Calculate new head. */
    180257                head += length;
    181258                if (head >= vs->buffer_size) {
     
    184261
    185262                /* Check for buffer overflow. */
    186263                if (head == vs->tail) {
     264                        vs->overflow_error_count++;
     265                        pthread_mutex_unlock(&vs->lock);
    187266                        continue;
    188267                }
    189268
    190269                /* Atomic update. */
    191270                vs->head = head;
     271
     272                pthread_mutex_unlock(&vs->lock);
    192273        }
    193274
    194275        return NULL;
     
    196277
    197278uint8_t *hdhomerun_video_recv(struct hdhomerun_video_sock_t *vs, size_t max_size, size_t *pactual_size)
    198279{
     280        pthread_mutex_lock(&vs->lock);
     281
    199282        size_t head = vs->head;
    200283        size_t tail = vs->tail;
    201284
     
    212295        if (head == tail) {
    213296                vs->advance = 0;
    214297                *pactual_size = 0;
     298                pthread_mutex_unlock(&vs->lock);
    215299                return NULL;
    216300        }
    217301
     
    219303        if (size == 0) {
    220304                vs->advance = 0;
    221305                *pactual_size = 0;
     306                pthread_mutex_unlock(&vs->lock);
    222307                return NULL;
    223308        }
    224309
     
    233318        }
    234319        vs->advance = size;
    235320        *pactual_size = size;
    236         return vs->buffer + tail;
     321        uint8_t *result = vs->buffer + tail;
     322
     323        pthread_mutex_unlock(&vs->lock);
     324        return result;
    237325}
    238326
    239327void hdhomerun_video_flush(struct hdhomerun_video_sock_t *vs)
    240328{
    241         /* Atomic update of tail. */
     329        pthread_mutex_lock(&vs->lock);
     330
    242331        vs->tail = vs->head;
    243332        vs->advance = 0;
     333
     334        memset((void *)vs->sequence, 0xFF, sizeof(vs->sequence));
     335
     336        vs->rtp_sequence = 0xFFFFFFFF;
     337
     338        vs->packet_count = 0;
     339        vs->transport_error_count = 0;
     340        vs->network_error_count = 0;
     341        vs->sequence_error_count = 0;
     342        vs->overflow_error_count = 0;
     343
     344        pthread_mutex_unlock(&vs->lock);
    244345}
    245346
     347void hdhomerun_video_debug_print_stats(struct hdhomerun_video_sock_t *vs)
     348{
     349        struct hdhomerun_video_stats_t stats;
     350        hdhomerun_video_get_stats(vs, &stats);
     351
     352        hdhomerun_debug_printf(vs->dbg, "video sock: pkt=%ld net=%ld te=%ld miss=%ld drop=%ld\n",
     353                stats.packet_count, stats.network_error_count,
     354                stats.transport_error_count, stats.sequence_error_count,
     355                stats.overflow_error_count
     356        );
     357}
     358
     359void hdhomerun_video_get_stats(struct hdhomerun_video_sock_t *vs, struct hdhomerun_video_stats_t *stats)
     360{
     361        memset(stats, 0, sizeof(struct hdhomerun_video_stats_t));
     362
     363        pthread_mutex_lock(&vs->lock);
     364
     365        stats->packet_count = vs->packet_count;
     366        stats->network_error_count = vs->network_error_count;
     367        stats->transport_error_count = vs->transport_error_count;
     368        stats->sequence_error_count = vs->sequence_error_count;
     369        stats->overflow_error_count = vs->overflow_error_count;
     370
     371        pthread_mutex_unlock(&vs->lock);
     372}
  • libs/libmythtv/hdhomerun/hdhomerun_os_posix.h

     
     1/*
     2 * hdhomerun_os_posix.h
     3 *
     4 * Copyright © 2006-2008 Silicondust USA Inc. <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}
  • libs/libmythtv/hdhomerun/hdhomerun_types.h

     
     1/*
     2 * hdhomerun_types.h
     3 *
     4 * Copyright © 2008-2009 Silicondust USA Inc. <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 HDHOMERUN_STATUS_COLOR_NEUTRAL  0xFFFFFFFF
     34#define HDHOMERUN_STATUS_COLOR_RED              0xFFFF0000
     35#define HDHOMERUN_STATUS_COLOR_YELLOW   0xFFFFFF00
     36#define HDHOMERUN_STATUS_COLOR_GREEN    0xFF00C000
     37
     38struct hdhomerun_device_t;
     39struct hdhomerun_device_allocation_t;
     40
     41struct hdhomerun_tuner_status_t {
     42        char channel[32];
     43        char lock_str[32];
     44        bool_t signal_present;
     45        bool_t lock_supported;
     46        bool_t lock_unsupported;
     47        unsigned int signal_strength;
     48        unsigned int signal_to_noise_quality;
     49        unsigned int symbol_error_quality;
     50        uint32_t raw_bits_per_second;
     51        uint32_t packets_per_second;
     52};
     53
     54struct hdhomerun_channelscan_program_t {
     55        char program_str[64];
     56        uint16_t program_number;
     57        uint16_t virtual_major;
     58        uint16_t virtual_minor;
     59        uint16_t type;
     60        char name[32];
     61};
     62
     63#define HDHOMERUN_CHANNELSCAN_MAX_PROGRAM_COUNT 64
     64
     65struct hdhomerun_channelscan_result_t {
     66        char channel_str[64];
     67        uint32_t channelmap;
     68        uint32_t frequency;
     69        struct hdhomerun_tuner_status_t status;
     70        int program_count;
     71        struct hdhomerun_channelscan_program_t programs[HDHOMERUN_CHANNELSCAN_MAX_PROGRAM_COUNT];
     72        bool_t transport_stream_id_detected;
     73        uint16_t transport_stream_id;
     74};
     75
     76struct hdhomerun_plotsample_t {
     77        int16_t real;
     78        int16_t imag;
     79};
  • libs/libmythtv/hdhomerun/hdhomerun_video.h

     
    11/*
    22 * hdhomerun_video.h
    33 *
    4  * Copyright © 2006 Silicondust Engineering Ltd. <www.silicondust.com>.
     4 * Copyright © 2006 Silicondust USA Inc. <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 USA Inc. <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 *next_line = streaminfo;
     153        int program_count = 0;
     154
     155        while (1) {
     156                char *line = next_line;
     157
     158                next_line = strchr(line, '\n');
     159                if (!next_line) {
     160                        break;
     161                }
     162                *next_line++ = 0;
     163
     164                unsigned int transport_stream_id;
     165                if (sscanf(line, "tsid=0x%x", &transport_stream_id) == 1) {
     166                        result->transport_stream_id = transport_stream_id;
     167                        result->transport_stream_id_detected = TRUE;
     168                        continue;
     169                }
     170
     171                if (program_count >= HDHOMERUN_CHANNELSCAN_MAX_PROGRAM_COUNT) {
     172                        continue;
     173                }
     174
     175                struct hdhomerun_channelscan_program_t program;
     176                memset(&program, 0, sizeof(program));
     177
     178                strncpy(program.program_str, line, sizeof(program.program_str));
     179                program.program_str[sizeof(program.program_str) - 1] = 0;
     180
     181                unsigned int program_number;
     182                unsigned int virtual_major, virtual_minor;
     183                if (sscanf(line, "%u: %u.%u", &program_number, &virtual_major, &virtual_minor) != 3) {
     184                        if (sscanf(line, "%u: %u", &program_number, &virtual_major) != 2) {
     185                                continue;
     186                        }
     187                        virtual_minor = 0;
     188                }
     189
     190                program.program_number = program_number;
     191                program.virtual_major = virtual_major;
     192                program.virtual_minor = virtual_minor;
     193
     194                channelscan_extract_name(&program, line);
     195
     196                if (strstr(line, "(control)")) {
     197                        program.type = HDHOMERUN_CHANNELSCAN_PROGRAM_CONTROL;
     198                } else if (strstr(line, "(encrypted)")) {
     199                        program.type = HDHOMERUN_CHANNELSCAN_PROGRAM_ENCRYPTED;
     200                } else if (strstr(line, "(no data)")) {
     201                        program.type = HDHOMERUN_CHANNELSCAN_PROGRAM_NODATA;
     202                        *pincomplete = TRUE;
     203                } else {
     204                        program.type = HDHOMERUN_CHANNELSCAN_PROGRAM_NORMAL;
     205                        if ((program.virtual_major == 0) || (program.name[0] == 0)) {
     206                                *pincomplete = TRUE;
     207                        }
     208                }
     209
     210                if (memcmp(&result->programs[program_count], &program, sizeof(program)) != 0) {
     211                        memcpy(&result->programs[program_count], &program, sizeof(program));
     212                        *pchanged = TRUE;
     213                }
     214
     215                program_count++;
     216        }
     217
     218        if (program_count == 0) {
     219                *pincomplete = TRUE;
     220        }
     221        if (result->program_count != program_count) {
     222                result->program_count = program_count;
     223                *pchanged = TRUE;
     224        }
     225
     226        return 1;
     227}
     228
     229int channelscan_advance(struct hdhomerun_channelscan_t *scan, struct hdhomerun_channelscan_result_t *result)
     230{
     231        memset(result, 0, sizeof(struct hdhomerun_channelscan_result_t));
     232
     233        struct hdhomerun_channel_entry_t *entry = scan->next_channel;
     234        if (!entry) {
     235                return 0;
     236        }
     237
     238        /* Combine channels with same frequency. */
     239        result->frequency = hdhomerun_channel_entry_frequency(entry);
     240        strncpy(result->channel_str, hdhomerun_channel_entry_name(entry), sizeof(result->channel_str) - 1);
     241        result->channel_str[sizeof(result->channel_str) - 1] = 0;
     242
     243        while (1) {
     244                entry = hdhomerun_channel_list_prev(scan->channel_list, entry);
     245                if (!entry) {
     246                        scan->next_channel = NULL;
     247                        break;
     248                }
     249
     250                if (hdhomerun_channel_entry_frequency(entry) != result->frequency) {
     251                        scan->next_channel = entry;
     252                        break;
     253                }
     254
     255                char *ptr = strchr(result->channel_str, 0);
     256                sprintf(ptr, ", %s", hdhomerun_channel_entry_name(entry));
     257        }
     258
     259        return 1;
     260}
     261
     262int channelscan_detect(struct hdhomerun_channelscan_t *scan, struct hdhomerun_channelscan_result_t *result)
     263{
     264        scan->scanned_channels++;
     265
     266        /* Find lock. */
     267        int ret = channelscan_find_lock(scan, result->frequency, result);
     268        if (ret <= 0) {
     269                return ret;
     270        }
     271        if (!result->status.lock_supported) {
     272                return 1;
     273        }
     274
     275        /* Detect programs. */
     276        result->program_count = 0;
     277
     278        uint64_t timeout;
     279        if (strstr(hdhomerun_device_get_model_str(scan->hd), "atsc")) {
     280                timeout = getcurrenttime() + 4000;
     281        } else {
     282                timeout = getcurrenttime() + 10000;
     283        }
     284
     285        uint64_t complete_time = getcurrenttime() + 1000;
     286
     287        while (1) {
     288                bool_t changed, incomplete;
     289                ret = channelscan_detect_programs(scan, result, &changed, &incomplete);
     290                if (ret <= 0) {
     291                        return ret;
     292                }
     293
     294                if (changed) {
     295                        complete_time = getcurrenttime() + 1000;
     296                }
     297
     298                if (!incomplete && (getcurrenttime() >= complete_time)) {
     299                        break;
     300                }
     301
     302                if (getcurrenttime() >= timeout) {
     303                        break;
     304                }
     305
     306                msleep(250);
     307        }
     308
     309        /* Lock => skip overlapping channels. */
     310        uint32_t max_next_frequency = result->frequency - 5500000;
     311        while (1) {
     312                if (!scan->next_channel) {
     313                        break;
     314                }
     315
     316                if (hdhomerun_channel_entry_frequency(scan->next_channel) <= max_next_frequency) {
     317                        break;
     318                }
     319
     320                scan->next_channel = hdhomerun_channel_list_prev(scan->channel_list, scan->next_channel);
     321        }
     322
     323        /* Success. */
     324        return 1;
     325}
     326
     327uint8_t channelscan_get_progress(struct hdhomerun_channelscan_t *scan)
     328{
     329        struct hdhomerun_channel_entry_t *entry = scan->next_channel;
     330        if (!entry) {
     331                return 100;
     332        }
     333
     334        uint32_t channels_remaining = 1;
     335        uint32_t frequency = hdhomerun_channel_entry_frequency(entry);
     336
     337        while (1) {
     338                entry = hdhomerun_channel_list_prev(scan->channel_list, entry);
     339                if (!entry) {
     340                        break;
     341                }
     342
     343                if (hdhomerun_channel_entry_frequency(entry) != frequency) {
     344                        channels_remaining++;
     345                        frequency = hdhomerun_channel_entry_frequency(entry);
     346                }
     347        }
     348
     349        return scan->scanned_channels * 100 / (scan->scanned_channels + channels_remaining);
     350}
  • 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 USA Inc. <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#define HDHOMERUN_DISOCVER_MAX_SOCK_COUNT 16
    3548
    3649struct hdhomerun_discover_sock_t {
    3750        int sock;
     51        uint32_t local_ip;
     52        uint32_t subnet_mask;
    3853};
    3954
    40 static struct hdhomerun_discover_sock_t *hdhomerun_discover_create(void)
     55struct hdhomerun_discover_t {
     56        struct hdhomerun_discover_sock_t socks[HDHOMERUN_DISOCVER_MAX_SOCK_COUNT];
     57        unsigned int sock_count;
     58        struct hdhomerun_pkt_t tx_pkt;
     59        struct hdhomerun_pkt_t rx_pkt;
     60};
     61
     62static bool_t hdhomerun_discover_sock_create(struct hdhomerun_discover_t *ds, uint32_t local_ip, uint32_t subnet_mask)
    4163{
    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;
     64        if (ds->sock_count >= HDHOMERUN_DISOCVER_MAX_SOCK_COUNT) {
     65                return FALSE;
    4566        }
    46        
     67
    4768        /* Create socket. */
    48         ds->sock = (int)socket(AF_INET, SOCK_DGRAM, 0);
    49         if (ds->sock == -1) {
    50                 free(ds);
    51                 return NULL;
     69        int sock = (int)socket(AF_INET, SOCK_DGRAM, 0);
     70        if (sock == -1) {
     71                return FALSE;
    5272        }
    5373
    5474        /* Set timeouts. */
    55         setsocktimeout(ds->sock, SOL_SOCKET, SO_SNDTIMEO, 1000);
    56         setsocktimeout(ds->sock, SOL_SOCKET, SO_RCVTIMEO, 1000);
     75        setsocktimeout(sock, SOL_SOCKET, SO_SNDTIMEO, 1000);
     76        setsocktimeout(sock, SOL_SOCKET, SO_RCVTIMEO, 1000);
    5777
    5878        /* Allow broadcast. */
    5979        int sock_opt = 1;
    60         setsockopt(ds->sock, SOL_SOCKET, SO_BROADCAST, (char *)&sock_opt, sizeof(sock_opt));
     80        setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&sock_opt, sizeof(sock_opt));
    6181
    6282        /* Bind socket. */
    6383        struct sockaddr_in sock_addr;
    6484        memset(&sock_addr, 0, sizeof(sock_addr));
    6585        sock_addr.sin_family = AF_INET;
    66         sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
     86        sock_addr.sin_addr.s_addr = htonl(local_ip);
    6787        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;
     88        if (bind(sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) {
     89                close(sock);
     90                return FALSE;
    7291        }
    7392
    74         /* Success. */
    75         return ds;
    76 }
     93        /* Write sock entry. */
     94        struct hdhomerun_discover_sock_t *dss = &ds->socks[ds->sock_count++];
     95        dss->sock = sock;
     96        dss->local_ip = local_ip;
     97        dss->subnet_mask = subnet_mask;
    7798
    78 static void hdhomerun_discover_destroy(struct hdhomerun_discover_sock_t *ds)
    79 {
    80         close(ds->sock);
    81         free(ds);
     99        return TRUE;
    82100}
    83101
    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)
     102#if defined(USE_IPHLPAPI)
     103static void hdhomerun_discover_sock_detect(struct hdhomerun_discover_t *ds)
    85104{
    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 {
    218105        PIP_ADAPTER_INFO pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));
    219106        ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
    220107
     
    222109        if (Ret != NO_ERROR) {
    223110                free(pAdapterInfo);
    224111                if (Ret != ERROR_BUFFER_OVERFLOW) {
    225                         return -1;
     112                        return;
    226113                }
    227114                pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen);
    228115                Ret = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen);
    229116                if (Ret != NO_ERROR) {
    230117                        free(pAdapterInfo);
    231                         return -1;
     118                        return;
    232119                }
    233120        }
    234121
    235         unsigned int send_count = 0;
    236122        PIP_ADAPTER_INFO pAdapter = pAdapterInfo;
    237123        while (pAdapter) {
    238124                IP_ADDR_STRING *pIPAddr = &pAdapter->IpAddressList;
    239125                while (pIPAddr) {
    240                         uint32_t addr = ntohl(inet_addr(pIPAddr->IpAddress.String));
     126                        uint32_t local_ip = ntohl(inet_addr(pIPAddr->IpAddress.String));
    241127                        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                         }
    248128
    249                         if (hdhomerun_discover_send_packet(ds, broadcast, device_type, device_id) < 0) {
     129                        if (local_ip == 0) {
    250130                                pIPAddr = pIPAddr->Next;
    251131                                continue;
    252132                        }
    253133
    254                         send_count++;
    255 
     134                        hdhomerun_discover_sock_create(ds, local_ip, mask);
    256135                        pIPAddr = pIPAddr->Next;
    257136                }
    258137
     
    260139        }
    261140
    262141        free(pAdapterInfo);
    263 
    264         if (send_count == 0) {
    265                 return -1;
    266         }
    267         return 0;
    268142}
    269143
    270 #elif defined(__linux__)
     144#else
    271145
    272 static int hdhomerun_discover_send_internal(struct hdhomerun_discover_sock_t *ds, uint32_t device_type, uint32_t device_id)
     146static void hdhomerun_discover_sock_detect(struct hdhomerun_discover_t *ds)
    273147{
    274         FILE *fp = fopen("/proc/net/route", "r");
    275         if (!fp) {
    276                 return -1;
     148        int fd = socket(AF_INET, SOCK_DGRAM, 0);
     149        if (fd == -1) {
     150                return;
    277151        }
    278152
    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;
     153        struct ifconf ifc;
     154        uint8_t buf[8192];
     155        ifc.ifc_len = sizeof(buf);
     156        ifc.ifc_buf = (char *)buf;
    286157
    287                 uint32_t dest;
    288                 uint32_t mask;
    289                 if (sscanf(line, "%*s %x %*x %*x %*d %*d %*d %x", &dest, &mask) != 2) {
     158        memset(buf, 0, sizeof(buf));
     159
     160        if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
     161                close(fd);
     162                return;
     163        }
     164
     165        uint8_t *ptr = (uint8_t *)ifc.ifc_req;
     166        uint8_t *end = (uint8_t *)&ifc.ifc_buf[ifc.ifc_len];
     167
     168        while (ptr <= end) {
     169                struct ifreq *ifr = (struct ifreq *)ptr;
     170                ptr += _SIZEOF_ADDR_IFREQ(*ifr);
     171
     172                if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
    290173                        continue;
    291174                }
    292                 dest = ntohl(dest);
    293                 mask = ntohl(mask);
    294                
    295                 uint32_t broadcast = dest | ~mask;
    296 
    297                 if ((broadcast == 0x00000000) || (broadcast == 0xFFFFFFFF)) {
     175                struct sockaddr_in *addr_in = (struct sockaddr_in *)&(ifr->ifr_addr);
     176                uint32_t local_ip = ntohl(addr_in->sin_addr.s_addr);
     177                if (local_ip == 0) {
    298178                        continue;
    299179                }
    300180
    301                 if (hdhomerun_discover_send_packet(ds, broadcast, device_type, device_id) < 0) {
     181                if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
    302182                        continue;
    303183                }
     184                struct sockaddr_in *mask_in = (struct sockaddr_in *)&(ifr->ifr_addr);
     185                uint32_t mask = ntohl(mask_in->sin_addr.s_addr);
    304186
    305                 send_count++;
     187                hdhomerun_discover_sock_create(ds, local_ip, mask);
    306188        }
     189}
     190#endif
    307191
    308         fclose(fp);
    309         if (send_count == 0) {
    310                 return -1;
     192static struct hdhomerun_discover_t *hdhomerun_discover_create(void)
     193{
     194        struct hdhomerun_discover_t *ds = (struct hdhomerun_discover_t *)calloc(1, sizeof(struct hdhomerun_discover_t));
     195        if (!ds) {
     196                return NULL;
    311197        }
    312         return 0;
     198
     199        /* Create a routable socket. */
     200        if (!hdhomerun_discover_sock_create(ds, 0, 0)) {
     201                free(ds);
     202                return NULL;
     203        }
     204
     205        /* Detect & create local sockets. */
     206        hdhomerun_discover_sock_detect(ds);
     207
     208        /* Success. */
     209        return ds;
    313210}
    314211
    315 #else
     212static void hdhomerun_discover_destroy(struct hdhomerun_discover_t *ds)
     213{
     214        unsigned int i;
     215        for (i = 0; i < ds->sock_count; i++) {
     216                struct hdhomerun_discover_sock_t *dss = &ds->socks[i];
     217                close(dss->sock);
     218        }
    316219
    317 static int hdhomerun_discover_send_internal(struct hdhomerun_discover_sock_t *ds, uint32_t device_type, uint32_t device_id)
     220        free(ds);
     221}
     222
     223static 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)
    318224{
    319         return -1;
     225        struct hdhomerun_pkt_t *tx_pkt = &ds->tx_pkt;
     226        hdhomerun_pkt_reset(tx_pkt);
     227
     228        hdhomerun_pkt_write_u8(tx_pkt, HDHOMERUN_TAG_DEVICE_TYPE);
     229        hdhomerun_pkt_write_var_length(tx_pkt, 4);
     230        hdhomerun_pkt_write_u32(tx_pkt, device_type);
     231        hdhomerun_pkt_write_u8(tx_pkt, HDHOMERUN_TAG_DEVICE_ID);
     232        hdhomerun_pkt_write_var_length(tx_pkt, 4);
     233        hdhomerun_pkt_write_u32(tx_pkt, device_id);
     234        hdhomerun_pkt_seal_frame(tx_pkt, HDHOMERUN_TYPE_DISCOVER_REQ);
     235
     236        struct sockaddr_in sock_addr;
     237        memset(&sock_addr, 0, sizeof(sock_addr));
     238        sock_addr.sin_family = AF_INET;
     239        sock_addr.sin_addr.s_addr = htonl(target_ip);
     240        sock_addr.sin_port = htons(HDHOMERUN_DISCOVER_UDP_PORT);
     241
     242        int length = (int)(tx_pkt->end - tx_pkt->start);
     243        if (sendto(dss->sock, (char *)tx_pkt->start, length, 0, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != length) {
     244                return FALSE;
     245        }
     246
     247        return TRUE;
    320248}
    321 #endif
    322249
    323 static int hdhomerun_discover_send(struct hdhomerun_discover_sock_t *ds, uint32_t device_type, uint32_t device_id)
     250static bool_t hdhomerun_discover_send_wildcard_ip(struct hdhomerun_discover_t *ds, uint32_t device_type, uint32_t device_id)
    324251{
    325         if (hdhomerun_discover_send_internal(ds, device_type, device_id) < 0) {
    326                 return hdhomerun_discover_send_packet(ds, 0xFFFFFFFF, device_type, device_id);
     252        bool_t result = FALSE;
     253
     254        /*
     255         * Send subnet broadcast using each local ip socket.
     256         * This will work with multiple separate 169.254.x.x interfaces.
     257         */
     258        unsigned int i;
     259        for (i = 1; i < ds->sock_count; i++) {
     260                struct hdhomerun_discover_sock_t *dss = &ds->socks[i];
     261                uint32_t target_ip = dss->local_ip | ~dss->subnet_mask;
     262                result |= hdhomerun_discover_send_internal(ds, dss, target_ip, device_type, device_id);
    327263        }
    328         return 0;
     264
     265        /*
     266         * If no local ip sockets then fall back to sending a global broadcast letting the OS choose the interface.
     267         */
     268        if (!result) {
     269                struct hdhomerun_discover_sock_t *dss = &ds->socks[0];
     270                result = hdhomerun_discover_send_internal(ds, dss, 0xFFFFFFFF, device_type, device_id);
     271        }
     272
     273        return result;
    329274}
    330275
    331 static int hdhomerun_discover_recv(struct hdhomerun_discover_sock_t *ds, struct hdhomerun_discover_device_t *result)
     276static bool_t hdhomerun_discover_send_target_ip(struct hdhomerun_discover_t *ds, uint32_t target_ip, uint32_t device_type, uint32_t device_id)
    332277{
    333         struct timeval t;
    334         t.tv_sec = 0;
    335         t.tv_usec = 250000;
     278        bool_t result = FALSE;
    336279
    337         fd_set readfds;
    338         FD_ZERO(&readfds);
    339         FD_SET(ds->sock, &readfds);
     280        /*
     281         * Send targeted packet from any local ip that is in the same subnet.
     282         * This will work with multiple separate 169.254.x.x interfaces.
     283         */
     284        unsigned int i;
     285        for (i = 1; i < ds->sock_count; i++) {
     286                struct hdhomerun_discover_sock_t *dss = &ds->socks[i];
     287                if ((target_ip & dss->subnet_mask) != (dss->local_ip & dss->subnet_mask)) {
     288                        continue;
     289                }
    340290
    341         if (select(ds->sock+1, &readfds, NULL, NULL, &t) < 0) {
    342                 return -1;
     291                result |= hdhomerun_discover_send_internal(ds, dss, target_ip, device_type, device_id);
    343292        }
    344         if (!FD_ISSET(ds->sock, &readfds)) {
    345                 return 0;
     293
     294        /*
     295         * If target IP does not match a local subnet then fall back to letting the OS choose the gateway interface.
     296         */
     297        if (!result) {
     298                struct hdhomerun_discover_sock_t *dss = &ds->socks[0];
     299                result = hdhomerun_discover_send_internal(ds, dss, target_ip, device_type, device_id);
    346300        }
    347301
    348         uint8_t buffer[1024];
     302        return result;
     303}
     304
     305static bool_t hdhomerun_discover_send(struct hdhomerun_discover_t *ds, uint32_t target_ip, uint32_t device_type, uint32_t device_id)
     306{
     307        if (target_ip != 0) {
     308                return hdhomerun_discover_send_target_ip(ds, target_ip, device_type, device_id);
     309        }
     310
     311        return hdhomerun_discover_send_wildcard_ip(ds, device_type, device_id);
     312}
     313
     314static int hdhomerun_discover_recv_internal(struct hdhomerun_discover_t *ds, struct hdhomerun_discover_sock_t *dss, struct hdhomerun_discover_device_t *result)
     315{
     316        struct hdhomerun_pkt_t *rx_pkt = &ds->rx_pkt;
     317        hdhomerun_pkt_reset(rx_pkt);
     318
    349319        struct sockaddr_in sock_addr;
     320        memset(&sock_addr, 0, sizeof(sock_addr));
    350321        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);
     322
     323        int rx_length = recvfrom(dss->sock, (char *)rx_pkt->end, (int)(rx_pkt->limit - rx_pkt->end), 0, (struct sockaddr *)&sock_addr, &sockaddr_size);
    352324        if (rx_length <= 0) {
    353325                /* Don't return error - windows machine on VPN can sometimes cause a sock error here but otherwise works. */
    354326                return 0;
    355327        }
    356         if (rx_length < HDHOMERUN_MIN_PEEK_LENGTH) {
    357                 return 0;
    358         }
     328        rx_pkt->end += rx_length;
    359329
    360         size_t length = hdhomerun_peek_packet_length(buffer);
    361         if (length > (size_t)rx_length) {
     330        uint16_t type;
     331        if (hdhomerun_pkt_open_frame(rx_pkt, &type) <= 0) {
    362332                return 0;
    363333        }
    364 
    365         uint8_t *ptr = buffer;
    366         uint8_t *end = buffer + length;
    367         int type = hdhomerun_process_packet(&ptr, &end);
    368334        if (type != HDHOMERUN_TYPE_DISCOVER_RPY) {
    369335                return 0;
    370336        }
     
    372338        result->ip_addr = ntohl(sock_addr.sin_addr.s_addr);
    373339        result->device_type = 0;
    374340        result->device_id = 0;
     341
    375342        while (1) {
    376343                uint8_t tag;
    377344                size_t len;
    378                 uint8_t *value;
    379                 if (hdhomerun_read_tlv(&ptr, end, &tag, &len, &value) < 0) {
     345                uint8_t *next = hdhomerun_pkt_read_tlv(rx_pkt, &tag, &len);
     346                if (!next) {
    380347                        break;
    381348                }
    382349
     
    385352                        if (len != 4) {
    386353                                break;
    387354                        }
    388                         result->device_type = hdhomerun_read_u32(&value);
     355                        result->device_type = hdhomerun_pkt_read_u32(rx_pkt);
    389356                        break;
     357
    390358                case HDHOMERUN_TAG_DEVICE_ID:
    391359                        if (len != 4) {
    392360                                break;
    393361                        }
    394                         result->device_id = hdhomerun_read_u32(&value);
     362                        result->device_id = hdhomerun_pkt_read_u32(rx_pkt);
    395363                        break;
     364
    396365                default:
    397366                        break;
    398367                }
     368
     369                rx_pkt->pos = next;
    399370        }
    400371
    401372        return 1;
    402373}
    403374
    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)
     375static int hdhomerun_discover_recv(struct hdhomerun_discover_t *ds, struct hdhomerun_discover_device_t *result)
    405376{
     377        struct timeval t;
     378        t.tv_sec = 0;
     379        t.tv_usec = 250000;
     380
     381        fd_set readfds;
     382        FD_ZERO(&readfds);
     383        int max_sock = -1;
     384
     385        unsigned int i;
     386        for (i = 0; i < ds->sock_count; i++) {
     387                struct hdhomerun_discover_sock_t *dss = &ds->socks[i];
     388                FD_SET(dss->sock, &readfds);
     389                if (dss->sock > max_sock) {
     390                        max_sock = dss->sock;
     391                }
     392        }
     393
     394        if (select(max_sock+1, &readfds, NULL, NULL, &t) < 0) {
     395                return -1;
     396        }
     397
     398        for (i = 0; i < ds->sock_count; i++) {
     399                struct hdhomerun_discover_sock_t *dss = &ds->socks[i];
     400                if (!FD_ISSET(dss->sock, &readfds)) {
     401                        continue;
     402                }
     403
     404                if (hdhomerun_discover_recv_internal(ds, dss, result) <= 0) {
     405                        continue;
     406                }
     407
     408                return 1;
     409        }
     410
     411        return 0;
     412}
     413
     414static struct hdhomerun_discover_device_t *hdhomerun_discover_find_in_list(struct hdhomerun_discover_device_t result_list[], int count, uint32_t ip_addr)
     415{
    406416        int index;
    407417        for (index = 0; index < count; index++) {
    408418                struct hdhomerun_discover_device_t *result = &result_list[index];
    409                 if (result->device_id == device_id) {
     419                if (result->ip_addr == ip_addr) {
    410420                        return result;
    411421                }
    412422        }
     
    414424        return NULL;
    415425}
    416426
    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)
     427static 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)
    418428{
    419429        int count = 0;
    420 
    421430        int attempt;
    422431        for (attempt = 0; attempt < 4; attempt++) {
    423                 if (hdhomerun_discover_send(ds, device_type, device_id) < 0) {
     432                if (!hdhomerun_discover_send(ds, target_ip, device_type, device_id)) {
    424433                        return -1;
    425434                }
    426435
     
    433442                                return -1;
    434443                        }
    435444                        if (ret == 0) {
    436                                 break;
     445                                continue;
    437446                        }
    438447
    439448                        /* Filter. */
     
    449458                        }
    450459
    451460                        /* Ensure not already in list. */
    452                         if (hdhomerun_discover_find_in_list(result_list, count, result->device_id)) {
     461                        if (hdhomerun_discover_find_in_list(result_list, count, result->ip_addr)) {
    453462                                continue;
    454463                        }
    455464
     
    464473        return count;
    465474}
    466475
    467 int hdhomerun_discover_find_device(uint32_t device_id, struct hdhomerun_discover_device_t *result)
     476int 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)
    468477{
    469         struct hdhomerun_discover_sock_t *ds = hdhomerun_discover_create();
     478        struct hdhomerun_discover_t *ds = hdhomerun_discover_create();
    470479        if (!ds) {
    471480                return -1;
    472481        }
    473482
    474         int ret = hdhomerun_discover_find_devices_internal(ds, HDHOMERUN_DEVICE_TYPE_WILDCARD, device_id, result, 1);
     483        int ret = hdhomerun_discover_find_devices_internal(ds, target_ip, device_type, device_id, result_list, max_count);
    475484
    476485        hdhomerun_discover_destroy(ds);
    477486        return ret;
    478487}
    479488
    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 
    493489bool_t hdhomerun_discover_validate_device_id(uint32_t device_id)
    494490{
    495491        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_control.c

     
    11/*
    22 * hdhomerun_control.c
    33 *
    4  * Copyright © 2006 Silicondust Engineering Ltd. <www.silicondust.com>.
     4 * Copyright © 2006 Silicondust USA Inc. <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        }
    6696
    67         /* Find ip address. */
    68         uint32_t device_ip = cs->device_ip;
    69         if (device_ip == 0) {
    70                 struct hdhomerun_discover_device_t result;
    71                 if (hdhomerun_discover_find_device(cs->device_id, &result) <= 0) {
    72                         return FALSE;
    73                 }
    74                 device_ip = result.ip_addr;
     97        if ((cs->desired_device_id == 0) && (cs->desired_device_ip == 0)) {
     98                hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_connect_sock: no device specified\n");
     99                return FALSE;
    75100        }
    76101
     102        /* Find device. */
     103        struct hdhomerun_discover_device_t result;
     104        if (hdhomerun_discover_find_devices_custom(cs->desired_device_ip, HDHOMERUN_DEVICE_TYPE_WILDCARD, cs->desired_device_id, &result, 1) <= 0) {
     105                hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_connect_sock: device not found\n");
     106                return FALSE;
     107        }
     108        cs->actual_device_ip = result.ip_addr;
     109        cs->actual_device_id = result.device_id;
     110
    77111        /* Create socket. */
    78112        cs->sock = (int)socket(AF_INET, SOCK_STREAM, 0);
    79113        if (cs->sock == -1) {
     114                hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_connect_sock: failed to create socket (%d)\n", sock_getlasterror);
    80115                return FALSE;
    81116        }
    82117
    83118        /* Set timeouts. */
    84         setsocktimeout(cs->sock, SOL_SOCKET, SO_SNDTIMEO, 1000);
    85         setsocktimeout(cs->sock, SOL_SOCKET, SO_RCVTIMEO, 1000);
     119        setsocktimeout(cs->sock, SOL_SOCKET, SO_SNDTIMEO, HDHOMERUN_CONTROL_SEND_TIMEOUT);
     120        setsocktimeout(cs->sock, SOL_SOCKET, SO_RCVTIMEO, HDHOMERUN_CONTROL_RECV_TIMEOUT);
    86121
    87122        /* Initiate connection. */
    88123        struct sockaddr_in sock_addr;
    89124        memset(&sock_addr, 0, sizeof(sock_addr));
    90125        sock_addr.sin_family = AF_INET;
    91         sock_addr.sin_addr.s_addr = htonl(device_ip);
     126        sock_addr.sin_addr.s_addr = htonl(cs->actual_device_ip);
    92127        sock_addr.sin_port = htons(HDHOMERUN_CONTROL_TCP_PORT);
    93128        if (connect(cs->sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) {
     129                hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_connect_sock: failed to connect (%d)\n", sock_getlasterror);
    94130                hdhomerun_control_close_sock(cs);
    95131                return FALSE;
    96132        }
     
    99135        return TRUE;
    100136}
    101137
     138uint32_t hdhomerun_control_get_device_id(struct hdhomerun_control_sock_t *cs)
     139{
     140        if (!hdhomerun_control_connect_sock(cs)) {
     141                hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_get_device_id: connect failed\n");
     142                return 0;
     143        }
     144
     145        return cs->actual_device_id;
     146}
     147
     148uint32_t hdhomerun_control_get_device_ip(struct hdhomerun_control_sock_t *cs)
     149{
     150        if (!hdhomerun_control_connect_sock(cs)) {
     151                hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_get_device_ip: connect failed\n");
     152                return 0;
     153        }
     154
     155        return cs->actual_device_ip;
     156}
     157
     158uint32_t hdhomerun_control_get_device_id_requested(struct hdhomerun_control_sock_t *cs)
     159{
     160        return cs->desired_device_id;
     161}
     162
     163uint32_t hdhomerun_control_get_device_ip_requested(struct hdhomerun_control_sock_t *cs)
     164{
     165        return cs->desired_device_ip;
     166}
     167
    102168uint32_t hdhomerun_control_get_local_addr(struct hdhomerun_control_sock_t *cs)
    103169{
    104170        if (!hdhomerun_control_connect_sock(cs)) {
     171                hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_get_local_addr: connect failed\n");
    105172                return 0;
    106173        }
    107174
    108175        struct sockaddr_in sock_addr;
    109176        socklen_t sockaddr_size = sizeof(sock_addr);
    110177        if (getsockname(cs->sock, (struct sockaddr*)&sock_addr, &sockaddr_size) != 0) {
     178                hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_get_local_addr: getsockname failed (%d)\n", sock_getlasterror);
    111179                return 0;
    112180        }
    113181
    114182        return ntohl(sock_addr.sin_addr.s_addr);
    115183}
    116184
    117 static int hdhomerun_control_send(struct hdhomerun_control_sock_t *cs, uint8_t *start, uint8_t *end)
     185static int hdhomerun_control_send_sock(struct hdhomerun_control_sock_t *cs, struct hdhomerun_pkt_t *tx_pkt)
    118186{
    119         int length = (int)(end - start);
    120         if (send(cs->sock, (char *)start, (int)length, 0) != length) {
     187        int length = (int)(tx_pkt->end - tx_pkt->start);
     188        if (send(cs->sock, (char *)tx_pkt->start, (int)length, 0) != length) {
     189                hdhomerun_debug_printf(cs->dbg, "hdhomerun_control_send_sock: send failed (%d)\n", sock_getlasterror);
     190                hdhomerun_control_close_sock(cs);
    121191                return -1;
    122192        }
    123193
    124         return length;
     194        return 1;
    125195}
    126196
    127 static int hdhomerun_control_recv_sock(struct hdhomerun_control_sock_t *cs, uint8_t *buffer, uint8_t *limit)
     197static int hdhomerun_control_recv_sock(struct hdhomerun_control_sock_t *cs, struct hdhomerun_pkt_t *rx_pkt, uint16_t *ptype, uint64_t recv_timeout)
    128198{
    129         struct timeval t;
    130         t.tv_sec = 0;
    131         t.tv_usec = 250000;
     199        uint64_t stop_time = getcurrenttime() + recv_timeout;
     200        hdhomerun_pkt_reset(rx_pkt);
    132201
    133         fd_set readfds;
    134         FD_ZERO(&readfds);
    135         FD_SET(cs->sock, &readfds);
     202        while (getcurrenttime() < stop_time) {
     203                struct timeval t;
     204                t.tv_sec = 0;
     205                t.tv_usec = 250000;
     206