On Thu, 17 Jul 2014, Adam Williamson wrote:

Roger. Well, I guess I'll send the IDs and we'll go from there :)

Yep, that's the first step.

[  +0.088528] usb 1-1.5: New USB device found, idVendor=046d, idProduct=c129
[  +0.000006] usb 1-1.5: New USB device strings: Mfr=1, Product=2, 
SerialNumber=0
[  +0.000002] usb 1-1.5: Product: Harmony Remote
[  +0.000002] usb 1-1.5: Manufacturer: Logitech

that's the Hub.

Ah. Looks like I had already added that PID when I was working on a patch the Harmony Touch. This patch should at least get 'concordance -iv' working for you, I think.
commit 5435adcb37df825726256f33ff2006171052c263
Author: Scott Talbert <s...@techie.net>
Date:   Wed Dec 11 18:22:31 2013 -0500

    Attempt at supporting the Harmony Touch (v11)
    
    Add the PID for the Touch to the list of MH PIDs.
    Add the Touch's Skin/Arch to the remote_info structs.
    Add support for handling the Touch's non-standard serial number, and provide
    a libconcord call to expose this information.
    Don't try to read the /cfg/usercfg on the Link/Touch.
    Remove set_configuration - doesn't seem to be needed and causes problems for
    Harmony Touch.
    Add new API methods so that MHGUI can perform a sync operation.
    Fix WriteFile() so that it reads and responds to the periodic acks.
    Implement SetTime() for the Touch.

diff --git a/concordance/concordance.c b/concordance/concordance.c
index 4471697..6b66527 100644
--- a/concordance/concordance.c
+++ b/concordance/concordance.c
@@ -900,8 +900,11 @@ int print_version_info(struct options_t *options)
         printf("  USB PID: %04X\n", get_usb_pid());
         printf("  USB Ver: %04X\n", get_usb_bcd());
 
-        printf("  Serial Number: %s\n\t%s\n\t%s\n", get_serial(1),
-               get_serial(2), get_serial(3));
+        if (strlen(mh_get_serial()) != 0)
+            printf("  Serial Number: %s\n", mh_get_serial());
+        else
+            printf("  Serial Number: %s\n\t%s\n\t%s\n", get_serial(1),
+                   get_serial(2), get_serial(3));
     }
 
     used = get_config_bytes_used();
diff --git a/libconcord/bindings/python/libconcord.py b/libconcord/bindings/python/libconcord.py
index 718fc0e..491471a 100644
--- a/libconcord/bindings/python/libconcord.py
+++ b/libconcord/bindings/python/libconcord.py
@@ -973,3 +973,30 @@ mh_set_wifi_config = _create_func(
     _ret_lc_concord(),
     _in('config', POINTER(mh_wifi_config))
 )
+
+# const char *mh_get_serial();
+mh_get_serial = _create_func(
+    'mh_get_serial',
+    c_char_p
+)
+
+#int mh_read_file(const char *filename, uint8_t *buffer, const uint32_t buflen,
+#                 uint32_t *data_read);
+mh_read_file = _create_func(
+    'mh_read_file',
+    _ret_lc_concord(),
+    _in('filename', c_char_p),
+    _in('buffer', POINTER(c_ubyte)),
+    _in('buflen', c_uint),
+    _out('data_read', c_uint)
+)
+
+#int mh_write_file(const char *filename, uint8_t *buffer,
+#                  const uint32_t buflen);
+mh_write_file = _create_func(
+    'mh_write_file',
+    _ret_lc_concord(),
+    _in('filename', c_char_p),
+    _in('buffer', POINTER(c_ubyte)),
+    _in('buflen', c_uint)
+)
diff --git a/libconcord/libconcord.cpp b/libconcord/libconcord.cpp
index be54ab5..e9e8560 100644
--- a/libconcord/libconcord.cpp
+++ b/libconcord/libconcord.cpp
@@ -229,6 +229,8 @@ int is_mh_pid(unsigned int pid)
         case 0xC124: /* Harmony 300 */
         case 0xC125: /* Harmony 200 */
         case 0xC126: /* Harmony Link */
+        case 0xC129: /* Harmony Ultimate Hub */
+        case 0xC12B: /* Harmony Touch/Ultimate */
             return 1;
         default:
             return 0;
