Fix HDHR device discovery

Fix HDHR device discovery code path:
dev_init()
  discover_devices()
    hdhomerun_discover_find_devices_custom()
    get_dev_model_and_fw()
      parse_http_page()
        hdhomerun_parser()

Change-Id: Ib943026a73ed24ad289d286823983e34bd818e9c
diff --git a/hdhomerun_dev.c b/hdhomerun_dev.c
index 62e12fa..79356c5 100644
--- a/hdhomerun_dev.c
+++ b/hdhomerun_dev.c
@@ -93,24 +93,47 @@
 
 static int hdhomerun_parser(void *context, char *buf, int bytes)
 {
-  char *p;
+  char *line, *nl, *p;
   struct hdhr_tuner_t *ht = (struct hdhr_tuner_t *)context;
-  p = strstr(buf, "Model:");
-  if (p != NULL) {
-    if (strlen(p + 6) < 10)
-      return p - buf;
-    if (get_string_by_name(p, "Model", ht->model, sizeof(ht->model), NULL)) {
-      cleanup_txt(ht->model);
+
+  line = buf;
+  while ((nl = strchr(line, '\n')) != NULL) {
+    // replace \r\n with \0
+    *nl = '\0';
+    if (nl > line && *(nl - 1) == '\r') {
+      *(nl - 1) = '\0';
     }
+
+    // process line
+    p = strstr(line, "Model:");
+    if (p) {
+      if (get_string_by_name(p, "Model", ht->model, sizeof(ht->model), NULL)) {
+        cleanup_txt(ht->model);
+        p = strstr(ht->model, "-CC");
+        if (p) {
+          ht->cc_tuner = 1;
+        }
+        p = strstr(ht->model, "HDTC");
+        if (p) {
+          ht->transcode_tuner = 1;
+        }
+      }
+    }
+
+    p = strstr(line, "Firmware:");
+    if (p) {
+      if (get_string_by_name(p, "Firmware", ht->firmware, sizeof(ht->firmware), NULL)) {
+        cleanup_txt(ht->firmware);
+      }
+    }
+
+    line = nl + 1;
   }
 
-  if (strstr(buf, "CableCARD Menu") != NULL) {
-    ht->cc_tuner = 1;
-  }
-  return bytes;
+  return (line - buf);
 }
 
-int get_dev_model(struct hdhr_tuner_t *ht)
+int get_dev_model_and_fw(struct hdhr_tuner_t *ht)
 {
   int ret = parse_http_page(ht->ip, "/", hdhomerun_parser, ht);
   return ret;
diff --git a/hdhomerun_dev.h b/hdhomerun_dev.h
index 2848ce0..7e607ad 100644
--- a/hdhomerun_dev.h
+++ b/hdhomerun_dev.h
@@ -1,7 +1,7 @@
 #ifndef _HDHOMERUN_DEV_H_
 #define _HDHOMERUN_DEV_H_
 
-int get_dev_model(struct hdhr_tuner_t *ht);
+int get_dev_model_and_fw(struct hdhr_tuner_t *ht);
 int get_vchannel_list(struct vchan_tbl_t *vt);
 
 #endif
diff --git a/hdhomerun_plugin.c b/hdhomerun_plugin.c
index 98ea933..9edf076 100644
--- a/hdhomerun_plugin.c
+++ b/hdhomerun_plugin.c
@@ -24,27 +24,9 @@
   struct hdhr_tuner_t *hdhrs;
 };
 
-static int discover_hdhrs(struct hdhr_tuner_t *ht, int max_ht_num)
-{
-  int i, ret = 0;
-  ret = discover_device(ht, max_ht_num);
-  if (ret > 0) {
-    for (i = 0; i < ret; i++) {
-      // if a unit shares a source input in a device, copy data.
-      if (i > 0 && tuner_input_sharing(&ht[i - 1], &ht[i])) {
-        ht[i].cc_tuner = ht[i - 1].cc_tuner;
-        strncpy(ht[i].model, ht[i - 1].model, sizeof(ht[i].model));
-      } else
-        get_dev_model(&ht[i]);
-    }
-    return i;
-  }
-  return 0;
-}
-
 void *dev_init(int *num)
 {
-  int i, index = 0, tuner_num;
+  int i;
   struct device_list *devices;
 
   sage_log((_LOG_TRACE, 3, "hdhr:hdhomerun device init"));
@@ -53,30 +35,23 @@
   if (devices != NULL) {
     devices->hdhrs = (struct hdhr_tuner_t *)malloc(sizeof(struct hdhr_tuner_t) *
                                                    MAX_TUNER_NUM);
-    memset(devices->hdhrs, 0,
-           sizeof(sizeof(struct hdhr_tuner_t) * MAX_TUNER_NUM));
     if (devices->hdhrs == NULL) {
       free(devices);
-      return 0;
+      return NULL;
     }
+    memset(devices->hdhrs, 0,
+           sizeof(sizeof(struct hdhr_tuner_t) * MAX_TUNER_NUM));
     devices->list_num = MAX_TUNER_NUM;
-    devices->tuner_num = 0;
-    tuner_num = discover_hdhrs(devices->hdhrs, MAX_TUNER_NUM);
-    for (i = 0; i < tuner_num; i++) {
-      devices->hdhrs[i].tuner_id = index++;
-      snprintf(devices->hdhrs[i].tuner_name,
-               sizeof(devices->hdhrs[i].tuner_name), "%s-%s",
-               devices->hdhrs[i].model, devices->hdhrs[i].name);
-      devices->tuner_num++;
-      sage_log((_LOG_TRACE, 3, "hdhr:%d %s %s %s", i,
+    devices->tuner_num = discover_devices(devices->hdhrs, MAX_TUNER_NUM);
+    for (i = 0; i < devices->tuner_num; i++) {
+      sage_log((_LOG_TRACE, 3, "hdhr:%d %s %s %s %s", i,
                 devices->hdhrs[i].tuner_name, devices->hdhrs[i].model,
-                devices->hdhrs[i].cc_tuner ? "CableCard" : ""));
+                devices->hdhrs[i].cc_tuner ? "CableCard" : "ATSC",
+                devices->hdhrs[i].firmware));
     }
-    devices->tuner_num = tuner_num;
-    *num = tuner_num;
-    return devices;
+    *num = devices->tuner_num;
   }
-  return NULL;
+  return devices;
 }
 
 void dev_release(void *handle)
diff --git a/hdhomerun_tuner.c b/hdhomerun_tuner.c
index d220d64..e04052b 100644
--- a/hdhomerun_tuner.c
+++ b/hdhomerun_tuner.c
@@ -349,33 +349,43 @@
   return buf;
 }
 
-int discover_device(struct hdhr_tuner_t *ht, int max_ht_num)
+int discover_devices(struct hdhr_tuner_t *ht, int max_ht_num)
 {
-  int i, k, num = 0;
-  struct hdhomerun_discover_device_t *device_info =
-      malloc(max_ht_num * sizeof(struct hdhomerun_discover_device_t));
-  int ret = hdhomerun_discover_find_devices_custom(
-      0, HDHOMERUN_DEVICE_TYPE_TUNER, -1, device_info, 16);
-  if (ret <= 0) {
-    free(device_info);
-    return 0;
+  int i, k, count, num = 0;
+  struct hdhomerun_discover_device_t device_info[max_ht_num];
+  struct hdhr_tuner_t hdhr;
+
+  while (1) {
+    count = hdhomerun_discover_find_devices_custom(0,
+                HDHOMERUN_DEVICE_TYPE_TUNER, HDHOMERUN_DEVICE_ID_WILDCARD,
+                device_info, max_ht_num);
+    if (count > 0) {
+      break;
+    }
+    sleep(3);
   }
-  // printf( "found %d hdhomerun device\n", ret );
-  for (i = 0; i < ret; i++) {
-    // printf( "ip:%x type:%x id:%x num:%d\n", device_info[i].ip_addr,
-    // device_info[i].device_type, device_info[i].device_id,
-    //    device_info[i].tuner_count );
+
+  for (i = 0; i < count; i++) {
+    memset(&hdhr, 0, sizeof(hdhr));
+    ip4_address(device_info[i].ip_addr, hdhr.ip, sizeof(hdhr.ip));
+    get_dev_model_and_fw(&hdhr);
+
     for (k = 0; k < device_info[i].tuner_count && num < max_ht_num; k++) {
+      ht[num].tuner_id = num;
+      ht[num].type = device_info[i].device_type;
       snprintf(ht[num].name, sizeof(ht[num].name), "%X-%d",
                device_info[i].device_id, k);
-      ip4_address(device_info[i].ip_addr, ht[num].ip, sizeof(ht[num].ip));
-      ht[num].type = device_info[i].device_type;
-      ht[num].cc_tuner = 0;
-      ht[num].model[0] = 0;
+      snprintf(ht[num].ip, sizeof(ht[num].ip), "%s", hdhr.ip);
+      snprintf(ht[num].model, sizeof(ht[num].model), "%s", hdhr.model);
+      snprintf(ht[num].firmware, sizeof(ht[num].firmware), "%s", hdhr.firmware);
+      snprintf(ht[num].tuner_name, sizeof(ht[num].tuner_name), "%s-%s",
+               ht[num].model, ht[num].name);
+      ht[num].cc_tuner = hdhr.cc_tuner;
+      ht[num].transcode_tuner = hdhr.transcode_tuner;
       num++;
     }
   }
-  free(device_info);
+
   return num;
 }
 
@@ -552,13 +562,6 @@
   return 1;
 }
 
-int tuner_input_sharing(struct hdhr_tuner_t *ht1, struct hdhr_tuner_t *ht2)
-{
-  if (ht1->cc_tuner == 1 && !strcmp(ht1->ip, ht2->ip))
-    return 1;
-  return 0;
-}
-
 #ifdef TEST_APP
 static int scan_channel(void *device, int index, struct channel_entry_t *ce,
                         int ce_channel_num, int ce_num)
@@ -773,17 +776,10 @@
   int tuner_count = 0;
   struct hdhr_tuner_t ht[16];
 
-  ret = discover_device(ht, 16);
+  ret = discover_devices(ht, 16);
   printf("found tuners:%d\n", ret);
   if (ret > 0) {
     for (i = 0; i < ret; i++) {
-      // if a unit shares a source input in a device, copy data.
-      if (i > 0 && tuner_input_sharing(&ht[i - 1], &ht[i])) {
-        ht[i].cc_tuner = ht[i - 1].cc_tuner;
-        strncpy(ht[i].model, ht[i - 1].model, sizeof(ht[i].model));
-      } else
-        get_dev_model(&ht[i]);
-
       printf("%d tuner:%s ip:%s type:%d cc:%d model:%s\n", i, ht[i].name,
              ht[i].ip, ht[i].type, ht[i].cc_tuner, ht[i].model);
     }
diff --git a/hdhomerun_tuner.h b/hdhomerun_tuner.h
index 4f1ed2e..6ac2403 100644
--- a/hdhomerun_tuner.h
+++ b/hdhomerun_tuner.h
@@ -8,8 +8,10 @@
   char name[16];        // internal used by hdhomerun device
   char ip[16];          // device unit ip
   char model[16];       // device model
+  char firmware[32];    // device firmware
   int type;             // device type 1:atsc 2:qam 3:dvb
   int cc_tuner;         // cable card tuner
+  int transcode_tuner;  // transcoding tuner
   void *channel_table;  // channel scan private data
 };
 
@@ -27,7 +29,7 @@
 
 struct channel_entry_t;
 
-int discover_device(struct hdhr_tuner_t *ht, int max_ht_num);
+int discover_devices(struct hdhr_tuner_t *ht, int max_ht_num);
 void *open_hdhr(char *name);
 void close_hdhr(void *device);
 char *get_unit_name(struct hdhr_tuner_t *ht, char *name, int size);
@@ -41,7 +43,6 @@
                         char *stream_target);
 int stop_channel(void *device);
 int scan_vchannel(void *device, int vchannel, struct channel_entry_t *ce);
-int tuner_input_sharing(struct hdhr_tuner_t *ht1, struct hdhr_tuner_t *ht2);
 struct vchan_tbl_t *create_vchan_tbl(struct hdhr_tuner_t *ht);
 void release_vchan_tbl(struct vchan_tbl_t *vt);
 int grow_vhcan_tbl(struct vchan_tbl_t *vt);