Attached is a patch which implements config dumping for MH remotes, rebased on git.
commit 57726be8c00398da63122fa9b355a5cde966fa18
Author: Scott Talbert <s...@techie.net>
Date:   Sun Jun 9 17:40:05 2013 -0400

    Implement config dumping for MH remotes.
    
    Signed-off-by: Scott Talbert <s...@techie.net>

diff --git a/libconcord/configure.ac b/libconcord/configure.ac
index 47fc747..5a85e08 100644
--- a/libconcord/configure.ac
+++ b/libconcord/configure.ac
@@ -17,6 +17,12 @@ if test $a == 0
 then
        AC_MSG_ERROR([Error, libzzip is missing!])
 fi
+AC_CHECK_HEADER(zip.h, [], [a=0])
+AC_CHECK_LIB(zip, zip_open, [], [a=0])
+if test $a == 0
+then
+       AC_MSG_ERROR([Error, libzip is missing!])
+fi
 AC_CONFIG_HEADERS([config.h])
 AC_CONFIG_FILES([
  Makefile
diff --git a/libconcord/libconcord.cpp b/libconcord/libconcord.cpp
index 1959ea3..be1406a 100644
--- a/libconcord/libconcord.cpp
+++ b/libconcord/libconcord.cpp
@@ -30,6 +30,7 @@
 #include <stdlib.h>
 #include <errno.h>
 #include <zzip/lib.h>
+#include <zip.h>
 #include <list>
 #include <unistd.h>
 #include <vector>
@@ -1036,6 +1037,82 @@ int _write_config_to_remote(lc_callback cb, void 
*cb_arg, uint32_t cb_stage)
     return 0;
 }
 
+/*
+ * When MH configs are read from the remote, sometimes the remote returns extra
+ * data after the end of the config file proper.  This function searches for
+ * the sequence of bytes that indicates the end of the config and returns the
+ * real length of the config that should be written out to disk.
+ */
+uint32_t _mh_get_config_len(uint8_t *in, uint32_t size)
+{
+    for (int i = 0; (i + 3) < size; i++) {
+        if (!memcmp(&in[i], MH_EOF_BYTES, 4)) {
+            return i + 4;
+        }
+    }
+    debug("Failed to find MH config EOF sequence");
+    return 0;
+}
+
+int _mh_write_config_to_file(uint8_t *in, uint32_t size, char *file_name)
+{
+    int zip_err;
+    struct zip *zip = zip_open(file_name, ZIP_CREATE | ZIP_EXCL, &zip_err);
+    if (!zip) {
+        if (zip_err == ZIP_ER_EXISTS) {
+            printf("Error: file %s already exists\n", file_name);
+        } else {
+            debug("Failed to create zip file %s", file_name);
+        }
+        return LC_ERROR_OS_FILE;
+    }
+    int index;
+
+    // Write XML
+    extern const char *mh_config_header;
+    int xml_buffer_len = strlen(mh_config_header) + 100;
+    char *xml_buffer = new char[xml_buffer_len];
+    uint16_t checksum = mh_get_checksum(in, size);
+    int xml_len = snprintf(xml_buffer, xml_buffer_len, mh_config_header,
+        size, size - 6, checksum, ri.skin);
+    if (xml_len >= xml_buffer_len) {
+        debug("Error, XML buffer length exceeded");
+        return LC_ERROR;
+    }
+    struct zip_source *xml = zip_source_buffer(zip, xml_buffer, xml_len, 0);
+    if (!xml) {
+        debug("Failed to create zip_source_buffer for XML file");
+        return LC_ERROR_OS_FILE;
+    }
+    index = zip_add(zip, "Description.xml", xml);
+    if (index == -1) {
+        debug("Error writing XML to zip file");
+        zip_source_free(xml);
+        return LC_ERROR_OS_FILE;
+    }
+       
+    // Write EzHex file
+    struct zip_source *ezhex = zip_source_buffer(zip, in, size, 0);
+    if (!ezhex) {
+        debug("Failed to create zip_source_buffer for EzHex file");
+        return LC_ERROR_OS_FILE;
+    }
+    index = zip_add(zip, "Result.EzHex", ezhex);
+    if (index == -1) {
+        debug("Error writing EzHex to zip file");
+        zip_source_free(ezhex);
+        return LC_ERROR_OS_FILE;
+    }
+
+    if (zip_close(zip) != 0) {
+        debug("Error closing zip file");
+        return LC_ERROR_OS_FILE;
+    }
+
+    delete[] xml_buffer;
+    return 0;
+}
+
 int write_config_to_remote(lc_callback cb, void *cb_arg)
 {
     return _write_config_to_remote(cb, cb_arg, LC_CB_STAGE_WRITE_CONFIG);
@@ -1044,6 +1121,17 @@ int write_config_to_remote(lc_callback cb, void *cb_arg)
 int write_config_to_file(uint8_t *in, uint32_t size, char *file_name,
     int binary)
 {
+    // If this is an MH remote, need to find the real end of the binary
+    if (is_mh_remote()) {
+        size = _mh_get_config_len(in, size);
+        ri.config_bytes_used = size;
+    }
+
+    // If this is an MH remote, need to write out zip file with XML/binary
+    if (!binary && is_mh_remote()) {
+        return _mh_write_config_to_file(in, size, file_name);
+    }
+
     binaryoutfile of;
 
     if (of.open(file_name) != 0) {
diff --git a/libconcord/remote.h b/libconcord/remote.h
index 31bb5f1..6a4c399 100644
--- a/libconcord/remote.h
+++ b/libconcord/remote.h
@@ -35,6 +35,7 @@
    which is 1 (num params) + 3 (3 parameter size bytes) + 1 (param 1)
    + 1024 (param 2) + 4 (param 3) = 1033. */
 #define USBNET_MAX_PACKET_SIZE 1033
+const uint8_t MH_EOF_BYTES[] = { 0x50, 0x54, 0x59, 0x59 };
 
 /*
  * limits for IR signal learning, stop when any is reached:
@@ -151,6 +152,7 @@ void setup_ri_pointers(TRemoteInfo &ri);
 void make_serial(uint8_t *ser, TRemoteInfo &ri);
 int LearnIRInnerLoop(uint32_t *freq, uint32_t **ir_signal,
     uint32_t *ir_signal_length, uint8_t seq);
+uint16_t mh_get_checksum(uint8_t* rd, const uint32_t len);
 
 class CRemoteBase            // Base class for all remotes
 {
diff --git a/libconcord/remote_mh.cpp b/libconcord/remote_mh.cpp
index ce55ee9..5038945 100644
--- a/libconcord/remote_mh.cpp
+++ b/libconcord/remote_mh.cpp
@@ -252,6 +252,18 @@ int CRemoteMH::GetIdentity(TRemoteInfo &ri, THIDINFO &hid, 
lc_callback cb,
     }
     debug("%s", identity.c_str());
 
+    if ((err = HID_WriteReport(msg_six))) {
+        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_six");
+    debug_print_packet(rsp);
+
     ri.fw_ver_major = strtol(find_value(identity, "fw_ver").c_str(), NULL, 10);
     ri.fw_ver_minor = strtol(find_value(identity, "fw_ver").c_str()+2, NULL,
                              10);
@@ -271,8 +283,29 @@ int CRemoteMH::GetIdentity(TRemoteInfo &ri, THIDINFO &hid, 
lc_callback cb,
         cb(cb_stage, cb_count++, 1, 2, LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
     }
 
-    ri.config_bytes_used = 0;
-    ri.max_config_size = 1;
+    // 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);
+       
+    // There are four extra bytes at the end of every MH config file - 
+    // we add an extra four here so there is space in ReadFlash() to add
+    // those bytes.
+    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) {
@@ -295,7 +328,9 @@ int CRemoteMH::GetIdentity(TRemoteInfo &ri, THIDINFO &hid, 
lc_callback cb,
     }
 
     /* reset the sequence number to 0 */
-    if ((err = HID_WriteReport(msg_six))) {
+    const uint8_t msg_reset_seq[MH_MAX_PACKET_SIZE] =
+        { 0xFF, 0x07, 0x01, 0x01, 0x01, 0x06 };
+    if ((err = HID_WriteReport(msg_reset_seq))) {
         debug("Failed to write to remote");
         return LC_ERROR_WRITE;
     }
@@ -304,17 +339,132 @@ int CRemoteMH::GetIdentity(TRemoteInfo &ri, THIDINFO 
&hid, lc_callback cb,
         debug("Failed to read from remote");
         return LC_ERROR_READ;
     }
-    debug("msg_six");
+    debug("msg_reset_seq");
     debug_print_packet(rsp);
 
     return 0;
 }
 
+// Calculates the XOR checksum for a config read from the remote.
+uint16_t mh_get_checksum(uint8_t* rd, const uint32_t len)
+{
+    // This is the "SEED" that all the configs from the website use.
+    uint16_t cksum = 0x4321;
+    // The part of the config that gets checksummed is consistently 6 bytes
+    // less than the length of the config.  Since we are checksumming two
+    // bytes at a type, we stop when i == len - 7, which is the same as 
+    // i + 1 == len - 6.  In the case of odd lengths, we skip the last byte.
+    for (int i = 0; i < (len - 7); i += 2) {
+        uint16_t j = (rd[i+1] << 8) + rd[i]; 
+        cksum ^= j;
+    }
+    debug("CHECKSUM=0x%04x", cksum);
+    return cksum;
+}
+
 int CRemoteMH::ReadFlash(uint32_t addr, const uint32_t len, uint8_t *rd,
                          unsigned int protocol, bool verify, lc_callback cb,
                          void *cb_arg, uint32_t cb_stage)
 {
-    return LC_ERROR_UNSUPP;
+    int err = 0;
+    uint32_t cb_count = 0;
+
+    const uint8_t msg_one[MH_MAX_PACKET_SIZE] =
+        { 0xFF, 0x01, 0x00, 0x03, 0x80, '/', 'c', 'f', 'g', '/',
+          'u', 's', 'e', 'r', 'c', 'f', 'g', 0x00, 0x80, 'R', 0x00 };
+    uint8_t msg_ack[MH_MAX_PACKET_SIZE] =
+        { 0xFF, 0x04, 0x01, 0x02, 0x01, 0x00, 0x01, 0x33 };
+    const uint8_t msg_eof = { 0xFE };
+    uint8_t rsp[MH_MAX_PACKET_SIZE];
+
+    if ((err = HID_WriteReport(msg_one))) {
+        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_one");
+    debug_print_packet(rsp);
+
+    if ((err = HID_WriteReport(msg_ack))) {
+        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_ack");
+    debug_print_packet(rsp);
+
+    int packet_count = 0;
+    int data_read = 0;
+    uint8_t seq = 0x01;
+    uint8_t *rd_ptr = rd;
+    while(!(err = HID_ReadReport(rsp))) {
+        debug_print_packet(rsp);
+        if (rsp[0] == msg_eof) {
+            break;
+        }
+        // Ignore 1st two bits on 2nd byte for length.
+        int len = rsp[1] & 0x3F;
+        // Skip 1st two bytes, read up to packet length.  "len"
+        // represents the payload length (not including the two size
+        // bytes), so we read a full "len" bytes from 2 to len+2.
+        if (rd) {
+            memcpy(rd_ptr, &rsp[2], len);
+            rd_ptr += len;
+        }
+        data_read += len;
+        packet_count++;
+        if (packet_count == 50) {
+            msg_ack[2] = get_seq(seq);
+            debug_print_packet(msg_ack);
+            if ((err = HID_WriteReport(msg_ack))) {
+                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("ack");
+            debug_print_packet(rsp);
+            packet_count = 0;
+        }
+    }
+    debug("data_read=%d", data_read);
+
+    /*
+     * There are four extra bytes at the end of every config file, but they
+     * are not present when read from the remote.  Add them here.
+     */
+    if (rd) {
+        memcpy(rd_ptr, MH_EOF_BYTES, 4);
+        rd_ptr += 4;
+    }
+    data_read += 4;
+
+    /* send reset sequence message */
+    const uint8_t msg_reset_seq[MH_MAX_PACKET_SIZE] =
+        { 0xFF, 0x07, get_seq(seq), 0x01, 0x01, 0x06 };
+    if ((err = HID_WriteReport(msg_reset_seq))) {
+        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_reset_seq");
+    debug_print_packet(rsp);
+
+    return 0;
 }
 
 int CRemoteMH::InvalidateFlash(lc_callback cb, void *cb_arg, uint32_t lc_stage)
diff --git a/libconcord/xml_headers.h b/libconcord/xml_headers.h
index aa2d663..6f79253 100644
--- a/libconcord/xml_headers.h
+++ b/libconcord/xml_headers.h
@@ -129,6 +129,7 @@ const char *config_header="\
 </INFORMATION>\r\n";
 
 
+const char *mh_config_header = "<DATA><FILES><FILE NAME=\"Result.EzHex\" 
SIZE=\"%i\" PATH=\"/cfg/usercfg\" VERSION=\"1\" FW_VERSION=\"9.5\" 
OPERATIONTYPE=\"userconfiguration\"><CHECKSUM SEED=\"0x4321\" OFFSET=\"0x0\" 
LENGTH=\"0x%04x\" EXPECTEDVALUE=\"0x%04x\" 
TYPE=\"XOR\"/></FILE></FILES><INTENDED><SKIN>%i</SKIN></INTENDED><ORDER><ORDER_ELEMENT
 NAME=\"Result.EzHex\" RESET=\"true\"/></ORDER></DATA>";
 
 //User-Agent: HarmonyBrowser/7.7.0 (Build 0; UpdatedFrom 7.3.0.15; Skin 
logitech; Windows Vista 6.1; x86; en; rv: 1.8.0.2) Gecko/20060125\r\n\
 
------------------------------------------------------------------------------
How ServiceNow helps IT people transform IT departments:
1. A cloud service to automate IT design, transition and operations
2. Dashboards that offer high-level views of enterprise services
3. A single system of record for all IT processes
http://p.sf.net/sfu/servicenow-d2d-j
_______________________________________________
concordance-devel mailing list
concordance-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/concordance-devel

Reply via email to