1 /*
2  * vim:tw=80:ai:tabstop=4:softtabstop=4:shiftwidth=4:expandtab
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  *
18  * (C) Copyright Kevin Timmerman 2007
19  * (C) Copyright Phil Dibowitz 2007
20  */
21 
22 #include "remote.h"
23 
24 #include <string.h>
25 #include <errno.h>
26 
27 #include "libconcord.h"
28 #include "lc_internal.h"
29 #include "hid.h"
30 #include "protocol.h"
31 #include "remote_info.h"
32 
33 #define GUID_STR \
34   "{%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X}"
35 
setup_ri_pointers(TRemoteInfo & ri)36 void setup_ri_pointers(TRemoteInfo &ri)
37 {
38     unsigned int u;
39     for (u = 0; u < sizeof(FlashList)/sizeof(TFlash)-1; ++u) {
40         if (ri.flash_id == FlashList[u].id
41             && ri.flash_mfg == FlashList[u].mfg)
42             break;
43     }
44     ri.flash = &FlashList[u];
45 
46     ri.arch = (ri.architecture < sizeof(ArchList)/sizeof(TArchInfo))
47             ? &ArchList[ri.architecture] : NULL;
48 
49     ri.model = (ri.skin < max_model)
50             ? &ModelList[ri.skin] : &ModelList[max_model];
51 }
52 
make_guid(const uint8_t * const in,char * & out)53 void make_guid(const uint8_t * const in, char*&out)
54 {
55     char x[48];
56     // Non-HID remotes (ZWave-HID, ZWave-USBNet, MH) as well as Arch 14 seem
57     // to use a more normal byte ordering for serial #'s.
58     if (is_z_remote() || is_mh_remote() || (get_arch() == 14)) {
59         sprintf(x, GUID_STR, in[0], in[1], in[2], in[3], in[4], in[5], in[6],
60                 in[7], in[8], in[9], in[10], in[11], in[12], in[13], in[14],
61                 in[15]);
62     }
63     else {
64         sprintf(x, GUID_STR, in[3], in[2], in[1], in[0], in[5], in[4], in[7],
65                 in[6], in[8], in[9], in[10], in[11], in[12], in[13], in[14],
66                 in[15]);
67     }
68     out = strdup(x);
69 }
70 
make_serial(uint8_t * ser,TRemoteInfo & ri)71 void make_serial(uint8_t *ser, TRemoteInfo &ri)
72 {
73     make_guid(ser, ri.serial1);
74     make_guid(ser+16, ri.serial2);
75     make_guid(ser+32, ri.serial3);
76 }
77 
Reset(uint8_t kind)78 int CRemote::Reset(uint8_t kind)
79 {
80     uint8_t reset_cmd[64] = { COMMAND_RESET, kind };
81     int err;
82 
83     err = HID_WriteReport(reset_cmd);
84     /*
85      * Certain remotes (e.g., the 785) do not get a successful return from
86      * HID_WriteReport even though the reset succeeds.  Ignore this.
87      */
88     if (err == -ENODEV) {
89         debug("Ignoring error from reset command");
90         err = 0;
91     }
92     return err;
93 }
94 
95 /*
96  * Send the GET_VERSION command to the remote, and read the response.
97  *
98  * Then populate our struct with all the relevant info.
99  */
GetIdentity(TRemoteInfo & ri,THIDINFO & hid,lc_callback cb,void * cb_arg,uint32_t cb_stage)100 int CRemote::GetIdentity(TRemoteInfo &ri, THIDINFO &hid, lc_callback cb,
101                          void *cb_arg, uint32_t cb_stage)
102 {
103     int err = 0;
104     uint32_t cb_count = 0;
105 
106     const uint8_t qid[64] = { COMMAND_GET_VERSION };
107 
108     if ((err = HID_WriteReport(qid))) {
109         debug("Failed to write to remote");
110         return 1;
111     }
112 
113     uint8_t rsp[68];
114     if ((err = HID_ReadReport(rsp))) {
115         debug("Failed to read from remote");
116         return 1;
117     }
118 
119     /*
120       * See specs/protocol.txt for format
121       */
122     const unsigned int rx_len = rsp[0] & 0x0F;
123 
124     if ((rsp[0] & 0xF0) != RESPONSE_VERSION_DATA ||
125         (rx_len != 5 && rx_len != 7 && rx_len != 8)) {
126         debug("Bogus ident response: %02X", rsp[1]);
127         return LC_ERROR_INVALID_DATA_FROM_REMOTE;
128     }
129 
130     ri.fw_ver_major = rsp[1] >> 4;
131     ri.fw_ver_minor = rsp[1] & 0x0F;
132     ri.hw_ver_major = rsp[2] >> 4;
133     ri.hw_ver_minor = rsp[2] & 0x0F;
134     ri.hw_ver_micro = 0; /* usbnet remotes have a non-zero micro version */
135     ri.flash_id = rsp[3];
136     ri.flash_mfg = rsp[4];
137     ri.architecture = rx_len < 6 ? 2 : rsp[5] >> 4;
138     ri.fw_type = rx_len < 6 ? 0 : rsp[5] & 0x0F;
139     ri.skin = rx_len < 6 ? 2 : rsp[6];
140     if (rx_len < 7) {
141         ri.protocol = 0;
142     } else if (rx_len < 8) {
143         ri.protocol = rsp[7];
144     } else {
145         ri.protocol = ri.architecture;
146     }
147 
148     setup_ri_pointers(ri);
149 
150     uint8_t rd[1024];
151     if ((err=ReadFlash(ri.arch->config_base, 1024, rd, ri.protocol, false))) {
152         debug("Error reading first k of config data");
153         return LC_ERROR_READ;
154     }
155     if (cb) {
156         cb(cb_stage, cb_count++, 1, 2, LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
157     }
158 
159     /*
160      * Calculate cookie
161      *   see specs/protocol.txt for more info
162      */
163     const uint32_t cookie = (ri.arch->cookie_size == 2)
164             ? rd[0] | (rd[1] << 8)
165             : rd[0] | (rd[1] << 8) | (rd[2] << 16) | (rd[3] << 24);
166 
167     ri.valid_config = (cookie == ri.arch->cookie);
168 
169     if (ri.valid_config) {
170         ri.max_config_size = (ri.flash->size << 10)
171             - (ri.arch->config_base - ri.arch->flash_base);
172         const uint32_t end = rd[ri.arch->end_vector]
173                 | (rd[ri.arch->end_vector + 1] << 8)
174                 | (rd[ri.arch->end_vector + 2] << 16);
175         ri.config_bytes_used =
176             (end - (ri.arch->config_base - ri.arch->flash_base))
177             + 4;
178     } else {
179         ri.config_bytes_used = 0;
180         ri.max_config_size = 1;
181     }
182 
183     // read serial (see specs/protocol.txt for details)
184     switch (ri.arch->serial_location) {
185     case SERIAL_LOCATION_EEPROM:
186         err = ReadMiscByte(ri.arch->serial_address, SERIAL_SIZE,
187                            COMMAND_MISC_EEPROM, rsp);
188         break;
189     case SERIAL_LOCATION_FLASH:
190         err = ReadFlash(ri.arch->serial_address, SERIAL_SIZE, rsp, ri.protocol);
191         break;
192     default:
193         debug("Invalid TArchInfo\n");
194         return LC_ERROR_READ;
195     }
196     if (err) {
197         debug("Couldn't read serial\n");
198         return LC_ERROR_READ;
199     }
200 
201     if (cb) {
202         cb(cb_stage, cb_count++, 2, 2, LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
203     }
204 
205     make_serial(rsp, ri);
206 
207     return 0;
208 }
209 
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)210 int CRemote::ReadFlash(uint32_t addr, const uint32_t len, uint8_t *rd,
211                        unsigned int protocol, bool verify, lc_callback cb,
212                        void *cb_arg, uint32_t cb_stage)
213 {
214     uint32_t cb_count = 0;
215     const unsigned int max_chunk_len = protocol == 0 ? 700 : 1022;
216 
217     /*
218      * This is a mapping of the lower-half of the first command byte to
219      * the size of the total command to be sent.
220      *
221      * See specs/protocol.txt for more * info.
222      */
223     // Protocol 0 (745, safe mode)
224     static const unsigned int dl0[16] =
225         { 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 };
226     // All other protocols
227     static const unsigned int dlx[16] =
228         { 0, 0, 1, 2, 3, 4, 5, 6, 14, 30, 62, 0, 0, 0, 0, 0 };
229     const unsigned int *rxlenmap = protocol ? dlx : dl0;
230 
231     uint8_t *pr = rd;
232     const uint32_t end = addr+len;
233     unsigned int bytes_read = 0;
234     int err = 0;
235 
236     do {
237         static uint8_t cmd[64] = {0};
238         cmd[0] = COMMAND_READ_FLASH | 0x05;
239         cmd[1] = (addr >> 16) & 0xFF;
240         cmd[2] = (addr >> 8) & 0xFF;
241         cmd[3] = addr & 0xFF;
242         unsigned int chunk_len = end-addr;
243         if (chunk_len > max_chunk_len)
244             chunk_len = max_chunk_len;
245         cmd[4] = (chunk_len >> 8) & 0xFF;
246         cmd[5] = chunk_len & 0xFF;
247 
248         if ((err = HID_WriteReport(cmd)))
249             break;
250 
251         uint8_t seq = 1;
252 
253         do {
254             uint8_t rsp[68];
255             if ((err = HID_ReadReport(rsp)))
256                 break;
257 
258             const uint8_t r = rsp[0] & COMMAND_MASK;
259 
260             if (r == RESPONSE_READ_FLASH_DATA) {
261                 if (seq != rsp[1]) {
262                     err = LC_ERROR;
263                     debug("Invalid sequence %02X %02x",
264                         seq, rsp[1]);
265                     break;
266                 }
267                 seq += 0x11;
268                 const unsigned int rxlen =
269                     rxlenmap[rsp[0] & LENGTH_MASK];
270                 if (rxlen) {
271                     if (verify) {
272                         if (memcmp(pr, rsp+2, rxlen)) {
273                             debug("Verify fail");
274                             err = LC_ERROR_VERIFY;
275                             break;
276                         }
277                     } else {
278                         memcpy(pr, rsp+2, rxlen);
279                     }
280                     pr += rxlen;
281                     addr += rxlen;
282                     bytes_read += rxlen;
283                 }
284             } else if (r == RESPONSE_DONE) {
285                 break;
286             } else {
287                 debug("Invalid response [%02X]", rsp[0]);
288                 err = LC_ERROR;
289             }
290         } while (err == 0);
291 
292         if (cb) {
293             cb(cb_stage, cb_count++, bytes_read, len, LC_CB_COUNTER_TYPE_BYTES,
294                cb_arg, NULL);
295         }
296     } while (err == 0 && addr < end);
297 
298     return err;
299 }
300 
InvalidateFlash(lc_callback cb,void * cb_arg,uint32_t lc_stage)301 int CRemote::InvalidateFlash(lc_callback cb, void *cb_arg, uint32_t lc_stage)
302 {
303     const uint8_t ivf[64] = { COMMAND_WRITE_MISC | 0x01,
304                               COMMAND_MISC_INVALIDATE_FLASH };
305     int err;
306 
307     if (cb)
308         cb(lc_stage, 0, 0, 2, LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
309 
310     if ((err = HID_WriteReport(ivf)))
311         return err;
312 
313     if (cb)
314         cb(lc_stage, 1, 1, 2, LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
315 
316     uint8_t rsp[68];
317     if ((err = HID_ReadReport(rsp)))
318         return err;
319 
320     if ((rsp[0] & COMMAND_MASK) != RESPONSE_DONE ||
321         (rsp[1] & COMMAND_MASK) != COMMAND_WRITE_MISC) {
322         return 1;
323     }
324 
325     if (cb)
326         cb(lc_stage, 2, 2, 2, LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
327 
328     return 0;
329 }
330 
331 
EraseFlash(uint32_t addr,uint32_t len,const TRemoteInfo & ri,lc_callback cb,void * cb_arg,uint32_t cb_stage)332 int CRemote::EraseFlash(uint32_t addr, uint32_t len,  const TRemoteInfo &ri,
333                         lc_callback cb, void *cb_arg, uint32_t cb_stage)
334 {
335     const unsigned int *sectors = ri.flash->sectors;
336     const unsigned int flash_base = ri.arch->flash_base;
337 
338     const uint32_t end = addr + len;
339 
340     int err = 0;
341     uint32_t num_sectors = 0;
342 
343     uint32_t n = 0;
344 
345     // skip to where we need to start writing
346     while (sectors[n] + flash_base < addr) {
347         n++;
348     }
349     // start on the NEXT one
350     n++;
351 
352     num_sectors = n;
353     while (sectors[num_sectors] + flash_base < end) {
354         num_sectors++;
355     }
356     num_sectors -= n - 1;
357 
358     uint32_t sector_begin = sectors[n-1] + flash_base;
359     uint32_t sector_end = sectors[n] + flash_base;
360 
361     for (uint32_t i = 0; i < num_sectors; i++) {
362         static uint8_t erase_cmd[64] = {0};
363         erase_cmd[0] = COMMAND_ERASE_FLASH;
364         erase_cmd[1] = (sector_begin >> 16) & 0xFF;
365         erase_cmd[2] = (sector_begin >> 8) & 0xFF;
366         erase_cmd[3] = sector_begin & 0xFF;
367 
368         if ((err = HID_WriteReport(erase_cmd)))
369             break;
370 
371         uint8_t rsp[68];
372         if ((err = HID_ReadReport(rsp, 5000)))
373             break;
374 
375         if (cb)
376             cb(cb_stage, i, i+1, num_sectors, LC_CB_COUNTER_TYPE_STEPS,
377                cb_arg, NULL);
378         debug("erase sector %2i: %06X - %06X", n, sector_begin, sector_end);
379         sector_begin = sector_end;
380         sector_end = sectors[++n] + flash_base;
381     }
382 
383     return err;
384 }
385 
PrepFirmware(const TRemoteInfo & ri,lc_callback cb,void * cb_arg,uint32_t cb_stage)386 int CRemote::PrepFirmware(const TRemoteInfo &ri, lc_callback cb, void *cb_arg,
387                           uint32_t cb_stage)
388 {
389     int err = 0;
390     uint8_t data[1] = { 0x00 };
391 
392     if (cb)
393         cb(cb_stage, 0, 0, 2, LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
394 
395     if (ri.arch->firmware_update_base == ri.arch->firmware_base) {
396         /*
397          * The preperation for where the staging area IS the config
398          * area.
399          *    restart config
400          *    write "1" to flash addr 200000
401          */
402         if ((err = WriteMiscByte(0x09, 1, COMMAND_MISC_RESTART_CONFIG, data)))
403             return LC_ERROR;
404 
405         if (cb)
406             cb(cb_stage, 1, 1, 2, LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
407 
408         if ((err = WriteFlash(0x200000, 1, data, ri.protocol, NULL, NULL, 0)))
409             return LC_ERROR;
410     } else {
411         /*
412          * The preperation for where the staging area is distinct.
413          *    write "1" to ram addr 0
414          *    read it back
415          */
416         if ((err = WriteRam(0, 1, data)))
417             return LC_ERROR_WRITE;
418 
419         if (cb)
420             cb(cb_stage, 1, 1, 2, LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
421 
422         if ((err = ReadRam(0, 1, data)))
423             return LC_ERROR_WRITE;
424         if (data[0] != 0)
425             return LC_ERROR_VERIFY;
426     }
427     if (cb)
428         cb(cb_stage, 2, 2, 2, LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
429 
430     return 0;
431 }
432 
FinishFirmware(const TRemoteInfo & ri,lc_callback cb,void * cb_arg,uint32_t cb_stage)433 int CRemote::FinishFirmware(const TRemoteInfo &ri, lc_callback cb, void *cb_arg,
434                             uint32_t cb_stage)
435 {
436     int err = 0;
437 
438     if (cb)
439         cb(cb_stage, 0, 0, 3, LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
440 
441     uint8_t data[1];
442     if (ri.arch->firmware_update_base == ri.arch->firmware_base) {
443         data[0] = 0x02;
444         if ((err = WriteFlash(0x200000, 1, data, ri.protocol, NULL, NULL, 0)))
445             return LC_ERROR;
446         if (cb)
447             cb(cb_stage, 1, 1, 3, LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
448     } else {
449         data[0] = 0x02;
450         if ((err = WriteRam(0, 1, data))) {
451             debug("Failed to write 2 to RAM 0");
452             return LC_ERROR_WRITE;
453         }
454         if (cb)
455             cb(cb_stage, 1, 1, 3, LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
456         if ((err = ReadRam(0, 1, data))) {
457             debug("Failed to from RAM 0");
458             return LC_ERROR_WRITE;
459         }
460         if (cb)
461             cb(cb_stage, 2, 2, 3, LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
462         if (data[0] != 2) {
463             printf("byte is %d\n", data[0]);
464             debug("Finalize byte didn't match");
465             return LC_ERROR_VERIFY;
466         }
467     }
468     if (cb)
469         cb(cb_stage, 3, 3, 3, LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
470 
471     return 0;
472 }
473 
PrepConfig(const TRemoteInfo & ri,lc_callback cb,void * cb_arg,uint32_t cb_stage)474 int CRemote::PrepConfig(const TRemoteInfo &ri, lc_callback cb, void *cb_arg,
475                         uint32_t cb_stage)
476 {
477     int err;
478     uint8_t data_zero[1] = { 0x00 };
479 
480     if (ri.architecture != 14) {
481         if (cb) {
482             cb(cb_stage, 0, 0, 1, LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
483             cb(cb_stage, 1, 1, 1, LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
484         }
485         return 0;
486     }
487 
488     if (cb)
489         cb(cb_stage, 0, 0, 2, LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
490 
491     if ((err = WriteMiscByte(0x02, 1, COMMAND_MISC_RESTART_CONFIG, data_zero))) {
492         return err;
493     }
494 
495     if (cb)
496         cb(cb_stage, 1, 1, 2, LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
497 
498     if ((err = WriteMiscByte(0x05, 1, COMMAND_MISC_RESTART_CONFIG, data_zero))) {
499         return err;
500     }
501 
502     if (cb)
503         cb(cb_stage, 2, 2, 2, LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
504 
505     return 0;
506 }
507 
FinishConfig(const TRemoteInfo & ri,lc_callback cb,void * cb_arg,uint32_t cb_stage)508 int CRemote::FinishConfig(const TRemoteInfo &ri, lc_callback cb, void *cb_arg,
509                           uint32_t cb_stage)
510 {
511     int err;
512     uint8_t data_one[1]  = { 0x01 };
513     uint8_t data_zero[1] = { 0x00 };
514 
515     if (ri.architecture != 14) {
516         return 0;
517     }
518 
519     if (cb)
520         cb(cb_stage, 0, 0, 2, LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
521 
522     if ((err = WriteMiscByte(0x03, 1, COMMAND_MISC_RESTART_CONFIG, data_one))) {
523         return err;
524     }
525 
526     if (cb)
527         cb(cb_stage, 1, 1, 2, LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
528 
529     if ((err = WriteMiscByte(0x06, 1, COMMAND_MISC_RESTART_CONFIG,
530                              data_zero))) {
531         return err;
532     }
533 
534     if (cb)
535         cb(cb_stage, 2, 2, 2, LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
536 
537     return 0;
538 }
539 
WriteRam(uint32_t addr,const uint32_t len,uint8_t * wr)540 int CRemote::WriteRam(uint32_t addr, const uint32_t len, uint8_t *wr)
541 {
542     return WriteMiscByte(addr, len, COMMAND_MISC_RAM, wr);
543 }
544 
ReadRam(uint32_t addr,const uint32_t len,uint8_t * rd)545 int CRemote::ReadRam(uint32_t addr, const uint32_t len, uint8_t *rd)
546 {
547     return ReadMiscByte(addr, len, COMMAND_MISC_RAM, rd);
548 }
549 
WriteFlash(uint32_t addr,const uint32_t len,const uint8_t * wr,unsigned int protocol,lc_callback cb,void * cb_arg,uint32_t cb_stage)550 int CRemote::WriteFlash(uint32_t addr, const uint32_t len, const uint8_t *wr,
551     unsigned int protocol, lc_callback cb, void *cb_arg, uint32_t cb_stage)
552 {
553     uint32_t cb_count = 0;
554     const unsigned int max_chunk_len = protocol == 0 ? 749 : 3150;
555 
556     /* mapping of lenghts - see specs/protocol.txt */
557     static const unsigned int txlenmap0[] = { 0x07, 7, 6, 5, 4, 3, 2, 1 };
558     static const unsigned int txlenmapx[] =
559         { 0x0A, 63, 31, 15, 7, 6, 5, 4, 3, 2, 1 };
560     const unsigned int *txlenmap = protocol ? txlenmapx : txlenmap0;
561 
562     const uint8_t *pw = wr;
563     const uint32_t end = addr+len;
564     unsigned int bytes_written = 0;
565     int err = 0;
566 
567     do {
568         static uint8_t write_setup_cmd[64] = {0};
569         write_setup_cmd[0] = COMMAND_WRITE_FLASH | 0x05;
570         write_setup_cmd[1] = (addr >> 16) & 0xFF;
571         write_setup_cmd[2] = (addr >> 8) & 0xFF;
572         write_setup_cmd[3] = addr & 0xFF;
573         uint32_t chunk_len = end - addr;
574         if (chunk_len > max_chunk_len)
575             chunk_len = max_chunk_len;
576         write_setup_cmd[4] = (chunk_len >> 8) & 0xFF;
577         write_setup_cmd[5] = chunk_len & 0xFF;
578 
579         if ((err = HID_WriteReport(write_setup_cmd)))
580             break;
581 
582         while (chunk_len) {
583             unsigned int n = txlenmap[0];
584             unsigned int i = 1;
585             while (chunk_len < txlenmap[i]) {
586                 ++i;
587                 --n;
588             }
589             unsigned int block_len = txlenmap[i];
590             uint8_t wd[64] = {0};
591             wd[0] = COMMAND_WRITE_FLASH_DATA | n;
592             memcpy(wd+1, pw, block_len);
593             HID_WriteReport(wd);
594             pw += block_len;
595             addr += block_len;
596             bytes_written += block_len;
597             chunk_len -= block_len;
598         }
599 
600         uint8_t end_cmd[64] = { COMMAND_DONE, COMMAND_WRITE_FLASH };
601         HID_WriteReport(end_cmd);
602 
603         uint8_t rsp[68];
604         if ((err = HID_ReadReport(rsp, 5000)))
605             break;
606 
607         if (cb) {
608             cb(cb_stage, cb_count++, bytes_written, len,
609                LC_CB_COUNTER_TYPE_BYTES, cb_arg, NULL);
610         }
611     } while (addr < end);
612 
613     return err;
614 }
615 
ReadMiscByte(uint8_t addr,uint32_t len,uint8_t kind,uint8_t * rd)616 int CRemote::ReadMiscByte(uint8_t addr, uint32_t len, uint8_t kind, uint8_t *rd)
617 {
618     uint8_t rmb[64] = { COMMAND_READ_MISC | 0x02, kind, 0 };
619 
620     while (len--) {
621         rmb[2] = addr++;
622 
623         int err;
624         if ((err = HID_WriteReport(rmb)))
625             return err;
626 
627         uint8_t rsp[68];
628         if ((err = HID_ReadReport(rsp)))
629             return err;
630 
631         if (rsp[0] != (RESPONSE_READ_MISC_DATA | 0x02) ||
632             rsp[1] != kind)
633             return 1;
634 
635         *rd++ = rsp[2];
636     }
637     return 0;
638 }
639 
ReadMiscWord(uint16_t addr,uint32_t len,uint8_t kind,uint16_t * rd)640 int CRemote::ReadMiscWord(uint16_t addr, uint32_t len, uint8_t kind,
641                           uint16_t *rd)
642 {
643     uint8_t rmw[64] = { COMMAND_READ_MISC | 0x03, kind, 0, 0 };
644 
645     while (len--) {
646         rmw[2] = addr >> 8;
647         rmw[3] = addr & 0xFF;
648         ++addr;
649 
650         int err;
651         if ((err = HID_WriteReport(rmw)))
652             return err;
653 
654         uint8_t rsp[68];
655         if ((err = HID_ReadReport(rsp)))
656             return err;
657 
658         // WARNING: The 880 responds with C2 rather than C3
659         if ((rsp[0] & COMMAND_MASK) != RESPONSE_READ_MISC_DATA ||
660             rsp[1] != kind) {
661             return 1;
662         }
663 
664         *rd++ = (rsp[2] << 8) | rsp[3];
665     }
666     return 0;
667 }
668 
WriteMiscByte(uint8_t addr,uint32_t len,uint8_t kind,uint8_t * wr)669 int CRemote::WriteMiscByte(uint8_t addr, uint32_t len, uint8_t kind,
670                            uint8_t *wr)
671 {
672     uint8_t wmb[64] = {0};
673     wmb[0] = COMMAND_WRITE_MISC | 0x03;
674     wmb[1] = kind;
675 
676     while (len--) {
677         wmb[2] = addr++;
678         wmb[3] = *wr++;
679 
680         int err;
681         if ((err = HID_WriteReport(wmb)))
682             return err;
683 
684         uint8_t rsp[68];
685         if ((err = HID_ReadReport(rsp)))
686             return err;
687         if ((rsp[0] & COMMAND_MASK) != RESPONSE_DONE ||
688             rsp[1] != COMMAND_WRITE_MISC) {
689             return 1;
690         }
691     }
692     return 0;
693 }
694 
WriteMiscWord(uint16_t addr,uint32_t len,uint8_t kind,uint16_t * wr)695 int CRemote::WriteMiscWord(uint16_t addr, uint32_t len, uint8_t kind,
696                            uint16_t *wr)
697 {
698     uint8_t wmw[64] = {0};
699     wmw[0] = COMMAND_WRITE_MISC | 0x05;
700     wmw[1] = kind;
701 
702     while (len--) {
703         wmw[2] = addr >> 8;
704         wmw[3] = addr & 0xFF;
705         ++addr;
706         wmw[4] = *wr >> 8;
707         wmw[5] = *wr & 0xFF;
708         ++wr;
709 
710         int err;
711         if ((err = HID_WriteReport(wmw)))
712             return err;
713 
714         uint8_t rsp[68];
715         if ((err = HID_ReadReport(rsp)))
716             return err;
717         if ((rsp[0] & COMMAND_MASK) != RESPONSE_DONE ||
718             rsp[1] != COMMAND_WRITE_MISC) {
719             return 1;
720         }
721     }
722     return 0;
723 }
724 
725 
GetTime(const TRemoteInfo & ri,THarmonyTime & ht)726 int CRemote::GetTime(const TRemoteInfo &ri, THarmonyTime &ht)
727 {
728     int err = 0;
729 
730     if (ri.architecture < 8) {
731         uint8_t tsv[8];
732         err = ReadMiscByte(0, 6, COMMAND_MISC_STATE, tsv);
733         ht.second = tsv[0];
734         ht.minute = tsv[1];
735         ht.hour = tsv[2];
736         ht.dow = 7;
737         ht.day = 1 + tsv[3];
738         ht.month = 1 + tsv[4];
739         ht.year = 2000 + tsv[5];
740     } else {
741         uint16_t tsv[8];
742         err = ReadMiscWord(0, 7, COMMAND_MISC_STATE, tsv);
743         ht.second = tsv[0];
744         ht.minute = tsv[1];
745         ht.hour = tsv[2];
746         ht.day = 1 + tsv[3];
747         ht.dow = tsv[4] & 7;
748         ht.month = 1 + tsv[5];
749         ht.year = 2000 + tsv[6];
750     }
751 
752     ht.utc_offset = 0;
753     ht.timezone = "";
754 
755     return err;
756 }
757 
SetTime(const TRemoteInfo & ri,const THarmonyTime & ht,lc_callback cb,void * cb_arg,uint32_t cb_stage)758 int CRemote::SetTime(const TRemoteInfo &ri, const THarmonyTime &ht,
759                      lc_callback cb, void *cb_arg, uint32_t cb_stage)
760 {
761     int err = 0;
762     uint8_t rsp[68];
763     int cb_count = 0;
764 
765     if (cb)
766         cb(cb_stage, cb_count++, 0, 2, LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
767 
768     if (ri.architecture < 8) {
769         uint8_t tsv[8];
770         tsv[0] = 0;
771         tsv[1] = ht.minute;
772         tsv[2] = ht.hour;
773         tsv[3] = ht.day - 1;
774         tsv[4] = ht.month  -1;
775         tsv[5] = ht.year - 2000;
776         if ((err = WriteMiscByte(0, 6, COMMAND_MISC_STATE, tsv)))
777             return err;
778         if (cb)
779             cb(cb_stage, cb_count++, 1, 3, LC_CB_COUNTER_TYPE_STEPS, cb_arg,
780                NULL);
781 
782         tsv[0] = ht.second;
783         err = WriteMiscByte(0, 1, COMMAND_MISC_STATE, tsv);
784     } else {
785         uint16_t tsv[8];
786         tsv[0] = 0;
787         tsv[1] = ht.minute;
788         tsv[2] = ht.hour;
789         tsv[3] = ht.day-1;
790         tsv[4] = ht.dow;
791         tsv[5] = ht.month-1;
792         tsv[6] = ht.year-2000;
793         if ((err = WriteMiscWord(0, 7, COMMAND_MISC_STATE, tsv)))
794             return err;
795         if (cb)
796             cb(cb_stage, cb_count++, 1, 3, LC_CB_COUNTER_TYPE_STEPS, cb_arg,
797                NULL);
798         tsv[0] = ht.second;
799         if ((err = WriteMiscWord(0, 1, COMMAND_MISC_STATE, tsv)))
800             return err;
801 
802         // Send Recalc Clock command for 880 only (not 360/520/550)
803         if (ri.architecture == 8) {
804             static const uint8_t rcc[64] = {
805                 COMMAND_WRITE_MISC | 0x01,
806                 COMMAND_MISC_CLOCK_RECALCULATE };
807             err = HID_WriteReport(rcc);
808         }
809     }
810     if (cb)
811         cb(cb_stage, cb_count++, 2, 3, LC_CB_COUNTER_TYPE_STEPS, cb_arg,
812             NULL);
813 
814         if (err != 0) {
815         return err;
816     }
817 
818     /*
819      * For some models, they return a RESPONSE_DONE, and we have to read
820      * it otherwise otherwise next command will fail.
821      * However, other devices don't return this, in which case the read
822      * failes.
823      * So, if the read succeeds, we check the response, otherwise we just
824      * move on with life.
825      */
826     err = HID_ReadReport(rsp);
827     if (err == 0) {
828         if ((rsp[0] & COMMAND_MASK) != RESPONSE_DONE) {
829             err = 1;
830         }
831     } else {
832         err = 0;
833     }
834     if (cb)
835         cb(cb_stage, cb_count++, 3, 3, LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
836 
837     return err;
838 }
839 
check_seq(int received_seq,uint8_t & expected_seq)840 bool check_seq(int received_seq, uint8_t &expected_seq)
841 {
842     if (received_seq == expected_seq) {
843         return true;
844     }
845 
846     if (received_seq == 0x1f && expected_seq == 0x10) {
847         /*
848          * Handle 880 SNAFU
849          *
850          * Does this indicate a bad learn???
851          * Needs more testing
852          */
853         debug("sequence glitch!");
854         expected_seq += 0x0F;
855         return true;
856     } else {
857         debug("\nInvalid sequence %02X %02x", expected_seq,
858             received_seq);
859         return false;
860     }
861 }
862 
_handle_ir_response(uint8_t rsp[64],uint32_t & ir_word,uint32_t & t_on,uint32_t & t_off,uint32_t & t_total,uint32_t & ir_count,uint32_t * & ir_signal,uint32_t & freq)863 int _handle_ir_response(uint8_t rsp[64], uint32_t &ir_word, uint32_t &t_on,
864                         uint32_t &t_off, uint32_t &t_total, uint32_t &ir_count,
865                         uint32_t *&ir_signal, uint32_t &freq)
866 {
867     const uint32_t len = rsp[63];
868     if ((len & 1) != 0) {
869         return 3;    // Invalid length
870     }
871 
872     for (uint32_t u = 2; u < len; u += 2) {
873         const uint32_t t = rsp[u] << 8 | rsp[1+u];
874         if (ir_word > 2) {
875             /*
876              * For ODD words, t is the total time, we'll
877              * update the total OFF time and be done.
878              *
879              * For EVEN words, t is just the ON time
880              * -- IF we have any ON time, then we go ahead
881              *    and record the off and on times we should
882              *    have now gathered.
883              *
884              * Why do we differentiate between even/odd?
885              * Perhaps just to make sure we've had two
886              * cycles, and thus have off/on?
887             */
888             if (ir_word & 1) {
889                 // t == on + off time
890                 if (t_on) {
891                     t_off = t - t_on;
892                 } else {
893                     t_off += t;
894                 }
895             } else {
896                 // t == on time
897                 t_on = t;
898                 if (t_on) {
899                     debug("-%i\n", t_off);
900                     if (ir_count < MAX_IR_SIGNAL_LENGTH) {
901                         ir_signal[ir_count++] = t_off;
902                     }
903                     debug("+%i\n", t_on);
904                     if (ir_count < MAX_IR_SIGNAL_LENGTH) {
905                         ir_signal[ir_count++] = t_on;
906                     }
907                     t_total += t_off + t_on;
908                 }
909             }
910         } else {
911             /*
912              * For the first 3 words...
913              *  the first one, we ignore, apparently
914              *  the second one, we start keeping track of ON time
915              *  the third one, we have enough data to calculate the
916              *    frequency and record the on time we've calculated
917              */
918             switch (ir_word) {
919                 case 0:    // ???
920                     break;
921                 case 1:    // on time of first burst
922                     t_on = t;
923                     break;
924                 case 2:    // carrier cycle count of first burst
925                     if (t_on) {
926                         freq = static_cast<uint32_t>(
927                             static_cast<uint64_t>(t)
928                                 *1000000/(t_on));
929                         debug("%i Hz", freq);
930                         debug("+%i", t_on);
931                         ir_signal[ir_count++] = t_on;
932                     }
933                     break;
934             }
935         }
936         ++ir_word;
937     }
938     return 0;
939 }
940 
941 // This section of IR learning code is common between pure HID and MH remotes.
942 // 'seq' is the starting sequence number, which differs between HID and MH.
LearnIRInnerLoop(uint32_t * freq,uint32_t ** ir_signal,uint32_t * ir_signal_length,uint8_t seq)943 int LearnIRInnerLoop(uint32_t *freq, uint32_t **ir_signal,
944                      uint32_t *ir_signal_length, uint8_t seq)
945 {
946     int err = 0;
947     uint8_t rsp[68];
948 
949     // Count of how man IR words we've received.
950     uint32_t ir_word = 0;
951     // Time button is on and off
952     uint32_t t_on = 0;
953     uint32_t t_off = 0;
954     // total duration of received signal:
955     // abort when > MAX_IR_SIGNAL_DURATION
956     uint32_t t_total = 0;
957 
958     *ir_signal_length = 0;
959     *ir_signal = new uint32_t[MAX_IR_SIGNAL_LENGTH];
960     /*
961      * Caller is responsible for deallocation of *ir_signal after use.
962      *
963      * Loop while we haven not:
964      * - any error (including signal duration and buffer overflow)
965      * - signal interrupted for IR_LEARN_DONE_TIMEOUT or longer
966      */
967     while ((err == 0) && (t_off < IR_LEARN_DONE_TIMEOUT * 1000)) {
968         if ((err = HID_ReadReport(rsp, ir_word ?
969             IR_LEARN_DONE_TIMEOUT : IR_LEARN_START_TIMEOUT))) {
970             err = LC_ERROR_READ;
971             break;
972         }
973         const uint8_t r = rsp[0] & COMMAND_MASK;
974         if (r == RESPONSE_IRCAP_DATA) {
975             if (!check_seq(rsp[1], seq)) {
976                 err = LC_ERROR;
977                 break;
978             }
979             seq += 0x10;
980             /*
981              * This will handle the IR response including updating
982              * t_off so we can exit the loop if long enough time
983              * goes by without action.
984              */
985             err = _handle_ir_response(rsp, ir_word, t_on, t_off,
986                 t_total, *ir_signal_length, *ir_signal,    *freq);
987             if (err != 0) {
988                 break;
989             }
990         } else if (r == RESPONSE_DONE) {
991             break;
992         } else {
993             debug("Invalid response [%02X]", rsp[1]);
994             err = LC_ERROR;
995         }
996         /* check for overflow: */
997         if ((t_total > MAX_IR_SIGNAL_DURATION * 1000)
998             || (*ir_signal_length > MAX_IR_SIGNAL_LENGTH)) {
999             err = LC_ERROR_IR_OVERFLOW;
1000         }
1001     }
1002 
1003     if ((err == 0) && (*ir_signal_length > 0)) {
1004         /* we have actually got some signal */
1005         if (t_off) {
1006             debug("-%i", t_off);
1007         }
1008         /* make sure we record a final off */
1009         if (*ir_signal_length < MAX_IR_SIGNAL_LENGTH) {
1010             (*ir_signal)[(*ir_signal_length)++] = t_off;
1011         }
1012     }
1013 
1014     return err;
1015 }
1016 
LearnIR(uint32_t * freq,uint32_t ** ir_signal,uint32_t * ir_signal_length,lc_callback cb,void * cb_arg,uint32_t cb_stage)1017 int CRemote::LearnIR(uint32_t *freq, uint32_t **ir_signal,
1018                      uint32_t *ir_signal_length, lc_callback cb, void *cb_arg,
1019                      uint32_t cb_stage)
1020 {
1021     int err = 0;
1022     uint8_t rsp[68];
1023 
1024     static const uint8_t start_ir_learn[64] = { COMMAND_START_IRCAP };
1025     static const uint8_t stop_ir_learn[64] = { COMMAND_STOP_IRCAP };
1026 
1027     if (cb) {
1028         cb(cb_stage, 0, 0, 1, LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
1029     }
1030 
1031     if (HID_WriteReport(start_ir_learn) != 0) {
1032         return LC_ERROR_WRITE;
1033     }
1034 
1035     err = LearnIRInnerLoop(freq, ir_signal, ir_signal_length, 0);
1036 
1037     if (HID_WriteReport(stop_ir_learn) != 0) {
1038         err = LC_ERROR_WRITE;
1039     }
1040 
1041     /* flush HID buffer until empty or RESPONSE_DONE: */
1042     do {
1043         if (HID_ReadReport(rsp, IR_LEARN_DONE_TIMEOUT) != 0) {
1044             err = LC_ERROR_READ;
1045             break;
1046         }
1047     } while ((rsp[0] & COMMAND_MASK) != RESPONSE_DONE);
1048 
1049     if (cb && !err) {
1050         cb(cb_stage, 1, 1, 1, LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
1051     }
1052 
1053     return err;
1054 }
1055 
ReadFile(const char * filename,uint8_t * rd,const uint32_t rdlen,uint32_t * data_read,uint8_t start_seq,lc_callback cb,void * cb_arg,uint32_t cb_stage)1056 int CRemote::ReadFile(const char *filename, uint8_t *rd, const uint32_t rdlen,
1057                       uint32_t *data_read, uint8_t start_seq, lc_callback cb,
1058                       void *cb_arg, uint32_t cb_stage)
1059 {
1060     return LC_ERROR_UNSUPP;
1061 }
1062 
WriteFile(const char * filename,uint8_t * wr,const uint32_t wrlen)1063 int CRemote::WriteFile(const char *filename, uint8_t *wr, const uint32_t wrlen)
1064 {
1065     return LC_ERROR_UNSUPP;
1066 }
1067