Hi Cedric,

Some other news - I think I finally reverse engineered the format that the Touch uses for setting the time. I've got a new patch for concordance (attached) that hopefully implements the time setting properly. If you can also test this when you get a chance, that would be much appreciated. Basically, run it and see if it reports any errors and also check to see whether the date and time is properly set on your remote after running it. To test it (much easier than doing a sync!) you can just run:
"concordance -K".

Note: I rebased the patch on git master (with Phil's latest commits), so you will probably have to roll back the old patch, do a git pull, and then apply this new patch.

Once we confirm the time setting works, I can add it to the config sync process, but I don't want to change that while we are still testing the basic sync stuff. :)

Thanks,
Scott

On Mon, 31 Mar 2014, Cédric de Launois wrote:

Great. I'll take a look.
Regarding the complete sync failure last time, I agree it is certainly not
related to your latest changes. It may be related to the firmware upgrade
that logitech forced during the last config sync. Hope my remote won't crash
every next failed sync ;-)

Thx again,
Cedric


2014-03-31 2:39 GMT+02:00 Scott Talbert <[email protected]>:
      OK, so the problem wasn't with the locale per se, but with
      positive UTC offsets.  Once I set my clock to UTC+1, I was able
      to see the problem. I've pushed a fix for this.  Please try
      again at your convenience. Hopefully this might work.  :-)  But
      if it still fails, could you please do a Wireshark capture of
      both the failed mhgui and successful Logitech sync.

      Thanks
      Scott

      On Sun, 30 Mar 2014, Scott Talbert wrote:

            Actually, after remembering what problem I was
            looking at last time (problems with dates), I looked
            and sure enough, those dates appear to still be
            problematic.  The weird thing is, the date handling
            seems to work fine on my machine.  I'll have to try
            it on Ubuntu to see if I can reproduce the problem
            there, or maybe with your locale.

            So, no need for a new capture just yet.  :)

            Scott

            On Sun, 30 Mar 2014, Scott Talbert wrote:

                  Hi Cedric,

                  Sorry about that, but I'm not sure why
                  this time it would have broken the
                  remote any worse than before.  :-)
                   There weren't any changes in the code
                  that interact with the remote, just
                  logging changes.

                  Anyway, unfortunately, I was not able to
                  tell anything from the logs - there were
                  differences but it wasn't possible to
                  sort out the differences that were due
                  to MHGUI vs differences in the
                  configuration.

                  Can you try again?  Unfortunately at
                  this point, I really need to see mhgui
                  and Logitech attempting to do the exact
                  same operation.  Also, please do a
                  Wireshark capture of both USB
                  interactions.

                  Thanks,
                  Scott

                  On Fri, 28 Mar 2014, Cédric de Launois
                  wrote:

                        Ouch, this time the failure
                        of mhgui completely broke
                        the remote. I had to
                        perform a hardware reset
                        because logitech was no
                        longer able to sync it.
                        I forgot all the changes I
                        made, so it may appear that
                        the config sync by
                        logitech is somewhat
                        different from the sync I
                        made with mhgui.
                        It is difficult to perform
                        the exact same sync if the
                        remote is crashing
                        with mhgui...

                        Hope this trace will help
                        anyway.

                        Cedric




commit 5435adcb37df825726256f33ff2006171052c263
Author: Scott Talbert <[email protected]>
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,
------------------------------------------------------------------------------
_______________________________________________
concordance-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/concordance-devel

Reply via email to