This update predominantly adds comments to explain some of the changes 
better.

Index: concordance/concordance.c
===================================================================
RCS file: /cvsroot/concordance/concordance/concordance/concordance.c,v
retrieving revision 1.41.2.20
diff -u -p -r1.41.2.20 concordance.c
--- concordance/concordance.c   20 Feb 2011 00:57:18 -0000      1.41.2.20
+++ concordance/concordance.c   11 Mar 2012 01:54:59 -0000
@@ -922,8 +922,8 @@ int print_version_info(struct options_t
        if ((*options).verbose)
                printf("  Firmware Type: %i\n", get_fw_type());

-       printf("  Hardware Version: %i.%i\n", get_hw_ver_maj(),
-               get_hw_ver_min());
+       printf("  Hardware Version: %i.%i.%i\n", get_hw_ver_maj(),
+               get_hw_ver_min(), get_hw_ver_mic());

        if ((*options).verbose) {
                int size = get_flash_size();
Index: libconcord/configure.ac
===================================================================
RCS file: /cvsroot/concordance/concordance/libconcord/configure.ac,v
retrieving revision 1.7.2.2
diff -u -p -r1.7.2.2 configure.ac
--- libconcord/configure.ac     11 Aug 2011 05:46:45 -0000      1.7.2.2
+++ libconcord/configure.ac     11 Mar 2012 01:54:59 -0000
@@ -11,7 +11,7 @@ then
        AC_MSG_ERROR([Error, libusb is missing!])
 fi
 AC_CHECK_HEADER(zzip/lib.h, [], [a=0])
-AC_CHECK_LIB(zzip, zzip_dir_open, [] [a=0])
+AC_CHECK_LIB(zzip, zzip_dir_open, [], [a=0])
 if test $a == 0
 then
        AC_MSG_ERROR([Error, libzzip is missing!])
Index: libconcord/lc_internal.h
===================================================================
RCS file: /cvsroot/concordance/concordance/libconcord/lc_internal.h,v
retrieving revision 1.2.2.1
diff -u -p -r1.2.2.1 lc_internal.h
--- libconcord/lc_internal.h    19 Sep 2010 16:06:25 -0000      1.2.2.1
+++ libconcord/lc_internal.h    11 Mar 2012 01:54:59 -0000
@@ -59,5 +59,6 @@ using namespace std;
 void report_net_error(const char *msg);
 /* NOTE: 1 for yes, 0 for no, unlike some other functions. */
 int is_z_remote();
+int is_usbnet_remote();

 #endif // ifndef LC_INTERNAL_H
Index: libconcord/libconcord.cpp
===================================================================
RCS file: /cvsroot/concordance/concordance/libconcord/libconcord.cpp,v
retrieving revision 1.42.2.18
diff -u -p -r1.42.2.18 libconcord.cpp
--- libconcord/libconcord.cpp   11 Aug 2011 05:46:45 -0000      1.42.2.18
+++ libconcord/libconcord.cpp   11 Mar 2012 01:54:59 -0000
@@ -47,7 +47,8 @@
 #define ZWAVE_HID_PID_MIN 0xC112
 #define ZWAVE_HID_PID_MAX 0xC115

-#define MAX_WAIT_FOR_BOOT 5
+// Certain remotes (e.g., 900) take longer to reboot, so extend wait time.
+#define MAX_WAIT_FOR_BOOT 10
 #define WAIT_FOR_BOOT_SLEEP 5

 static class CRemoteBase *rmt;
@@ -104,6 +105,11 @@ int get_hw_ver_min()
        return ri.hw_ver_minor;
 }

+int get_hw_ver_mic()
+{
+       return ri.hw_ver_micro;
+}
+
 int get_flash_size()
 {
        return ri.flash->size;
@@ -207,6 +213,11 @@ int is_z_remote()
        return rmt->IsZRemote() ? 1 : 0;
 }

+int is_usbnet_remote()
+{
+       return rmt->IsUSBNet() ? 1 : 0;
+}
+
 int get_time_second()
 {
        return rtime.second;
@@ -599,15 +610,11 @@ int init_concord()
        if ((err = FindRemote(hid_info))) {
                hid_info.pid = 0;

-#ifdef WIN32
                if ((err = FindUsbLanRemote())) {
                        return LC_ERROR_CONNECT;
                }

                rmt = new CRemoteZ_TCP;
-#else
-               return LC_ERROR_CONNECT;
-#endif
        }

        /*
@@ -635,8 +642,11 @@ int init_concord()
 int deinit_concord()
 {
        ShutdownUSB();
-       if (of)
-               delete of;
+       // Do not delete the OperationFile here.  It is used again in
+       // concordance after deinit_concord() is called.  Deleting it causes
+       // the final website check to fail in update config operations.
+       //if (of)
+               //delete of;
        if (rmt)
                delete rmt;
        return 0;
@@ -1074,7 +1084,7 @@ int update_configuration(lc_callback cb,
        if (err != 0)
                return err;

-       if (noreset || is_z_remote())
+       if (noreset || (is_z_remote() && !is_usbnet_remote()))
                return 0;

        if ((err = reset_remote(cb, cb_arg)))
Index: libconcord/libconcord.h
===================================================================
RCS file: /cvsroot/concordance/concordance/libconcord/libconcord.h,v
retrieving revision 1.22.2.14
diff -u -p -r1.22.2.14 libconcord.h
--- libconcord/libconcord.h     20 Feb 2011 00:27:19 -0000      1.22.2.14
+++ libconcord/libconcord.h     11 Mar 2012 01:54:59 -0000
@@ -132,6 +132,7 @@ int get_fw_ver_min();
 int get_fw_type();
 int get_hw_ver_maj();
 int get_hw_ver_min();
+int get_hw_ver_mic();
 int get_flash_size();
 int get_flash_mfg();
 int get_flash_id();
Index: libconcord/operationfile.cpp
===================================================================
RCS file: /cvsroot/concordance/concordance/libconcord/Attic/operationfile.cpp,v
retrieving revision 1.1.2.1
diff -u -p -r1.1.2.1 operationfile.cpp
--- libconcord/operationfile.cpp        19 Sep 2010 16:09:29 -0000      1.1.2.1
+++ libconcord/operationfile.cpp        11 Mar 2012 01:54:59 -0000
@@ -113,6 +113,7 @@ int OperationFile::ReadZipFile(char *fil
                        } else {
                                data_size = dirent.st_size;
                                data = new uint8_t[data_size];
+                               data_alloc = true;
                                zzip_size_t len = zzip_file_read(fh, data,
                                        data_size);
                        }
@@ -159,11 +160,12 @@ OperationFile::OperationFile()
 {
        data_size = xml_size = 0;
        data = xml = NULL;
+       data_alloc = false;
 }

 OperationFile::~OperationFile()
 {
-       if (data)
+       if (data && data_alloc)
                delete data;
        if (xml)
                delete xml;
@@ -186,6 +188,7 @@ int OperationFile::_ExtractFirmwareBinar
        debug("extracting firmware binary");
        uint32_t o_size = FIRMWARE_MAX_SIZE;
        data = new uint8_t[o_size];
+       data_alloc = true;
        uint8_t *o = data;

        uint8_t *x = xml;
Index: libconcord/operationfile.h
===================================================================
RCS file: /cvsroot/concordance/concordance/libconcord/Attic/operationfile.h,v
retrieving revision 1.1.2.1
diff -u -p -r1.1.2.1 operationfile.h
--- libconcord/operationfile.h  19 Sep 2010 16:09:29 -0000      1.1.2.1
+++ libconcord/operationfile.h  11 Mar 2012 01:54:59 -0000
@@ -29,6 +29,7 @@ class OperationFile {
 private:
        uint8_t *data;
        uint32_t data_size;
+       bool data_alloc;
        uint8_t *xml;
        uint32_t xml_size;
        int ReadPlainFile(char *file_name);
Index: libconcord/remote.cpp
===================================================================
RCS file: /cvsroot/concordance/concordance/libconcord/remote.cpp,v
retrieving revision 1.40.2.7
diff -u -p -r1.40.2.7 remote.cpp
--- libconcord/remote.cpp       20 Feb 2011 00:27:19 -0000      1.40.2.7
+++ libconcord/remote.cpp       11 Mar 2012 01:54:59 -0000
@@ -52,10 +52,19 @@ void setup_ri_pointers(TRemoteInfo &ri)
 void make_guid(const uint8_t * const in, char*&out)
 {
        char x[48];
-       sprintf(x,
-       
"{%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
-               in[3], in[2], in[1], in[0], in[5], in[4], in[7], in[6],
-               in[8], in[9], in[10], in[11], in[12], in[13], in[14], in[15]);
+       // usbnet remotes seem to use a more normal byte ordering for serial #'s
+       if (is_usbnet_remote()) {
+               sprintf(x,
+               
"{%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
+                       in[0], in[1], in[2], in[3], in[4], in[5], in[6], in[7],
+                       in[8], in[9], in[10], in[11], in[12], in[13], in[14], 
in[15]);
+       }
+       else {
+               sprintf(x,
+               
"{%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
+                       in[3], in[2], in[1], in[0], in[5], in[4], in[7], in[6],
+                       in[8], in[9], in[10], in[11], in[12], in[13], in[14], 
in[15]);
+       }
        out = strdup(x);
 }

@@ -112,6 +121,7 @@ int CRemote::GetIdentity(TRemoteInfo &ri
        ri.fw_ver_minor = rsp[1] & 0x0F;
        ri.hw_ver_major = rsp[2] >> 4;
        ri.hw_ver_minor = rsp[2] & 0x0F;
+       ri.hw_ver_micro = 0; /* usbnet remotes have a non-zero micro version */
        ri.flash_id = rsp[3];
        ri.flash_mfg = rsp[4];
        ri.architecture = rx_len < 6 ? 2 : rsp[5] >> 4;
Index: libconcord/remote.h
===================================================================
RCS file: /cvsroot/concordance/concordance/libconcord/remote.h,v
retrieving revision 1.20.2.8
diff -u -p -r1.20.2.8 remote.h
--- libconcord/remote.h 19 Sep 2010 16:06:25 -0000      1.20.2.8
+++ libconcord/remote.h 11 Mar 2012 01:54:59 -0000
@@ -100,6 +100,7 @@ struct TArchInfo {
 struct TRemoteInfo {
        uint16_t                hw_ver_major;
        uint16_t                hw_ver_minor;
+       uint16_t                hw_ver_micro;
        uint16_t                fw_ver_major;
        uint16_t                fw_ver_minor;
        uint8_t                 fw_type;
@@ -117,6 +118,13 @@ struct TRemoteInfo {
        bool                    valid_config;
        uint32_t                config_bytes_used;
        uint32_t                max_config_size;
+       uint8_t                 num_regions;   /* usbnet only from here down */
+       uint8_t                 *region_ids;
+       char                    **region_versions;
+       uint32_t                home_id;
+       uint8_t                 node_id;
+       char                    *tid;
+       char                    *xml_user_rf_setting;
 };

 struct THarmonyTime {
@@ -177,6 +185,7 @@ public:
                uint32_t *ir_signal_length, lc_callback cb=NULL,
                void *cb_arg=NULL, uint32_t cb_stage=NULL)=0;
        virtual int IsZRemote()=0;
+       virtual int IsUSBNet()=0;
 };

 class CRemote : public CRemoteBase     // All non-Z-Wave remotes
@@ -230,6 +239,7 @@ public:
                uint32_t *ir_signal_length, lc_callback cb=NULL,
                void *cb_arg=NULL, uint32_t cb_stage=NULL);
        int IsZRemote() {return false;}
+       int IsUSBNet() {return false;}
 };

 // Base class for all Z-Wave remotes
@@ -313,12 +323,14 @@ public:
        virtual ~CRemoteZ_HID() {};
        int UpdateConfig(const uint32_t len, const uint8_t *wr,
                lc_callback cb, void *cb_arg, uint32_t cb_stage);
+       int IsUSBNet() {return false;}
 };

 // 1000, 1000i
 class CRemoteZ_TCP : public CRemoteZ_Base
 {
 protected:
+       int TCPSendAndCheck(uint8_t cmd, uint32_t len=0, uint8_t *data=NULL);
        virtual int Write(uint8_t typ, uint8_t cmd, uint32_t len=0,
                uint8_t *data=NULL);
        virtual int Read(uint8_t &status, uint32_t &len, uint8_t *data);
@@ -329,6 +341,12 @@ protected:
 public:
        CRemoteZ_TCP() {};
        virtual ~CRemoteZ_TCP() {};
+       int UpdateConfig(const uint32_t len, const uint8_t *wr,
+               lc_callback cb, void *cb_arg, uint32_t cb_stage);
+       int GetTime(const TRemoteInfo &ri, THarmonyTime &ht);
+       int SetTime(const TRemoteInfo &ri, const THarmonyTime &ht,
+               lc_callback cb=NULL, void *cb_arg=NULL, uint32_t cb_stage=NULL);
+       int IsUSBNet() {return true;}
 };

 #endif //REMOTE_H