@@ -1942,6 +1944,27 @@ int mh_set_wifi_config(const struct mh_wifi_config *config)
     return err;
 }
 
+const char *mh_get_serial()
+{
+    return ri.mh_serial.c_str();
+}
+
+int mh_read_file(const char *filename, uint8_t *buffer, const uint32_t buflen,
+		 uint32_t *data_read)
+{
+    if (!is_mh_remote())
+        return LC_ERROR;
+    return rmt->ReadFile(filename, buffer, buflen, data_read, 0x00, NULL, NULL,
+                         0);
+}
+
+int mh_write_file(const char *filename, uint8_t *buffer, const uint32_t buflen)
+{
+    if (!is_mh_remote())
+        return LC_ERROR;
+    return rmt->WriteFile(filename, buffer, buflen);
+}
+
 /*
  * PRIVATE-SHARED INTERNAL FUNCTIONS
  * These are functions used by the whole library but are NOT part of the API
diff --git a/libconcord/libconcord.h b/libconcord/libconcord.h
index 8e6f7ec..c0d2ba0 100644
--- a/libconcord/libconcord.h
+++ b/libconcord/libconcord.h
@@ -527,6 +527,11 @@ int mh_set_cfg_properties(const struct mh_cfg_properties *properties);
 int mh_get_wifi_networks(struct mh_wifi_networks *networks);
 int mh_get_wifi_config(struct mh_wifi_config *config);
 int mh_set_wifi_config(const struct mh_wifi_config *config);
+const char *mh_get_serial();
+int mh_read_file(const char *filename, uint8_t *buffer, const uint32_t buflen,
+                 uint32_t *data_read);
+int mh_write_file(const char *filename, uint8_t *buffer,
+                  const uint32_t buflen);
 
 #ifdef __cplusplus
 }
diff --git a/libconcord/libusbhid.cpp b/libconcord/libusbhid.cpp
index 915c11f..86ba786 100644
--- a/libconcord/libusbhid.cpp
+++ b/libconcord/libusbhid.cpp
@@ -149,11 +149,6 @@ int FindRemote(THIDINFO &hid_info)
 #endif
 
     int err;
-    if ((err = usb_set_configuration(h_hid, 1))) {
-        debug("Failed to set device configuration: %d (%s)", err,
-              usb_strerror());
-        return err;
-    }
 
     if ((err=usb_claim_interface(h_hid, 0))) {
         debug("Failed to claim interface: %d (%s)", err,
diff --git a/libconcord/remote.h b/libconcord/remote.h
index 6f63f62..370cf53 100644
--- a/libconcord/remote.h
+++ b/libconcord/remote.h
@@ -133,6 +133,8 @@ struct TRemoteInfo {
     uint8_t node_id;
     char *tid;
     char *xml_user_rf_setting;
+    /* Special serial number that some MH remotes use */
+    string mh_serial;
 };
 
 struct THarmonyTime {
diff --git a/libconcord/remote_info.h b/libconcord/remote_info.h
index 72d55d7..84b3c0a 100644
--- a/libconcord/remote_info.h
+++ b/libconcord/remote_info.h
@@ -129,7 +129,18 @@ static const TModel ModelList[]={
 	{ MFG_UNK,	"Unknown",			NULL },
 	{ MFG_UNK,	"Unknown",			NULL },
 // 90
-	{ MFG_UNK,	"Unknown",			NULL }
+	{ MFG_UNK,	"Unknown",			NULL },
+	{ MFG_UNK,	"Unknown",			NULL },
+	{ MFG_UNK,	"Unknown",			NULL },
+	{ MFG_UNK,	"Unknown",			NULL },
+	{ MFG_UNK,	"Unknown",			NULL },
+	{ MFG_UNK,	"Unknown",			NULL },
+	{ MFG_UNK,	"Unknown",			NULL },
+	{ MFG_HAR,	"Harmony Ultimate Hub",		NULL },
+	{ MFG_UNK,	"Unknown",			NULL },
+	{ MFG_HAR,	"Harmony Touch",		NULL },
+// 100
+	{ MFG_HAR,	"Harmony Ultimate",		NULL }
 };
 
 static const unsigned int max_model=sizeof(ModelList)/sizeof(TModel)-1;
@@ -500,7 +511,7 @@ static const TArchInfo ArchList[]={
 		0,				// eeprom_size
 		"",				// usb
 	},
-	/* arch 17: Link */
+	/* arch 17: Link/Touch */
 	{
 		0,				// serial_location
 		0,				// serial_address
diff --git a/libconcord/remote_mh.cpp b/libconcord/remote_mh.cpp
index 88d5b45..22625df 100644
--- a/libconcord/remote_mh.cpp
+++ b/libconcord/remote_mh.cpp
@@ -367,13 +367,15 @@ int CRemoteMH::WriteFile(const char *filename, uint8_t *wr,
      */
     const uint8_t param = rsp[5];
 
-    uint8_t pkts_to_send = wrlen / MH_MAX_DATA_SIZE;
+    uint32_t pkts_to_send = wrlen / MH_MAX_DATA_SIZE;
     if ((wrlen % MH_MAX_DATA_SIZE) != 0)
         pkts_to_send++;
     pkts_to_send++; // count is always one more than the actual count
 
     uint8_t msg_ack[MH_MAX_PACKET_SIZE] =
-        { 0xFF, 0x03, get_seq(seq), 0x02, 0x01, param, 0x01, pkts_to_send };
+        { 0xFF, 0x03, get_seq(seq), 0x02, 0x01, param, 0x01, 0x33 };
+    if (pkts_to_send < 0x33)
+        msg_ack[7] = pkts_to_send;
 
     if ((err = HID_WriteReport(msg_ack))) {
         debug("Failed to write to remote");
@@ -386,6 +388,7 @@ int CRemoteMH::WriteFile(const char *filename, uint8_t *wr,
     uint32_t tlen = wrlen;
     uint8_t pkt_len;
     uint8_t tmp_pkt[MH_MAX_PACKET_SIZE];
+    int pkt_count = 0;
     while (tlen) {
         pkt_len = MH_MAX_DATA_SIZE;
         if (tlen < pkt_len) {
@@ -405,6 +408,29 @@ int CRemoteMH::WriteFile(const char *filename, uint8_t *wr,
             return err;
         }
         wr_ptr += pkt_len;
+        pkt_count++;
+        pkts_to_send--;
+
+        /* Every 50 data packets, the remote seems to send us an "ack"
+           of some sort.  Read it and send a response back. */
+        if (pkt_count == 50) {
+            if ((err = HID_ReadReport(rsp, MH_TIMEOUT))) {
+                debug("Failed to read from remote");
+                return LC_ERROR_READ;
+            }
+            debug_print_packet(rsp);
+            /* 3rd byte is the sequence number */
+            msg_ack[2] = get_seq(seq);
+            /* 2nd parameter is the number of packets remaining,
+               plus one */
+            if (pkts_to_send < 0x33)
+                msg_ack[7] = pkts_to_send;
+            if ((err = HID_WriteReport(msg_ack))) {
+                debug("Failed to write to remote");
+                return LC_ERROR_WRITE;
+            }
+            pkt_count = 0;
+        }
     }
 
     /*
@@ -503,38 +529,6 @@ int CRemoteMH::GetIdentity(TRemoteInfo &ri, THIDINFO &hid, lc_callback cb,
 
     setup_ri_pointers(ri);
 
-    if (cb) {
-        cb(cb_stage, cb_count++, 1, 2, LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
-    }
-
-    // Send the read config message to find the config bytes used.
-    const uint8_t msg_read_config[MH_MAX_PACKET_SIZE] =
-        { 0xFF, 0x01, 0x00, 0x03, 0x80, '/', 'c', 'f', 'g', '/',
-          'u', 's', 'e', 'r', 'c', 'f', 'g', 0x00, 0x80, 'R', 0x00 };
-    if ((err = HID_WriteReport(msg_read_config))) {
-        debug("Failed to write to remote");
-        return LC_ERROR_WRITE;
-    }
-
-    if ((err = HID_ReadReport(rsp))) {
-        debug("Failed to read from remote");
-        return LC_ERROR_READ;
-    }
-    debug("msg_read_config");
-    debug_print_packet(rsp);
-
-    // In ReadFlash() we add an extra four bytes to the end of the config file
-    // buffer, so we include space for those bytes here.
-    ri.config_bytes_used = (rsp[7] << 24) + (rsp[8] << 16) + (rsp[9] << 8)
-        + rsp[10] + 4;
-    debug("ri.config_bytes_used = %d", ri.config_bytes_used);
-    ri.max_config_size = (ri.flash->size << 10);
-    ri.valid_config = 1;
-
-    if (cb) {
-        cb(cb_stage, cb_count++, 2, 2, LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
-    }
-
     string guid_str = find_value(identity, "guid");
     if (guid_str.length() >= 98) {
         uint8_t guid[48];
@@ -549,9 +543,45 @@ int CRemoteMH::GetIdentity(TRemoteInfo &ri, THIDINFO &hid, lc_callback cb,
         }
         make_serial(guid, ri);
     }
+    ri.mh_serial = find_value(identity, "serial_number");
 
-    if ((err = reset_sequence(0x01, 0x06)))
-        return err;
+    if (cb) {
+        cb(cb_stage, cb_count++, 1, 2, LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
+    }
+
+    /* Arch 17 (Link/Touch) don't have the '/cfg/usercfg' so don't read it */
+    if (ri.architecture != 17) {
+        // Send the read config message to find the config bytes used.
+        const uint8_t msg_read_config[MH_MAX_PACKET_SIZE] =
+            { 0xFF, 0x01, 0x00, 0x03, 0x80, '/', 'c', 'f', 'g', '/',
+              'u', 's', 'e', 'r', 'c', 'f', 'g', 0x00, 0x80, 'R', 0x00 };
+        if ((err = HID_WriteReport(msg_read_config))) {
+            debug("Failed to write to remote");
+            return LC_ERROR_WRITE;
+        }
+
+        if ((err = HID_ReadReport(rsp))) {
+            debug("Failed to read from remote");
+            return LC_ERROR_READ;
+        }
+        debug("msg_read_config");
+        debug_print_packet(rsp);
+
+        if ((err = reset_sequence(0x01, 0x06)))
+            return err;
+
+        // In ReadFlash() we add an extra four bytes to the end of the config
+        // file buffer, so we include space for those bytes here.
+        ri.config_bytes_used = (rsp[7] << 24) + (rsp[8] << 16) + (rsp[9] << 8)
+            + rsp[10] + 4;
+        debug("ri.config_bytes_used = %d", ri.config_bytes_used);
+    }
+    ri.max_config_size = (ri.flash->size << 10);
+    ri.valid_config = 1;
+
+    if (cb) {
+        cb(cb_stage, cb_count++, 2, 2, LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
+    }
 
     return 0;
 }
@@ -684,12 +714,32 @@ int CRemoteMH::SetTime(const TRemoteInfo &ri, const THarmonyTime &ht,
                        lc_callback cb, void *cb_arg, uint32_t cb_stage)
 {
     /* 
-     * MH remotes do not support SetTime() operations, but we return
+     * Some MH remotes do not support SetTime() operations, but we return
      * success because some higher level operations (for example, update
      * configuration) call SetTime() and thus the whole operation would be
      * declared a failure, which we do not want.
      */
-    return 0;
+    if (ri.architecture != 17) {
+        return 0;
+    } else {
+        /* Yes, the official sw seems to hard code the US-East TZ */
+        const char *tz_str = "EST5EDT,M3.2.0,M11.1.0";
+        size_t tz_str_len = strlen(tz_str);
+        const uint32_t tsv_len = 16 + tz_str_len;
+        uint8_t tsv[tsv_len];
+        tsv[0] = ht.year >> 8;
+        tsv[1] = ht.year;
+        tsv[2] = ht.month;
+        tsv[3] = ht.day;
+        tsv[4] = ht.hour;
+        tsv[5] = ht.minute;
+        tsv[6] = ht.second;
+        tsv[7] = ht.dow;
+        for (int i = 8; i < 16; i++)
+            tsv[i] = 0;
+        memcpy(&tsv[16], tz_str, tz_str_len);
+        return WriteFile("/sys/time", tsv, tsv_len);
+    }
 }
 
 int CRemoteMH::LearnIR(uint32_t *freq, uint32_t **ir_signal,
------------------------------------------------------------------------------
Want fast and easy access to all the code in your enterprise? Index and
search up to 200,000 lines of code with a free copy of Black Duck
Code Sight - the same software that powers the world's largest code
search on Ohloh, the Black Duck Open Hub! Try it now.
http://p.sf.net/sfu/bds
_______________________________________________
concordance-devel mailing list
concordance-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/concordance-devel

Reply via email to