The Harmony Link is an MH "remote." Essentially it is a WiFi to IR bridge where you can issue commands on your smartphone via WiFI and the Link will convert them to IR to control your devices. In order to support the Link, we had to add a few API calls to allow configuration of WiFI (SSID, key, etc) as well as account configuration (email, etc). The Link does not receive its configuration via USB like other remotes - it receives it via WiFi.
Signed-off-by: Scott Talbert <s...@techie.net> --- Updates in v3: * Addressed Phil's comments on v2 - changed mh_get_value function to take just the key rather than the key plus the comma. * Made some changes to ReadFile() that make communication with the Link more reliable. * Added call to ReadFile() in GetIdentity() and removed a bit of code that was essentially doing the same thing. I should also be able to re-use ReadFile() for config dumping as well. It would be good if this could get faster turnaround. I would like to get David his Link back at some point. libconcord/bindings/python/libconcord.py | 82 ++++++++ libconcord/libconcord.cpp | 151 +++++++++++++++ libconcord/libconcord.h | 32 ++++ libconcord/remote.cpp | 11 ++ libconcord/remote.h | 18 ++ libconcord/remote_info.h | 18 ++ libconcord/remote_mh.cpp | 318 +++++++++++++++++++++++++------ libconcord/remote_z.cpp | 13 ++ specs/protocol_mh.txt | 4 + 9 files changed, 592 insertions(+), 55 deletions(-) diff --git a/libconcord/bindings/python/libconcord.py b/libconcord/bindings/python/libconcord.py index 1138a33..e0a2664 100644 --- a/libconcord/bindings/python/libconcord.py +++ b/libconcord/bindings/python/libconcord.py @@ -891,3 +891,85 @@ post_new_code = _create_func( _in('cb_arg', py_object) ) +#define MH_STRING_LENGTH 255 /* arbitrary */ +MH_STRING_LENGTH = 255 + +#define MH_MAX_WIFI_NETWORKS 30 /* arbitrary */ +MH_MAX_WIFI_NETWORKS = 30 + +#struct mh_cfg_properties { +# char host_name[MH_STRING_LENGTH]; +# char email[MH_STRING_LENGTH]; +# char service_link[MH_STRING_LENGTH]; +#}; +class mh_cfg_properties(Structure): + _fields_ = [("host_name", c_char * MH_STRING_LENGTH), + ("email", c_char * MH_STRING_LENGTH), + ("service_link", c_char * MH_STRING_LENGTH)] + +#struct mh_wifi_config { +# char ssid[MH_STRING_LENGTH]; +# char encryption[MH_STRING_LENGTH]; +# char password[MH_STRING_LENGTH]; +# char connect_status[MH_STRING_LENGTH]; +# char error_code[MH_STRING_LENGTH]; +#}; +class mh_wifi_config(Structure): + _fields_ = [("ssid", c_char * MH_STRING_LENGTH), + ("encryption", c_char * MH_STRING_LENGTH), + ("password", c_char * MH_STRING_LENGTH), + ("connect_status", c_char * MH_STRING_LENGTH), + ("error_code", c_char * MH_STRING_LENGTH)] + +#struct mh_wifi_network { +# char ssid[MH_STRING_LENGTH]; +# char signal_strength[MH_STRING_LENGTH]; +# char channel[MH_STRING_LENGTH]; +# char encryption[MH_STRING_LENGTH]; +#}; +class mh_wifi_network(Structure): + _fields_ = [("ssid", c_char * MH_STRING_LENGTH), + ("signal_strength", c_char * MH_STRING_LENGTH), + ("channel", c_char * MH_STRING_LENGTH), + ("encryption", c_char * MH_STRING_LENGTH)] + +#struct mh_wifi_networks { +# struct mh_wifi_network network[MH_MAX_WIFI_NETWORKS]; +#}; +class mh_wifi_networks(Structure): + _fields_ = [("network", mh_wifi_network * MH_MAX_WIFI_NETWORKS)] + +#int mh_get_cfg_properties(struct mh_cfg_properties *properties); +mh_get_cfg_properties = _create_func( + 'mh_get_cfg_properties', + _ret_lc_concord(), + _in('properties', POINTER(mh_cfg_properties)) +) + +#int mh_set_cfg_properties(const struct mh_cfg_properties *properties); +mh_set_cfg_properties = _create_func( + 'mh_set_cfg_properties', + _ret_lc_concord(), + _in('properties', POINTER(mh_cfg_properties)) +) + +#int mh_get_wifi_networks(struct mh_wifi_networks *networks); +mh_get_wifi_networks = _create_func( + 'mh_get_wifi_networks', + _ret_lc_concord(), + _in('networks', POINTER(mh_wifi_networks)) +) + +#int mh_get_wifi_config(struct mh_wifi_config *config); +mh_get_wifi_config = _create_func( + 'mh_get_wifi_config', + _ret_lc_concord(), + _in('config', POINTER(mh_wifi_config)) +) + +#int mh_set_wifi_config(const struct mh_wifi_config *config); +mh_set_wifi_config = _create_func( + 'mh_set_wifi_config', + _ret_lc_concord(), + _in('config', POINTER(mh_wifi_config)) +) diff --git a/libconcord/libconcord.cpp b/libconcord/libconcord.cpp index 3cb2611..82b3afe 100644 --- a/libconcord/libconcord.cpp +++ b/libconcord/libconcord.cpp @@ -230,6 +230,7 @@ int is_mh_pid(unsigned int pid) switch (pid) { case 0xC124: /* Harmony 300 */ case 0xC125: /* Harmony 200 */ + case 0xC126: /* Harmony Link */ return 1; default: return 0; @@ -1696,6 +1697,156 @@ int post_new_code(char *key_name, char *encoded_signal, lc_callback cb, } /* + * Special structures and methods for the Harmony Link + */ +/* + * Given a buffer holding key-value pairs of the form + * + * key1,val1 + * key2,val2 + * + * Will find the key passed in and copy the value on the other side of the + * comma into dest. + */ +void mh_get_value(char *buffer, const char *key, char *dest) +{ + char *start = NULL; + char *end = NULL; + int len; + std::string key_str(key); + key_str += ","; + start = strstr(buffer, key_str.c_str()); + if (start) { + start += key_str.length(); + end = strstr(start, "\n"); + if (end) { + len = end - start; + if (len >= MH_STRING_LENGTH) + start = NULL; + } + } + if (start && end) + strncpy(dest, start, len); +} + +int mh_get_cfg_properties(struct mh_cfg_properties *properties) +{ + if (!is_mh_remote()) + return LC_ERROR; + + int err; + int buflen = 5000; + char buffer[buflen]; + int data_read; + if (err = rmt->ReadFile("/cfg/properties", (uint8_t*)buffer, buflen, + &data_read)) + return err; + + mh_get_value(buffer, "host_name", properties->host_name); + mh_get_value(buffer, "account_email", properties->email); + mh_get_value(buffer, "discovery_service_link", properties->service_link); + + return 0; +} + +int mh_set_cfg_properties(const struct mh_cfg_properties *properties) +{ + if (!is_mh_remote()) + return LC_ERROR; + + int err; + std::string str_buffer; + str_buffer += "host_name,"; + str_buffer += properties->host_name; + str_buffer += "\n"; + str_buffer += "account_email,"; + str_buffer += properties->email; + str_buffer += "\n"; + str_buffer += "discovery_service_link,"; + str_buffer += properties->service_link; + str_buffer += "\n"; + + err = rmt->WriteFile("/cfg/properties", (uint8_t*)str_buffer.c_str(), + strlen(str_buffer.c_str())); + return err; +} + +int mh_get_wifi_networks(struct mh_wifi_networks *networks) +{ + if (!is_mh_remote()) + return LC_ERROR; + + int err; + int buflen = 5000; + char buffer[buflen]; + int data_read; + if (err = rmt->ReadFile("/sys/wifi/networks", (uint8_t*)buffer, buflen, + &data_read)) + return err; + + char *buf_ptr = buffer; + int i = 0; + while (strstr(buf_ptr, "item,") && (i < MH_MAX_WIFI_NETWORKS)) { + mh_get_value(buf_ptr, "ssid", networks->network[i].ssid); + mh_get_value(buf_ptr, "signal_strength", + networks->network[i].signal_strength); + mh_get_value(buf_ptr, "channel", networks->network[i].channel); + mh_get_value(buf_ptr, "encryption", networks->network[i].encryption); + buf_ptr = strstr(buf_ptr, "encryption,"); + if (buf_ptr) + buf_ptr = strstr(buf_ptr, "\n"); + i++; + } + + return 0; +} + +int mh_get_wifi_config(struct mh_wifi_config *config) +{ + if (!is_mh_remote()) + return LC_ERROR; + + int err; + int buflen = 5000; + char buffer[buflen]; + int data_read; + if (err = rmt->ReadFile("/sys/wifi/connect", (uint8_t*)buffer, buflen, + &data_read)) + return err; + + mh_get_value(buffer, "ssid", config->ssid); + mh_get_value(buffer, "encryption", config->encryption); + mh_get_value(buffer, "password", config->password); + mh_get_value(buffer, "connect_status", config->connect_status); + mh_get_value(buffer, "error_code", config->error_code); + + return 0; +} + +int mh_set_wifi_config(const struct mh_wifi_config *config) +{ + if (!is_mh_remote()) + return LC_ERROR; + + int err; + std::string str_buffer; + str_buffer += "ssid,"; + str_buffer += config->ssid; + str_buffer += "\n"; + str_buffer += "encryption,"; + str_buffer += config->encryption; + str_buffer += "\n"; + str_buffer += "user,\n"; /* not sure what this is - appears unused */ + str_buffer += "password,"; + str_buffer += config->password; + str_buffer += "\n"; + + err = rmt->WriteFile("/sys/wifi/connect", (uint8_t*)str_buffer.c_str(), + strlen(str_buffer.c_str())); + return err; +} + +/* * PRIVATE-SHARED INTERNAL FUNCTIONS * These are functions used by the whole library but are NOT part of the API * and probably should be somewhere else... diff --git a/libconcord/libconcord.h b/libconcord/libconcord.h index 3865c98..fd4926d 100644 --- a/libconcord/libconcord.h +++ b/libconcord/libconcord.h @@ -510,6 +510,38 @@ void delete_encoded_signal(char *encoded_signal); int post_new_code(char *key_name, char *encoded_signal, lc_callback cb, void *cb_arg); +/* + * Special structures and methods for the Harmony Link + */ +#define MH_STRING_LENGTH 255 /* arbitrary */ +#define MH_MAX_WIFI_NETWORKS 30 /* arbitrary */ +struct mh_cfg_properties { + char host_name[MH_STRING_LENGTH]; + char email[MH_STRING_LENGTH]; + char service_link[MH_STRING_LENGTH]; +}; +struct mh_wifi_config { + char ssid[MH_STRING_LENGTH]; + char encryption[MH_STRING_LENGTH]; + char password[MH_STRING_LENGTH]; + char connect_status[MH_STRING_LENGTH]; + char error_code[MH_STRING_LENGTH]; +}; +struct mh_wifi_network { + char ssid[MH_STRING_LENGTH]; + char signal_strength[MH_STRING_LENGTH]; + char channel[MH_STRING_LENGTH]; + char encryption[MH_STRING_LENGTH]; +}; +struct mh_wifi_networks { + struct mh_wifi_network network[MH_MAX_WIFI_NETWORKS]; +}; +int mh_get_cfg_properties(struct mh_cfg_properties *properties); +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); + #ifdef __cplusplus } #endif diff --git a/libconcord/remote.cpp b/libconcord/remote.cpp index 81735c7..ee9dde3 100644 --- a/libconcord/remote.cpp +++ b/libconcord/remote.cpp @@ -1053,3 +1053,14 @@ int CRemote::LearnIR(uint32_t *freq, uint32_t **ir_signal, return err; } + +int CRemote::ReadFile(const char *filename, uint8_t *rd, const uint32_t rdlen, + int *data_read, uint8_t start_seq) +{ + return LC_ERROR_UNSUPP; +} + +int CRemote::WriteFile(const char *filename, uint8_t *wr, const uint32_t wrlen) +{ + return LC_ERROR_UNSUPP; +} diff --git a/libconcord/remote.h b/libconcord/remote.h index d26ea4a..a53644e 100644 --- a/libconcord/remote.h +++ b/libconcord/remote.h @@ -197,6 +197,12 @@ public: virtual int IsZRemote()=0; virtual int IsUSBNet()=0; virtual int IsMHRemote()=0; + + virtual int ReadFile(const char *filename, uint8_t *rd, + const uint32_t rdlen, int *data_read, + uint8_t start_seq=0)=0; + virtual int WriteFile(const char *filename, uint8_t *wr, + const uint32_t wrlen)=0; }; class CRemote : public CRemoteBase // All non-Z-Wave remotes @@ -253,6 +259,10 @@ public: int IsZRemote() {return false;} int IsUSBNet() {return false;} int IsMHRemote() {return false;} + + int ReadFile(const char *filename, uint8_t *rd, const uint32_t rdlen, + int *data_read, uint8_t start_seq=0); + int WriteFile(const char *filename, uint8_t *wr, const uint32_t wrlen); }; // Base class for all Z-Wave remotes @@ -309,6 +319,10 @@ public: void *cb_arg=NULL, uint32_t cb_stage=0); int IsZRemote() {return true;} int IsMHRemote() {return false;} + + int ReadFile(const char *filename, uint8_t *rd, const uint32_t rdlen, + int *data_read, uint8_t start_seq=0); + int WriteFile(const char *filename, uint8_t *wr, const uint32_t wrlen); }; // 890, 890Pro, AVL-300, RF Extender @@ -426,6 +440,10 @@ public: int IsZRemote() {return false;} int IsUSBNet() {return false;} int IsMHRemote() {return true;} + + int ReadFile(const char *filename, uint8_t *rd, const uint32_t rdlen, + int *data_read, uint8_t start_seq=0); + int WriteFile(const char *filename, uint8_t *wr, const uint32_t wrlen); }; #endif //REMOTE_H diff --git a/libconcord/remote_info.h b/libconcord/remote_info.h index 83f18c3..72d55d7 100644 --- a/libconcord/remote_info.h +++ b/libconcord/remote_info.h @@ -499,6 +499,24 @@ static const TArchInfo ArchList[]={ 0, // ram_size 0, // eeprom_size "", // usb + }, + /* arch 17: Link */ + { + 0, // serial_location + 0, // serial_address + 0, // flash_base + 0, // firmware_base + 0, // config_base + 0, // firmware_update_base + 0, // firmware_4847_offset + 0x4D505347, // cookie + 0, // cookie_size + 0, // end_vector + "", // micro + 0, // flash_size + 0, // ram_size + 0, // eeprom_size + "", // usb } }; diff --git a/libconcord/remote_mh.cpp b/libconcord/remote_mh.cpp index ce55ee9..b30f306 100644 --- a/libconcord/remote_mh.cpp +++ b/libconcord/remote_mh.cpp @@ -35,6 +35,12 @@ /* Timeout to wait for a response, in ms. */ #define MH_TIMEOUT 5000 +/* + * This value is used in places where the timeout needs to be extended in + * order to support the Harmony Link. It takes a long time to respond to some + * commands. +*/ +#define LINK_TIMEOUT 20000 #define MH_MAX_PACKET_SIZE 64 /* In data mode, two bytes are used for the header. */ #define MH_MAX_DATA_SIZE 62 @@ -154,6 +160,256 @@ uint8_t get_seq(uint8_t &seq) return tmp; } +int CRemoteMH::ReadFile(const char *filename, uint8_t *rd, const uint32_t rdlen, + int *data_read, uint8_t start_seq) +{ + int err = 0; + uint8_t seq = start_seq; + + if (strlen(filename) > (MH_MAX_PACKET_SIZE - 9)) { + debug("Filename too long"); + return LC_ERROR; + } + uint8_t msg_idx = 0; + uint8_t msg_read_file[MH_MAX_PACKET_SIZE] = + { 0xFF, 0x01, get_seq(seq), 0x02, 0x80 }; + msg_idx += 5; + memcpy(&msg_read_file[msg_idx], filename, strlen(filename)); + msg_idx += strlen(filename); + msg_read_file[msg_idx++] = 0x00; + msg_read_file[msg_idx++] = 0x80; + msg_read_file[msg_idx++] = 'R'; + msg_read_file[msg_idx++] = 0x00; + + uint8_t msg_ack[MH_MAX_PACKET_SIZE] = + { 0xFF, 0x04, get_seq(seq), 0x02, 0x01, 0x00, 0x01, 0x00 }; + uint8_t rsp[MH_MAX_PACKET_SIZE]; + + if ((err = HID_WriteReport(msg_read_file))) { + debug("Failed to write to remote"); + return LC_ERROR_WRITE; + } + + if ((err = HID_ReadReport(rsp, MH_TIMEOUT))) { + debug("Failed to read from remote"); + return LC_ERROR_READ; + } + debug("msg_read_file"); + debug_print_packet(rsp); + + /* + * First parameter in the read file "ack" message is reused in subsequent + * messages to the remote. Save it. + */ + const uint8_t param = rsp[5]; + msg_ack[5] = param; + + /* + * Second parameter in the read file "ack" message is the data length. Use + * this to determine the number of packets we should expect. + */ + uint32_t data_len = (rsp[7] << 24) + (rsp[8] << 16) + (rsp[9] << 8) + + rsp[10]; + int pkts_to_read = data_len / MH_MAX_DATA_SIZE; + if ((data_len % MH_MAX_DATA_SIZE) != 0) + pkts_to_read++; + pkts_to_read++; // count is always one more than the actual count + if (pkts_to_read > 50) + msg_ack[7] = 0x33; + else + msg_ack[7] = pkts_to_read; + + 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 pkt_count = 0; + *data_read = 0; + uint8_t *rd_ptr = rd; + while(!(err = HID_ReadReport(rsp, MH_TIMEOUT))) { + debug_print_packet(rsp); + // 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) { + if ((*data_read + len) > rdlen) { + debug("ERROR: buffer length exceeded!"); + return LC_ERROR; + } + memcpy(rd_ptr, &rsp[2], len); + rd_ptr += len; + } + *data_read += len; + pkt_count++; + pkts_to_read--; + if (pkts_to_read == 1) { + break; + } + if (pkt_count == 50) { + msg_ack[2] = get_seq(seq); + if (pkts_to_read > 50) + msg_ack[7] = 0x33; + else + msg_ack[7] = pkts_to_read; + 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); + pkt_count = 0; + } + } + debug("data_read=%d", *data_read); + + /* send reset sequence message */ + const uint8_t msg_reset_seq[MH_MAX_PACKET_SIZE] = + { 0xFF, 0x07, get_seq(seq), 0x01, 0x01, param }; + 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::WriteFile(const char *filename, uint8_t *wr, + const uint32_t wrlen) +{ + int err = 0; + uint8_t seq = 0; + uint8_t rsp[MH_MAX_PACKET_SIZE]; + + if (strlen(filename) > (MH_MAX_PACKET_SIZE - 14)) { + debug("Filename too long"); + return LC_ERROR; + } + + uint8_t msg_idx = 0; + uint8_t msg_write_file[MH_MAX_PACKET_SIZE] = + { 0xFF, 0x01, get_seq(seq), 0x03, 0x80 }; + msg_idx += 5; + memcpy(&msg_write_file[msg_idx], filename, strlen(filename)); + msg_idx += strlen(filename); + msg_write_file[msg_idx++] = 0x00; + msg_write_file[msg_idx++] = 0x80; + msg_write_file[msg_idx++] = 'W'; + msg_write_file[msg_idx++] = 0x00; + msg_write_file[msg_idx++] = 0x04; + msg_write_file[msg_idx++] = (wrlen & 0xFF000000) >> 24; + msg_write_file[msg_idx++] = (wrlen & 0x00FF0000) >> 16; + msg_write_file[msg_idx++] = (wrlen & 0x0000FF00) >> 8; + msg_write_file[msg_idx++] = wrlen & 0x000000FF; + + if ((err = HID_WriteReport(msg_write_file))) { + debug("Failed to write to remote"); + return LC_ERROR_WRITE; + } + + if ((err = HID_ReadReport(rsp, MH_TIMEOUT))) { + debug("Failed to read from remote"); + return LC_ERROR_READ; + } + debug("msg_write_file"); + debug_print_packet(rsp); + + /* + * First parameter in the read file "ack" message is reused in subsequent + * messages to the remote. Save it. + */ + const uint8_t param = rsp[5]; + + uint8_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 }; + + if ((err = HID_WriteReport(msg_ack))) { + debug("Failed to write to remote"); + return LC_ERROR_WRITE; + } + debug("msg_ack"); + /* No response expected - proceed to send data. */ + + uint8_t *wr_ptr = const_cast<uint8_t*>(wr); + uint32_t tlen = wrlen; + uint8_t pkt_len; + uint8_t tmp_pkt[MH_MAX_PACKET_SIZE]; + while (tlen) { + pkt_len = MH_MAX_DATA_SIZE; + if (tlen < pkt_len) { + pkt_len = tlen; + for (int i = pkt_len; i < MH_MAX_PACKET_SIZE; i++) + tmp_pkt[i] = 0x00; + } + tlen -= pkt_len; + + tmp_pkt[0] = get_seq(seq); + tmp_pkt[1] = pkt_len; + memcpy(&tmp_pkt[2], wr_ptr, pkt_len); + + debug("DATA sending %d bytes, %d bytes left", pkt_len, tlen); + + if (err = HID_WriteReport(tmp_pkt)) { + return err; + } + wr_ptr += pkt_len; + } + + /* + * Wait for remote to send us a response. We extend the timeout here + * because the Harmony Link can take 7+ seconds to respond to this + * particular message. + */ + if ((err = HID_ReadReport(rsp, LINK_TIMEOUT))) { + debug("Failed to read from remote"); + return LC_ERROR_READ; + } + debug("after writing file"); + debug_print_packet(rsp); + + /* send reset sequence message */ + const uint8_t msg_reset_seq[MH_MAX_PACKET_SIZE] = + { 0xFF, 0x07, get_seq(seq), 0x01, 0x01, param }; + 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; +} + /* * Send the GET_VERSION command to the remote, and read the response. * @@ -171,13 +427,6 @@ int CRemoteMH::GetIdentity(TRemoteInfo &ri, THIDINFO &hid, lc_callback cb, { 0xFF, 0xFF, 0x01, 0x01, 0x01, 0x66 }; const uint8_t msg_three[MH_MAX_PACKET_SIZE] = { 0xFF, 0x00, 0x02 }; - const uint8_t msg_four[MH_MAX_PACKET_SIZE] = - { 0xFF, 0x01, 0x03, 0x02, 0x80, '/', 's', 'y', 's', '/', - 's', 'y', 's', 'i', 'n', 'f', 'o', 0x00, 0x80, 'R', 0x00 }; - const uint8_t msg_five[MH_MAX_PACKET_SIZE] = - { 0xFF, 0x04, 0x04, 0x02, 0x01, 0x06, 0x01, 0x06 }; - const uint8_t msg_six[MH_MAX_PACKET_SIZE] = - { 0xFF, 0x07, 0x05, 0x01, 0x01, 0x06 }; uint8_t rsp[MH_MAX_PACKET_SIZE]; /* @@ -215,41 +464,13 @@ int CRemoteMH::GetIdentity(TRemoteInfo &ri, THIDINFO &hid, lc_callback cb, debug("msg_three"); debug_print_packet(rsp); - if ((err = HID_WriteReport(msg_four))) { - 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_four"); - debug_print_packet(rsp); - - if ((err = HID_WriteReport(msg_five))) { - 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_five"); - debug_print_packet(rsp); - - string identity = ""; - while(!(err = HID_ReadReport(rsp))) { - // 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. - for (int i = 2; i < len + 2; i++) { - identity += rsp[i]; - } - } + int buflen = 1000; + char buffer[buflen]; + int data_read; + if (err = ReadFile("/sys/sysinfo", (uint8_t*)buffer, buflen, &data_read, + 0x03)) + return err; + string identity(buffer); debug("%s", identity.c_str()); ri.fw_ver_major = strtol(find_value(identity, "fw_ver").c_str(), NULL, 10); @@ -294,19 +515,6 @@ int CRemoteMH::GetIdentity(TRemoteInfo &ri, THIDINFO &hid, lc_callback cb, make_serial(guid, ri); } - /* reset the sequence number to 0 */ - 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); - return 0; } diff --git a/libconcord/remote_z.cpp b/libconcord/remote_z.cpp index f7ffa1a..decae45 100644 --- a/libconcord/remote_z.cpp +++ b/libconcord/remote_z.cpp @@ -1486,3 +1486,16 @@ int CRemoteZ_Base::LearnIR(uint32_t *freq, uint32_t **ir_signal, { return 0; } + +int CRemoteZ_Base::ReadFile(const char *filename, uint8_t *rd, + const uint32_t rdlen, int *data_read, + uint8_t start_seq) +{ + return LC_ERROR_UNSUPP; +} + +int CRemoteZ_Base::WriteFile(const char *filename, uint8_t *wr, + const uint32_t wrlen) +{ + return LC_ERROR_UNSUPP; +} diff --git a/specs/protocol_mh.txt b/specs/protocol_mh.txt index 2a29583..dd4f873 100644 --- a/specs/protocol_mh.txt +++ b/specs/protocol_mh.txt @@ -21,6 +21,10 @@ Command message 0x01 - Read/Write a file. Identity file is /sys/sysinfo Config file is /cfg/usercfg IR learn is /ir/ir_cap + Harmony Link Configuration is /cfg/properties + (room location, email, discovery service link) + Harmony Link Wifi Network Scan List is /sys/wifi/networks + Harmony Link Wifi Configuration is /sys/wifi/connect Parameter 2: String; 'W' for write, 'R' for read. Parameter 3: 4 bytes; length of data to write (only use for writes) Response (to a read command): -- 1.8.3.1 ------------------------------------------------------------------------------ Introducing Performance Central, a new site from SourceForge and AppDynamics. Performance Central is your source for news, insights, analysis and resources for efficient Application Performance Management. Visit us today! http://pubads.g.doubleclick.net/gampad/clk?id=48897511&iu=/4140/ostg.clktrk _______________________________________________ concordance-devel mailing list concordance-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/concordance-devel