Index: libconcord/remote_info.h
===================================================================
RCS file: /cvsroot/concordance/concordance/libconcord/remote_info.h,v
retrieving revision 1.12.2.1
diff -u -p -r1.12.2.1 remote_info.h
--- libconcord/remote_info.h    13 Mar 2011 09:40:50 -0000      1.12.2.1
+++ libconcord/remote_info.h    11 Mar 2012 01:54:59 -0000
@@ -92,7 +92,7 @@ static const TModel ModelList[]={
        { MFG_UNK,      "Unknown",                      NULL },
        { MFG_UNK,      "Unknown",                      NULL },
        { MFG_UNK,      "Unknown",                      NULL },                 
// 60
-       { MFG_UNK,      "Unknown",                      NULL },
+       { MFG_HAR,      "Harmony 900",                  NULL },
        { MFG_UNK,      "Unknown",                      NULL },
        { MFG_UNK,      "Unknown",                      NULL },
        { MFG_UNK,      "Unknown",                      NULL },
@@ -416,6 +416,24 @@ static const TArchInfo ArchList[]={
                0,                              // ram_size
                0,                              // eeprom_size
                "Internal",                     // usb
+       },
+       /* arch 15 - usbnet (e.g., 900) */
+       {
+               0,                              // serial_location
+               0,                              // serial_address
+               0,                              // flash_base
+               0,                              // firmware_base
+               0,                              // config_base
+               0,                              // firmware_update_base
+               0,                              // firmware_4847_offset
+               0x1, /* hack to make config test pass */        // cookie
+               0,                              // cookie_size
+               0,                              // end_vector
+               "",                             // micro
+               0,                              // flash_size
+               0,                              // ram_size
+               0,                              // eeprom_size
+               "",                             // usb
        }
 };

