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