Ticket #2807: mythtv_libhdhomerun_update_20061214.patch

File mythtv_libhdhomerun_update_20061214.patch, 104.3 KB (added by anonymous, 19 years ago)
  • libs/libmythtv/hdhomerun/hdhomerun.h

     
     1/*
     2 * hdhomerun_device.h
     3 *
     4 * Copyright © 2006 Silicondust Engineering Ltd. <www.silicondust.com>.
     5 *
     6 * This library is free software; you can redistribute it and/or
     7 * modify it under the terms of the GNU Lesser General Public
     8 * License as published by the Free Software Foundation; either
     9 * version 2.1 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, write to the Free Software
     18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     19 */
     20
     21#include "hdhomerun_os.h"
     22#include "hdhomerun_pkt.h"
     23#include "hdhomerun_discover.h"
     24#include "hdhomerun_control.h"
     25#include "hdhomerun_video.h"
     26#include "hdhomerun_device.h"
  • libs/libmythtv/hdhomerun/hdhomerun_control.h

     
    2323
    2424struct hdhomerun_control_sock_t;
    2525
    26 struct hdhomerun_control_data_t {
    27         int type;
    28         unsigned char buffer[1024];
    29         unsigned char *ptr;
    30         unsigned char *end;
    31 };
    32 
    33 extern struct hdhomerun_control_sock_t *hdhomerun_control_create(unsigned long ip_addr, unsigned long timeout);
     26/*
     27 * Create a control socket.
     28 *
     29 * This function will not attempt to connect to the device.
     30 * The connection will be established when first used.
     31 *
     32 * uint32_t device_id = 32-bit device id of device. Set to HDHOMERUN_DEVICE_ID_WILDCARD to match any device ID.
     33 * uint32_t device_ip = IP address of device. Set to 0 to auto-detect.
     34 *
     35 * Returns a pointer to the newly created control socket.
     36 *
     37 * When no longer needed, the socket should be destroyed by calling hdhomerun_control_destroy.
     38 */
     39extern struct hdhomerun_control_sock_t *hdhomerun_control_create(uint32_t device_id, uint32_t device_ip);
    3440extern void hdhomerun_control_destroy(struct hdhomerun_control_sock_t *cs);
    35 extern unsigned long hdhomerun_control_get_local_addr(struct hdhomerun_control_sock_t *cs);
    3641
    37 extern int hdhomerun_control_send(struct hdhomerun_control_sock_t *cs, unsigned char *start, unsigned char *end);
    38 extern int hdhomerun_control_send_get_request(struct hdhomerun_control_sock_t *cs, const char *name);
    39 extern int hdhomerun_control_send_set_request(struct hdhomerun_control_sock_t *cs, const char *name, const char *value);
    40 extern int hdhomerun_control_send_upgrade_request(struct hdhomerun_control_sock_t *cs, unsigned long sequence, void *data, int length);
     42/*
     43 * Get the local machine IP address used when communicating with the device.
     44 *
     45 * This function is useful for determining the IP address to use with set target commands.
     46 *
     47 * Returns 32-bit IP address with native endianness, or 0 on error.
     48 */
     49extern uint32_t hdhomerun_control_get_local_addr(struct hdhomerun_control_sock_t *cs);
    4150
    42 extern int hdhomerun_control_recv(struct hdhomerun_control_sock_t *cs, struct hdhomerun_control_data_t *result, unsigned long timeout);
     51/*
     52 * Get/set a control variable on the device.
     53 *
     54 * const char *name: The name of var to get/set (c-string). The supported vars is device/firmware dependant.
     55 * const char *value: The value to set (c-string). The format is device/firmware dependant.
    4356
     57 * char **pvalue: If provided, the caller-supplied char pointer will be populated with a pointer to the value
     58 *              string returned by the device, or NULL if the device returned an error string. The string will remain
     59 *              valid until the next call to a control sock function.
     60 * char **perror: If provided, the caller-supplied char pointer will be populated with a pointer to the error
     61 *              string returned by the device, or NULL if the device returned an value string. The string will remain
     62 *              valid until the next call to a control sock function.
     63 *
     64 * Returns 1 if the operation was successful (pvalue set, perror NULL).
     65 * Returns 0 if the operation was rejected (pvalue NULL, perror set).
     66 * Returns -1 if a communication error occurs.
     67 */
     68extern int hdhomerun_control_get(struct hdhomerun_control_sock_t *cs, const char *name, char **pvalue, char **perror);
     69extern int hdhomerun_control_set(struct hdhomerun_control_sock_t *cs, const char *name, const char *value, char **pvalue, char **perror);
     70
     71/*
     72 * Upload new firmware to the device.
     73 *
     74 * FILE *upgrade_file: File pointer to read from. The file must have been opened in binary mode for reading.
     75 *
     76 * Returns 1 if the upload succeeded.
     77 * Returns 0 if the upload was rejected.
     78 * Returns -1 if an error occurs.
     79 */
     80extern int hdhomerun_control_upgrade(struct hdhomerun_control_sock_t *cs, FILE *upgrade_file);
     81
    4482#ifdef __cplusplus
    4583}
    4684#endif
  • libs/libmythtv/hdhomerun/hdhomerun_os.h

     
    2121#include <stdlib.h>
    2222#include <stdio.h>
    2323#include <string.h>
     24
     25#if defined(WIN32)
     26#define __WINDOWS__
     27#endif
     28
     29#if defined(__WINDOWS__)
     30#include <windows.h>
     31#include <sys/types.h>
     32#include <sys/timeb.h>
     33#else
    2434#include <unistd.h>
    2535#include <errno.h>
    2636#include <sys/types.h>
     
    2939#include <arpa/inet.h>
    3040#include <netdb.h>
    3141#include <sys/time.h>
     42#include <sys/timeb.h>
    3243#include <fcntl.h>
     44#endif
    3345
     46#include <pthread.h>
     47
    3448#if !defined(TRUE)
    3549#define TRUE 1
    3650#endif
    3751#if !defined(FALSE)
    3852#define FALSE 0
    3953#endif
     54
     55#if defined(__WINDOWS__)
     56
     57typedef int bool_t;
     58typedef unsigned __int8 uint8_t;
     59typedef unsigned __int16 uint16_t;
     60typedef unsigned __int32 uint32_t;
     61typedef 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
     74static inline uint64_t getcurrenttime(void)
     75{
     76        struct timeb tb;
     77        ftime(&tb);
     78        return ((uint64_t)tb.time * 1000) + tb.millitm;
     79}
     80
     81static 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
     89typedef int bool_t;
     90
     91#define sock_getlasterror errno
     92#define sock_getlasterror_socktimeout (errno == EAGAIN)
     93
     94static 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
     101static 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_pkt.c

     
    1818 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    1919 */
    2020
    21 #include <string.h>
     21#include "hdhomerun_os.h"
    2222#include "hdhomerun_pkt.h"
    2323
    24 unsigned char hdhomerun_read_u8(unsigned char **pptr)
     24uint8_t hdhomerun_read_u8(uint8_t **pptr)
    2525{
    26         unsigned char *ptr = *pptr;
    27         unsigned char v = *ptr++;
     26        uint8_t *ptr = *pptr;
     27        uint8_t v = *ptr++;
    2828        *pptr = ptr;
    2929        return v;
    3030}
    3131
    32 unsigned short hdhomerun_read_u16(unsigned char **pptr)
     32uint16_t hdhomerun_read_u16(uint8_t **pptr)
    3333{
    34         unsigned char *ptr = *pptr;
    35         unsigned short v;
    36         v =  (unsigned short)*ptr++ << 8;
    37         v |= (unsigned short)*ptr++ << 0;
     34        uint8_t *ptr = *pptr;
     35        uint16_t v;
     36        v =  (uint16_t)*ptr++ << 8;
     37        v |= (uint16_t)*ptr++ << 0;
    3838        *pptr = ptr;
    3939        return v;
    4040}
    4141
    42 unsigned long hdhomerun_read_u32(unsigned char **pptr)
     42uint32_t hdhomerun_read_u32(uint8_t **pptr)
    4343{
    44         unsigned char *ptr = *pptr;
    45         unsigned long v;
    46         v =  (unsigned long)*ptr++ << 24;
    47         v |= (unsigned long)*ptr++ << 16;
    48         v |= (unsigned long)*ptr++ << 8;
    49         v |= (unsigned long)*ptr++ << 0;
     44        uint8_t *ptr = *pptr;
     45        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;
    5050        *pptr = ptr;
    5151        return v;
    5252}
    5353
    54 static int hdhomerun_read_var_length(unsigned char **pptr, unsigned char *end)
     54size_t hdhomerun_read_var_length(uint8_t **pptr, uint8_t *end)
    5555{
    56         unsigned char *ptr = *pptr;
    57         unsigned int length;
     56        uint8_t *ptr = *pptr;
     57        size_t length;
    5858       
    5959        if (ptr + 1 > end) {
    6060                return -1;
    6161        }
    6262
    63         length = (unsigned int)*ptr++;
     63        length = (size_t)*ptr++;
    6464        if (length & 0x0080) {
    6565                if (ptr + 1 > end) {
    6666                        return -1;
    6767                }
    6868
    6969                length &= 0x007F;
    70                 length |= (unsigned int)*ptr++ << 7;
     70                length |= (size_t)*ptr++ << 7;
    7171        }
    7272       
    7373        *pptr = ptr;
    74         return (int)length;
     74        return length;
    7575}
    7676
    77 int hdhomerun_read_tlv(unsigned char **pptr, unsigned char *end, unsigned char *ptag, int *plength, unsigned char **pvalue)
     77int hdhomerun_read_tlv(uint8_t **pptr, uint8_t *end, uint8_t *ptag, size_t *plength, uint8_t **pvalue)
    7878{
    7979        if (end - *pptr < 2) {
    8080                return -1;
     
    8484        *plength = hdhomerun_read_var_length(pptr, end);
    8585        *pvalue = *pptr;
    8686       
    87         if (*plength < 0) {
     87        if ((size_t)(end - *pptr) < *plength) {
    8888                return -1;
    8989        }
    90         if (end - *pptr < *plength) {
    91                 return -1;
    92         }
    9390       
    9491        *pptr += *plength;
    9592        return 0;
    9693}
    9794
    98 void hdhomerun_write_u8(unsigned char **pptr, unsigned char v)
     95void hdhomerun_write_u8(uint8_t **pptr, uint8_t v)
    9996{
    100         unsigned char *ptr = *pptr;
     97        uint8_t *ptr = *pptr;
    10198        *ptr++ = v;
    10299        *pptr = ptr;
    103100}
    104101
    105 void hdhomerun_write_u16(unsigned char **pptr, unsigned short v)
     102void hdhomerun_write_u16(uint8_t **pptr, uint16_t v)
    106103{
    107         unsigned char *ptr = *pptr;
    108         *ptr++ = (v >> 8) & 0xFF;
    109         *ptr++ = (v >> 0) & 0xFF;
     104        uint8_t *ptr = *pptr;
     105        *ptr++ = (uint8_t)(v >> 8);
     106        *ptr++ = (uint8_t)(v >> 0);
    110107        *pptr = ptr;
    111108}
    112109
    113 void hdhomerun_write_u32(unsigned char **pptr, unsigned long v)
     110void hdhomerun_write_u32(uint8_t **pptr, uint32_t v)
    114111{
    115         unsigned char *ptr = *pptr;
    116         *ptr++ = (v >> 24) & 0xFF;
    117         *ptr++ = (v >> 16) & 0xFF;
    118         *ptr++ = (v >> 8) & 0xFF;
    119         *ptr++ = (v >> 0) & 0xFF;
     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);
    120117        *pptr = ptr;
    121118}
    122119
    123 void hdhomerun_write_var_length(unsigned char **pptr, int v)
     120void hdhomerun_write_var_length(uint8_t **pptr, size_t v)
    124121{
    125         unsigned char *ptr = *pptr;
     122        uint8_t *ptr = *pptr;
    126123        if (v <= 127) {
    127                 *ptr++ = v;
     124                *ptr++ = (uint8_t)v;
    128125        } else {
    129                 *ptr++ = v | 0x80;
    130                 *ptr++ = v >> 7;
     126                *ptr++ = (uint8_t)(v | 0x80);
     127                *ptr++ = (uint8_t)(v >> 7);
    131128        }
    132129        *pptr = ptr;
    133130}
    134131
    135 static void hdhomerun_write_mem(unsigned char **pptr, void *mem, int length)
     132static void hdhomerun_write_mem(uint8_t **pptr, void *mem, size_t length)
    136133{
    137         unsigned char *ptr = *pptr;
     134        uint8_t *ptr = *pptr;
    138135        memcpy(ptr, mem, length);
    139136        ptr += length;
    140137        *pptr = ptr;
    141138}
    142139
    143 static unsigned long hdhomerun_calc_crc(unsigned char *start, unsigned char *end)
     140static uint32_t hdhomerun_calc_crc(uint8_t *start, uint8_t *end)
    144141{
    145         unsigned char *ptr = start;
    146         unsigned long crc = 0xFFFFFFFF;
     142        uint8_t *ptr = start;
     143        uint32_t crc = 0xFFFFFFFF;
    147144        while (ptr < end) {
    148         unsigned char x = (crc & 0x000000FF) ^ *ptr++;
    149         crc >>= 8;
     145                uint8_t x = (uint8_t)(crc) ^ *ptr++;
     146                crc >>= 8;
    150147                if (x & 0x01) crc ^= 0x77073096;
    151148                if (x & 0x02) crc ^= 0xEE0E612C;
    152149                if (x & 0x04) crc ^= 0x076DC419;
     
    159156        return crc ^ 0xFFFFFFFF;
    160157}
    161158
    162 static int hdhomerun_check_crc(unsigned char *start, unsigned char *end)
     159static int hdhomerun_check_crc(uint8_t *start, uint8_t *end)
    163160{
    164161        if (end - start < 8) {
    165162                return -1;
    166163        }
    167         unsigned char *ptr = end -= 4;
    168         unsigned long actual_crc = hdhomerun_calc_crc(start, ptr);
    169         unsigned long packet_crc;
    170         packet_crc =  (unsigned long)*ptr++ << 0;
    171         packet_crc |= (unsigned long)*ptr++ << 8;
    172         packet_crc |= (unsigned long)*ptr++ << 16;
    173         packet_crc |= (unsigned long)*ptr++ << 24;
     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;
    174171        if (actual_crc != packet_crc) {
    175172                return -1;
    176173        }
    177174        return 0;
    178175}
    179176
    180 static void hdhomerun_write_header_length(unsigned char *ptr, unsigned long length)
     177static void hdhomerun_write_header_length(uint8_t *ptr, size_t length)
    181178{
    182         hdhomerun_write_u16(&ptr, length);
     179        hdhomerun_write_u16(&ptr, (uint16_t)length);
    183180}
    184181
    185 void hdhomerun_write_crc(unsigned char **pptr, unsigned char *start)
     182void hdhomerun_write_crc(uint8_t **pptr, uint8_t *start)
    186183{
    187         unsigned char *ptr = *pptr;
    188         unsigned long crc = hdhomerun_calc_crc(start, ptr);
    189         *ptr++ = (crc >> 0) & 0xFF;
    190         *ptr++ = (crc >> 8) & 0xFF;
    191         *ptr++ = (crc >> 16) & 0xFF;
    192         *ptr++ = (crc >> 24) & 0xFF;
     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);
    193190        *pptr = ptr;
    194191}
    195192
    196 void hdhomerun_write_discover_request(unsigned char **pptr, unsigned long device_type, unsigned long device_id)
     193void hdhomerun_write_discover_request(uint8_t **pptr, uint32_t device_type, uint32_t device_id)
    197194{
    198         unsigned char *start = *pptr;
     195        uint8_t *start = *pptr;
    199196        hdhomerun_write_u16(pptr, HDHOMERUN_TYPE_DISCOVER_REQ);
    200197        hdhomerun_write_u16(pptr, 0);
    201198
     
    206203        hdhomerun_write_var_length(pptr, 4);
    207204        hdhomerun_write_u32(pptr, device_id);
    208205
    209         hdhomerun_write_header_length(start + 2, *pptr - start - 4);
     206        hdhomerun_write_header_length(start + 2, (int)(*pptr - start - 4));
    210207        hdhomerun_write_crc(pptr, start);
    211208}
    212209
    213 void hdhomerun_write_get_request(unsigned char **pptr, const char *name)
     210void hdhomerun_write_get_set_request(uint8_t **pptr, const char *name, const char *value)
    214211{
    215         unsigned char *start = *pptr;
     212        uint8_t *start = *pptr;
    216213        hdhomerun_write_u16(pptr, HDHOMERUN_TYPE_GETSET_REQ);
    217214        hdhomerun_write_u16(pptr, 0);
    218215
    219         int name_len = strlen(name) + 1;
     216        int name_len = (int)strlen(name) + 1;
    220217        hdhomerun_write_u8(pptr, HDHOMERUN_TAG_GETSET_NAME);
    221218        hdhomerun_write_var_length(pptr, name_len);
    222219        hdhomerun_write_mem(pptr, (void *)name, name_len);
    223220
    224         hdhomerun_write_header_length(start + 2, *pptr - start - 4);
    225         hdhomerun_write_crc(pptr, start);
    226 }
     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);
     226        }
    227227
    228 void hdhomerun_write_set_request(unsigned char **pptr, const char *name, const char *value)
    229 {
    230         unsigned char *start = *pptr;
    231         hdhomerun_write_u16(pptr, HDHOMERUN_TYPE_GETSET_REQ);
    232         hdhomerun_write_u16(pptr, 0);
    233 
    234         int name_len = strlen(name) + 1;
    235         int value_len = strlen(value) + 1;
    236         hdhomerun_write_u8(pptr, HDHOMERUN_TAG_GETSET_NAME);
    237         hdhomerun_write_var_length(pptr, name_len);
    238         hdhomerun_write_mem(pptr, (void *)name, name_len);
    239         hdhomerun_write_u8(pptr, HDHOMERUN_TAG_GETSET_VALUE);
    240         hdhomerun_write_var_length(pptr, value_len);
    241         hdhomerun_write_mem(pptr, (void *)value, value_len);
    242 
    243         hdhomerun_write_header_length(start + 2, *pptr - start - 4);
     228        hdhomerun_write_header_length(start + 2, (int)(*pptr - start - 4));
    244229        hdhomerun_write_crc(pptr, start);
    245230}
    246231
    247 void hdhomerun_write_upgrade_request(unsigned char **pptr, unsigned long sequence, void *data, int length)
     232void hdhomerun_write_upgrade_request(uint8_t **pptr, uint32_t sequence, void *data, size_t length)
    248233{
    249         unsigned char *start = *pptr;
     234        uint8_t *start = *pptr;
    250235        hdhomerun_write_u16(pptr, HDHOMERUN_TYPE_UPGRADE_REQ);
    251236        hdhomerun_write_u16(pptr, 0);
    252237
     
    259244        hdhomerun_write_crc(pptr, start);
    260245}
    261246
    262 int hdhomerun_peek_packet_length(unsigned char *ptr)
     247size_t hdhomerun_peek_packet_length(uint8_t *ptr)
    263248{
    264249        ptr += 2;
    265         return hdhomerun_read_u16(&ptr) + 8;
     250        return (size_t)hdhomerun_read_u16(&ptr) + 8;
    266251}
    267252
    268 int hdhomerun_process_packet(unsigned char **pptr, unsigned char **pend)
     253int hdhomerun_process_packet(uint8_t **pptr, uint8_t **pend)
    269254{
    270255        if (hdhomerun_check_crc(*pptr, *pend) < 0) {
    271256                return -1;
    272257        }
    273258        *pend -= 4;
    274259       
    275         unsigned short type = hdhomerun_read_u16(pptr);
    276         unsigned short length = hdhomerun_read_u16(pptr);
     260        uint16_t type = hdhomerun_read_u16(pptr);
     261        uint16_t length = hdhomerun_read_u16(pptr);
    277262        if ((*pend - *pptr) < length) {
    278263                return -1;
    279264        }
    280265        *pend = *pptr + length;
    281266        return (int)type;
    282267}
     268
  • libs/libmythtv/hdhomerun/hdhomerun_device.c

     
     1/*
     2 * hdhomerun_record.c
     3 *
     4 * Copyright © 2006 Silicondust Engineering Ltd. <www.silicondust.com>.
     5 *
     6 * This library is free software; you can redistribute it and/or
     7 * modify it under the terms of the GNU Lesser General Public
     8 * License as published by the Free Software Foundation; either
     9 * version 2.1 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, write to the Free Software
     18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     19 */
     20
     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"
     26
     27struct hdhomerun_device_t {
     28        struct hdhomerun_control_sock_t *cs;
     29        struct hdhomerun_video_sock_t *vs;
     30        unsigned int tuner;
     31        char result_buffer[1024];
     32};
     33
     34struct hdhomerun_device_t *hdhomerun_device_create(uint32_t device_id, uint32_t device_ip, unsigned int tuner)
     35{
     36        struct hdhomerun_device_t *hd = (struct hdhomerun_device_t *)calloc(1, sizeof(struct hdhomerun_device_t));
     37        if (!hd) {
     38                return NULL;
     39        }
     40
     41        hd->tuner = tuner;
     42
     43        hd->cs = hdhomerun_control_create(device_id, device_ip);
     44        if (!hd->cs) {
     45                free(hd);
     46                return NULL;
     47        }
     48
     49        return hd;
     50}
     51
     52void hdhomerun_device_destroy(struct hdhomerun_device_t *hd)
     53{
     54        if (hd->vs) {
     55                hdhomerun_video_destroy(hd->vs);
     56        }
     57
     58        hdhomerun_control_destroy(hd->cs);
     59
     60        free(hd);
     61}
     62
     63void hdhomerun_device_set_tuner(struct hdhomerun_device_t *hd, unsigned int tuner)
     64{
     65        hd->tuner = tuner;
     66}
     67
     68struct hdhomerun_control_sock_t *hdhomerun_device_get_control_sock(struct hdhomerun_device_t *hd)
     69{
     70        return hd->cs;
     71}
     72
     73struct hdhomerun_video_sock_t *hdhomerun_device_get_video_sock(struct hdhomerun_device_t *hd)
     74{
     75        if (!hd->vs) {
     76                hd->vs = hdhomerun_video_create(0, VIDEO_DATA_BUFFER_SIZE_1S);
     77        }
     78        return hd->vs;
     79}
     80
     81uint32_t hdhomerun_device_get_local_machine_addr(struct hdhomerun_device_t *hd)
     82{
     83        return hdhomerun_control_get_local_addr(hd->cs);
     84}
     85
     86static uint32_t hdhomerun_device_get_status_parse(const char *status_str, const char *tag)
     87{
     88        const char *ptr = strstr(status_str, tag);
     89        if (!ptr) {
     90                return 0;
     91        }
     92
     93        unsigned long value = 0;
     94        sscanf(ptr + strlen(tag), "%lu", &value);
     95
     96        return (uint32_t)value;
     97}
     98
     99int hdhomerun_device_get_tuner_status(struct hdhomerun_device_t *hd, struct hdhomerun_tuner_status_t *status)
     100{
     101        memset(status, 0, sizeof(struct hdhomerun_tuner_status_t));
     102
     103        char name[32];
     104        sprintf(name, "/tuner%u/status", hd->tuner);
     105
     106        char *status_str;
     107        int ret = hdhomerun_control_get(hd->cs, name, &status_str, NULL);
     108        if (ret <= 0) {
     109                return ret;
     110        }
     111
     112        char *channel = strstr(status_str, "ch=");
     113        if (channel) {
     114                sscanf(channel + 3, "%s", status->channel);
     115        }
     116
     117        status->signal_strength = (unsigned int)hdhomerun_device_get_status_parse(status_str, "ss=");
     118        status->signal_to_noise_quality = (unsigned int)hdhomerun_device_get_status_parse(status_str, "snq=");
     119        status->symbol_error_quality = (unsigned int)hdhomerun_device_get_status_parse(status_str, "seq=");
     120        status->raw_bits_per_second = hdhomerun_device_get_status_parse(status_str, "bps=");
     121        status->packets_per_second = hdhomerun_device_get_status_parse(status_str, "pps=");
     122
     123        return 1;
     124}
     125
     126int hdhomerun_device_get_tuner_streaminfo(struct hdhomerun_device_t *hd, char **pstreaminfo)
     127{
     128        char name[32];
     129        sprintf(name, "/tuner%u/streaminfo", hd->tuner);
     130        return hdhomerun_control_get(hd->cs, name, pstreaminfo, NULL);
     131}
     132
     133int hdhomerun_device_get_tuner_channel(struct hdhomerun_device_t *hd, char **pchannel)
     134{
     135        char name[32];
     136        sprintf(name, "/tuner%u/channel", hd->tuner);
     137        return hdhomerun_control_get(hd->cs, name, pchannel, NULL);
     138}
     139
     140int hdhomerun_device_get_tuner_channelmap(struct hdhomerun_device_t *hd, char **pchannelmap)
     141{
     142        char name[32];
     143        sprintf(name, "/tuner%u/channelmap", hd->tuner);
     144        return hdhomerun_control_get(hd->cs, name, pchannelmap, NULL);
     145}
     146
     147int hdhomerun_device_get_tuner_filter(struct hdhomerun_device_t *hd, char **pfilter)
     148{
     149        char name[32];
     150        sprintf(name, "/tuner%u/filter", hd->tuner);
     151        return hdhomerun_control_get(hd->cs, name, pfilter, NULL);
     152}
     153
     154int hdhomerun_device_get_tuner_program(struct hdhomerun_device_t *hd, uint16_t *pprogram_number)
     155{
     156        char name[32];
     157        sprintf(name, "/tuner%u/program", hd->tuner);
     158
     159        char *program_str;
     160        int ret = hdhomerun_control_get(hd->cs, name, &program_str, NULL);
     161        if (ret <= 0) {
     162                return ret;
     163        }
     164
     165        *pprogram_number = (uint16_t)atol(program_str);
     166        return 1;
     167}
     168
     169int hdhomerun_device_get_tuner_target(struct hdhomerun_device_t *hd, char **ptarget)
     170{
     171        char name[32];
     172        sprintf(name, "/tuner%u/target", hd->tuner);
     173        return hdhomerun_control_get(hd->cs, name, ptarget, NULL);
     174}
     175
     176int hdhomerun_device_get_ir_target(struct hdhomerun_device_t *hd, char **ptarget)
     177{
     178        return hdhomerun_control_get(hd->cs, "/ir/target", ptarget, NULL);
     179}
     180
     181int hdhomerun_device_get_version(struct hdhomerun_device_t *hd, char **pversion_str, uint32_t *pversion_num)
     182{
     183        char *version_str;
     184        int ret = hdhomerun_control_get(hd->cs, "/sys/version", &version_str, NULL);
     185        if (ret <= 0) {
     186                return ret;
     187        }
     188
     189        if (pversion_str) {
     190                *pversion_str = version_str;
     191        }
     192
     193        if (pversion_num) {
     194                unsigned long version_num;
     195                if (sscanf(version_str, "%lu", &version_num) != 1) {
     196                        *pversion_num = 0;
     197                } else {
     198                        *pversion_num = (uint32_t)version_num;
     199                }
     200        }
     201
     202        return 1;
     203}
     204
     205int hdhomerun_device_set_tuner_channel(struct hdhomerun_device_t *hd, const char *channel)
     206{
     207        char name[32];
     208        sprintf(name, "/tuner%u/channel", hd->tuner);
     209        return hdhomerun_control_set(hd->cs, name, channel, NULL, NULL);
     210}
     211
     212int hdhomerun_device_set_tuner_channelmap(struct hdhomerun_device_t *hd, const char *channelmap)
     213{
     214        char name[32];
     215        sprintf(name, "/tuner%u/channelmap", hd->tuner);
     216        return hdhomerun_control_set(hd->cs, name, channelmap, NULL, NULL);
     217}
     218
     219int hdhomerun_device_set_tuner_filter(struct hdhomerun_device_t *hd, const char *filter)
     220{
     221        char name[32];
     222        sprintf(name, "/tuner%u/filter", hd->tuner);
     223        return hdhomerun_control_set(hd->cs, name, filter, NULL, NULL);
     224}
     225
     226int hdhomerun_device_set_tuner_program(struct hdhomerun_device_t *hd, uint16_t program_number)
     227{
     228        char name[32], value[32];
     229        sprintf(name, "/tuner%u/program", hd->tuner);
     230        sprintf(value, "%u", program_number);
     231        return hdhomerun_control_set(hd->cs, name, value, NULL, NULL);
     232}
     233
     234int hdhomerun_device_set_tuner_target(struct hdhomerun_device_t *hd, char *target)
     235{
     236        char name[32];
     237        sprintf(name, "/tuner%u/target", hd->tuner);
     238        return hdhomerun_control_set(hd->cs, name, target, NULL, NULL);
     239}
     240
     241static int hdhomerun_device_set_tuner_target_to_local(struct hdhomerun_device_t *hd)
     242{
     243        char target[64];
     244        uint32_t local_ip = hdhomerun_control_get_local_addr(hd->cs);
     245        uint16_t local_port = hdhomerun_video_get_local_port(hd->vs);
     246        sprintf(target, "%u.%u.%u.%u:%u",
     247                (unsigned int)(local_ip >> 24) & 0xFF, (unsigned int)(local_ip >> 16) & 0xFF,
     248                (unsigned int)(local_ip >> 8) & 0xFF, (unsigned int)(local_ip >> 0) & 0xFF,
     249                (unsigned int)local_port
     250        );
     251
     252        return hdhomerun_device_set_tuner_target(hd, target);
     253}
     254
     255int hdhomerun_device_set_ir_target(struct hdhomerun_device_t *hd, const char *target)
     256{
     257        return hdhomerun_control_set(hd->cs, "/ir/target", target, NULL, NULL);
     258}
     259
     260int hdhomerun_device_get_var(struct hdhomerun_device_t *hd, const char *name, char **pvalue, char **perror)
     261{
     262        return hdhomerun_control_get(hd->cs, name, pvalue, perror);
     263}
     264
     265int hdhomerun_device_set_var(struct hdhomerun_device_t *hd, const char *name, const char *value, char **pvalue, char **perror)
     266{
     267        return hdhomerun_control_set(hd->cs, name, value, pvalue, perror);
     268}
     269
     270int hdhomerun_device_stream_start(struct hdhomerun_device_t *hd)
     271{
     272        /* Create video socket. */
     273        hdhomerun_device_get_video_sock(hd);
     274        if (!hd->vs) {
     275                return -1;
     276        }
     277
     278        /* Set target. */
     279        int ret = hdhomerun_device_set_tuner_target_to_local(hd);
     280        if (ret <= 0) {
     281                return ret;
     282        }
     283
     284        /* Flush video buffer. */
     285        usleep(64000);
     286        hdhomerun_video_flush(hd->vs);
     287
     288        /* Success. */
     289        return 1;
     290}
     291
     292uint8_t *hdhomerun_device_stream_recv(struct hdhomerun_device_t *hd, size_t max_size, size_t *pactual_size)
     293{
     294        return hdhomerun_video_recv(hd->vs, max_size, pactual_size);
     295}
     296
     297void hdhomerun_device_stream_stop(struct hdhomerun_device_t *hd)
     298{
     299        hdhomerun_device_set_tuner_target(hd, "none");
     300}
     301
     302int hdhomerun_device_firmware_version_check(struct hdhomerun_device_t *hd, uint32_t features)
     303{
     304        uint32_t version;
     305        if (hdhomerun_device_get_version(hd, NULL, &version) <= 0) {
     306                return -1;
     307        }
     308
     309        if (version >= 20061213) {
     310                return 1;
     311        }
     312
     313        return 0;
     314}
     315
     316int hdhomerun_device_upgrade(struct hdhomerun_device_t *hd, FILE *upgrade_file)
     317{
     318        hdhomerun_control_set(hd->cs, "/tuner0/channel", "none", NULL, NULL);
     319        hdhomerun_control_set(hd->cs, "/tuner1/channel", "none", NULL, NULL);
     320        return hdhomerun_control_upgrade(hd->cs, upgrade_file);
     321}
  • libs/libmythtv/hdhomerun/hdhomerun_pkt.h

     
    2121extern "C" {
    2222#endif
    2323
     24/*
     25 * The discover protocol (UDP port 65001) and control protocol (TCP port 65001)
     26 * both use the same packet based format:
     27 *      uint16_t        Packet type
     28 *      uint16_t        Payload length (bytes)
     29 *      uint8_t[]       Payload data (0-n bytes).
     30 *      uint32_t        CRC (Ethernet style 32-bit CRC)
     31 *
     32 * All variables are big-endian except for the crc which is little-endian.
     33 *
     34 * Valid values for the packet type are listed below as defines prefixed
     35 * with "HDHOMERUN_TYPE_"
     36 *
     37 * Discovery:
     38 *
     39 * The payload for a discovery request or reply is a simple sequence of
     40 * tag-length-value data:
     41 *      uint8_t         Tag
     42 *      varlen          Length
     43 *      uint8_t[]       Value (0-n bytes)
     44 *
     45 * The length field can be one or two bytes long.
     46 * For a length <= 127 bytes the length is expressed as a single byte. The
     47 * most-significant-bit is clear indicating a single-byte length.
     48 * For a length >= 128 bytes the length is expressed as a sequence of two bytes as follows:
     49 * The first byte is contains the least-significant 7-bits of the length. The
     50 * most-significant bit is then set (add 0x80) to indicate that it is a two byte length.
     51 * The second byte contains the length shifted down 7 bits.
     52 *
     53 * A discovery request packet has a packet type of HDHOMERUN_TYPE_DISCOVER_REQ and should
     54 * contain two tags: HDHOMERUN_TAG_DEVICE_TYPE and HDHOMERUN_TAG_DEVICE_ID.
     55 * The HDHOMERUN_TAG_DEVICE_TYPE value should be set to HDHOMERUN_DEVICE_TYPE_TUNER.
     56 * The HDHOMERUN_TAG_DEVICE_ID value should be set to HDHOMERUN_DEVICE_ID_WILDCARD to match
     57 * all devices, or to the 32-bit device id number to match a single device.
     58 *
     59 * The discovery response packet has a packet type of HDHOMERUN_TYPE_DISCOVER_RPY and has the
     60 * same format as the discovery request packet with the two tags: HDHOMERUN_TAG_DEVICE_TYPE and
     61 * HDHOMERUN_TAG_DEVICE_ID. In the future additional tags may also be returned - unknown tags
     62 * should be skipped and not treated as an error.
     63 *
     64 * Control get/set:
     65 *
     66 * The payload for a control get/set request is a simple sequence of tag-length-value data
     67 * following the same format as for discover packets.
     68 *
     69 * A get request packet has a packet type of HDHOMERUN_TYPE_GETSET_REQ and should contain
     70 * the tag: HDHOMERUN_TAG_GETSET_NAME. The HDHOMERUN_TAG_GETSET_NAME value should be a sequence
     71 * of bytes forming a null-terminated string, including the NULL. The TLV length must include
     72 * the NULL character so the length field should be set to strlen(str) + 1.
     73 *
     74 * A set request packet has a packet type of HDHOMERUN_TYPE_GETSET_REQ (same as a get request)
     75 * and should contain two tags: HDHOMERUN_TAG_GETSET_NAME and HDHOMERUN_TAG_GETSET_VALUE.
     76 * The HDHOMERUN_TAG_GETSET_NAME value should be a sequence of bytes forming a null-terminated
     77 * string, including the NULL.
     78 * The HDHOMERUN_TAG_GETSET_VALUE value  should be a sequence of bytes forming a null-terminated
     79 * string, including the NULL.
     80 *
     81 * The get and set reply packets have the packet type HDHOMERUN_TYPE_GETSET_RPY and have the same
     82 * format as the set request packet with the two tags: HDHOMERUN_TAG_GETSET_NAME and
     83 * HDHOMERUN_TAG_GETSET_VALUE. A set request is also implicit get request so the updated value is
     84 * returned.
     85 *
     86 * If the device encounters an error handling the get or set request then the get/set reply packet
     87 * will contain the tag HDHOMERUN_TAG_ERROR_MESSAGE. The format of the value is a sequence of
     88 * bytes forming a null-terminated string, including the NULL.
     89 *
     90 * In the future additional tags may also be returned - unknown tags should be skipped and not
     91 * treated as an error.
     92 *
     93 * Security note: The application should not rely on the NULL character being present. The
     94 * application should write a NULL character based on the TLV length to protect the application
     95 * from a potential attack.
     96 *
     97 * Firmware Upgrade:
     98 *
     99 * A firmware upgrade packet has a packet type of HDHOMERUN_TYPE_UPGRADE_REQ and has a fixed format:
     100 *      uint32_t        Position in bytes from start of file.
     101 *      uint8_t[256]    Firmware data (256 bytes)
     102 *
     103 * The data must be uploaded in 256 byte chunks and must be uploaded in order.
     104 * The position number is in bytes so will increment by 256 each time.
     105 *
     106 * When all data is uploaded it should be signaled complete by sending another packet of type
     107 * HDHOMERUN_TYPE_UPGRADE_REQ with payload of a single uint32_t with the value 0xFFFFFFFF.
     108 */
     109
    24110#define HDHOMERUN_DISCOVER_UDP_PORT 65001
    25111#define HDHOMERUN_CONTROL_TCP_PORT 65001
    26112
     
    43129
    44130#define HDHOMERUN_MIN_PEEK_LENGTH 4
    45131
    46 extern unsigned char hdhomerun_read_u8(unsigned char **pptr);
    47 extern unsigned short hdhomerun_read_u16(unsigned char **pptr);
    48 extern unsigned long hdhomerun_read_u32(unsigned char **pptr);
    49 extern void hdhomerun_write_u8(unsigned char **pptr, unsigned char v);
    50 extern void hdhomerun_write_u16(unsigned char **pptr, unsigned short v);
    51 extern void hdhomerun_write_u32(unsigned char **pptr, unsigned long v);
    52 extern void hdhomerun_write_crc(unsigned char **pptr, unsigned char *start);
     132extern uint8_t hdhomerun_read_u8(uint8_t **pptr);
     133extern uint16_t hdhomerun_read_u16(uint8_t **pptr);
     134extern uint32_t hdhomerun_read_u32(uint8_t **pptr);
     135extern size_t hdhomerun_read_var_length(uint8_t **pptr, uint8_t *end);
     136extern void hdhomerun_write_u8(uint8_t **pptr, uint8_t v);
     137extern void hdhomerun_write_u16(uint8_t **pptr, uint16_t v);
     138extern void hdhomerun_write_u32(uint8_t **pptr, uint32_t v);
     139extern void hdhomerun_write_var_length(uint8_t **pptr, size_t v);
     140extern void hdhomerun_write_crc(uint8_t **pptr, uint8_t *start);
    53141
    54 extern int hdhomerun_peek_packet_length(unsigned char *ptr);
    55 extern int hdhomerun_process_packet(unsigned char **pptr, unsigned char **pend);
    56 extern int hdhomerun_read_tlv(unsigned char **pptr, unsigned char *end, unsigned char *ptag, int *plength, unsigned char **pvalue);
     142extern size_t hdhomerun_peek_packet_length(uint8_t *ptr);
     143extern int hdhomerun_process_packet(uint8_t **pptr, uint8_t **pend);
     144extern int hdhomerun_read_tlv(uint8_t **pptr, uint8_t *end, uint8_t *ptag, size_t *plength, uint8_t **pvalue);
    57145
    58 extern void hdhomerun_write_discover_request(unsigned char **pptr, unsigned long device_type, unsigned long device_id);
    59 extern void hdhomerun_write_get_request(unsigned char **pptr, const char *name);
    60 extern void hdhomerun_write_set_request(unsigned char **pptr, const char *name, const char *value);
    61 extern void hdhomerun_write_upgrade_request(unsigned char **pptr, unsigned long sequence, void *data, int length);
     146extern void hdhomerun_write_discover_request(uint8_t **pptr, uint32_t device_type, uint32_t device_id);
     147extern void hdhomerun_write_get_set_request(uint8_t **pptr, const char *name, const char *value);
     148extern void hdhomerun_write_upgrade_request(uint8_t **pptr, uint32_t sequence, void *data, size_t length);
    62149
    63150#ifdef __cplusplus
    64151}
    65152#endif
     153
  • libs/libmythtv/hdhomerun/hdhomerun_device.h

     
     1/*
     2 * hdhomerun_device.h
     3 *
     4 * Copyright © 2006 Silicondust Engineering Ltd. <www.silicondust.com>.
     5 *
     6 * This library is free software; you can redistribute it and/or
     7 * modify it under the terms of the GNU Lesser General Public
     8 * License as published by the Free Software Foundation; either
     9 * version 2.1 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, write to the Free Software
     18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     19 */
     20
     21#ifdef __cplusplus
     22extern "C" {
     23#endif
     24
     25#define HDHOMERUN_DEVICE_MAX_TUNE_TO_LOCK_TIME 1500
     26#define HDHOMERUN_DEVICE_MAX_LOCK_TO_DATA_TIME 2000
     27#define HDHOMERUN_DEVICE_MAX_TUNE_TO_DATA_TIME (HDHOMERUN_DEVICE_MAX_TUNE_TO_LOCK_TIME + HDHOMERUN_DEVICE_MAX_LOCK_TO_DATA_TIME)
     28
     29struct hdhomerun_device_t;
     30
     31struct 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
     40/*
     41 * Create a device object.
     42 *
     43 * Typically a device object will be created for each tuner.
     44 * It is valid to have multiple device objects communicating with a single HDHomeRun.
     45 *
     46 * For example, a threaded application that streams video from 4 tuners (2 HDHomeRun devices) and has
     47 * 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.
     49 *
     50 * This function will not attempt to connect to the device.
     51 * The connection will be established when first used.
     52 *
     53 * uint32_t device_id = 32-bit device id of device. Set to HDHOMERUN_DEVICE_ID_WILDCARD to match any device ID.
     54 * uint32_t device_ip = IP address of device. Set to 0 to auto-detect.
     55 * unsigned int tuner = tuner index (0 or 1). Can be changed later by calling hdhomerun_device_set_tuner.
     56 *
     57 * Returns a pointer to the newly created device object.
     58 *
     59 * When no longer needed, the socket should be destroyed by calling hdhomerun_device_destroy.
     60 */
     61extern struct hdhomerun_device_t *hdhomerun_device_create(uint32_t device_id, uint32_t device_ip, unsigned int tuner);
     62extern void hdhomerun_device_destroy(struct hdhomerun_device_t *hd);
     63extern void hdhomerun_device_set_tuner(struct hdhomerun_device_t *hd, unsigned int tuner);
     64
     65/*
     66 * Get the local machine IP address used when communicating with the device.
     67 *
     68 * This function is useful for determining the IP address to use with set target commands.
     69 *
     70 * Returns 32-bit IP address with native endianness, or 0 on error.
     71 */
     72extern uint32_t hdhomerun_device_get_local_machine_addr(struct hdhomerun_device_t *hd);
     73
     74/*
     75 * Get operations.
     76 *
     77 * struct hdhomerun_tuner_status_t *status = Pointer to caller supplied status struct to be populated with result.
     78 * const char **p<name> = Caller supplied char * to be updated to point to the result string. The string will remain
     79 *              valid until another call to a device function.
     80 *
     81 * Returns 1 if the operation was successful.
     82 * Returns 0 if the operation was rejected.
     83 * Returns -1 if a communication error occurred.
     84 */
     85extern int hdhomerun_device_get_tuner_status(struct hdhomerun_device_t *hd, struct hdhomerun_tuner_status_t *status);
     86extern int hdhomerun_device_get_tuner_streaminfo(struct hdhomerun_device_t *hd, char **pstreaminfo);
     87extern int hdhomerun_device_get_tuner_channel(struct hdhomerun_device_t *hd, char **pchannel);
     88extern int hdhomerun_device_get_tuner_channelmap(struct hdhomerun_device_t *hd, char **pchannelmap);
     89extern int hdhomerun_device_get_tuner_filter(struct hdhomerun_device_t *hd, char **pfilter);
     90extern int hdhomerun_device_get_tuner_program(struct hdhomerun_device_t *hd, uint16_t *pprogram_number);
     91extern int hdhomerun_device_get_tuner_target(struct hdhomerun_device_t *hd, char **ptarget);
     92extern int hdhomerun_device_get_ir_target(struct hdhomerun_device_t *hd, char **ptarget);
     93extern int hdhomerun_device_get_version(struct hdhomerun_device_t *hd, char **pversion_str, uint32_t *pversion_num);
     94
     95/*
     96 * Set operations.
     97 *
     98 * const char *<name> = String to send to device.
     99 *
     100 * Returns 1 if the operation was successful.
     101 * Returns 0 if the operation was rejected.
     102 * Returns -1 if a communication error occurred.
     103 */
     104extern int hdhomerun_device_set_tuner_channel(struct hdhomerun_device_t *hd, const char *channel);
     105extern int hdhomerun_device_set_tuner_channelmap(struct hdhomerun_device_t *hd, const char *channelmap);
     106extern int hdhomerun_device_set_tuner_filter(struct hdhomerun_device_t *hd, const char *filter);
     107extern int hdhomerun_device_set_tuner_program(struct hdhomerun_device_t *hd, uint16_t program_number);
     108extern int hdhomerun_device_set_tuner_target(struct hdhomerun_device_t *hd, char *target);
     109extern int hdhomerun_device_set_ir_target(struct hdhomerun_device_t *hd, const char *target);
     110
     111/*
     112 * Get/set a named control variable on the device.
     113 *
     114 * const char *name: The name of var to get/set (c-string). The supported vars is device/firmware dependant.
     115 * const char *value: The value to set (c-string). The format is device/firmware dependant.
     116
     117 * char **pvalue: If provided, the caller-supplied char pointer will be populated with a pointer to the value
     118 *              string returned by the device, or NULL if the device returned an error string. The string will remain
     119 *              valid until the next call to a control sock function.
     120 * char **perror: If provided, the caller-supplied char pointer will be populated with a pointer to the error
     121 *              string returned by the device, or NULL if the device returned an value string. The string will remain
     122 *              valid until the next call to a control sock function.
     123 *
     124 * Returns 1 if the operation was successful (pvalue set, perror NULL).
     125 * Returns 0 if the operation was rejected (pvalue NULL, perror set).
     126 * Returns -1 if a communication error occurs.
     127 */
     128extern int hdhomerun_device_get_var(struct hdhomerun_device_t *hd, const char *name, char **pvalue, char **perror);
     129extern int hdhomerun_device_set_var(struct hdhomerun_device_t *hd, const char *name, const char *value, char **pvalue, char **perror);
     130
     131/*
     132 * Stream a filtered program or the unfiltered stream.
     133 *
     134 * The hdhomerun_device_stream_start function initializes the process and tells the device to start streamin data.
     135 *
     136 * uint16_t program_number = The program number to filer, or 0 for unfiltered.
     137 *
     138 * Returns 1 if the oprtation started successfully.
     139 * Returns 0 if the operation was rejected.
     140 * Returns -1 if a communication error occurs.
     141 *
     142 * The hdhomerun_device_stream_recv function should be called periodically to receive the stream data.
     143 * The buffer can losslessly store 1 second of data, however a more typical call rate would be every 64ms.
     144 *
     145 * The hdhomerun_device_stream_stop function tells the device to stop streaming data.
     146 */
     147extern int hdhomerun_device_stream_start(struct hdhomerun_device_t *hd);
     148extern uint8_t *hdhomerun_device_stream_recv(struct hdhomerun_device_t *hd, size_t max_size, size_t *pactual_size);
     149extern void hdhomerun_device_stream_stop(struct hdhomerun_device_t *hd);
     150
     151/*
     152 * Check that the device is running the recommended firmware.
     153 *
     154 * uint32_t features: Reserved for future use. Set to zero.
     155 *
     156 * Returns 1 if the firmware meets the minimum requriements for all operations.
     157 * Returns 0 if th firmware does not meet the minimum requriements for all operations.
     158 * Returns -1 if an error occurs.
     159 */
     160extern int hdhomerun_device_firmware_version_check(struct hdhomerun_device_t *hd, uint32_t features);
     161
     162/*
     163 * Upload new firmware to the device.
     164 *
     165 * FILE *upgrade_file: File pointer to read from. The file must have been opened in binary mode for reading.
     166 *
     167 * Returns 1 if the upload succeeded.
     168 * Returns 0 if the upload was rejected.
     169 * Returns -1 if an error occurs.
     170 */
     171extern int hdhomerun_device_upgrade(struct hdhomerun_device_t *hd, FILE *upgrade_file);
     172
     173/*
     174 * Low level accessor functions.
     175 */
     176extern struct hdhomerun_control_sock_t *hdhomerun_device_get_control_sock(struct hdhomerun_device_t *hd);
     177extern struct hdhomerun_video_sock_t *hdhomerun_device_get_video_sock(struct hdhomerun_device_t *hd);
     178
     179#ifdef __cplusplus
     180}
     181#endif
  • libs/libmythtv/hdhomerun/hdhomerun_config.c

     
    1818 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    1919 */
    2020
    21 #include "hdhomerun_os.h"
    22 #include "hdhomerun_pkt.h"
    23 #include "hdhomerun_discover.h"
    24 #include "hdhomerun_control.h"
     21#include "hdhomerun.h"
    2522
    26 const char *appname;
     23static const char *appname;
    2724
     25struct hdhomerun_device_t *hd;
     26
    2827static int help(void)
    2928{
    3029        printf("Usage:\n");
    3130        printf("\t%s discover\n", appname);
    32         printf("\t%s <id|ip> get help\n", appname);
    33         printf("\t%s <id|ip> get <item>\n", appname);
    34         printf("\t%s <id|ip> set <item> <value>\n", appname);
    35         printf("\t%s <id|ip> scan <tuner> <starting channel>\n", appname);
    36         printf("\t%s <id|ip> upgrade <filename>\n", appname);
    37         return 1;
     31        printf("\t%s <id> get help\n", appname);
     32        printf("\t%s <id> get <item>\n", appname);
     33        printf("\t%s <id> set <item> <value>\n", appname);
     34        printf("\t%s <id> scan <tuner> <starting channel>\n", appname);
     35        printf("\t%s <id> upgrade <filename>\n", appname);
     36        return -1;
    3837}
    3938
    4039static void extract_appname(const char *argv0)
    4140{
    42         char *ptr = strrchr(argv0, '/');
     41        const char *ptr = strrchr(argv0, '/');
    4342        if (ptr) {
    4443                argv0 = ptr + 1;
    4544        }
     
    5049        appname = argv0;
    5150}
    5251
    53 static int contains(const char *arg, const char *cmpstr)
     52static bool_t contains(const char *arg, const char *cmpstr)
    5453{
    5554        if (strcmp(arg, cmpstr) == 0) {
    56                 return 1;
     55                return TRUE;
    5756        }
    5857
    5958        if (*arg++ != '-') {
    60                 return 0;
     59                return FALSE;
    6160        }
    6261        if (*arg++ != '-') {
    63                 return 0;
     62                return FALSE;
    6463        }
    6564        if (strcmp(arg, cmpstr) == 0) {
    66                 return 1;
     65                return TRUE;
    6766        }
    6867
    69         return 0;
     68        return FALSE;
    7069}
    7170
    72 static int discover_print_internal(struct hdhomerun_discover_sock_t *discover_sock)
    73 {
    74         if (hdhomerun_discover_send(discover_sock, HDHOMERUN_DEVICE_TYPE_TUNER, HDHOMERUN_DEVICE_ID_WILDCARD) < 0) {
    75                 fprintf(stderr, "unable to send discover request\n");
    76                 return 1;
    77         }
    78 
    79         while (1) {
    80                 struct hdhomerun_discover_device_t result;
    81                 int ret = hdhomerun_discover_recv(discover_sock, &result, 1000);
    82                 if (ret < 0) {
    83                         fprintf(stderr, "error listening for discover response\n");
    84                         return 1;
    85                 }
    86                 if (ret == 0) {
    87                         return 0;
    88                 }
    89 
    90                 printf("hdhomerun device %08lX found at %ld.%ld.%ld.%ld\n",
    91                         result.device_id,
    92                         (result.ip_addr >> 24) & 0x0FF, (result.ip_addr >> 16) & 0x0FF,
    93                         (result.ip_addr >> 8) & 0x0FF, (result.ip_addr >> 0) & 0x0FF
    94                 );
    95         }
    96 }
    97 
    9871static int discover_print(void)
    9972{
    100         struct hdhomerun_discover_sock_t *discover_sock = hdhomerun_discover_create(1000);
    101         if (!discover_sock) {
    102                 fprintf(stderr, "unable to create discover socket\n");
    103                 return 1;
     73        struct hdhomerun_discover_device_t result_list[64];
     74        int count = hdhomerun_discover_find_devices(HDHOMERUN_DEVICE_TYPE_TUNER, result_list, 64);
     75        if (count < 0) {
     76                fprintf(stderr, "error sending discover request\n");
     77                return -1;
    10478        }
    105 
    106         int ret = discover_print_internal(discover_sock);
    107 
    108         hdhomerun_discover_destroy(discover_sock);
    109         return ret;
    110 }
    111 
    112 static unsigned long get_ip_addr(struct hdhomerun_discover_sock_t *discover_sock, const char *id_str)
    113 {
    114         int a[4];
    115         if (sscanf(id_str, "%u.%u.%u.%u", &a[0], &a[1], &a[2], &a[3]) == 4) {
    116                 return (a[0] << 24) | (a[1] << 16) | (a[2] << 8) | (a[3] << 0);
    117         }
    118 
    119         unsigned long id = (unsigned long)strtoll(id_str, NULL, 16);
    120         if (!hdhomerun_discover_validate_device_id(id)) {
    121                 fprintf(stderr, "invalid device id: %s\n", id_str);
     79        if (count == 0) {
     80                printf("no devices found\n");
    12281                return 0;
    12382        }
    12483
    125         if (hdhomerun_discover_send(discover_sock, HDHOMERUN_DEVICE_TYPE_TUNER, id) < 0) {
    126                 fprintf(stderr, "unable to send discover request\n");
    127                 return 0;
     84        int index;
     85        for (index = 0; index < count; index++) {
     86                struct hdhomerun_discover_device_t *result = &result_list[index];
     87                printf("hdhomerun device %08lX found at %u.%u.%u.%u\n",
     88                        (unsigned long)result->device_id,
     89                        (unsigned int)(result->ip_addr >> 24) & 0x0FF, (unsigned int)(result->ip_addr >> 16) & 0x0FF,
     90                        (unsigned int)(result->ip_addr >> 8) & 0x0FF, (unsigned int)(result->ip_addr >> 0) & 0x0FF
     91                );
    12892        }
    12993
    130         struct hdhomerun_discover_device_t result;
    131         int ret = hdhomerun_discover_recv(discover_sock, &result, 1000);
    132         if (ret < 0) {
    133                 fprintf(stderr, "error listening for discover response\n");
    134                 return 0;
    135         }
    136         if (ret == 0) {
    137                 fprintf(stderr, "unable to find hdhomerun device %08lX\n", id);
    138                 return 0;
    139         }
    140 
    141         return result.ip_addr;
     94        return count;
    14295}
    14396
    144 static struct hdhomerun_control_sock_t *create_control_sock(const char *id_str)
     97static bool_t parse_device_id_str(const char *s, uint32_t *pdevice_id, uint32_t *pdevice_ip)
    14598{
    146         struct hdhomerun_discover_sock_t *discover_sock = hdhomerun_discover_create(1000);
    147         if (!discover_sock) {
    148                 fprintf(stderr, "unable to create discover socket\n");
    149                 return NULL;
     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;
    150104        }
    151105
    152         unsigned long ip_addr = get_ip_addr(discover_sock, id_str);
    153 
    154         hdhomerun_discover_destroy(discover_sock);
    155         if (ip_addr == 0) {
    156                 return NULL;
     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;
    157110        }
    158111
    159         struct hdhomerun_control_sock_t *control_sock = hdhomerun_control_create(ip_addr, 1000);
    160         if (!control_sock) {
    161                 fprintf(stderr, "unable to connect to hdhomerun device\n");
    162                 return NULL;
     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;
    163116        }
    164117
    165         return control_sock;
     118        *pdevice_id = device_id;
     119        *pdevice_ip = 0;
     120        return TRUE;
    166121}
    167122
    168 int cmd_get(struct hdhomerun_control_sock_t *control_sock, const char *item)
     123static int cmd_get(const char *item)
    169124{
    170         if (hdhomerun_control_send_get_request(control_sock, item) < 0) {
     125        char *ret_value;
     126        char *ret_error;
     127        if (hdhomerun_device_get_var(hd, item, &ret_value, &ret_error) < 0) {
    171128                fprintf(stderr, "communication error sending request to hdhomerun device\n");
    172                 return 1;
     129                return -1;
    173130        }
    174131
    175         struct hdhomerun_control_data_t result;
    176         if (hdhomerun_control_recv(control_sock, &result, 1000) <= 0) {
    177                 fprintf(stderr, "communication error receiving response from hdhomerun device\n");
    178                 return 1;
     132        if (ret_error) {
     133                printf("%s\n", ret_error);
     134                return 0;
    179135        }
    180         if (result.type != HDHOMERUN_TYPE_GETSET_RPY) {
    181                 fprintf(stderr, "unexpected reply type from hdhomerun device\n");
    182                 return 1;
    183         }
    184136
    185         while (result.ptr < result.end) {
    186                 unsigned char tag;
    187                 int length;
    188                 unsigned char *value;
    189                 if (hdhomerun_read_tlv(&result.ptr, result.end, &tag, &length, &value) < 0) {
    190                         break;
    191                 }
    192                 switch (tag) {
    193                 case HDHOMERUN_TAG_ERROR_MESSAGE:
    194                 case HDHOMERUN_TAG_GETSET_VALUE:
    195                         printf("%s\n", (char *)value);
    196                         break;
    197                 }
    198         }
    199 
    200         return 0;
     137        printf("%s\n", ret_value);
     138        return 1;
    201139}
    202140
    203 int cmd_set(struct hdhomerun_control_sock_t *control_sock, const char *item, const char *value)
     141static int cmd_set(const char *item, const char *value)
    204142{
    205         if (hdhomerun_control_send_set_request(control_sock, item, value) < 0) {
     143        char *ret_error;
     144        if (hdhomerun_device_set_var(hd, item, value, NULL, &ret_error) < 0) {
    206145                fprintf(stderr, "communication error sending request to hdhomerun device\n");
    207                 return 1;
     146                return -1;
    208147        }
    209148
    210         struct hdhomerun_control_data_t result;
    211         if (hdhomerun_control_recv(control_sock, &result, 1000) <= 0) {
    212                 fprintf(stderr, "communication error receiving response from hdhomerun device\n");
    213                 return 1;
     149        if (ret_error) {
     150                printf("%s\n", ret_error);
     151                return 0;
    214152        }
    215         if (result.type != HDHOMERUN_TYPE_GETSET_RPY) {
    216                 fprintf(stderr, "unexpected reply type from hdhomerun device\n");
    217                 return 1;
    218         }
    219153
    220         while (result.ptr < result.end) {
    221                 unsigned char tag;
    222                 int length;
    223                 unsigned char *value;
    224                 if (hdhomerun_read_tlv(&result.ptr, result.end, &tag, &length, &value) < 0) {
    225                         break;
    226                 }
    227                 switch (tag) {
    228                 case HDHOMERUN_TAG_ERROR_MESSAGE:
    229                         printf("%s\n", (char *)value);
    230                         break;
    231                 }
    232         }
    233 
    234         return 0;
     154        return 1;
    235155}
    236156
    237 int cmd_scan(struct hdhomerun_control_sock_t *control_sock, const char *tuner_str, const char *start_value)
     157static int cmd_streaminfo(const char *tuner_str)
    238158{
    239         int tuner = atoi(tuner_str);
     159        fprintf(stderr, "streaminfo: use \"get /tuner<n>/streaminfo\"\n");
     160        return -1;
     161}
    240162
    241         /* Test starting channel. */
    242         char item[64];
    243         sprintf(item, "/tuner%d/channel", tuner);
    244         int ret = cmd_set(control_sock, item, start_value);
    245         if (ret != 0) {
    246                 return ret;
     163static int cmd_scan(const char *tuner_str, const char *start_value)
     164{
     165        unsigned int tuner;
     166        if (sscanf(tuner_str, "%u", &tuner) != 1) {
     167                fprintf(stderr, "invalid tuner number\n");
     168                return -1;
    247169        }
    248170
    249         char channel_value[64];
    250         strncpy(channel_value, start_value, sizeof(channel_value));
    251         channel_value[sizeof(channel_value) - 8] = 0;
     171        hdhomerun_device_set_tuner(hd, tuner);
    252172
    253         char *ptr = strrchr(channel_value, ':');
    254         if (!ptr) {
    255                 ptr = channel_value;
     173        char channel_str[64];
     174        strncpy(channel_str, start_value, sizeof(channel_str));
     175        channel_str[sizeof(channel_str) - 8] = 0;
     176
     177        char *channel_number_ptr = strrchr(channel_str, ':');
     178        if (!channel_number_ptr) {
     179                channel_number_ptr = channel_str;
    256180        } else {
    257                 ptr++;
     181                channel_number_ptr++;
    258182        }
    259183
    260         int channel = atol(ptr);
    261         if (channel == 0) {
     184        unsigned int channel_number = atol(channel_number_ptr);
     185        if (channel_number == 0) {
    262186                fprintf(stderr, "invalid starting channel\n");
    263                 return 1;
     187                return -1;
    264188        }
    265189
     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");
     194                return -1;
     195        }
     196        if (ret == 0) {
     197                fprintf(stderr, "invalid starting channel\n");
     198                return -1;
     199        }
     200
    266201        while (1) {
    267202                /* Update channel value */
    268                 sprintf(ptr, "%d", channel);
     203                sprintf(channel_number_ptr, "%u", channel_number);
    269204
    270205                /* Set channel. */
    271                 sprintf(item, "/tuner%d/channel", tuner);
    272                 if (hdhomerun_control_send_set_request(control_sock, item, channel_value) < 0) {
     206                ret = hdhomerun_device_set_tuner_channel(hd, channel_str);
     207                if (ret < 0) {
    273208                        fprintf(stderr, "communication error sending request to hdhomerun device\n");
    274                         return 1;
     209                        return -1;
    275210                }
    276        
    277                 /* Verify set succeeded. */
    278                 struct hdhomerun_control_data_t result;
    279                 if (hdhomerun_control_recv(control_sock, &result, 1000) <= 0) {
    280                         fprintf(stderr, "communication error receiving response from hdhomerun device\n");
    281                         return 1;
     211                if (ret == 0) {
     212                        return 0;
    282213                }
    283                 if (result.type != HDHOMERUN_TYPE_GETSET_RPY) {
    284                         fprintf(stderr, "unexpected reply type from hdhomerun device\n");
    285                         return 1;
    286                 }
    287                 while (result.ptr < result.end) {
    288                         unsigned char tag;
    289                         int length;
    290                         unsigned char *value;
    291                         if (hdhomerun_read_tlv(&result.ptr, result.end, &tag, &length, &value) < 0) {
    292                                 break;
    293                         }
    294                         if (tag == HDHOMERUN_TAG_ERROR_MESSAGE) {
    295                                 return 0;
    296                         }
    297                 }
    298214
    299                 /* Wait for 1s. */
    300                 sleep(1);
     215                /* Wait 1.5s for lock (qam auto is the slowest to lock). */
     216                usleep(HDHOMERUN_DEVICE_MAX_TUNE_TO_LOCK_TIME * 1000);
    301217
    302                 /* Get status. */
    303                 sprintf(item, "/tuner%d/status", tuner);
    304                 if (hdhomerun_control_send_get_request(control_sock, item) < 0) {
     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) {
    305221                        fprintf(stderr, "communication error sending request to hdhomerun device\n");
    306                         return 1;
     222                        return -1;
    307223                }
    308224
    309                 /* Status result. */
    310                 if (hdhomerun_control_recv(control_sock, &result, 1000) <= 0) {
    311                         fprintf(stderr, "communication error receiving response from hdhomerun device\n");
    312                         return 1;
     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;
    313230                }
    314                 if (result.type != HDHOMERUN_TYPE_GETSET_RPY) {
    315                         fprintf(stderr, "unexpected reply type from hdhomerun device\n");
    316                         return 1;
     231
     232                /* Wait for 2s. */
     233                usleep(HDHOMERUN_DEVICE_MAX_LOCK_TO_DATA_TIME * 1000);
     234
     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");
     238                        return -1;
    317239                }
    318                 char *status = NULL;
    319                 while (result.ptr < result.end) {
    320                         unsigned char tag;
    321                         int length;
    322                         unsigned char *value;
    323                         if (hdhomerun_read_tlv(&result.ptr, result.end, &tag, &length, &value) < 0) {
    324                                 break;
    325                         }
    326                         if (tag == HDHOMERUN_TAG_ERROR_MESSAGE) {
    327                                 return 0;
    328                         }
    329                         if (tag == HDHOMERUN_TAG_GETSET_VALUE) {
    330                                 status = (char *)value;
    331                         }
     240                if (status.signal_strength == 0) {
     241                        printf("%s: no signal\n", channel_str);
     242                        channel_number++;
     243                        continue;
    332244                }
    333                 if (!status) {
    334                         fprintf(stderr, "unexpected reply type from hdhomerun device\n");
    335                         return 1;
    336                 }
     245                printf("%s: ss=%u snq=%u seq=%u\n", channel_str, status.signal_strength, status.signal_to_noise_quality, status.symbol_error_quality);
    337246
    338                 /* If no signal then advance to next channel. */
    339                 char *ss_str = strstr(status, "ss=");
    340                 if (!ss_str) {
    341                         printf("%s\n", status);
    342                         channel++;
     247                /* Detect sub channels. */
     248                usleep(4 * 1000000);
     249                char *streaminfo;
     250                if (hdhomerun_device_get_tuner_streaminfo(hd, &streaminfo) <= 0) {
     251                        channel_number++;
    343252                        continue;
    344253                }
    345                 int ss = atoi(ss_str + strlen("ss="));
    346                 if (ss == 0) {
    347                         printf("%s\n", status);
    348                         channel++;
    349                         continue;
    350                 }
     254                while (1) {
     255                        char *end = strchr(streaminfo, '\n');
     256                        if (!end) {
     257                                break;
     258                        }
    351259
    352                 /* Wait for 2s. */
    353                 sleep(2);
     260                        *end++ = 0;
     261                        printf("program %s\n", streaminfo);
    354262
    355                 /* Display channel status. */
    356                 cmd_get(control_sock, item);
     263                        streaminfo = end;
     264                }
    357265
    358266                /* Advance to next channel. */
    359                 channel++;
     267                channel_number++;
    360268        }
    361269}
    362270
    363 int cmd_upgrade(struct hdhomerun_control_sock_t *control_sock, const char *filename)
     271static int cmd_upgrade(const char *filename)
    364272{
    365273        FILE *fp = fopen(filename, "rb");
    366274        if (!fp) {
    367275                fprintf(stderr, "unable to open file %s\n", filename);
    368                 return 1;
     276                return -1;
    369277        }
    370278
    371         unsigned long sequence = 0;
    372         while (1) {
    373                 unsigned char data[256];
    374                 int length = fread(data, 1, 256, fp);
    375                 if (length == 0) {
    376                         break;
    377                 }
    378 
    379                 int ret = hdhomerun_control_send_upgrade_request(control_sock, sequence, data, length);
    380                 if (ret < 0) {
    381                         fprintf(stderr, "communication error sending upgrade request to hdhomerun device\n");
    382                         fclose(fp);
    383                         return 1;
    384                 }
    385 
    386                 sequence += length;
     279        if (hdhomerun_device_upgrade(hd, fp) <= 0) {
     280                fprintf(stderr, "error sending upgrade file to hdhomerun device\n");
     281                fclose(fp);
     282                return -1;
    387283        }
    388284
    389         fclose(fp);
    390         if (sequence == 0) {
    391                 fprintf(stderr, "upgrade file does not contain data\n");
    392                 return 1;
    393         }
    394 
    395         int ret = hdhomerun_control_send_upgrade_request(control_sock, 0xFFFFFFFF, NULL, 0);
    396         if (ret < 0) {
    397                 fprintf(stderr, "communication error sending upgrade request to hdhomerun device\n");
    398                 return 1;
    399         }
    400 
    401285        printf("upgrade complete\n");
    402286        return 0;
    403287}
    404288
    405 int main_cmd(struct hdhomerun_control_sock_t *control_sock, int argc, char *argv[])
     289static int main_cmd(int argc, char *argv[])
    406290{
    407291        if (argc < 1) {
    408292                return help();
     
    414298                if (argc < 1) {
    415299                        return help();
    416300                }
    417                 return cmd_get(control_sock, argv[0]);
     301                return cmd_get(argv[0]);
    418302        }
    419303
    420304        if (contains(cmd, "set")) {
    421305                if (argc < 2) {
    422306                        return help();
    423307                }
    424                 return cmd_set(control_sock, argv[0], argv[1]);
     308                return cmd_set(argv[0], argv[1]);
    425309        }
    426310
     311        if (contains(cmd, "streaminfo")) {
     312                if (argc < 1) {
     313                        return help();
     314                }
     315                return cmd_streaminfo(argv[0]);
     316        }
     317
    427318        if (contains(cmd, "scan")) {
    428319                if (argc < 2) {
    429320                        return help();
    430321                }
    431                 return cmd_scan(control_sock, argv[0], argv[1]);
     322                return cmd_scan(argv[0], argv[1]);
    432323        }
    433324
    434325        if (contains(cmd, "upgrade")) {
    435326                if (argc < 1) {
    436327                        return help();
    437328                }
    438                 return cmd_upgrade(control_sock, argv[0]);
     329                return cmd_upgrade(argv[0]);
    439330        }
    440331
    441332        return help();
    442333}
    443334
    444 int main(int argc, char *argv[])
     335static int main_internal(int argc, char *argv[])
    445336{
    446         extract_appname(argv[0]);
     337#if defined(__WINDOWS__)
     338        //Start pthreads
     339        pthread_win32_process_attach_np();
    447340
     341        // Start WinSock
     342        WORD wVersionRequested = MAKEWORD(2, 0);
     343        WSADATA wsaData;
     344        WSAStartup(wVersionRequested, &wsaData);
     345#endif
     346
     347        extract_appname(argv[0]);
    448348        argv++;
    449349        argc--;
    450350
     
    460360                return discover_print();
    461361        }
    462362
    463         struct hdhomerun_control_sock_t *control_sock = create_control_sock(id_str);
    464         if (!control_sock) {
    465                 return 1;
     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;
    466367        }
    467368
    468         int ret = main_cmd(control_sock, argc, argv);
    469         hdhomerun_control_destroy(control_sock);
     369        /* Device object. */
     370        hd = hdhomerun_device_create(device_id, device_ip, 0);
     371        if (!hd) {
     372                fprintf(stderr, "unable to create device\n");
     373                return -1;
     374        }
     375
     376        /* Connect to device and check firmware version. */
     377        int ret = hdhomerun_device_firmware_version_check(hd, 0);
     378        if (ret < 0) {
     379                fprintf(stderr, "unable to connect to device\n");
     380                hdhomerun_device_destroy(hd);
     381                return -1;
     382        }
     383        if (ret == 0) {
     384                fprintf(stderr, "WARNING: firmware upgrade needed for all operations to function\n");
     385        }
     386
     387        /* Command. */
     388        ret = main_cmd(argc, argv);
     389
     390        /* Cleanup. */
     391        hdhomerun_device_destroy(hd);
     392
     393        /* Complete. */
    470394        return ret;
    471395}
     396
     397int main(int argc, char *argv[])
     398{
     399        int ret = main_internal(argc, argv);
     400        if (ret <= 0) {
     401                return 1;
     402        }
     403        return 0;
     404}
  • libs/libmythtv/hdhomerun/hdhomerun_video.c

     
    2121#include "hdhomerun_os.h"
    2222#include "hdhomerun_pkt.h"
    2323#include "hdhomerun_video.h"
    24 #include <pthread.h>
    2524
    2625struct hdhomerun_video_sock_t {
    27         unsigned char *buffer;
    28         unsigned long buffer_size;
    29         volatile unsigned long head;
    30         volatile unsigned long tail;
    31         unsigned long advance;
    32         volatile int running;
    33         volatile int terminate;
     26        uint8_t *buffer;
     27        size_t buffer_size;
     28        volatile size_t head;
     29        volatile size_t tail;
     30        size_t advance;
     31        volatile bool_t running;
     32        volatile bool_t terminate;
    3433        pthread_t thread;
    3534        int sock;
    3635};
    3736
    3837static void *hdhomerun_video_thread(void *arg);
    3938
    40 struct hdhomerun_video_sock_t *hdhomerun_video_create(unsigned long buffer_size, unsigned long timeout)
     39static bool_t hdhomerun_video_bind_sock_internal(struct hdhomerun_video_sock_t *vs, uint16_t listen_port)
    4140{
    42         /* Buffer size. */
    43         buffer_size = (buffer_size / VIDEO_DATA_PACKET_SIZE) * VIDEO_DATA_PACKET_SIZE;
    44         if (buffer_size == 0) {
    45                 return NULL;
     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;
    4648        }
    47         buffer_size += VIDEO_DATA_PACKET_SIZE;
     49        return TRUE;
     50}
    4851
     52static 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
     75struct hdhomerun_video_sock_t *hdhomerun_video_create(uint16_t listen_port, size_t buffer_size)
     76{
    4977        /* Create object. */
    5078        struct hdhomerun_video_sock_t *vs = (struct hdhomerun_video_sock_t *)calloc(1, sizeof(struct hdhomerun_video_sock_t));
    5179        if (!vs) {
    5280                return NULL;
    5381        }
    5482
     83        /* Buffer size. */
     84        vs->buffer_size = (buffer_size / VIDEO_DATA_PACKET_SIZE) * VIDEO_DATA_PACKET_SIZE;
     85        if (vs->buffer_size == 0) {
     86                free(vs);
     87                return NULL;
     88        }
     89        vs->buffer_size += VIDEO_DATA_PACKET_SIZE;
     90
    5591        /* Create buffer. */
    56         vs->buffer_size = buffer_size;
    57         vs->buffer = (unsigned char *)malloc(buffer_size);
     92        vs->buffer = (uint8_t *)malloc(vs->buffer_size);
    5893        if (!vs->buffer) {
    5994                free(vs);
    6095                return NULL;
    6196        }
    6297       
    6398        /* Create socket. */
    64         vs->sock = socket(AF_INET, SOCK_DGRAM, 0);
     99        vs->sock = (int)socket(AF_INET, SOCK_DGRAM, 0);
    65100        if (vs->sock == -1) {
    66101                free(vs->buffer);
    67102                free(vs);
    68103                return NULL;
    69104        }
    70105
    71         /* Set buffer size. */
    72         unsigned long rx_size = 1024 * 1024;
    73         setsockopt(vs->sock, SOL_SOCKET, SO_RCVBUF, &rx_size, sizeof(rx_size));
     106        /* Expand socket buffer size. */
     107        int rx_size = 1024 * 1024;
     108        setsockopt(vs->sock, SOL_SOCKET, SO_RCVBUF, (char *)&rx_size, sizeof(rx_size));
    74109
    75         /* Set timeout. */
    76         struct timeval t;
    77         t.tv_sec = timeout / 1000;
    78         t.tv_usec = (timeout % 1000) * 1000;
    79         setsockopt(vs->sock, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(t));
     110        /* Set timeouts. */
     111        setsocktimeout(vs->sock, SOL_SOCKET, SO_SNDTIMEO, 1000);
     112        setsocktimeout(vs->sock, SOL_SOCKET, SO_RCVTIMEO, 1000);
    80113
    81114        /* Bind socket. */
    82         struct sockaddr_in sock_addr;
    83         memset(&sock_addr, 0, sizeof(sock_addr));
    84         sock_addr.sin_family = AF_INET;
    85         sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    86         sock_addr.sin_port = htons(0);
    87         if (bind(vs->sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) {
     115        if (!hdhomerun_video_bind_sock(vs, listen_port)) {
    88116                hdhomerun_video_destroy(vs);
    89117                return NULL;
    90118        }
     
    111139        free(vs);
    112140}
    113141
    114 unsigned short hdhomerun_video_get_local_port(struct hdhomerun_video_sock_t *vs)
     142uint16_t hdhomerun_video_get_local_port(struct hdhomerun_video_sock_t *vs)
    115143{
    116144        struct sockaddr_in sock_addr;
    117145        socklen_t sockaddr_size = sizeof(sock_addr);
     
    121149        return ntohs(sock_addr.sin_port);
    122150}
    123151
    124 int hdhomerun_video_get_state(struct hdhomerun_video_sock_t *vs)
    125 {
    126         if (vs->terminate) {
    127                 return 0;
    128         }
    129         return 1;
    130 }
    131 
    132152int hdhomerun_video_get_sock(struct hdhomerun_video_sock_t *vs)
    133153{
    134154        return vs->sock;
     
    139159        struct hdhomerun_video_sock_t *vs = (struct hdhomerun_video_sock_t *)arg;
    140160
    141161        while (!vs->terminate) {
    142                 unsigned long head = vs->head;
     162                size_t head = vs->head;
    143163
    144164                /* Receive. */
    145                 int length = recv(vs->sock, vs->buffer + head, VIDEO_DATA_PACKET_SIZE, 0);
     165                int length = recv(vs->sock, (char *)vs->buffer + head, VIDEO_DATA_PACKET_SIZE, 0);
    146166                if (length != VIDEO_DATA_PACKET_SIZE) {
    147167                        if (length > 0) {
    148168                                /* Data received but not valid - ignore. */
    149169                                continue;
    150170                        }
    151                         if (errno == EAGAIN) {
     171                        if (sock_getlasterror_socktimeout) {
    152172                                /* Wait for more data. */
    153173                                continue;
    154174                        }
     
    174194        return NULL;
    175195}
    176196
    177 static void hdhomerun_copy_and_advance_tail(struct hdhomerun_video_sock_t *vs, unsigned char *buffer, unsigned long size)
     197uint8_t *hdhomerun_video_recv(struct hdhomerun_video_sock_t *vs, size_t max_size, size_t *pactual_size)
    178198{
    179         unsigned long tail = vs->tail;
    180         memcpy(buffer, vs->buffer + tail, size);
     199        size_t head = vs->head;
     200        size_t tail = vs->tail;
    181201
    182         tail += size;
    183         if (tail >= vs->buffer_size) {
    184                 tail -= vs->buffer_size;
    185         }
    186 
    187         /* Atomic update. */
    188         vs->tail = tail;
    189 }
    190 
    191 unsigned long hdhomerun_video_available_length(struct hdhomerun_video_sock_t *vs)
    192 {
    193         unsigned long head = vs->head;
    194         unsigned long tail = vs->tail;
    195 
    196         if (head >= tail) {
    197                 return head - tail - vs->advance;
    198         } else {
    199                 return head + vs->buffer_size - tail - vs->advance;
    200         }
    201 }
    202 
    203 unsigned long hdhomerun_video_recv_memcpy(struct hdhomerun_video_sock_t *vs, unsigned char *buffer, unsigned long size)
    204 {
    205         unsigned long head = vs->head;
    206         unsigned long tail = vs->tail;
    207 
    208         if (head == tail) {
    209                 return 0;
    210         }
    211 
    212         size = (size / VIDEO_DATA_PACKET_SIZE) * VIDEO_DATA_PACKET_SIZE;
    213 
    214         /* Straight memcpy case. */
    215         if (head > tail) {
    216                 unsigned long avail = head - tail;
    217                 if (size > avail) {
    218                         size = avail;
    219                 }
    220                 hdhomerun_copy_and_advance_tail(vs, buffer, size);
    221                 return size;
    222         }
    223 
    224         /* Memcpy with wrap around check. */
    225         unsigned long avail = vs->buffer_size - tail;
    226         if (avail >= size) {
    227                 hdhomerun_copy_and_advance_tail(vs, buffer, size);
    228                 return size;
    229         }
    230 
    231         /* Memcpy with wrap around. */
    232         hdhomerun_copy_and_advance_tail(vs, buffer, avail);
    233         return avail + hdhomerun_video_recv_memcpy(vs, buffer + avail, size - avail);
    234 }
    235 
    236 unsigned char *hdhomerun_video_recv_inplace(struct hdhomerun_video_sock_t *vs, unsigned long max_size, unsigned long *pactual_size)
    237 {
    238         unsigned long head = vs->head;
    239         unsigned long tail = vs->tail;
    240 
    241202        if (vs->advance > 0) {
    242203                tail += vs->advance;
    243204                if (tail >= vs->buffer_size) {
     
    254215                return NULL;
    255216        }
    256217
    257         unsigned long size = (max_size / VIDEO_DATA_PACKET_SIZE) * VIDEO_DATA_PACKET_SIZE;
     218        size_t size = (max_size / VIDEO_DATA_PACKET_SIZE) * VIDEO_DATA_PACKET_SIZE;
     219        if (size == 0) {
     220                vs->advance = 0;
     221                *pactual_size = 0;
     222                return NULL;
     223        }
    258224
    259         unsigned long avail;
     225        size_t avail;
    260226        if (head > tail) {
    261227                avail = head - tail;
    262228        } else {
     
    274240{
    275241        /* Atomic update of tail. */
    276242        vs->tail = vs->head;
     243        vs->advance = 0;
    277244}
     245
  • libs/libmythtv/hdhomerun/hdhomerun_video.h

     
    2323
    2424struct hdhomerun_video_sock_t;
    2525
     26#define TS_PACKET_SIZE 188
    2627#define VIDEO_DATA_PACKET_SIZE (188 * 7)
    2728#define VIDEO_DATA_BUFFER_SIZE_1S (20000000 / 8)
    2829
    29 extern struct hdhomerun_video_sock_t *hdhomerun_video_create(unsigned long buffer_size, unsigned long timeout);
     30/*
     31 * Create a video/data socket.
     32 *
     33 * uint16_t listen_port: Port number to listen on. Set to 0 to auto-select.
     34 * size_t buffer_size: Size of receive buffer. For 1 second of buffer use VIDEO_DATA_BUFFER_SIZE_1S.
     35 *
     36 * Returns a pointer to the newly created control socket.
     37 *
     38 * When no longer needed, the socket should be destroyed by calling hdhomerun_control_destroy.
     39 */
     40extern struct hdhomerun_video_sock_t *hdhomerun_video_create(uint16_t listen_port, size_t buffer_size);
    3041extern void hdhomerun_video_destroy(struct hdhomerun_video_sock_t *vs);
    31 extern unsigned short hdhomerun_video_get_local_port(struct hdhomerun_video_sock_t *vs);
    32 extern int hdhomerun_video_get_state(struct hdhomerun_video_sock_t *vs);
     42
     43/*
     44 * Get the port the socket is listening on.
     45 *
     46 * Returns 16-bit port with native endianness, or 0 on error.
     47 */
     48extern uint16_t hdhomerun_video_get_local_port(struct hdhomerun_video_sock_t *vs);
     49
     50/*
     51 * Get the low-level socket handle.
     52 */
    3353extern int hdhomerun_video_get_sock(struct hdhomerun_video_sock_t *vs);
    34 extern unsigned long hdhomerun_video_available_length(struct hdhomerun_video_sock_t *vs);
    35 extern unsigned long hdhomerun_video_recv_memcpy(struct hdhomerun_video_sock_t *vs, unsigned char *buffer, unsigned long size);
    36 extern unsigned char *hdhomerun_video_recv_inplace(struct hdhomerun_video_sock_t *vs, unsigned long max_size, unsigned long *pactual_size);
     54
     55/*
     56 * Read data from buffer.
     57 *
     58 * size_t max_size: The maximum amount of data to be returned.
     59 * size_t *pactual_size: The caller-supplied pactual_size value will be updated to contain the amount
     60 *              of data available to the caller.
     61 *
     62 * Returns a pointer to the data, or NULL if no data is available.
     63 * The data will remain valid until another call to hdhomerun_video_recv.
     64 *
     65 * The amount of data returned will always be a multiple of VIDEO_DATA_PACKET_SIZE (1316).
     66 * Attempting to read a single TS frame (188 bytes) will not return data as it is less than
     67 * the minimum size.
     68 *
     69 * The buffer is implemented as a ring buffer. It is possible for this function to return a small
     70 * amount of data when more is available due to the wrap-around case.
     71 */
     72extern uint8_t *hdhomerun_video_recv(struct hdhomerun_video_sock_t *vs, size_t max_size, size_t *pactual_size);
     73
     74/*
     75 * Flush the buffer.
     76 */
    3777extern void hdhomerun_video_flush(struct hdhomerun_video_sock_t *vs);
    3878
    3979#ifdef __cplusplus
  • libs/libmythtv/hdhomerun/hdhomerun_discover.c

     
    2222#include "hdhomerun_pkt.h"
    2323#include "hdhomerun_discover.h"
    2424
    25 #if defined(__CYGWIN__)
     25#if defined(__CYGWIN__) || defined(__WINDOWS__)
    2626#include <windows.h>
    2727#include <iptypes.h>
    2828#include <iphlpapi.h>
     
    3232        int sock;
    3333};
    3434
    35 struct hdhomerun_discover_sock_t *hdhomerun_discover_create(unsigned long timeout)
     35static struct hdhomerun_discover_sock_t *hdhomerun_discover_create(void)
    3636{
    3737        struct hdhomerun_discover_sock_t *ds = (struct hdhomerun_discover_sock_t *)malloc(sizeof(struct hdhomerun_discover_sock_t));
    3838        if (!ds) {
     
    4040        }
    4141       
    4242        /* Create socket. */
    43         ds->sock = socket(AF_INET, SOCK_DGRAM, 0);
     43        ds->sock = (int)socket(AF_INET, SOCK_DGRAM, 0);
    4444        if (ds->sock == -1) {
    4545                free(ds);
    4646                return NULL;
    4747        }
    4848
    49         /* Set timeout. */
    50         struct timeval t;
    51         t.tv_sec = timeout / 1000;
    52         t.tv_usec = (timeout % 1000) * 1000;
    53         setsockopt(ds->sock, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(t));
     49        /* Set timeouts. */
     50        setsocktimeout(ds->sock, SOL_SOCKET, SO_SNDTIMEO, 1000);
     51        setsocktimeout(ds->sock, SOL_SOCKET, SO_RCVTIMEO, 1000);
    5452
    5553        /* Allow broadcast. */
    5654        int sock_opt = 1;
     
    6361        sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    6462        sock_addr.sin_port = htons(0);
    6563        if (bind(ds->sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) {
    66                 hdhomerun_discover_destroy(ds);
     64                close(ds->sock);
     65                free(ds);
    6766                return NULL;
    6867        }
    6968
     
    7170        return ds;
    7271}
    7372
    74 void hdhomerun_discover_destroy(struct hdhomerun_discover_sock_t *ds)
     73static void hdhomerun_discover_destroy(struct hdhomerun_discover_sock_t *ds)
    7574{
    7675        close(ds->sock);
    7776        free(ds);
    7877}
    7978
    80 static int hdhomerun_discover_send_packet(struct hdhomerun_discover_sock_t *ds, unsigned long ip_addr, unsigned long device_type, unsigned long device_id)
     79static int hdhomerun_discover_send_packet(struct hdhomerun_discover_sock_t *ds, uint32_t ip_addr, uint32_t device_type, uint32_t device_id)
    8180{
    82         unsigned char buffer[1024];
    83         unsigned char *ptr = buffer;
     81        uint8_t buffer[1024];
     82        uint8_t *ptr = buffer;
    8483        hdhomerun_write_discover_request(&ptr, device_type, device_id);
    8584
    8685        struct sockaddr_in sock_addr;
     
    8988        sock_addr.sin_addr.s_addr = htonl(ip_addr);
    9089        sock_addr.sin_port = htons(HDHOMERUN_DISCOVER_UDP_PORT);
    9190
    92         int length = ptr - buffer;
    93         if (sendto(ds->sock, (char *)buffer, length, 0, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != length) {
     91        int length = (int)(ptr - buffer);
     92        if (sendto(ds->sock, (char *)buffer, (int)length, 0, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != length) {
    9493                return -1;
    9594        }
    9695
    9796        return 0;
    9897}
    9998
    100 #if defined(__CYGWIN__)
    101 static int hdhomerun_discover_send_internal(struct hdhomerun_discover_sock_t *ds, unsigned long device_type, unsigned long device_id)
     99#if defined(__CYGWIN__) || defined(__WINDOWS__)
     100static int hdhomerun_discover_send_internal(struct hdhomerun_discover_sock_t *ds, uint32_t device_type, uint32_t device_id)
    102101{
    103102        PIP_ADAPTER_INFO pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));
    104         unsigned long ulOutBufLen = sizeof(IP_ADAPTER_INFO);
     103        ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
    105104
    106105        DWORD Ret = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen);
    107106        if (Ret != NO_ERROR) {
     
    117116                }
    118117        }
    119118
    120         int send_count = 0;
     119        unsigned int send_count = 0;
    121120        PIP_ADAPTER_INFO pAdapter = pAdapterInfo;
    122121        while (pAdapter) {
    123122                IP_ADDR_STRING *pIPAddr = &pAdapter->IpAddressList;
    124123                while (pIPAddr) {
    125                         unsigned long addr = ntohl(inet_addr(pIPAddr->IpAddress.String));
    126                         unsigned long mask = ntohl(inet_addr(pIPAddr->IpMask.String));
     124                        uint32_t addr = ntohl(inet_addr(pIPAddr->IpAddress.String));
     125                        uint32_t mask = ntohl(inet_addr(pIPAddr->IpMask.String));
    127126                       
    128                         unsigned long broadcast = addr | ~mask;
     127                        uint32_t broadcast = addr | ~mask;
    129128                        if ((broadcast == 0x00000000) || (broadcast == 0xFFFFFFFF)) {
    130129                                pIPAddr = pIPAddr->Next;
    131130                                continue;
    132131                        }
    133132
    134                         hdhomerun_discover_send_packet(ds, broadcast, device_type, device_id);
     133                        if (hdhomerun_discover_send_packet(ds, broadcast, device_type, device_id) < 0) {
     134                                pIPAddr = pIPAddr->Next;
     135                                continue;
     136                        }
     137
    135138                        send_count++;
    136139
    137140                        pIPAddr = pIPAddr->Next;
     
    150153#endif
    151154
    152155#if defined(__linux__)
    153 static int hdhomerun_discover_send_internal(struct hdhomerun_discover_sock_t *ds, unsigned long device_type, unsigned long device_id)
     156static int hdhomerun_discover_send_internal(struct hdhomerun_discover_sock_t *ds, uint32_t device_type, uint32_t device_id)
    154157{
    155158        FILE *fp = fopen("/proc/net/route", "r");
    156159        if (!fp) {
    157160                return -1;
    158161        }
    159162
    160         int send_count = 0;
     163        unsigned int send_count = 0;
    161164        while (1) {
    162165                char line[256];
    163166                if (!fgets(line, sizeof(line), fp)) {
     
    165168                }
    166169                line[255] = 0;
    167170
    168                 unsigned long dest;
    169                 unsigned long mask;
    170                 if (sscanf(line, "%*s %lx %*x %*x %*d %*d %*d %lx", &dest, &mask) != 2) {
     171                uint32_t dest;
     172                uint32_t mask;
     173                if (sscanf(line, "%*s %x %*x %*x %*d %*d %*d %x", &dest, &mask) != 2) {
    171174                        continue;
    172175                }
    173176                dest = ntohl(dest);
    174177                mask = ntohl(mask);
    175178               
    176                 unsigned long broadcast = dest | ~mask;
     179                uint32_t broadcast = dest | ~mask;
    177180
    178181                if ((broadcast == 0x00000000) || (broadcast == 0xFFFFFFFF)) {
    179182                        continue;
    180183                }
    181184
    182                 hdhomerun_discover_send_packet(ds, broadcast, device_type, device_id);
     185                if (hdhomerun_discover_send_packet(ds, broadcast, device_type, device_id) < 0) {
     186                        continue;
     187                }
     188
    183189                send_count++;
    184190        }
    185191
     
    191197}
    192198#endif
    193199
    194 #if !defined(__CYGWIN__) && !defined(__linux__)
    195 static int hdhomerun_discover_send_internal(struct hdhomerun_discover_sock_t *ds, unsigned long device_type, unsigned long device_id)
     200#if !defined(__CYGWIN__) && !defined(__WINDOWS__) && !defined(__linux__)
     201static int hdhomerun_discover_send_internal(struct hdhomerun_discover_sock_t *ds, uint32_t device_type, uint32_t device_id)
    196202{
    197203        return -1;
    198204}
    199205#endif
    200206
    201 int hdhomerun_discover_send(struct hdhomerun_discover_sock_t *ds, unsigned long device_type, unsigned long device_id)
     207static int hdhomerun_discover_send(struct hdhomerun_discover_sock_t *ds, uint32_t device_type, uint32_t device_id)
    202208{
    203209        if (hdhomerun_discover_send_internal(ds, device_type, device_id) < 0) {
    204210                return hdhomerun_discover_send_packet(ds, 0xFFFFFFFF, device_type, device_id);
     
    206212        return 0;
    207213}
    208214
    209 int hdhomerun_discover_recv(struct hdhomerun_discover_sock_t *ds, struct hdhomerun_discover_device_t *result, unsigned long timeout)
     215static int hdhomerun_discover_recv(struct hdhomerun_discover_sock_t *ds, struct hdhomerun_discover_device_t *result)
    210216{
    211217        struct timeval t;
    212         t.tv_sec = timeout / 1000;
    213         t.tv_usec = (timeout % 1000) * 1000;
     218        t.tv_sec = 0;
     219        t.tv_usec = 250000;
    214220
    215221        fd_set readfds;
    216222        FD_ZERO(&readfds);
     
    223229                return 0;
    224230        }
    225231
    226         unsigned char buffer[1024];
     232        uint8_t buffer[1024];
    227233        struct sockaddr_in sock_addr;
    228234        socklen_t sockaddr_size = sizeof(sock_addr);
    229235        int rx_length = recvfrom(ds->sock, (char *)buffer, sizeof(buffer), 0, (struct sockaddr *)&sock_addr, &sockaddr_size);
    230236        if (rx_length <= 0) {
    231                 return -1;
     237                /* Don't return error - windows machine on VPN can sometimes cause a sock error here but otherwise works. */
     238                return 0;
    232239        }
    233240        if (rx_length < HDHOMERUN_MIN_PEEK_LENGTH) {
    234241                return 0;
    235242        }
    236         int length = hdhomerun_peek_packet_length(buffer);
    237         if (rx_length < length) {
     243
     244        size_t length = hdhomerun_peek_packet_length(buffer);
     245        if (length > (size_t)rx_length) {
    238246                return 0;
    239247        }
    240248
    241         unsigned char *ptr = buffer;
    242         unsigned char *end = buffer + length;
     249        uint8_t *ptr = buffer;
     250        uint8_t *end = buffer + length;
    243251        int type = hdhomerun_process_packet(&ptr, &end);
    244252        if (type != HDHOMERUN_TYPE_DISCOVER_RPY) {
    245253                return 0;
     
    249257        result->device_type = 0;
    250258        result->device_id = 0;
    251259        while (1) {
    252                 unsigned char tag;
    253                 int len;
    254                 unsigned char *value;
     260                uint8_t tag;
     261                size_t len;
     262                uint8_t *value;
    255263                if (hdhomerun_read_tlv(&ptr, end, &tag, &len, &value) < 0) {
    256264                        break;
    257265                }
     
    277285        return 1;
    278286}
    279287
    280 int hdhomerun_discover_validate_device_id(unsigned long device_id)
     288static struct hdhomerun_discover_device_t *hdhomerun_discover_find_in_list(struct hdhomerun_discover_device_t result_list[], int count, uint32_t device_id)
    281289{
    282         static unsigned long lookup_table[16] = {0xA, 0x5, 0xF, 0x6, 0x7, 0xC, 0x1, 0xB, 0x9, 0x2, 0x8, 0xD, 0x4, 0x3, 0xE, 0x0};
     290        int index;
     291        for (index = 0; index < count; index++) {
     292                struct hdhomerun_discover_device_t *result = &result_list[index];
     293                if (result->device_id == device_id) {
     294                        return result;
     295                }
     296        }
    283297
    284         unsigned long checksum = 0;
     298        return NULL;
     299}
    285300
     301static 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)
     302{
     303        int count = 0;
     304
     305        int attempt;
     306        for (attempt = 0; attempt < 4; attempt++) {
     307                if (hdhomerun_discover_send(ds, device_type, device_id) < 0) {
     308                        return -1;
     309                }
     310
     311                uint64_t timeout = getcurrenttime() + 250;
     312                while (getcurrenttime() < timeout) {
     313                        struct hdhomerun_discover_device_t *result = &result_list[count];
     314
     315                        int ret = hdhomerun_discover_recv(ds, result);
     316                        if (ret < 0) {
     317                                return -1;
     318                        }
     319                        if (ret == 0) {
     320                                break;
     321                        }
     322
     323                        /* Filter. */
     324                        if (device_type != HDHOMERUN_DEVICE_TYPE_WILDCARD) {
     325                                if (device_type != result->device_type) {
     326                                        continue;
     327                                }
     328                        }
     329                        if (device_id != HDHOMERUN_DEVICE_ID_WILDCARD) {
     330                                if (device_id != result->device_id) {
     331                                        continue;
     332                                }
     333                        }
     334
     335                        /* Ensure not already in list. */
     336                        if (hdhomerun_discover_find_in_list(result_list, count, result->device_id)) {
     337                                continue;
     338                        }
     339
     340                        /* Add to list. */
     341                        count++;
     342                        if (count >= max_count) {
     343                                return count;
     344                        }
     345                }
     346        }
     347
     348        return count;
     349}
     350
     351int hdhomerun_discover_find_device(uint32_t device_id, struct hdhomerun_discover_device_t *result)
     352{
     353        struct hdhomerun_discover_sock_t *ds = hdhomerun_discover_create();
     354        if (!ds) {
     355                return -1;
     356        }
     357
     358        int ret = hdhomerun_discover_find_devices_internal(ds, HDHOMERUN_DEVICE_TYPE_WILDCARD, device_id, result, 1);
     359
     360        hdhomerun_discover_destroy(ds);
     361        return ret;
     362}
     363
     364int hdhomerun_discover_find_devices(uint32_t device_type, struct hdhomerun_discover_device_t result_list[], int max_count)
     365{
     366        struct hdhomerun_discover_sock_t *ds = hdhomerun_discover_create();
     367        if (!ds) {
     368                return -1;
     369        }
     370
     371        int ret = hdhomerun_discover_find_devices_internal(ds, device_type, HDHOMERUN_DEVICE_ID_WILDCARD, result_list, max_count);
     372
     373        hdhomerun_discover_destroy(ds);
     374        return ret;
     375}
     376
     377bool_t hdhomerun_discover_validate_device_id(uint32_t device_id)
     378{
     379        static uint32_t lookup_table[16] = {0xA, 0x5, 0xF, 0x6, 0x7, 0xC, 0x1, 0xB, 0x9, 0x2, 0x8, 0xD, 0x4, 0x3, 0xE, 0x0};
     380
     381        uint32_t checksum = 0;
     382
    286383        checksum ^= lookup_table[(device_id >> 28) & 0x0F];
    287384        checksum ^= (device_id >> 24) & 0x0F;
    288385        checksum ^= lookup_table[(device_id >> 20) & 0x0F];
     
    294391
    295392        return (checksum == 0);
    296393}
     394
  • libs/libmythtv/hdhomerun/hdhomerun_control.c

     
    2020
    2121#include "hdhomerun_os.h"
    2222#include "hdhomerun_pkt.h"
     23#include "hdhomerun_discover.h"
    2324#include "hdhomerun_control.h"
    2425
    2526struct hdhomerun_control_sock_t {
     27        uint32_t device_id;
     28        uint32_t device_ip;
    2629        int sock;
    27         unsigned char rx_buffer[1024];
    28         unsigned char *rx_pos;
    29         unsigned char *rx_end;
     30        uint8_t buffer[16384];
    3031};
    3132
    32 struct hdhomerun_control_sock_t *hdhomerun_control_create(unsigned long ip_addr, unsigned long timeout)
     33struct hdhomerun_control_sock_t *hdhomerun_control_create(uint32_t device_id, uint32_t device_ip)
    3334{
    3435        struct hdhomerun_control_sock_t *cs = (struct hdhomerun_control_sock_t *)malloc(sizeof(struct hdhomerun_control_sock_t));
    3536        if (!cs) {
    3637                return NULL;
    3738        }
    3839       
     40        cs->device_id = device_id;
     41        cs->device_ip = device_ip;
     42        cs->sock = -1;
     43
     44        return cs;
     45}
     46
     47void hdhomerun_control_destroy(struct hdhomerun_control_sock_t *cs)
     48{
     49        if (cs->sock != -1) {
     50                close(cs->sock);
     51        }
     52        free(cs);
     53}
     54
     55static void hdhomerun_control_close_sock(struct hdhomerun_control_sock_t *cs)
     56{
     57        close(cs->sock);
     58        cs->sock = -1;
     59}
     60
     61static bool_t hdhomerun_control_connect_sock(struct hdhomerun_control_sock_t *cs)
     62{
     63        if (cs->sock != -1) {
     64                return TRUE;
     65        }
     66
     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;
     75        }
     76
    3977        /* Create socket. */
    40         cs->sock = socket(AF_INET, SOCK_STREAM, 0);
     78        cs->sock = (int)socket(AF_INET, SOCK_STREAM, 0);
    4179        if (cs->sock == -1) {
    42                 free(cs);
    43                 return NULL;
     80                return FALSE;
    4481        }
    4582
    46         /* Set timeout. */
    47         struct timeval t;
    48         t.tv_sec = timeout / 1000;
    49         t.tv_usec = (timeout % 1000) * 1000;
    50         setsockopt(cs->sock, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(t));
     83        /* Set timeouts. */
     84        setsocktimeout(cs->sock, SOL_SOCKET, SO_SNDTIMEO, 1000);
     85        setsocktimeout(cs->sock, SOL_SOCKET, SO_RCVTIMEO, 1000);
    5186
    5287        /* Initiate connection. */
    5388        struct sockaddr_in sock_addr;
    5489        memset(&sock_addr, 0, sizeof(sock_addr));
    5590        sock_addr.sin_family = AF_INET;
    56         sock_addr.sin_addr.s_addr = htonl(ip_addr);
     91        sock_addr.sin_addr.s_addr = htonl(device_ip);
    5792        sock_addr.sin_port = htons(HDHOMERUN_CONTROL_TCP_PORT);
    5893        if (connect(cs->sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) {
    59                 hdhomerun_control_destroy(cs);
    60                 return NULL;
     94                hdhomerun_control_close_sock(cs);
     95                return FALSE;
    6196        }
    6297
    6398        /* Success. */
    64         cs->rx_pos = cs->rx_buffer;
    65         cs->rx_end = cs->rx_buffer + sizeof(cs->rx_buffer);
    66         return cs;
     99        return TRUE;
    67100}
    68101
    69 void hdhomerun_control_destroy(struct hdhomerun_control_sock_t *cs)
     102uint32_t hdhomerun_control_get_local_addr(struct hdhomerun_control_sock_t *cs)
    70103{
    71         close(cs->sock);
    72         free(cs);
    73 }
     104        if (!hdhomerun_control_connect_sock(cs)) {
     105                return 0;
     106        }
    74107
    75 unsigned long hdhomerun_control_get_local_addr(struct hdhomerun_control_sock_t *cs)
    76 {
    77108        struct sockaddr_in sock_addr;
    78109        socklen_t sockaddr_size = sizeof(sock_addr);
    79110        if (getsockname(cs->sock, (struct sockaddr*)&sock_addr, &sockaddr_size) != 0) {
    80111                return 0;
    81112        }
     113
    82114        return ntohl(sock_addr.sin_addr.s_addr);
    83115}
    84116
    85 int hdhomerun_control_send(struct hdhomerun_control_sock_t *cs, unsigned char *start, unsigned char *end)
     117static int hdhomerun_control_send(struct hdhomerun_control_sock_t *cs, uint8_t *start, uint8_t *end)
    86118{
    87         int length = end - start;
    88         if (send(cs->sock, (char *)start, length, 0) != length) {
     119        int length = (int)(end - start);
     120        if (send(cs->sock, (char *)start, (int)length, 0) != length) {
    89121                return -1;
    90122        }
    91         return 0;
    92 }
    93123
    94 int hdhomerun_control_send_get_request(struct hdhomerun_control_sock_t *cs, const char *name)
    95 {
    96         unsigned char buffer[1024];
    97         unsigned char *ptr = buffer;
    98         hdhomerun_write_get_request(&ptr, name);
    99         return hdhomerun_control_send(cs, buffer, ptr);
     124        return length;
    100125}
    101126
    102 int hdhomerun_control_send_set_request(struct hdhomerun_control_sock_t *cs, const char *name, const char *value)
     127static int hdhomerun_control_recv_sock(struct hdhomerun_control_sock_t *cs, uint8_t *buffer, uint8_t *limit)
    103128{
    104         unsigned char buffer[1024];
    105         unsigned char *ptr = buffer;
    106         hdhomerun_write_set_request(&ptr, name, value);
    107         return hdhomerun_control_send(cs, buffer, ptr);
    108 }
     129        struct timeval t;
     130        t.tv_sec = 0;
     131        t.tv_usec = 250000;
    109132
    110 int hdhomerun_control_send_upgrade_request(struct hdhomerun_control_sock_t *cs, unsigned long sequence, void *data, int length)
    111 {
    112         unsigned char buffer[1024 + 64];
    113         unsigned char *ptr = buffer;
     133        fd_set readfds;
     134        FD_ZERO(&readfds);
     135        FD_SET(cs->sock, &readfds);
    114136
    115         if (length + 64 > (int)sizeof(buffer)) {
     137        if (select(cs->sock+1, &readfds, NULL, NULL, &t) < 0) {
    116138                return -1;
    117139        }
    118140
    119         hdhomerun_write_upgrade_request(&ptr, sequence, data, length);
    120         return hdhomerun_control_send(cs, buffer, ptr);
     141        if (!FD_ISSET(cs->sock, &readfds)) {
     142                return 0;
     143        }
     144
     145        int length = recv(cs->sock, (char *)buffer, (int)(limit - buffer), 0);
     146        if (length <= 0) {
     147                return -1;
     148        }
     149
     150        return length;
    121151}
    122152
    123 static int hdhomerun_control_recv_sock(struct hdhomerun_control_sock_t *cs, unsigned long timeout)
     153static int hdhomerun_control_recv(struct hdhomerun_control_sock_t *cs, uint8_t *buffer, uint8_t *limit)
    124154{
    125         struct timeval t;
    126         t.tv_sec = timeout / 1000;
    127         t.tv_usec = (timeout % 1000) * 1000;
     155        uint64_t timeout = getcurrenttime() + 1000;
     156        uint8_t *ptr = buffer;
    128157
    129         fd_set readfds;
    130         FD_ZERO(&readfds);
    131         FD_SET(cs->sock, &readfds);
     158        while (getcurrenttime() < timeout) {
     159                int length = hdhomerun_control_recv_sock(cs, ptr, limit);
     160                if (length < 0) {
     161                        return -1;
     162                }
     163                if (length == 0) {
     164                        continue;
     165                }
     166                ptr += length;
    132167
    133         if (select(cs->sock+1, &readfds, NULL, NULL, &t) < 0) {
     168                if (buffer + HDHOMERUN_MIN_PEEK_LENGTH > limit) {
     169                        continue;
     170                }
     171
     172                length = (int)hdhomerun_peek_packet_length(buffer);
     173                if (buffer + length > limit) {
     174                        continue;
     175                }
     176
     177                return length;
     178        }
     179
     180        return -1;
     181}
     182
     183static int hdhomerun_control_get_set(struct hdhomerun_control_sock_t *cs, const char *name, const char *value, char **pvalue, char **perror)
     184{
     185        /* Send request. */
     186        uint8_t *ptr = cs->buffer;
     187        hdhomerun_write_get_set_request(&ptr, name, value);
     188        if (hdhomerun_control_send(cs, cs->buffer, ptr) < 0) {
    134189                return -1;
    135190        }
    136         if (!FD_ISSET(cs->sock, &readfds)) {
    137                 return 0;
     191
     192        /* Receive response. */
     193        int length = hdhomerun_control_recv(cs, cs->buffer, cs->buffer + sizeof(cs->buffer));
     194        if (length <= 0) {
     195                return -1;
    138196        }
    139197
    140         int rx_length = recv(cs->sock, (char *)cs->rx_pos, cs->rx_end - cs->rx_pos, 0);
    141         if (rx_length <= 0) {
     198        /* Parse response. */
     199        ptr = cs->buffer;
     200        uint8_t *end = ptr + length;
     201        int type = hdhomerun_process_packet(&ptr, &end);
     202        if (type < 0) {
    142203                return -1;
    143204        }
    144         cs->rx_pos += rx_length;
    145         return 1;
     205        if (type != HDHOMERUN_TYPE_GETSET_RPY) {
     206                return -1;
     207        }
     208
     209        while (ptr < end) {
     210                uint8_t tag;
     211                size_t len;
     212                uint8_t *val;
     213                if (hdhomerun_read_tlv(&ptr, end, &tag, &len, &val) < 0) {
     214                        break;
     215                }
     216                switch (tag) {
     217                case HDHOMERUN_TAG_GETSET_VALUE:
     218                        if (pvalue) {
     219                                *pvalue = (char *)val;
     220                                val[len] = 0;
     221                        }
     222                        if (perror) {
     223                                *perror = NULL;
     224                        }
     225                        return 1;
     226
     227                case HDHOMERUN_TAG_ERROR_MESSAGE:
     228                        if (pvalue) {
     229                                *pvalue = NULL;
     230                        }
     231                        if (perror) {
     232                                *perror = (char *)val;
     233                                val[len] = 0;
     234                        }
     235                        return 0;
     236                }
     237        }
     238
     239        return -1;
    146240}
    147241
    148 static int hdhomerun_control_recv_process(struct hdhomerun_control_sock_t *cs, struct hdhomerun_control_data_t *result)
     242int hdhomerun_control_get(struct hdhomerun_control_sock_t *cs, const char *name, char **pvalue, char **perror)
    149243{
    150         int rx_length = cs->rx_pos - cs->rx_buffer;
    151         if (rx_length < HDHOMERUN_MIN_PEEK_LENGTH) {
    152                 return 0;
     244        if (!hdhomerun_control_connect_sock(cs)) {
     245                return -1;
    153246        }
    154         int length = hdhomerun_peek_packet_length(cs->rx_buffer);
    155         if (rx_length < length) {
    156                 return 0;
     247
     248        int ret = hdhomerun_control_get_set(cs, name, NULL, pvalue, perror);
     249        if (ret < 0) {
     250                hdhomerun_control_close_sock(cs);
     251                return -1;
    157252        }
    158253
    159         memcpy(result->buffer, cs->rx_buffer, length);
    160         if (rx_length > length) {
    161                 memcpy(cs->rx_buffer, cs->rx_buffer + length, rx_length - length);
     254        return ret;
     255}
     256
     257int hdhomerun_control_set(struct hdhomerun_control_sock_t *cs, const char *name, const char *value, char **pvalue, char **perror)
     258{
     259        if (!hdhomerun_control_connect_sock(cs)) {
     260                return -1;
    162261        }
    163         cs->rx_pos = cs->rx_buffer + (rx_length - length);
    164262
    165         result->ptr = result->buffer;
    166         result->end = result->buffer + length;
    167         result->type = hdhomerun_process_packet(&result->ptr, &result->end);
    168         if (result->type < 0) {
     263        int ret = hdhomerun_control_get_set(cs, name, value, pvalue, perror);
     264        if (ret < 0) {
     265                hdhomerun_control_close_sock(cs);
    169266                return -1;
    170267        }
    171268
    172         return 1;
     269        return ret;
    173270}
    174271
    175 int hdhomerun_control_recv(struct hdhomerun_control_sock_t *cs, struct hdhomerun_control_data_t *result, unsigned long timeout)
     272int hdhomerun_control_upgrade(struct hdhomerun_control_sock_t *cs, FILE *upgrade_file)
    176273{
    177         int ret = hdhomerun_control_recv_process(cs, result);
    178         if (ret != 0) {
    179                 return ret;
     274        if (!hdhomerun_control_connect_sock(cs)) {
     275                return -1;
    180276        }
    181277
    182         struct timeval t;
    183         gettimeofday(&t, NULL);
    184         unsigned long long stop_time = ((unsigned long long)t.tv_sec * 1000) + (t.tv_usec / 1000) + timeout;
     278        uint32_t sequence = 0;
     279        uint8_t *ptr;
    185280
    186281        while (1) {
    187                 ret = hdhomerun_control_recv_sock(cs, timeout);
    188                 if (ret < 0) {
    189                         return ret;
     282                uint8_t data[256];
     283                size_t length = fread(data, 1, 256, upgrade_file);
     284                if (length == 0) {
     285                        break;
    190286                }
    191                 if (ret == 1) {
    192                         ret = hdhomerun_control_recv_process(cs, result);
    193                         if (ret != 0) {
    194                                 return ret;
    195                         }
     287
     288                ptr = cs->buffer;
     289                hdhomerun_write_upgrade_request(&ptr, sequence, data, length);
     290                if (hdhomerun_control_send(cs, cs->buffer, ptr) < 0) {
     291                        hdhomerun_control_close_sock(cs);
     292                        return -1;
    196293                }
    197294
    198                 gettimeofday(&t, NULL);
    199                 unsigned long long current_time = ((unsigned long long)t.tv_sec * 1000) + (t.tv_usec / 1000);
    200                 if (current_time >= stop_time) {
    201                         return 0;
    202                 }
     295                sequence += (uint32_t)length;
    203296        }
     297
     298        if (sequence == 0) {
     299                /* No data in file. Error, but no need to close connection. */
     300                return 0;
     301        }
     302
     303        ptr = cs->buffer;
     304        hdhomerun_write_upgrade_request(&ptr, 0xFFFFFFFF, NULL, 0);
     305        if (hdhomerun_control_send(cs, cs->buffer, ptr) < 0) {
     306                hdhomerun_control_close_sock(cs);
     307                return -1;
     308        }
     309
     310        return 1;
    204311}
  • libs/libmythtv/hdhomerun/Makefile

     
    22SRCS += hdhomerun_pkt.c
    33SRCS += hdhomerun_discover.c
    44SRCS += hdhomerun_control.c
     5SRCS += hdhomerun_video.c
     6SRCS += hdhomerun_device.c
    57SRCS += hdhomerun_config.c
    68
    7 CFLAGS += -Wall -O2
     9CFLAGS += -Wall -O2 -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wpointer-arith
    810
    911hdhomerun_config : $(SRCS)
    10         gcc $(CFLAGS) $(SRCS) -o $@
     12        gcc $(CFLAGS) $(SRCS) -lpthread -o $@
    1113        strip $@
    1214
    1315hdhomerun_config.exe : $(SRCS)
    14         gcc $(CFLAGS) $(SRCS) -liphlpapi -o $@
     16        gcc $(CFLAGS) $(SRCS) -lpthread -liphlpapi -o $@
    1517        strip $@
    1618
    1719clean :
  • libs/libmythtv/hdhomerun/hdhomerun_discover.h

     
    2121extern "C" {
    2222#endif
    2323
    24 struct hdhomerun_discover_sock_t;
    25 
    2624struct hdhomerun_discover_device_t {
    27         unsigned long ip_addr;
    28         unsigned long device_type;
    29         unsigned long device_id;
     25        uint32_t ip_addr;
     26        uint32_t device_type;
     27        uint32_t device_id;
    3028};
    3129
    32 extern struct hdhomerun_discover_sock_t *hdhomerun_discover_create(unsigned long timeout);
    33 extern void hdhomerun_discover_destroy(struct hdhomerun_discover_sock_t *ds);
    34 extern int hdhomerun_discover_send(struct hdhomerun_discover_sock_t *ds, unsigned long device_type, unsigned long device_id);
    35 extern int hdhomerun_discover_recv(struct hdhomerun_discover_sock_t *ds, struct hdhomerun_discover_device_t *result, unsigned long timeout);
     30/*
     31 * Find a device by device ID.
     32 *
     33 * The device information is stored in caller-supplied hdhomerun_discover_device_t var.
     34 * Multiple attempts are made to find the device.
     35 * Worst-case execution time is 1 second.
     36 *
     37 * Returns 1 on success.
     38 * Returns 0 if not found.
     39 * Retruns -1 on error.
     40 */
     41extern int hdhomerun_discover_find_device(uint32_t device_id, struct hdhomerun_discover_device_t *result);
    3642
    37 extern int hdhomerun_discover_validate_device_id(unsigned long device_id);
     43/*
     44 * Find all devices of a given type.
     45 *
     46 * The device information is stored in caller-supplied array of hdhomerun_discover_device_t vars.
     47 * Multiple attempts are made to find devices.
     48 * Execution time is 1 second.
     49 *
     50 * Returns the number of devices found.
     51 * Retruns -1 on error.
     52 */
     53extern int hdhomerun_discover_find_devices(uint32_t device_type, struct hdhomerun_discover_device_t result_list[], int max_count);
    3854
     55/*
     56 * Verify that the device ID given is valid.
     57 *
     58 * The device ID contains a self-check sequence that detects common user input errors including
     59 * single-digit errors and two digit transposition errors.
     60 *
     61 * Returns TRUE if valid.
     62 * Returns FALSE if not valid.
     63 */
     64extern bool_t hdhomerun_discover_validate_device_id(uint32_t device_id);
     65
    3966#ifdef __cplusplus
    4067}
    4168#endif
  • libs/libmythtv/hdhrsignalmonitor.cpp

     
    138138    dtvMonitorRunning = true;
    139139
    140140    struct hdhomerun_video_sock_t *_video_socket;
    141     _video_socket = hdhomerun_video_create(VIDEO_DATA_BUFFER_SIZE_1S, 50);
     141    _video_socket = hdhomerun_video_create(0, VIDEO_DATA_BUFFER_SIZE_1S);
    142142    if (!_video_socket)
    143143    {
    144144        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to get video socket");
     
    164164
    165165        unsigned long data_length;
    166166        unsigned char *data_buffer =
    167             hdhomerun_video_recv_inplace(_video_socket,
     167            hdhomerun_video_recv(_video_socket,
    168168                                         VIDEO_DATA_BUFFER_SIZE_1S / 5,
    169169                                         &data_length);
    170170
     
    174174            continue;
    175175        }
    176176
    177         if (!hdhomerun_video_get_state(_video_socket))
    178         {
    179             VERBOSE(VB_IMPORTANT, LOC_ERR + "Recv error" + ENO);
    180             break;
    181         }
    182177        usleep(2500);
    183178    }
    184179
  • libs/libmythtv/hdhrrecorder.cpp

     
    100100    }
    101101
    102102    /* Create TS socket. */
    103     _video_socket = hdhomerun_video_create(VIDEO_DATA_BUFFER_SIZE_1S, 50);
     103    _video_socket = hdhomerun_video_create(0, VIDEO_DATA_BUFFER_SIZE_1S);
    104104    if (!_video_socket)
    105105    {
    106106        VERBOSE(VB_IMPORTANT, LOC + "Open() failed to open socket");
     
    357357
    358358        unsigned long data_length;
    359359        unsigned char *data_buffer =
    360             hdhomerun_video_recv_inplace(_video_socket,
    361                                          VIDEO_DATA_BUFFER_SIZE_1S / 5,
    362                                          &data_length);
     360            hdhomerun_video_recv(_video_socket,
     361                                 VIDEO_DATA_BUFFER_SIZE_1S / 5,
     362                                 &data_length);
    363363        if (!data_buffer)
    364364        {
    365             if (hdhomerun_video_get_state(_video_socket) == 0)
    366             {
    367                 VERBOSE(VB_IMPORTANT, LOC_ERR + "Recv error" + ENO);
    368                 break;
    369             }
    370365            usleep(5000);
    371366            continue;
    372367        }
  • libs/libmythtv/hdhrchannel.cpp

     
    9090
    9191    _device_ip = 0;
    9292
    93     /* Create socket. */
    94     struct hdhomerun_discover_sock_t *discoverSock = NULL;
    95     discoverSock = hdhomerun_discover_create(500);
    96 
    97     if (!discoverSock)
     93    /* Discover. */
     94    struct hdhomerun_discover_device_t result;
     95    int ret = hdhomerun_discover_find_device(_device_id, &result);
     96    if (ret < 0)
    9897    {
    99         VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to create discovery socket");
     98        VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to send discovery request" + ENO);
    10099        return false;
    101100    }
    102 
    103     /* Discover. */
    104     for (int retry = 0; retry < 6; retry++)
     101    if (ret == 0)
    105102    {
    106         /* Send discovery request. */
    107         int ret = hdhomerun_discover_send(discoverSock,
    108                                           HDHOMERUN_DEVICE_TYPE_TUNER,
    109                                           _device_id);
    110         if (ret < 0)
    111         {
    112             VERBOSE(VB_IMPORTANT, LOC_ERR +
    113                     "Unable to send discovery request" + ENO);
    114             break;
    115         }
    116 
    117         /* Wait for response. */
    118         struct hdhomerun_discover_device_t device;
    119         ret = hdhomerun_discover_recv(discoverSock, &device, 500);
    120         if (ret < 0)
    121         {
    122             VERBOSE(VB_IMPORTANT, LOC_ERR +
    123                     "Unable to listen for discovery response" + ENO);
    124             break;
    125         }
    126         if (ret == 0)
    127         {
    128             continue;
    129         }
    130 
    131         /* Found. */
    132         _device_ip = device.ip_addr;
    133 
    134         VERBOSE(VB_IMPORTANT, LOC +
    135                 QString("device found at address %1.%2.%3.%4")
    136                 .arg((_device_ip>>24) & 0xFF).arg((_device_ip>>16) & 0xFF)
    137                 .arg((_device_ip>> 8) & 0xFF).arg((_device_ip>> 0) & 0xFF));
    138 
    139         hdhomerun_discover_destroy(discoverSock);
    140         return true;
     103        VERBOSE(VB_IMPORTANT, LOC_ERR + QString("device not found"));
     104        return false;
    141105    }
    142106
    143     VERBOSE(VB_IMPORTANT, LOC_ERR + QString("device not found"));
    144     hdhomerun_discover_destroy(discoverSock);
     107    /* Found. */
     108    _device_ip = result.ip_addr;
    145109
    146     return false;
     110    VERBOSE(VB_IMPORTANT, LOC +
     111            QString("device found at address %1.%2.%3.%4")
     112            .arg((_device_ip>>24) & 0xFF).arg((_device_ip>>16) & 0xFF)
     113            .arg((_device_ip>> 8) & 0xFF).arg((_device_ip>> 0) & 0xFF));
     114
     115    return true;
    147116}
    148117
    149118bool HDHRChannel::Connect(void)
    150119{
    151     _control_socket = hdhomerun_control_create(_device_ip, 2000);
     120    _control_socket = hdhomerun_control_create(_device_id, _device_ip);
    152121    if (!_control_socket)
    153122    {
     123        VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to create control socket");
     124        return false;
     125    }
     126
     127    if (hdhomerun_control_get_local_addr(_control_socket) == 0)
     128    {
    154129        VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to connect to device");
    155130        return false;
    156131    }
     
    162137QString HDHRChannel::DeviceGet(const QString &name)
    163138{
    164139    QMutexLocker locker(&_lock);
    165     //VERBOSE(VB_CHANNEL, LOC + QString("DeviceGet(%1)").arg(name));
    166140
    167141    if (!_control_socket)
    168142    {
     
    170144        return QString::null;
    171145    }
    172146
    173     /* Send request. */
    174     if (hdhomerun_control_send_get_request(_control_socket, name) < 0)
     147    char *value = NULL;
     148    char *error = NULL;
     149    if (hdhomerun_control_get(_control_socket, name, &value, &error) < 0)
    175150    {
    176         VERBOSE(VB_IMPORTANT, LOC_ERR + "Get request failed (send)" + ENO);
     151        VERBOSE(VB_IMPORTANT, LOC_ERR + "Get request failed" + ENO);
    177152        return QString::null;
    178153    }
    179154
    180     /* Wait for response. */
    181     struct hdhomerun_control_data_t response;
    182     if (hdhomerun_control_recv(_control_socket, &response, 2000) <= 0)
    183     {
    184         VERBOSE(VB_IMPORTANT, LOC_ERR + "Get request failed (timeout)");
     155    if (error) {
     156        VERBOSE(VB_IMPORTANT, LOC_ERR + QString("DeviceGet(%1): %2").arg(name).arg(error));
    185157        return QString::null;
    186158    }
    187     if (response.type != HDHOMERUN_TYPE_GETSET_RPY)
    188     {
    189         VERBOSE(VB_IMPORTANT, LOC_ERR +
    190                 "Get request failed (unexpected response)");
    191         return QString::null;
    192     }
    193159
    194     QString ret = QString::null;
    195     unsigned char *ptr = response.ptr, *data = NULL;
    196     unsigned char tag;
    197     int dlen;
    198     while (hdhomerun_read_tlv(&ptr, response.end, &tag, &dlen, &data) >= 0)
    199     {
    200         char buf[1024+64];
    201         if (HDHOMERUN_TAG_GETSET_VALUE == tag)
    202         {
    203             memcpy(buf, (char*)data, dlen);
    204             buf[dlen - 1] = 0x0;
    205             ret = QString(buf);
    206         }
    207         else if (HDHOMERUN_TAG_ERROR_MESSAGE == tag)
    208         {
    209             memcpy(buf, (char*)data, dlen);
    210             buf[dlen - 1] = 0x0;
    211             VERBOSE(VB_IMPORTANT, LOC_ERR + QString("DeviceGet(%1): %2")
    212                     .arg(name).arg(buf));
    213         }
    214     }
    215 
    216     //VERBOSE(VB_CHANNEL, LOC + QString("DeviceGet(%1) -> '%2' len(%3)")
    217     //        .arg(name).arg(ret).arg(len));
    218 
    219     return ret;
     160    return QString(value);
    220161}
    221162
    222163QString HDHRChannel::DeviceSet(const QString &name, const QString &val)
     
    229170        return QString::null;
    230171    }
    231172
    232     /* Send request. */
    233     if (hdhomerun_control_send_set_request(_control_socket, name, val) < 0)
     173    char *value = NULL;
     174    char *error = NULL;
     175    if (hdhomerun_control_set(_control_socket, name, val, &value, &error) < 0)
    234176    {
    235         VERBOSE(VB_IMPORTANT, LOC_ERR + "Set request failed (send)" + ENO);
     177        VERBOSE(VB_IMPORTANT, LOC_ERR + "Set request failed" + ENO);
    236178        return QString::null;
    237179    }
    238180
    239     /* Wait for response. */
    240     struct hdhomerun_control_data_t response;
    241     bzero(&response, sizeof(response));
    242     if (hdhomerun_control_recv(_control_socket, &response, 2000) <= 0)
    243     {
    244         VERBOSE(VB_IMPORTANT, LOC_ERR + "Set request failed (timeout)");
     181    if (error) {
     182        VERBOSE(VB_IMPORTANT, LOC_ERR + QString("DeviceSet(%1 %2): %3").arg(name).arg(val).arg(error));
    245183        return QString::null;
    246184    }
    247     if (response.type != HDHOMERUN_TYPE_GETSET_RPY)
    248     {
    249         VERBOSE(VB_IMPORTANT, LOC_ERR +
    250                 "Set request failed (unexpected response)");
    251         return QString::null;
    252     }
    253185
    254     QStringList list;
    255     QString tmp = "";
    256     unsigned char *ptr = response.ptr;
    257     for (;ptr < response.end; ptr++)
    258     {
    259         if (*ptr)
    260         {
    261             tmp += QChar(*((char*)ptr));
    262             continue;
    263         }
    264         list.push_back(tmp);
    265         tmp = "";
    266         ptr++;
    267         ptr++;
    268     }
    269 
    270     if (list.size() >= 2)
    271         return list[1];
    272     return "";
     186    return QString(value);
    273187}
    274188
    275189QString HDHRChannel::TunerGet(const QString &name)
  • libs/libmythtv/hdhrchannel.h

     
    1414#include "dtvchannel.h"
    1515
    1616// HDHomeRun headers
    17 #include "hdhomerun/hdhomerun_pkt.h"
    18 #include "hdhomerun/hdhomerun_discover.h"
    19 #include "hdhomerun/hdhomerun_control.h"
    20 #include "hdhomerun/hdhomerun_video.h"
     17#include "hdhomerun/hdhomerun.h"
    2118
    2219typedef struct hdhomerun_control_sock_t hdhr_socket_t;
    2320