Index: libconcord/remote_z.cpp
===================================================================
RCS file: /cvsroot/concordance/concordance/libconcord/remote_z.cpp,v
retrieving revision 1.25.2.14
diff -u -p -r1.25.2.14 remote_z.cpp
--- libconcord/remote_z.cpp     19 Sep 2010 16:06:25 -0000      1.25.2.14
+++ libconcord/remote_z.cpp     11 Mar 2012 01:54:59 -0000
@@ -271,7 +271,10 @@ int CRemoteZ_HID::ParseParams(uint32_t l
 int CRemoteZ_TCP::Write(uint8_t typ, uint8_t cmd, uint32_t len,
        uint8_t *data)
 {
-       if (len > 60) {
+       /* Largest packet size for usbnet is the COMMAND_WRITE_UPDATE_DATA
+          which is 1 (num params) + 3 (3 parameter size bytes) + 1 (param 1)
+          + 1024 (param 2) + 4 (param 3) = 1033. */
+       if (len > 1033) {
                return LC_ERROR;
        }

@@ -279,7 +282,7 @@ int CRemoteZ_TCP::Write(uint8_t typ, uin
        const bool request = (typ == TYPE_REQUEST);
        const uint8_t status = STATUS_OK;

-       uint8_t pkt[68];
+       uint8_t pkt[1036]; /* largest packet (1033) + standard 3-byte header */
        pkt[0] = service_type << 4 | (cmd >> 8) & 0x0F;
        pkt[1] = cmd & 0xFF;
        pkt[2] = request ? 0x80 : (status & 0x7F);
@@ -343,6 +346,239 @@ int CRemoteZ_TCP::ParseParams(uint32_t l
        return 0;
 }

+int CRemoteZ_TCP::TCPSendAndCheck(uint8_t cmd, uint32_t len, uint8_t *data)
+{
+       int err = 0;
+       uint8_t status;
+       unsigned int rlen;
+       uint8_t rsp[60];
+
+       if ((err = Write(TYPE_REQUEST, cmd, len, data))) {
+               debug("Failed to send request %02X", cmd);
+               return LC_ERROR_WRITE;
+       }
+
+       if ((err = Read(status, rlen, rsp))) {
+               debug("Failed to read from remote");
+               return LC_ERROR_READ;
+       }
+
+       if (rsp[2] != TYPE_RESPONSE) {
+               debug("Packet didn't have response bit!");
+               return LC_ERROR;
+       }
+
+       if (rsp[1] != cmd) {
+               debug("The cmd bit didn't match our request packet");
+               return LC_ERROR;
+       }
+
+       return 0;
+}
+
+int CRemoteZ_TCP::UpdateConfig(const uint32_t len, const uint8_t *wr,
+       lc_callback cb, void *arg, uint32_t cb_stage)
+{
+       int err = 0;
+       int cb_count = 0;
+       uint8_t rsp[60];
+       unsigned int rlen;
+       uint8_t status;
+
+       cb(LC_CB_STAGE_INITIALIZE_UPDATE, cb_count++, 0, 2,
+               LC_CB_COUNTER_TYPE_STEPS, arg);
+
+       /* ACK it with a command to start an update */
+       debug("START_UPDATE");
+       // 2 parameters, each 1 byte.
+       // 1st parameter "flags" seems to always be 0.
+       uint8_t cmd[60] = { 0x02, 0x01, 0x00, 0x01, REGION_USER_CONFIG };
+       if ((err = TCPSendAndCheck(COMMAND_START_UPDATE, 5, cmd))) {
+               return err;
+       }
+
+       cb(LC_CB_STAGE_INITIALIZE_UPDATE, cb_count++, 1, 2,
+               LC_CB_COUNTER_TYPE_STEPS, arg);
+
+       /* write update-header */
+       debug("UPDATE_HEADER");
+       cmd[0] = 0x02; // 2 parameters
+       cmd[1] = 0x04; // 1st parameter 4 bytes (size)
+       cmd[2] = (len & 0xFF000000) >> 24; 
+       cmd[3] = (len & 0x00FF0000) >> 16;
+       cmd[4] = (len & 0x0000FF00) >> 8;
+       cmd[5] = (len & 0x000000FF);
+       cmd[6] = 0x01; // 2nd parameter 1 byte (region id)
+       cmd[7] = REGION_USER_CONFIG;
+       if ((err = TCPSendAndCheck(COMMAND_WRITE_UPDATE_HEADER, 8, cmd))) {
+               return err;
+       }
+
+       cb(LC_CB_STAGE_INITIALIZE_UPDATE, cb_count++, 2, 2,
+               LC_CB_COUNTER_TYPE_STEPS, arg);
+       cb_count = 0;
+
+       /* write data */
+       debug("UPDATE_DATA");
+       uint32_t pkt_len;
+       int tlen = len;
+       int bytes_written = 0;
+       uint8_t *wr_ptr = const_cast<uint8_t*>(wr);
+       uint8_t tmp_pkt[1033];
+       tmp_pkt[0] = 0x03; // 3 parameters
+       tmp_pkt[1] = 0x01; // 1st parameter, 1 byte (region id)
+       tmp_pkt[2] = REGION_USER_CONFIG;
+       tmp_pkt[3] = 0xC2; // 2nd parameter, 1024 bytes (data)
+       tmp_pkt[1028] = 0x04; // 3rd parameter, 4 bytes (length)
+       while (tlen) {
+               pkt_len = 1024; // max packet length seems to be 1024
+               if (tlen < pkt_len) {
+                       pkt_len = tlen;
+               }
+               tlen -= pkt_len;
+
+               memcpy(&tmp_pkt[4], wr_ptr, pkt_len);
+               tmp_pkt[1029] = (pkt_len & 0xFF000000) >> 24;
+               tmp_pkt[1030] = (pkt_len & 0x00FF0000) >> 16;
+               tmp_pkt[1031] = (pkt_len & 0x0000FF00) >> 8;
+               tmp_pkt[1032] = (pkt_len & 0x000000FF);
+
+               debug("DATA %d, sending %d bytes, %d bytes left", cb_count,
+                       pkt_len, tlen);
+
+               if ((err = TCPSendAndCheck(COMMAND_WRITE_UPDATE_DATA, 1033,
+                       tmp_pkt))) {
+                       return err;
+               }
+               wr_ptr += pkt_len;
+
+               if (cb) {
+                       cb(LC_CB_STAGE_WRITE_CONFIG, cb_count++,
+                               (int)(wr_ptr - wr), len,
+                               LC_CB_COUNTER_TYPE_BYTES, arg);
+               }
+       }
+
+       /* write update-done */
+       cb_count = 0;
+       cb(LC_CB_STAGE_FINALIZE_UPDATE, cb_count++, 0, 3,
+               LC_CB_COUNTER_TYPE_STEPS, arg);
+
+       debug("UPDATE_DATA_DONE");
+       cmd[0] = 0x01; // 1 parameter
+       cmd[1] = 0x01; // 1st parameter 1 byte (region id)
+       cmd[2] = REGION_USER_CONFIG;
+       if ((err = TCPSendAndCheck(COMMAND_WRITE_UPDATE_DATA_DONE, 3, cmd))) {
+               return err;
+       }
+
+       cb(LC_CB_STAGE_FINALIZE_UPDATE, cb_count++, 1, 3,
+               LC_CB_COUNTER_TYPE_STEPS, arg);
+
+       /* send get-cheksum */
+       debug("GET_CHECKSUM");
+       cmd[0] = 0x02; // 2 parameters
+       cmd[1] = 0x02; // 1st parameter 2 bytes (seed)
+       cmd[2] = 0xFF; // seed seems to always be FF
+       cmd[3] = 0xFF; // seed seems to always be FF
+       cmd[4] = 0x01; // 2nd parameter 1 byte (region id)
+       cmd[5] = REGION_USER_CONFIG;
+       if ((err = TCPSendAndCheck(COMMAND_GET_UPDATE_CHECKSUM, 6, cmd))) {
+               return err;
+       }
+
+       cb(LC_CB_STAGE_FINALIZE_UPDATE, cb_count++, 2, 3,
+               LC_CB_COUNTER_TYPE_STEPS, arg);
+
+       /* send finish-update */
+       debug("FINISH_UPDATE");
+       cmd[0] = 0x02; // 2 parameters
+       cmd[1] = 0x01; // 1st parameter 1 byte (validate)
+       cmd[2] = 0x01; // validate?
+       cmd[3] = 0x01; // 2nd parameter 1 byte (region id)
+       cmd[4] = REGION_USER_CONFIG;
+       if ((err = TCPSendAndCheck(COMMAND_FINISH_UPDATE, 5, cmd))) {
+               return err;
+       }
+
+       cb(LC_CB_STAGE_FINALIZE_UPDATE, cb_count++, 3, 3,
+               LC_CB_COUNTER_TYPE_STEPS, arg);
+
+       return 0;
+}
+
+int CRemoteZ_TCP::GetTime(const TRemoteInfo &ri, THarmonyTime &ht)
+{
+       int err = 0;
+       if ((err = Write(TYPE_REQUEST, COMMAND_GET_CURRENT_TIME))) {
+               debug("Failed to write to remote");
+               return LC_ERROR_WRITE;
+       }
+       uint8_t time[60];
+       unsigned int len;
+       uint8_t status;
+       if ((err = Read(status, len, time))) {
+               debug("Failed to read to remote");
+               return LC_ERROR_READ;
+       }
+
+       if (time[2] != TYPE_RESPONSE || time[1] != COMMAND_GET_CURRENT_TIME) {
+               debug("Incorrect response type from Get Time");
+               return LC_ERROR_INVALID_DATA_FROM_REMOTE;
+       }
+
+       CRemoteZ_Base::TParamList pl;
+       ParseParams(len, time, pl);
+
+       ht.year = GetWord(pl.p[0]);
+       ht.month = *pl.p[1];
+       ht.day = *pl.p[2];
+       ht.hour = *pl.p[3];
+       ht.minute = *pl.p[4];
+       ht.second = *pl.p[5];
+       ht.dow = *pl.p[6]&7;
+       ht.utc_offset = static_cast<int16_t>(GetWord(pl.p[7]));
+       if (pl.count > 11) {
+               ht.timezone = reinterpret_cast<char*>(pl.p[11]);
+               ht.timezone[3] = '\0';
+       } else {
+               ht.timezone = "";
+       }
+
+       return 0;
+}
+
+int CRemoteZ_TCP::SetTime(const TRemoteInfo &ri, const THarmonyTime &ht,
+       lc_callback cb, void *cb_arg, uint32_t cb_stage)
+{
+       debug("SetTime");
+       int err = 0;
+
+       uint8_t tsv[32] = {
+               0x0C, // 12 parameters
+               0x02, ht.year >> 8, ht.year, // 2 bytes
+               0x01, ht.month,
+               0x01, ht.day,
+               0x01, ht.hour,
+               0x01, ht.minute,
+               0x01, ht.second,
+               0x01, ht.dow,
+               // utcOffset
+               0x02, 0, 0, // 2 bytes - 900 doesn't seem to accept this
+               // 0s
+               0x02, 0, 0, // 2 bytes
+               0x02, 0, 0, // 2 bytes
+               0x02, 0, 0, // 2 bytes
+               0x83, 0, 0, 0 // 900 doesn't seem to accept this, don't bother
+               };
+
+       if ((err = TCPSendAndCheck(COMMAND_UPDATE_TIME, 32, tsv))) {
+               debug("Failed to write to remote");
+               return err;
+       }
+
+       return 0;
+}

 int CRemoteZ_Base::Reset(uint8_t kind)
 {
@@ -414,8 +650,8 @@ int CRemoteZ_Base::GetIdentity(TRemoteIn
                hid.frl = 0;
                hid.mfg = "Logitech";
                hid.prod = "Harmony 1000";
-               ri.flash_mfg = 0;       // todo
-               ri.flash_id = 0;        // todo
+               ri.flash_mfg = 0x01; // Seems to be the same as regular zwave
+               ri.flash_id = 0x49;  // Seems to be the same as regular zwave
        } else {                                // Not 1000
                ri.flash_mfg = 0x01;// todo
                ri.flash_id = 0x49;     // todo
@@ -428,10 +664,10 @@ int CRemoteZ_Base::GetIdentity(TRemoteIn
        const unsigned int hw = GetWord(pl.p[7]);
        ri.hw_ver_major = hw >> 8;              // ???
        ri.hw_ver_minor = (hw >> 4) & 0x0F;     // ???
-       // hw_ver_micro = hw & 0x0F             // ???
+       ri.hw_ver_micro = hw & 0x0F;            // 900 has this and is non-zero
        //ri.hw_ver_major = hw >> 4;
        //ri.hw_ver_minor = hw & 0x0F;
-       ri.protocol = 0;
+       ri.protocol = GetWord(pl.p[2]); // Seems to be the same as arch?

        setup_ri_pointers(ri);

@@ -457,7 +693,12 @@ int CRemoteZ_Base::GetIdentity(TRemoteIn
        ri.max_config_size = 1;
        ri.valid_config = 1;

-#if 0  // Get region info - 1000 only!
+       if (!IsUSBNet()) {
+               return 0;
+       }
+ 
+       // Get region info - everything below is extra stuff that only the
+       // usbnet remotes seem to use.
        uint8_t rr[] = { 1, 1, 1 }; // AddByteParam(1);
        if ((err = Write(TYPE_REQUEST, COMMAND_GET_REGION_IDS, 3, rr))) {
                debug("Failed to write to remote");
@@ -471,9 +712,33 @@ int CRemoteZ_Base::GetIdentity(TRemoteIn
        ParseParams(len, rgn, pl);
        if (pl.count == 1) {
                const unsigned int rc = *(pl.p[0]-1) & 0x3F;
+               ri.num_regions = rc + 1;
+               ri.region_ids = new uint8_t[ri.num_regions];
+               ri.region_versions = new char*[ri.num_regions];
+
+               // There seems to be an implied Region 0 that the Windows
+               // software requests but it is not listed in the Region IDs.
+               uint8_t rz[] = { 1, 1, 0 }; // 1 parameter, 1 byte, value = 0
+               if ((err = Write(TYPE_REQUEST,
+                               COMMAND_GET_REGION_VERSION, 3, rz))) {
+                       debug("Failed to write to remote");
+                       return LC_ERROR;
+               }
+               uint8_t rgz[64];
+               if ((err = Read(status, len, rgz))) {
+                       debug("Failed to read from remote");
+                       return LC_ERROR;
+               }
+               CRemoteZ_Base::TParamList rzp;
+               ParseParams(len, rgz, rzp);
+               ri.region_ids[0] = 0x00; // Store region 0.
+               ri.region_versions[0] = new char[4];
+               snprintf(ri.region_versions[0], 4, "%d.%d", *(rzp.p[0]+1),
+                        *rzp.p[0]);
+
                for(unsigned int r = 0; r < rc; ++r) {
                        const uint8_t rn = *(pl.p[0]+r);
-                       printf("Region %i\n", rn);
+                       debug("Region %i", rn);
                        uint8_t rv[] = { 1, 1, rn }; // AddByteParam(rn);
                        if ((err = Write(TYPE_REQUEST,
                                        COMMAND_GET_REGION_VERSION, 3, rv))) {
@@ -487,10 +752,61 @@ int CRemoteZ_Base::GetIdentity(TRemoteIn
                        }
                        CRemoteZ_Base::TParamList rp;
                        ParseParams(len, rgv, rp);
+                       ri.region_ids[r+1] = rn;
+                       ri.region_versions[r+1] = new char[4];
+                       snprintf(ri.region_versions[r+1], 4, "%d.%d",
+                                *(rp.p[0]+1), *rp.p[0]);
                }
        }
-#endif

+       // Get HOMEID, NODEID, TID
+       if ((err = Write(TYPE_REQUEST, COMMAND_GET_HOME_ID))) {
+               debug("Failed to write to remote");
+               return LC_ERROR;
+       }
+       if ((err = Read(status, len, rsp))) {
+               debug("Failed to read from remote");
+               return LC_ERROR;
+       }
+       ParseParams(len, rsp, pl);
+       ri.home_id = (*pl.p[0] << 24) + (*(pl.p[0]+1) << 16) +
+                       (*(pl.p[0]+2) << 8) + *(pl.p[0]+3);
+       if ((err = Write(TYPE_REQUEST, COMMAND_GET_NODE_ID))) {
+               debug("Failed to write to remote");
+               return LC_ERROR;
+       }
+       if ((err = Read(status, len, rsp))) {
+               debug("Failed to read from remote");
+               return LC_ERROR;
+       }
+       ParseParams(len, rsp, pl);
+       ri.node_id = *pl.p[0];
+       // Get the "TID" - not entirely sure what this is, but it appears to be
+       // contained in the INTERFACE_LIST.
+       if ((err = Write(TYPE_REQUEST, COMMAND_GET_INTERFACE_LIST))) {
+               debug("Failed to write to remote");
+               return LC_ERROR;
+       }
+       if ((err = Read(status, len, rsp))) {
+               debug("Failed to read from remote");
+               return LC_ERROR;
+       }
+       ParseParams(len, rsp, pl);
+       ri.tid = new char[21];
+       ri.tid[0] = '0';
+       ri.tid[1] = 'x';
+       // "TID" appears to be contained in the middle of the INTERFACE_LIST.
+       for (int i=0; i<9; i++)
+               snprintf(&ri.tid[(i*2)+2], 3, "%02X", *(pl.p[1]+i+2));
+       ri.tid[20] = '\0';
+
+       // Get the "XMLUserRFSetting" - the usbnet remote appears to have a web
+       // server running where the Windows driver grabs this data.
+       if (err = GetXMLUserRFSetting(&ri.xml_user_rf_setting)) {
+               debug("Failed to read XML User RF Settings");
+               return LC_ERROR;
+       }
+
        return 0;
 }

Index: libconcord/usblan.cpp
===================================================================
RCS file: /cvsroot/concordance/concordance/libconcord/usblan.cpp,v
retrieving revision 1.13.2.1
diff -u -p -r1.13.2.1 usblan.cpp
--- libconcord/usblan.cpp       19 Sep 2010 16:06:25 -0000      1.13.2.1
+++ libconcord/usblan.cpp       11 Mar 2012 01:54:59 -0000
@@ -48,6 +48,12 @@ static SOCKET sock = SOCKET_ERROR;
 const char * const remote_ip_address = "169.254.1.2";
 const u_short remote_port            = 3074;

+const char * const http_get_cmd = "\
+GET /xmluserrfsetting HTTP/1.1\r\n\
+User-Agent: Jakarta Commons-HttpClient/3.1\r\n\
+Host: 169.254.1.2\r\n\
+\r\n";
+
 int InitializeUsbLan(void)
 {
        return 0;
@@ -127,3 +133,63 @@ int UsbLan_Read(unsigned int &len, uint8

        return 0;
 }
+
+int GetXMLUserRFSetting(char **data)
+{
+       int err;
+       int web_sock;
+       char buf[4096];
+
+       hostent* addr = gethostbyname(remote_ip_address);
+
+       if (!addr) {
+               report_net_error("gethostbyname()");
+               return LC_ERROR_OS_NET;
+       }
+
+       sockaddr_in sa;
+       memcpy(&(sa.sin_addr), addr->h_addr, addr->h_length);
+       sa.sin_family = AF_INET;                // TCP/IP
+       sa.sin_port = htons(80);                // Web Server port
+
+       web_sock = socket(sa.sin_family, SOCK_STREAM, 0);       // TCP
+
+       if ((err = connect(web_sock,(struct sockaddr*)&sa,sizeof(sa)))) {
+               report_net_error("connect()");
+               return LC_ERROR_OS_NET;
+       }
+       debug("Connected to USB LAN web server!");
+
+       err = send(web_sock, http_get_cmd, strlen(http_get_cmd), 0);
+       if (err == SOCKET_ERROR) {
+               report_net_error("send()");
+               return LC_ERROR_OS_NET;
+       }
+       debug("%i bytes sent", err);
+
+       unsigned int len = 0;
+       char* buf_ptr = buf;
+       do {
+               err = recv(web_sock, buf_ptr, sizeof(buf)-len, 0);
+               if (err == SOCKET_ERROR) {
+                       report_net_error("recv()");
+                       len = 0;
+                       return LC_ERROR_OS_NET;
+               }
+               len += err;
+               buf_ptr += err;
+               debug("%i bytes received", err);
+       } while (err > 0); // recv will return 0 when the message is done.
+       buf[len] = '\0';
+
+       buf_ptr = strstr(buf, "\r\n\r\n"); // search for end of the http header
+       if (buf_ptr == NULL) {
+               report_net_error("strstr()");
+               return LC_ERROR_OS_NET;
+       }
+       buf_ptr += 4;
+       *data = new char[strlen(buf_ptr)+1];
+       strncpy(*data, buf_ptr, strlen(buf_ptr)+1);
+
+       return 0;
+}
Index: libconcord/usblan.h
===================================================================
RCS file: /cvsroot/concordance/concordance/libconcord/usblan.h,v
retrieving revision 1.5.2.1
diff -u -p -r1.5.2.1 usblan.h
--- libconcord/usblan.h 19 Sep 2010 16:06:25 -0000      1.5.2.1
+++ libconcord/usblan.h 11 Mar 2012 01:54:59 -0000
@@ -30,5 +30,6 @@ int ShutdownUsbLan(void);
 int FindUsbLanRemote(void);
 int UsbLan_Write(unsigned int len, uint8_t *data);
 int UsbLan_Read(unsigned int &len, uint8_t *data);
+int GetXMLUserRFSetting(char **data);

 #endif
Index: libconcord/web.cpp
===================================================================
RCS file: /cvsroot/concordance/concordance/libconcord/web.cpp,v
retrieving revision 1.27.2.2
diff -u -p -r1.27.2.2 web.cpp
--- libconcord/web.cpp  18 Sep 2010 14:14:54 -0000      1.27.2.2
+++ libconcord/web.cpp  11 Mar 2012 01:54:59 -0000
@@ -256,6 +256,19 @@ int encode_ir_signal(uint32_t carrier_cl
        return 0;
 }

+int add_usbnet_headers(char *post_data, TRemoteInfo &ri)
+{
+       sprintf(post_data+strlen(post_data), post_xml_usbnet1, ri.home_id, 
+               ri.node_id, ri.tid);
+       for (int i=0; i<ri.num_regions; i++) {
+               sprintf(post_data+strlen(post_data),
+                       post_xml_usbnet_region, ri.region_ids[i],
+                       ri.region_versions[i]);
+       }
+       sprintf(post_data+strlen(post_data), "%s", post_xml_usbnet2);
+       sprintf(post_data+strlen(post_data), "%s", ri.xml_user_rf_setting);
+       sprintf(post_data+strlen(post_data), "%s", post_xml_usbnet3);
+}

 int Post(uint8_t *xml, uint32_t xml_size, const char *root, TRemoteInfo &ri,
        bool has_userid, bool add_cookiekeyval, bool z_post,
@@ -301,7 +314,7 @@ int Post(uint8_t *xml, uint32_t xml_size
        if (learn_seq == NULL) {
                char serial[144];
                sprintf(serial, "%s%s%s", ri.serial1, ri.serial2, ri.serial3);
-               char post_data[2000];
+               char post_data[4000]; // large enough for extra usbnet headers
                if (z_post) {
                        sprintf(post_data, z_post_xml,
                                ri.hw_ver_major, ri.hw_ver_minor,
@@ -311,8 +324,14 @@ int Post(uint8_t *xml, uint32_t xml_size
                        sprintf(post_data, post_xml,
                                ri.fw_ver_major, ri.fw_ver_minor, ri.fw_type,
                                serial, ri.hw_ver_major, ri.hw_ver_minor,
-                               ri.flash_mfg, ri.flash_id, ri.protocol,
-                               ri.architecture, ri.skin);
+                               ri.hw_ver_micro, ri.flash_mfg, ri.flash_id,
+                               ri.protocol, ri.architecture, ri.skin);
+                       if (is_usbnet_remote()) {
+                               add_usbnet_headers(post_data, ri);
+                       } else {
+                               sprintf(post_data+strlen(post_data), "%s", 
+                                       post_xml_trailer);
+                       }
                }

                debug("post data: %s",post_data);
Index: libconcord/xml_headers.h
===================================================================
RCS file: /cvsroot/concordance/concordance/libconcord/xml_headers.h,v
retrieving revision 1.7.2.1
diff -u -p -r1.7.2.1 xml_headers.h
--- libconcord/xml_headers.h    25 Aug 2010 22:27:22 -0000      1.7.2.1
+++ libconcord/xml_headers.h    11 Mar 2012 01:54:59 -0000
@@ -153,16 +153,36 @@ const char *post_xml="\
 <SOFTWARE>%i.%i</SOFTWARE>\
 <SOFTWARETYPE>%i</SOFTWARETYPE>\
 <ID>%s</ID>\
-<BOARD>%i.%i.0</BOARD>\
+<BOARD>%i.%i.%i</BOARD>\
 <FLASH>0x%02X:0x%02X</FLASH>\
 <PROTOCOL>%i</PROTOCOL>\
 <ARCHITECTURE>%i</ARCHITECTURE>\
-<SKIN>%i</SKIN>\
+<SKIN>%i</SKIN>";
+
+const char *post_xml_trailer="\
 <REGIONS/>\
 </VERSION>\
 </VERSIONINFORMATION>\
 </EASYZAPPERDATA>\r\n";

+const char *post_xml_usbnet1="\
+<HOMEID>0x%08X</HOMEID>\
+<NODEID>%i</NODEID>\
+<TID>%s</TID>\
+<FIRMWARE>";
+
+const char *post_xml_usbnet_region="\
+<REGION ID=\"%i\">%s</REGION>";
+
+const char *post_xml_usbnet2="\
+</FIRMWARE>\
+<REGIONS/>\
+</VERSION>\
+</VERSIONINFORMATION>";
+
+const char *post_xml_usbnet3="\
+</EASYZAPPERDATA>";
+
 const char *z_post_xml="\
 <DATA>\
 <STATUS>Success</STATUS>\
Index: libconcord/libusb/libusbhid.cpp
===================================================================
RCS file: /cvsroot/concordance/concordance/libconcord/libusb/libusbhid.cpp,v
retrieving revision 1.19
diff -u -p -r1.19 libusbhid.cpp
--- libconcord/libusb/libusbhid.cpp     17 Jul 2010 22:17:37 -0000      1.19
+++ libconcord/libusb/libusbhid.cpp     11 Mar 2012 01:54:59 -0000
@@ -135,6 +135,11 @@ int FindRemote(THIDINFO &hid_info)
        }

 #ifdef linux
+       /* If this is a usbnet remote, abort before trying to detach drivers */
+       if (h_dev && (h_dev->descriptor.idProduct == 0xC11F)) {
+               return LC_ERROR_CONNECT;
+       }
+
        /*
         * Before we attempt to claim the interface, lets go ahead and get
         * the kernel off of it, in case it claimed it already.

------------------------------------------------------------------------------
Virtualization & Cloud Management Using Capacity Planning
Cloud computing makes use of virtualization - but cloud computing 
also focuses on allowing computing to be delivered as a service.
http://www.accelacomm.com/jaw/sfnl/114/51521223/
_______________________________________________
concordance-devel mailing list
concordance-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/concordance-devel

Reply via email to