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 2010
20  */
21 
22 #include <string.h>
23 #include "libconcord.h"
24 #include "lc_internal.h"
25 #include "hid.h"
26 #include "remote.h"
27 #include "usblan.h"
28 #include "protocol_z.h"
29 
30 /* Have we acked the syn packet yet? */
31 static bool SYN_ACKED = false;
32 static unsigned int last_seq;
33 static unsigned int last_ack;
34 static unsigned int last_payload_bytes;
35 
TCP_Ack(bool increment_ack=false,bool fin=false)36 int TCP_Ack(bool increment_ack = false, bool fin = false) {
37     uint8_t pkt[HID_UDP_MAX_PACKET_SIZE];
38 
39     /*
40      * Note: It's the caller's responsibility to ensure we've already
41      * seen the SYN packet.
42      */
43 
44     uint8_t seq;
45     uint8_t ack;
46     uint8_t flags;
47 
48     seq = last_ack;
49     ack = last_seq + last_payload_bytes;
50     if (increment_ack)
51         ack++;
52     flags = TYPE_TCP_ACK;
53     if (fin)
54         flags |= TYPE_TCP_FIN;
55     pkt[0] = 3;
56     pkt[1] = flags;
57     pkt[2] = seq;
58     pkt[3] = ack;
59 
60     debug("Writing packet:");
61 #ifdef _DEBUG
62     for (int i = 0; i <= pkt[0]; i++) {
63         fprintf(stderr, "%02X ", pkt[i]);
64     }
65     fprintf(stderr, "\n");
66 #endif
67 
68     return HID_WriteReport(pkt);
69 }
70 
71 
72 /*
73  * The HID-based zwave remotes have two modes: so called "UDP" and "TCP". Do
74  * not confuse these with the network protocols of similar names.
75  *
76  * The non-HID based zwave remotes only use "TCP".
77  *
78  * For more information on the various Read/Write functions here and how they
79  * fit together, see the specs/protocol_z.txt file.
80  */
UDP_Write(uint8_t typ,uint8_t cmd,uint32_t len,uint8_t * data)81 int CRemoteZ_HID::UDP_Write(uint8_t typ, uint8_t cmd, uint32_t len,
82                             uint8_t *data)
83 {
84     if (len > 60)
85         return LC_ERROR;
86     uint8_t pkt[HID_UDP_MAX_PACKET_SIZE];
87     pkt[0] = 3+len;
88     pkt[1] = 1; // UDP
89     pkt[2] = typ;
90     pkt[3] = 0xFF & cmd;
91     if (data && len)
92         memcpy(pkt + 4, data, len);
93 
94     debug("Writing packet:");
95 #ifdef _DEBUG
96     for (int i = 0; i <= pkt[0]; i++) {
97         fprintf(stderr, "%02X ", pkt[i]);
98     }
99     fprintf(stderr, "\n");
100 #endif
101 
102     return HID_WriteReport(pkt);
103 }
104 
UDP_Read(uint8_t & status,uint32_t & len,uint8_t * data)105 int CRemoteZ_HID::UDP_Read(uint8_t &status, uint32_t &len, uint8_t *data)
106 {
107     uint8_t pkt[HID_UDP_MAX_PACKET_SIZE];
108     int err;
109     if ((err = HID_ReadReport(pkt))) {
110         return LC_ERROR_READ;
111     }
112 
113     debug("Reading packet:");
114 #ifdef _DEBUG
115     for (int i = 0; i <= pkt[0]; i++) {
116         fprintf(stderr, "%02X ", pkt[i]);
117     }
118     fprintf(stderr, "\n");
119 #endif
120 
121     if (pkt[0] < 4) {
122         return LC_ERROR;
123     }
124     if (pkt[0] > 4) {
125         status = pkt[4];
126     }
127     len = pkt[0] - 4;
128     /*
129      * pkt[0] is the index of the last byte, which means it is equal to the
130      * length of the packet minus one byte.  We want to copy everything but the
131      * first byte, so we copy pkt[0] bytes.
132      */
133     memcpy(data, pkt + 1, pkt[0]);
134     return 0;
135 }
136 
TCP_Write(uint8_t typ,uint8_t cmd,uint32_t len,uint8_t * data)137 int CRemoteZ_HID::TCP_Write(uint8_t typ, uint8_t cmd, uint32_t len,
138                             uint8_t *data)
139 {
140     uint8_t pkt[HID_UDP_MAX_PACKET_SIZE];
141 
142     /*
143      * Note: It's the caller's responsibility to ensure we've already
144      * seen the SYN packet.
145      */
146 
147     uint8_t seq;
148     uint8_t ack;
149     uint8_t flags;
150 
151     if (!SYN_ACKED) {
152         seq = 0x28;
153         ack = last_seq + 1;
154         flags = TYPE_TCP_ACK | TYPE_TCP_SYN;
155         SYN_ACKED = true;
156     } else {
157         seq = last_ack;
158         ack = last_seq + last_payload_bytes;
159         flags = TYPE_TCP_ACK;
160     }
161 
162     if (len > 60)
163         return LC_ERROR;
164     pkt[0] = 5+len;
165     pkt[1] = flags;
166     pkt[2] = seq;
167     pkt[3] = ack;
168     pkt[4] = typ;
169     pkt[5] = cmd;
170     if (data && len)
171         memcpy(pkt + 6, data, len);
172 
173     debug("Writing packet:");
174 #ifdef _DEBUG
175     for (int i = 0; i <= pkt[0]; i++) {
176         fprintf(stderr, "%02X ", pkt[i]);
177     }
178     fprintf(stderr, "\n");
179 #endif
180 
181     return HID_WriteReport(pkt);
182 }
183 
184 
TCP_Read(uint8_t & status,uint32_t & len,uint8_t * data)185 int CRemoteZ_HID::TCP_Read(uint8_t &status, uint32_t &len, uint8_t *data)
186 {
187     uint8_t pkt[HID_UDP_MAX_PACKET_SIZE];
188     int err;
189     /*
190      * Many TCP operations can take a while, like computing checksums,
191      * and it will be a while before we get a response. So we set the
192      * timeout to 30 seconds.
193      */
194     if ((err = HID_ReadReport(pkt, 30000))) {
195         return LC_ERROR_READ;
196     }
197 
198     debug("Reading packet:");
199 #ifdef _DEBUG
200     for (int i = 0; i <= pkt[0]; i++) {
201         fprintf(stderr, "%02X ", pkt[i]);
202     }
203     fprintf(stderr, "\n");
204 #endif
205 
206     if (pkt[0] < 3) {
207         return LC_ERROR;
208     }
209     /*
210      * pkt[0] is the index of the last byte, which means it is equal to the
211      * length of packet minus one byte.  'len' is expected to be set to the
212      * payload size.  To get the payload size we subtract both the TCP and
213      * UDP headers from pkt[0] and then add one.
214      */
215     len = pkt[0] - HID_TCP_HDR_SIZE - HID_UDP_HDR_SIZE + 1;
216     last_seq = pkt[2];
217     last_ack = pkt[3];
218     last_payload_bytes = len + HID_UDP_HDR_SIZE; // tcp payload size
219     //if(!len) return 0;
220     //memcpy(data, pkt + 6, len);
221     // include headers, minus the size
222     memcpy(data, pkt + 1, len + HID_TCP_HDR_SIZE + HID_UDP_HDR_SIZE - 1);
223     return 0;
224 }
225 
Write(uint8_t typ,uint8_t cmd,uint32_t len,uint8_t * data)226 int CRemoteZ_HID::Write(uint8_t typ, uint8_t cmd, uint32_t len, uint8_t *data)
227 {
228     return UDP_Write(typ, cmd, len, data);
229 }
230 
Read(uint8_t & status,uint32_t & len,uint8_t * data)231 int CRemoteZ_HID::Read(uint8_t &status, uint32_t &len, uint8_t *data)
232 {
233     return UDP_Read(status, len, data);
234 }
235 
ParseParams(uint32_t len,uint8_t * data,TParamList & pl)236 int CRemoteZ_HID::ParseParams(uint32_t len, uint8_t *data, TParamList &pl)
237 {
238     debug("ParseParams, %02x %02x %02x %02x %02x %02x\n", data[0], data[1],
239           data[2], data[3], data[4], data[5]);
240     switch (data[2]) {
241         case COMMAND_GET_SYSTEM_INFO:
242             pl.count = 8;
243             pl.p[0] = data + 4;
244             pl.p[1] = data + 6;
245             pl.p[2] = data + 8;
246             pl.p[3] = data + 10;
247             pl.p[4] = data + 12;
248             pl.p[5] = data + 14;
249             pl.p[6] = data + 15;
250             pl.p[7] = data + 17;
251             break;
252         case COMMAND_GET_CURRENT_TIME:
253             pl.count = (len > 16) ? 12 : 8;
254             pl.p[0] = data + 4;
255             pl.p[1] = data + 6;
256             pl.p[2] = data + 7;
257             pl.p[3] = data + 8;
258             pl.p[4] = data + 9;
259             pl.p[5] = data + 10;
260             pl.p[6] = data + 11;
261             pl.p[7] = data + 12;
262             pl.p[8] = data + 14;
263             pl.p[9] = data + 16;
264             pl.p[10] = data + 18;
265             pl.p[11] = data + 20;
266             break;
267         case COMMAND_GET_GUID:
268             pl.count = 1;
269             pl.p[0] = data + 4;
270             break;
271     }
272     return 0;
273 }
274 
275 
Write(uint8_t typ,uint8_t cmd,uint32_t len,uint8_t * data)276 int CRemoteZ_USBNET::Write(uint8_t typ, uint8_t cmd, uint32_t len,
277                            uint8_t *data)
278 {
279     if (len > USBNET_MAX_PACKET_SIZE) {
280         return LC_ERROR;
281     }
282 
283     static const uint8_t service_type = SERVICE_FAMILY_CLIENT;
284     const bool request = (typ == TYPE_REQUEST);
285     const uint8_t status = STATUS_OK;
286 
287     uint8_t pkt[USBNET_MAX_PACKET_SIZE+3]; /* add standard 3-byte header */
288     pkt[0] = (service_type << 4) | ((cmd >> 8) & 0x0F);
289     pkt[1] = cmd & 0xFF;
290     pkt[2] = request ? 0x80 : (status & 0x7F);
291 
292     if (len && data) {
293         memcpy(pkt + 3, data, len);
294         len += 3;
295     } else {
296         pkt[3] = 0x00;    // Param count
297         len = 4;
298     }
299 
300     return UsbLan_Write(len, pkt);
301 }
302 
Read(uint8_t & status,uint32_t & len,uint8_t * data)303 int CRemoteZ_USBNET::Read(uint8_t &status, uint32_t &len, uint8_t *data)
304 {
305     uint8_t buf[1600];
306     len = sizeof(buf);
307     int err;
308     if ((err = UsbLan_Read(len, buf)))
309         return err;
310 
311     memcpy(data, buf, len);
312 
313     return err;
314 }
315 
ParseParams(uint32_t len,uint8_t * data,TParamList & pl)316 int CRemoteZ_USBNET::ParseParams(uint32_t len, uint8_t *data, TParamList &pl)
317 {
318     unsigned int n = 0;
319     unsigned int i = 4;
320     while (i < len) {
321         unsigned int param_len = data[i];
322         switch (param_len & 0xC0) {
323             case 0x00:
324             case 0x80:
325                 param_len &= 0x3F;
326                 break;
327             case 0x40:
328                 param_len = (param_len & 0x3F) * 4;
329                 break;
330             case 0xC0:
331                 param_len = (param_len & 0x3F) * 512;
332                 break;
333         }
334         ++i;
335         pl.p[n++] = data+i;
336 #ifdef _DEBUG
337         fprintf(stderr, "DEBUG (%s): %3i:", __FUNCTION__, param_len);
338         for(unsigned int j = 0; j < param_len; ++j)
339             fprintf(stderr, " %02X", data[i+j]);
340         fprintf(stderr, "\n");
341 #endif
342         i += param_len;
343     }
344 
345     //data[3];    // Number of parameters
346     pl.count = n;
347 
348     return 0;
349 }
350 
TCPSendAndCheck(uint8_t cmd,uint32_t len,uint8_t * data)351 int CRemoteZ_USBNET::TCPSendAndCheck(uint8_t cmd, uint32_t len, uint8_t *data)
352 {
353     int err = 0;
354     uint8_t status;
355     unsigned int rlen;
356     uint8_t rsp[60];
357 
358     if ((err = Write(TYPE_REQUEST, cmd, len, data))) {
359         debug("Failed to send request %02X", cmd);
360         return LC_ERROR_WRITE;
361     }
362 
363     if ((err = Read(status, rlen, rsp))) {
364         debug("Failed to read from remote");
365         return LC_ERROR_READ;
366     }
367 
368     if (rsp[2] != TYPE_RESPONSE) {
369         debug("Packet didn't have response bit!");
370         return LC_ERROR;
371     }
372 
373     if (rsp[1] != cmd) {
374         debug("The cmd bit didn't match our request packet");
375         return LC_ERROR;
376     }
377 
378     return 0;
379 }
380 
UpdateConfig(const uint32_t len,const uint8_t * wr,lc_callback cb,void * cb_arg,uint32_t cb_stage,uint32_t xml_size,uint8_t * xml)381 int CRemoteZ_USBNET::UpdateConfig(const uint32_t len, const uint8_t *wr,
382                                   lc_callback cb, void *cb_arg,
383                                   uint32_t cb_stage, uint32_t xml_size,
384                                   uint8_t *xml)
385 {
386     int err = 0;
387     int cb_count = 0;
388 
389     cb(LC_CB_STAGE_INITIALIZE_UPDATE, cb_count++, 0, 2,
390        LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
391 
392     /* ACK it with a command to start an update */
393     debug("START_UPDATE");
394     // 2 parameters, each 1 byte.
395     // 1st parameter "flags" seems to always be 0.
396     uint8_t cmd[60] = { 0x02, 0x01, 0x00, 0x01, REGION_USER_CONFIG };
397     if ((err = TCPSendAndCheck(COMMAND_START_UPDATE, 5, cmd))) {
398         return err;
399     }
400 
401     cb(LC_CB_STAGE_INITIALIZE_UPDATE, cb_count++, 1, 2,
402         LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
403 
404     /* write update-header */
405     debug("UPDATE_HEADER");
406     cmd[0] = 0x02; // 2 parameters
407     cmd[1] = 0x04; // 1st parameter 4 bytes (size)
408     cmd[2] = (len & 0xFF000000) >> 24;
409     cmd[3] = (len & 0x00FF0000) >> 16;
410     cmd[4] = (len & 0x0000FF00) >> 8;
411     cmd[5] = (len & 0x000000FF);
412     cmd[6] = 0x01; // 2nd parameter 1 byte (region id)
413     cmd[7] = REGION_USER_CONFIG;
414     if ((err = TCPSendAndCheck(COMMAND_WRITE_UPDATE_HEADER, 8, cmd))) {
415         return err;
416     }
417 
418     cb(LC_CB_STAGE_INITIALIZE_UPDATE, cb_count++, 2, 2,
419        LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
420     cb_count = 0;
421 
422     /* write data */
423     debug("UPDATE_DATA");
424     uint32_t pkt_len;
425     uint32_t tlen = len;
426     uint8_t *wr_ptr = const_cast<uint8_t*>(wr);
427     uint8_t tmp_pkt[1033];
428     tmp_pkt[0] = 0x03; // 3 parameters
429     tmp_pkt[1] = 0x01; // 1st parameter, 1 byte (region id)
430     tmp_pkt[2] = REGION_USER_CONFIG;
431     tmp_pkt[3] = 0xC2; // 2nd parameter, 1024 bytes (data)
432     tmp_pkt[1028] = 0x04; // 3rd parameter, 4 bytes (length)
433     while (tlen) {
434         pkt_len = 1024; // max packet length seems to be 1024
435         if (tlen < pkt_len) {
436             pkt_len = tlen;
437         }
438         tlen -= pkt_len;
439 
440         memcpy(&tmp_pkt[4], wr_ptr, pkt_len);
441         tmp_pkt[1029] = (pkt_len & 0xFF000000) >> 24;
442         tmp_pkt[1030] = (pkt_len & 0x00FF0000) >> 16;
443         tmp_pkt[1031] = (pkt_len & 0x0000FF00) >> 8;
444         tmp_pkt[1032] = (pkt_len & 0x000000FF);
445 
446         debug("DATA %d, sending %d bytes, %d bytes left", cb_count,
447             pkt_len, tlen);
448 
449         if ((err = TCPSendAndCheck(COMMAND_WRITE_UPDATE_DATA, 1033, tmp_pkt))) {
450             return err;
451         }
452         wr_ptr += pkt_len;
453 
454         if (cb) {
455             cb(LC_CB_STAGE_WRITE_CONFIG, cb_count++, (int)(wr_ptr - wr), len,
456                LC_CB_COUNTER_TYPE_BYTES, cb_arg, NULL);
457         }
458     }
459 
460     /* write update-done */
461     cb_count = 0;
462     cb(LC_CB_STAGE_FINALIZE_UPDATE, cb_count++, 0, 3, LC_CB_COUNTER_TYPE_STEPS,
463        cb_arg, NULL);
464 
465     debug("UPDATE_DATA_DONE");
466     cmd[0] = 0x01; // 1 parameter
467     cmd[1] = 0x01; // 1st parameter 1 byte (region id)
468     cmd[2] = REGION_USER_CONFIG;
469     if ((err = TCPSendAndCheck(COMMAND_WRITE_UPDATE_DATA_DONE, 3, cmd))) {
470         return err;
471     }
472 
473     cb(LC_CB_STAGE_FINALIZE_UPDATE, cb_count++, 1, 3, LC_CB_COUNTER_TYPE_STEPS,
474        cb_arg, NULL);
475 
476     /* send get-cheksum */
477     debug("GET_CHECKSUM");
478     cmd[0] = 0x02; // 2 parameters
479     cmd[1] = 0x02; // 1st parameter 2 bytes (seed)
480     cmd[2] = 0xFF; // seed seems to always be FF
481     cmd[3] = 0xFF; // seed seems to always be FF
482     cmd[4] = 0x01; // 2nd parameter 1 byte (region id)
483     cmd[5] = REGION_USER_CONFIG;
484     if ((err = TCPSendAndCheck(COMMAND_GET_UPDATE_CHECKSUM, 6, cmd))) {
485         return err;
486     }
487 
488     cb(LC_CB_STAGE_FINALIZE_UPDATE, cb_count++, 2, 3, LC_CB_COUNTER_TYPE_STEPS,
489        cb_arg, NULL);
490 
491     /* send finish-update */
492     debug("FINISH_UPDATE");
493     cmd[0] = 0x02; // 2 parameters
494     cmd[1] = 0x01; // 1st parameter 1 byte (validate)
495     cmd[2] = 0x01; // validate?
496     cmd[3] = 0x01; // 2nd parameter 1 byte (region id)
497     cmd[4] = REGION_USER_CONFIG;
498     if ((err = TCPSendAndCheck(COMMAND_FINISH_UPDATE, 5, cmd))) {
499         return err;
500     }
501 
502     cb(LC_CB_STAGE_FINALIZE_UPDATE, cb_count++, 3, 3, LC_CB_COUNTER_TYPE_STEPS,
503        cb_arg, NULL);
504 
505     return 0;
506 }
507 
GetTime(const TRemoteInfo & ri,THarmonyTime & ht)508 int CRemoteZ_USBNET::GetTime(const TRemoteInfo &ri, THarmonyTime &ht)
509 {
510     int err = 0;
511     if ((err = Write(TYPE_REQUEST, COMMAND_GET_CURRENT_TIME))) {
512         debug("Failed to write to remote");
513         return LC_ERROR_WRITE;
514     }
515     uint8_t time[60];
516     unsigned int len;
517     uint8_t status;
518     if ((err = Read(status, len, time))) {
519         debug("Failed to read to remote");
520         return LC_ERROR_READ;
521     }
522 
523     if (time[2] != TYPE_RESPONSE || time[1] != COMMAND_GET_CURRENT_TIME) {
524         debug("Incorrect response type from Get Time");
525         return LC_ERROR_INVALID_DATA_FROM_REMOTE;
526     }
527 
528     CRemoteZ_Base::TParamList pl;
529     ParseParams(len, time, pl);
530 
531     ht.year = GetWord(pl.p[0]);
532     ht.month = *pl.p[1];
533     ht.day = *pl.p[2];
534     ht.hour = *pl.p[3];
535     ht.minute = *pl.p[4];
536     ht.second = *pl.p[5];
537     ht.dow = *pl.p[6]&7;
538     ht.utc_offset = static_cast<int16_t>(GetWord(pl.p[7]));
539     if (pl.count > 11) {
540         ht.timezone = reinterpret_cast<char*>(pl.p[11]);
541         ht.timezone[3] = '\0';
542     } else {
543         ht.timezone = "";
544     }
545 
546     return 0;
547 }
548 
SetTime(const TRemoteInfo & ri,const THarmonyTime & ht,lc_callback cb,void * cb_arg,uint32_t cb_stage)549 int CRemoteZ_USBNET::SetTime(const TRemoteInfo &ri, const THarmonyTime &ht,
550                              lc_callback cb, void *cb_arg, uint32_t cb_stage)
551 {
552     debug("SetTime");
553     int err = 0;
554 
555     uint8_t tsv[32] = {
556         0x0C, // 12 parameters
557         0x02, static_cast<uint8_t>(ht.year >> 8),
558         static_cast<uint8_t>(ht.year), // 2 bytes
559         0x01, static_cast<uint8_t>(ht.month),
560         0x01, static_cast<uint8_t>(ht.day),
561         0x01, static_cast<uint8_t>(ht.hour),
562         0x01, static_cast<uint8_t>(ht.minute),
563         0x01, static_cast<uint8_t>(ht.second),
564         0x01, static_cast<uint8_t>(ht.dow),
565         // utcOffset
566         0x02, 0, 0, // 2 bytes - 900 doesn't seem to accept this
567         // 0s
568         0x02, 0, 0, // 2 bytes
569         0x02, 0, 0, // 2 bytes
570         0x02, 0, 0, // 2 bytes
571         0x83, 0, 0, 0 // 900 doesn't seem to accept this, don't bother
572         };
573 
574     if ((err = TCPSendAndCheck(COMMAND_UPDATE_TIME, 32, tsv))) {
575         debug("Failed to write to remote");
576         return err;
577     }
578 
579     return 0;
580 }
581 
LearnIR(uint32_t * freq,uint32_t ** ir_signal,uint32_t * ir_signal_length,lc_callback cb,void * cb_arg,uint32_t cb_stage)582 int CRemoteZ_USBNET::LearnIR(uint32_t *freq, uint32_t **ir_signal,
583                              uint32_t *ir_signal_length, lc_callback cb,
584                              void *cb_arg, uint32_t cb_stage)
585 {
586     return LC_ERROR_UNSUPP;
587 }
588 
ReadRegion(uint8_t region,uint32_t & rgn_len,uint8_t * rd,lc_callback cb,void * cb_arg,uint32_t cb_stage)589 int CRemoteZ_USBNET::ReadRegion(uint8_t region, uint32_t &rgn_len, uint8_t *rd,
590                                 lc_callback cb, void *cb_arg, uint32_t cb_stage)
591 {
592     int err = 0;
593     int cb_count = 0;
594     uint8_t rsp[60];
595     unsigned int rlen;
596     uint8_t status;
597     CRemoteZ_Base::TParamList pl;
598 
599     debug("READ_REGION");
600     // 1 parameters, 1 byte, region to read.
601     uint8_t cmd[60] = { 0x01, 0x01, region };
602     if ((err = Write(TYPE_REQUEST, COMMAND_READ_REGION, 3, cmd))) {
603         debug("Failed to write to remote");
604         return LC_ERROR_WRITE;
605     }
606     if ((err = Read(status, rlen, rsp))) {
607         debug("Failed to read to remote");
608         return LC_ERROR_READ;
609     }
610     if (rsp[2] != TYPE_RESPONSE || rsp[1] != COMMAND_READ_REGION || rlen != 9 ||
611         rsp[4] != 0x04) {
612         debug("Incorrect response type from remote");
613         return LC_ERROR_INVALID_DATA_FROM_REMOTE;
614     }
615     ParseParams(rlen, rsp, pl);
616     rgn_len = GetWord32(pl.p[0]);
617 
618     debug("READ_REGION_DATA");
619     uint32_t pkt_len;
620     unsigned int data_to_read = rgn_len;
621     uint8_t *rd_ptr = rd;
622     uint8_t tmp_pkt[USBNET_MAX_PACKET_SIZE];
623     cmd[0] = 0x01; // 1 parameter
624     cmd[1] = 0x01; // 1st parameter, 1 byte (region id)
625     cmd[2] = region;
626 
627     while (data_to_read) {
628         if ((err = Write(TYPE_REQUEST, COMMAND_READ_REGION_DATA, 3, cmd))) {
629             debug("Failed to write to remote");
630             return LC_ERROR_WRITE;
631         }
632         if ((err = Read(status, rlen, tmp_pkt))) {
633             debug("Failed to read to remote");
634             return LC_ERROR_READ;
635         }
636         if (tmp_pkt[2] != TYPE_RESPONSE ||
637             tmp_pkt[1] != COMMAND_READ_REGION_DATA) {
638             debug("Incorrect response type from remote");
639             return LC_ERROR_INVALID_DATA_FROM_REMOTE;
640         }
641         ParseParams(rlen, tmp_pkt, pl);
642         pkt_len = GetWord32(pl.p[2]);
643         data_to_read -= pkt_len;
644 
645         if (rd) {
646             memcpy(rd_ptr, pl.p[1], pkt_len);
647             rd_ptr += pkt_len;
648         }
649 
650         debug("DATA %d, read %d bytes, %d bytes left", cb_count, pkt_len,
651               data_to_read);
652 
653         if (cb) {
654             cb(cb_stage, cb_count++, rgn_len - data_to_read, rgn_len,
655                LC_CB_COUNTER_TYPE_BYTES, cb_arg, NULL);
656         }
657     }
658 
659     debug("READ_REGION_DONE");
660     // 1 parameter, 1 byte, region to read.
661     cmd[0] = 0x01;
662     cmd[1] = 0x01;
663     cmd[2] = region;
664     if ((err = TCPSendAndCheck(COMMAND_READ_REGION_DONE, 3, cmd))) {
665         return err;
666     }
667 
668     return 0;
669 }
670 
Reset(uint8_t kind)671 int CRemoteZ_Base::Reset(uint8_t kind)
672 {
673     int err = 0;
674     /*
675      * TODO: I don't believe the zwaves have a "kind" of reset
676      * ... is this needed here?
677      */
678     if (kind != 2) {
679         return LC_ERROR;
680     }
681 
682     if ((err = Write(TYPE_REQUEST, COMMAND_Z_RESET))) {
683         debug("Failed to write to remote");
684         return LC_ERROR_WRITE;
685     }
686     uint8_t rsp[60];
687     unsigned int len;
688     uint8_t status;
689     if ((err = Read(status, len, rsp))) {
690         debug("Failed to read to remote");
691         return LC_ERROR_READ;
692     }
693 
694     /*
695      * TODO: Either the remote is gone at this point, and reading
696      * will fail, or we need a "finalize action" command afterwards,
697      * in which case we should check the actual return status from
698      * the remote.
699      */
700     /*
701     if (time[1] != TYPE_RESPONSE || time[2] != COMMAND_Z_RESET) {
702         return LC_ERROR_INVALID_DATA_FROM_REMOTE;
703     }
704     */
705 
706     return 0;
707 }
708 
GetIdentity(TRemoteInfo & ri,THIDINFO & hid,lc_callback cb,void * cb_arg,uint32_t cb_stage)709 int CRemoteZ_Base::GetIdentity(TRemoteInfo &ri, THIDINFO &hid, lc_callback cb,
710                                void *cb_arg, uint32_t cb_stage)
711 {
712     int err = 0;
713     if ((err = Write(TYPE_REQUEST, COMMAND_GET_SYSTEM_INFO))) {
714         debug("Failed to write to remote");
715         return LC_ERROR_WRITE;
716     }
717     uint8_t rsp[60];
718     unsigned int len;
719     uint8_t status;
720     if ((err = Read(status, len, rsp))) {
721         debug("Failed to read from remote");
722         return LC_ERROR_READ;
723     }
724 
725     if (cb) {
726         cb(cb_stage, 0, 1, 2, LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
727     }
728 
729     CRemoteZ_Base::TParamList pl;
730     ParseParams(len, rsp, pl);
731 
732     ri.flash_mfg = 0x01;
733     ri.flash_id = 0x49;
734     ri.architecture = GetWord(pl.p[2]);
735     ri.fw_ver_major = GetWord(pl.p[3]);
736     ri.fw_ver_minor = GetWord(pl.p[4]);
737     ri.fw_type = *pl.p[5];
738     ri.skin = GetWord(pl.p[6]);
739     const unsigned int hw = GetWord(pl.p[7]);
740     ri.hw_ver_major = hw >> 8;        // ???
741     ri.hw_ver_minor = (hw >> 4) & 0x0F;    // ???
742     ri.hw_ver_micro = hw & 0x0F;        // 900 has this and is non-zero
743     //ri.hw_ver_major = hw >> 4;
744     //ri.hw_ver_minor = hw & 0x0F;
745     ri.protocol = GetWord(pl.p[2]); // Seems to be the same as arch?
746 
747     setup_ri_pointers(ri);
748 
749     if (IsUSBNet()) {
750         hid.vid = GetWord(pl.p[0]);
751         hid.pid = GetWord(pl.p[1]);
752         hid.ver = 0;
753         hid.irl = 0;
754         hid.orl = 0;
755         hid.frl = 0;
756         hid.mfg = ri.model->mfg;
757         hid.prod = ri.model->model;
758     }
759 
760     if ((err = Write(TYPE_REQUEST, COMMAND_GET_GUID))) {
761         debug("Failed to write to remote");
762         return LC_ERROR_WRITE;
763     }
764     if ((err = Read(status, len, rsp))) {
765         debug("Failed to read from remote");
766         return LC_ERROR_READ;
767     }
768 
769     if (cb) {
770         cb(LC_CB_STAGE_GET_IDENTITY, 1, 2, 2, LC_CB_COUNTER_TYPE_STEPS, cb_arg,
771            NULL);
772     }
773 
774     ParseParams(len, rsp, pl);
775 
776     make_serial(pl.p[0], ri);
777 
778     if (IsUSBNet()) {
779         // Get the User Config Region to find the config bytes used.
780         if ((err = ReadRegion(REGION_USER_CONFIG, ri.config_bytes_used, NULL,
781                               NULL, NULL, 0))) {
782             return err;
783         }
784     } else {
785         ri.config_bytes_used = 0;
786     }
787     ri.max_config_size = 1;
788     ri.valid_config = 1;
789 
790     if (!IsUSBNet()) {
791         return 0;
792     }
793 
794     // Get region info - everything below is extra stuff that only the
795     // usbnet remotes seem to use.
796     uint8_t rr[] = { 1, 1, 1 }; // AddByteParam(1);
797     if ((err = Write(TYPE_REQUEST, COMMAND_GET_REGION_IDS, 3, rr))) {
798         debug("Failed to write to remote");
799         return LC_ERROR;
800     }
801     uint8_t rgn[64];
802     if ((err = Read(status, len, rgn))) {
803         debug("Failed to read from remote");
804         return LC_ERROR;
805     }
806     ParseParams(len, rgn, pl);
807     if (pl.count == 1) {
808         const unsigned int rc = *(pl.p[0]-1) & 0x3F;
809         ri.num_regions = rc + 1;
810         ri.region_ids = new uint8_t[ri.num_regions];
811         ri.region_versions = new char*[ri.num_regions];
812 
813         // There seems to be an implied Region 0 that the Windows
814         // software requests but it is not listed in the Region IDs.
815         uint8_t rz[] = { 1, 1, 0 }; // 1 parameter, 1 byte, value = 0
816         if ((err = Write(TYPE_REQUEST, COMMAND_GET_REGION_VERSION, 3, rz))) {
817             debug("Failed to write to remote");
818             return LC_ERROR;
819         }
820         uint8_t rgz[64];
821         if ((err = Read(status, len, rgz))) {
822             debug("Failed to read from remote");
823             return LC_ERROR;
824         }
825         CRemoteZ_Base::TParamList rzp;
826         ParseParams(len, rgz, rzp);
827         ri.region_ids[0] = 0x00; // Store region 0.
828         ri.region_versions[0] = new char[4];
829         snprintf(ri.region_versions[0], 4, "%d.%d", *(rzp.p[0]+1), *rzp.p[0]);
830 
831         for(unsigned int r = 0; r < rc; ++r) {
832             const uint8_t rn = *(pl.p[0]+r);
833             debug("Region %i", rn);
834             uint8_t rv[] = { 1, 1, rn }; // AddByteParam(rn);
835             if ((err = Write(TYPE_REQUEST, COMMAND_GET_REGION_VERSION, 3,
836                              rv))) {
837                 debug("Failed to write to remote");
838                 return LC_ERROR;
839             }
840             uint8_t rgv[64];
841             if ((err = Read(status, len, rgv))) {
842                 debug("Failed to read from remote");
843                 return LC_ERROR;
844             }
845             CRemoteZ_Base::TParamList rp;
846             ParseParams(len, rgv, rp);
847             ri.region_ids[r+1] = rn;
848             ri.region_versions[r+1] = new char[4];
849             snprintf(ri.region_versions[r+1], 4, "%d.%d", *(rp.p[0]+1),
850                      *rp.p[0]);
851         }
852     }
853 
854     // Get HOMEID, NODEID, TID
855     if ((err = Write(TYPE_REQUEST, COMMAND_GET_HOME_ID))) {
856         debug("Failed to write to remote");
857         return LC_ERROR;
858     }
859     if ((err = Read(status, len, rsp))) {
860         debug("Failed to read from remote");
861         return LC_ERROR;
862     }
863     ParseParams(len, rsp, pl);
864     ri.home_id = (*pl.p[0] << 24) + (*(pl.p[0]+1) << 16) +
865             (*(pl.p[0]+2) << 8) + *(pl.p[0]+3);
866     if ((err = Write(TYPE_REQUEST, COMMAND_GET_NODE_ID))) {
867         debug("Failed to write to remote");
868         return LC_ERROR;
869     }
870     if ((err = Read(status, len, rsp))) {
871         debug("Failed to read from remote");
872         return LC_ERROR;
873     }
874     ParseParams(len, rsp, pl);
875     ri.node_id = *pl.p[0];
876     // Get the "TID" - not entirely sure what this is, but it appears to be
877     // contained in the INTERFACE_LIST.
878     if ((err = Write(TYPE_REQUEST, COMMAND_GET_INTERFACE_LIST))) {
879         debug("Failed to write to remote");
880         return LC_ERROR;
881     }
882     if ((err = Read(status, len, rsp))) {
883         debug("Failed to read from remote");
884         return LC_ERROR;
885     }
886     ParseParams(len, rsp, pl);
887     ri.tid = new char[21];
888     ri.tid[0] = '0';
889     ri.tid[1] = 'x';
890     // "TID" appears to be contained in the middle of the INTERFACE_LIST.
891     for (int i = 0; i < 9; i++)
892         snprintf(&ri.tid[(i*2)+2], 3, "%02X", *(pl.p[1]+i+2));
893     ri.tid[20] = '\0';
894 
895     // Get the "XMLUserRFSetting" - the usbnet remote appears to have a web
896     // server running where the Windows driver grabs this data.
897     if ((err = GetXMLUserRFSetting(&ri.xml_user_rf_setting))) {
898         debug("Failed to read XML User RF Settings");
899         return LC_ERROR;
900     }
901 
902     return 0;
903 }
904 
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)905 int CRemoteZ_Base::ReadFlash(uint32_t addr, const uint32_t len, uint8_t *rd,
906                              unsigned int protocol, bool verify, lc_callback cb,
907                              void *cb_arg, uint32_t cb_stage)
908 {
909     uint32_t tmp;
910     return ReadRegion(addr, tmp, rd, cb, cb_arg, cb_stage);
911 }
912 
913 /*
914  * When reading a config from the remote, we need to look for a sequence of
915  * four bytes to determine when to stop reading the config.  The tricky part is
916  * that the sequence could be split across two packets.  Thus, we need to
917  * search the last three bytes of the previous packet plus the current packet.
918  * This function searches for the "end of file" sequence in a set of two
919  * packets.  If the sequence is found, returns the number of bytes in the
920  * second packet up to and including the sequence.  Returns 0 if the sequence
921  * is not found.  Parameters point to the data section of the packets.  Note for
922  * the first packet, only the last 3 bytes are expected to be passed in.
923  */
FindEndSeq(uint8_t * pkt_1,uint8_t * pkt_2)924 int FindEndSeq(uint8_t *pkt_1, uint8_t *pkt_2)
925 {
926     uint8_t end_seq[4] = { 0x44, 0x4B, 0x44, 0x4B }; // end of file sequence
927     uint8_t tmp[57]; // 3 bytes from the 1st packet, 54 bytes from the 2nd
928     memcpy(&tmp, pkt_1, 3);
929     memcpy(&tmp[3], pkt_2, 54);
930     for (int i=0; i<54; i++) {
931         if (memcmp(&end_seq, &tmp[i], 4) == 0) {
932             return i + 1;
933         }
934     }
935     return 0;
936 }
937 
ReadRegion(uint8_t region,uint32_t & rgn_len,uint8_t * rd,lc_callback cb,void * cb_arg,uint32_t cb_stage)938 int CRemoteZ_HID::ReadRegion(uint8_t region, uint32_t &rgn_len, uint8_t *rd,
939                              lc_callback cb, void *cb_arg, uint32_t cb_stage)
940 {
941     int err = 0;
942     int cb_count = 0;
943     uint8_t rsp[60];
944     unsigned int rlen;
945     uint8_t status;
946 
947     /* Start a TCP transfer */
948     if ((err = Write(TYPE_REQUEST, COMMAND_INITIATE_UPDATE_TCP_CHANNEL))) {
949         debug("Failed to write to remote");
950         return LC_ERROR_WRITE;
951     }
952 
953     /* Make sure the remote is ready to start the TCP transfer */
954     if ((err = Read(status, rlen, rsp))) {
955         debug("Failed to read from remote");
956         return LC_ERROR_READ;
957     }
958 
959     if (rsp[1] != TYPE_RESPONSE || rsp[2] !=
960         COMMAND_INITIATE_UPDATE_TCP_CHANNEL) {
961         return LC_ERROR;
962     }
963 
964     /* Look for a SYN packet */
965     debug("Looking for syn");
966     if ((err = TCP_Read(status, rlen, rsp))) {
967         debug("Failed to read syn from remote");
968         return LC_ERROR_READ;
969     }
970 
971     if (rsp[0] != TYPE_TCP_SYN) {
972         debug("Not a SYN packet!");
973         return LC_ERROR;
974     }
975 
976     /* ACK it with a command to read a region */
977     debug("READ_REGION");
978     // 1 parameters, 1 byte, region to read.
979     uint8_t cmd[60] = { region };
980     if ((err = TCP_Write(TYPE_REQUEST, COMMAND_READ_REGION, 1, cmd))) {
981         debug("Failed to write to remote");
982         return LC_ERROR_WRITE;
983     }
984     if ((err = TCP_Read(status, rlen, rsp))) {
985         debug("Failed to read to remote");
986         return LC_ERROR_READ;
987     }
988     if (rsp[0] != TYPE_TCP_ACK || rsp[3] != TYPE_RESPONSE ||
989         rsp[4] != COMMAND_READ_REGION) {
990          debug("Incorrect response type from remote");
991         return LC_ERROR_INVALID_DATA_FROM_REMOTE;
992     }
993 
994     rgn_len = 0;
995 
996     debug("READ_REGION_DATA");
997     int data_read = 0;
998     uint8_t *rd_ptr = rd;
999     cmd[0] = region;
1000     int eof_found = 0;
1001     uint8_t prev_pkt_tail[3] = { 0x00, 0x00, 0x00 };
1002 
1003     while (1) {
1004         if ((err = TCP_Write(TYPE_REQUEST, COMMAND_READ_REGION_DATA, 1, cmd))) {
1005             debug("Failed to write to remote");
1006             return LC_ERROR_WRITE;
1007         }
1008         if ((err = TCP_Read(status, rlen, rsp))) {
1009             debug("Failed to read to remote");
1010             return LC_ERROR_READ;
1011         }
1012         if (rsp[0] != TYPE_TCP_ACK || rsp[3] != TYPE_RESPONSE ||
1013             ((rsp[4] != COMMAND_READ_REGION_DATA) &&
1014             (rsp[4] != COMMAND_READ_REGION_DONE))) {
1015              debug("Incorrect response type from remote");
1016             return LC_ERROR_INVALID_DATA_FROM_REMOTE;
1017         }
1018         if (rsp[4] == COMMAND_READ_REGION_DONE) {
1019             break;
1020         }
1021         data_read += rlen;
1022 
1023         if (!eof_found) {
1024             eof_found = FindEndSeq(prev_pkt_tail, &rsp[5]);
1025             if (eof_found) {
1026                 rlen = eof_found;
1027             }
1028             rgn_len += rlen;
1029             memcpy(&prev_pkt_tail, &rsp[56], 3);
1030 
1031             if (rd) {
1032                 memcpy(rd_ptr, &rsp[5], rlen);
1033                 rd_ptr += rlen;
1034             }
1035         }
1036 
1037         debug("DATA %d, read %d bytes, %d bytes total", cb_count, rlen,
1038               data_read);
1039 
1040         if (cb) {
1041             cb(cb_stage, cb_count++, data_read, data_read+1,
1042                LC_CB_COUNTER_TYPE_BYTES, cb_arg, NULL);
1043         }
1044     }
1045 
1046     debug("FIN-ACK");
1047     if ((err = TCP_Ack(false, true))) {
1048         debug("Failed to send fin-ack");
1049         return LC_ERROR_WRITE;
1050     }
1051 
1052     if ((err = TCP_Read(status, rlen, rsp))) {
1053         debug("Failed to read from remote");
1054         return LC_ERROR_READ;
1055     }
1056 
1057     /* Make sure we got an ack */
1058     if (rsp[0] != (TYPE_TCP_ACK | TYPE_TCP_FIN)) {
1059         debug("Failed to read finish-update ack");
1060         return LC_ERROR;
1061     }
1062 
1063     if ((err = TCP_Ack(true, false))) {
1064         debug("Failed to ack the ack of our fin-ack");
1065         return LC_ERROR_WRITE;
1066     }
1067 
1068     /* Return TCP state to initial conditions */
1069     SYN_ACKED = false;
1070 
1071     if (cb) {
1072         cb(cb_stage, cb_count++, data_read, data_read, LC_CB_COUNTER_TYPE_BYTES,
1073            cb_arg, NULL);
1074     }
1075 
1076     return 0;
1077 }
1078 
InvalidateFlash(lc_callback cb,void * cb_arg,uint32_t cb_stage)1079 int CRemoteZ_Base::InvalidateFlash(lc_callback cb, void *cb_arg,
1080                                    uint32_t cb_stage)
1081 {
1082     return 0;
1083 }
1084 
EraseFlash(uint32_t addr,uint32_t len,const TRemoteInfo & ri,lc_callback cb,void * cb_arg,uint32_t cb_stage)1085 int CRemoteZ_Base::EraseFlash(uint32_t addr, uint32_t len,
1086                               const TRemoteInfo &ri, lc_callback cb,
1087                               void *cb_arg, uint32_t cb_stage)
1088 {
1089     return 0;
1090 }
1091 
WriteFlash(uint32_t addr,const uint32_t len,const uint8_t * wr,unsigned int protocol,lc_callback cb,void * arg,uint32_t cb_stage)1092 int CRemoteZ_Base::WriteFlash(uint32_t addr, const uint32_t len,
1093                               const uint8_t *wr, unsigned int protocol,
1094                               lc_callback cb, void *arg, uint32_t cb_stage)
1095 {
1096     return 0;
1097 }
1098 
WriteRam(uint32_t addr,const uint32_t len,uint8_t * wr)1099 int CRemoteZ_Base::WriteRam(uint32_t addr, const uint32_t len, uint8_t *wr)
1100 {
1101     return 0;
1102 }
1103 
ReadRam(uint32_t addr,const uint32_t len,uint8_t * rd)1104 int CRemoteZ_Base::ReadRam(uint32_t addr, const uint32_t len, uint8_t *rd)
1105 {
1106     return 0;
1107 }
1108 
PrepFirmware(const TRemoteInfo & ri,lc_callback cb,void * cb_arg,uint32_t cb_stage)1109 int CRemoteZ_Base::PrepFirmware(const TRemoteInfo &ri, lc_callback cb,
1110                                 void *cb_arg, uint32_t cb_stage)
1111 {
1112     return 0;
1113 }
1114 
FinishFirmware(const TRemoteInfo & ri,lc_callback cb,void * cb_arg,uint32_t cb_stage)1115 int CRemoteZ_Base::FinishFirmware(const TRemoteInfo &ri, lc_callback cb,
1116                                   void *cb_arg, uint32_t cb_stage)
1117 {
1118     return 0;
1119 }
1120 
PrepConfig(const TRemoteInfo & ri,lc_callback cb,void * cb_arg,uint32_t cb_stage)1121 int CRemoteZ_Base::PrepConfig(const TRemoteInfo &ri, lc_callback cb,
1122                               void *cb_arg, uint32_t cb_stage)
1123 {
1124     return 0;
1125 }
1126 
FinishConfig(const TRemoteInfo & ri,lc_callback cb,void * cb_arg,uint32_t cb_stage)1127 int CRemoteZ_Base::FinishConfig(const TRemoteInfo &ri, lc_callback cb,
1128                                 void *cb_arg, uint32_t cb_stage)
1129 {
1130     return 0;
1131 }
1132 
GetTime(const TRemoteInfo & ri,THarmonyTime & ht)1133 int CRemoteZ_Base::GetTime(const TRemoteInfo &ri, THarmonyTime &ht)
1134 {
1135     int err = 0;
1136     if ((err = Write(TYPE_REQUEST, COMMAND_GET_CURRENT_TIME))) {
1137         debug("Failed to write to remote");
1138         return LC_ERROR_WRITE;
1139     }
1140     uint8_t time[60];
1141     unsigned int len;
1142     uint8_t status;
1143     if ((err = Read(status, len, time))) {
1144         debug("Failed to read to remote");
1145         return LC_ERROR_READ;
1146     }
1147 
1148     if (time[1] != TYPE_RESPONSE || time[2] != COMMAND_GET_CURRENT_TIME) {
1149         debug("Incorrect response type from Get Time");
1150         return LC_ERROR_INVALID_DATA_FROM_REMOTE;
1151     }
1152 
1153     CRemoteZ_Base::TParamList pl;
1154     ParseParams(len, time, pl);
1155 
1156     ht.year = GetWord(pl.p[0]);
1157     ht.month = *pl.p[1];
1158     ht.day = *pl.p[2];
1159     ht.hour = *pl.p[3];
1160     ht.minute = *pl.p[4];
1161     ht.second = *pl.p[5];
1162     ht.dow = *pl.p[6]&7;
1163     ht.utc_offset = static_cast<int16_t>(GetWord(pl.p[7]));
1164     if (pl.count > 11) {
1165         ht.timezone = reinterpret_cast<char*>(pl.p[11]);
1166     } else {
1167         ht.timezone = "";
1168     }
1169 
1170     return 0;
1171 }
1172 
SetTime(const TRemoteInfo & ri,const THarmonyTime & ht,lc_callback cb,void * cb_arg,uint32_t cb_stage)1173 int CRemoteZ_Base::SetTime(const TRemoteInfo &ri, const THarmonyTime &ht,
1174                            lc_callback cb, void *cb_arg, uint32_t cb_stage)
1175 {
1176     int err = 0;
1177 
1178     uint8_t tsv[16] = { static_cast<uint8_t>(ht.year), 0, // 2 bytes
1179         static_cast<uint8_t>(ht.month),
1180         static_cast<uint8_t>(ht.day),
1181         static_cast<uint8_t>(ht.hour),
1182         static_cast<uint8_t>(ht.minute),
1183         static_cast<uint8_t>(ht.second),
1184         static_cast<uint8_t>(ht.dow),
1185         // utcOffset
1186         static_cast<uint8_t>(ht.utc_offset), 0, // 2 bytes
1187         // 0s
1188         0, 0, // 2 bytes
1189         0, 0, // 2 bytes
1190         0, 0, // 2 bytes
1191         // ht.timezone.c_str()
1192         };
1193 
1194     if ((err = Write(TYPE_REQUEST, COMMAND_UPDATE_TIME, 16, tsv))) {
1195         debug("Failed to write to remote");
1196         return LC_ERROR_WRITE;
1197     }
1198 
1199     uint8_t rsp[60];
1200     unsigned int len;
1201     uint8_t status;
1202     if ((err = Read(status, len, rsp))) {
1203         debug("failed to read from remote");
1204         return LC_ERROR_READ;
1205     }
1206 
1207     if (rsp[1] != TYPE_RESPONSE || rsp[2] != COMMAND_UPDATE_TIME) {
1208             return LC_ERROR;
1209     }
1210 
1211     return 0;
1212 }
1213 
TCPSendAndCheck(uint8_t cmd,uint32_t len,uint8_t * data,bool ackonly)1214 int CRemoteZ_HID::TCPSendAndCheck(uint8_t cmd, uint32_t len, uint8_t *data,
1215                                   bool ackonly)
1216 {
1217     int err = 0;
1218     uint8_t status;
1219     unsigned int rlen;
1220     uint8_t rsp[60];
1221 
1222     if ((err = TCP_Write(TYPE_REQUEST, cmd, len, data))) {
1223         debug("Failed to send request %02X", cmd);
1224         return LC_ERROR_WRITE;
1225     }
1226 
1227     if ((err = TCP_Read(status, rlen, rsp))) {
1228         debug("Failed to read from remote");
1229         return LC_ERROR_READ;
1230     }
1231 
1232     /* make sure it was the response we expected */
1233     if (rsp[0] != TYPE_TCP_ACK) {
1234         debug("Packet wasn't an ACK!");
1235         return LC_ERROR;
1236     }
1237     if (!ackonly) {
1238         if (rsp[3] != TYPE_RESPONSE) {
1239             debug("Packet didn't have response bit!");
1240             return LC_ERROR;
1241         }
1242         if (rsp[4] != cmd) {
1243             debug("The cmd bit didn't match our request packet");
1244             return LC_ERROR;
1245         }
1246     }
1247 
1248     return 0;
1249 }
1250 
UpdateConfig(const uint32_t len,const uint8_t * wr,lc_callback cb,void * cb_arg,uint32_t cb_stage,uint32_t xml_size,uint8_t * xml)1251 int CRemoteZ_HID::UpdateConfig(const uint32_t len, const uint8_t *wr,
1252                                lc_callback cb, void *cb_arg, uint32_t cb_stage,
1253                                uint32_t xml_size, uint8_t *xml)
1254 {
1255     int err = 0;
1256     int cb_count = 0;
1257 
1258     cb(LC_CB_STAGE_INITIALIZE_UPDATE, cb_count++, 0, 4,
1259        LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
1260     /* Start a TCP transfer */
1261     if ((err = Write(TYPE_REQUEST, COMMAND_INITIATE_UPDATE_TCP_CHANNEL))) {
1262         debug("Failed to write to remote");
1263         return LC_ERROR_WRITE;
1264     }
1265 
1266     uint8_t rsp[60];
1267     unsigned int rlen;
1268     uint8_t status;
1269 
1270     /* Make sure the remote is ready to start the TCP transfer */
1271     if ((err = Read(status, rlen, rsp))) {
1272         debug("Failed to read from remote");
1273         return LC_ERROR_READ;
1274     }
1275 
1276     if (rsp[1] != TYPE_RESPONSE || rsp[2] !=
1277         COMMAND_INITIATE_UPDATE_TCP_CHANNEL) {
1278         return LC_ERROR;
1279     }
1280     cb(LC_CB_STAGE_INITIALIZE_UPDATE, cb_count++, 1, 4,
1281        LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
1282 
1283     /* Look for a SYN packet */
1284     debug("Looking for syn");
1285     if ((err = TCP_Read(status, rlen, rsp))) {
1286         debug("Failed to read syn from remote");
1287         return LC_ERROR_READ;
1288     }
1289 
1290     if (rsp[0] != TYPE_TCP_SYN) {
1291         debug("Not a SYN packet!");
1292         return LC_ERROR;
1293     }
1294     cb(LC_CB_STAGE_INITIALIZE_UPDATE, cb_count++, 2, 4,
1295        LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
1296 
1297     /* ACK it with a command to start an update */
1298     debug("START_UPDATE");
1299     uint8_t cmd[60] = { 0x00, 0x04 };
1300     if ((err = TCP_Write(TYPE_REQUEST, COMMAND_START_UPDATE, 2, cmd))) {
1301         debug("Failed to write start-update to remote");
1302         return LC_ERROR_WRITE;
1303     }
1304 
1305     if ((err = TCP_Read(status, rlen, rsp))) {
1306         debug("Failed to read from remote");
1307         return LC_ERROR_READ;
1308     }
1309 
1310     /* make sure ot says 'start update response' */
1311     if (rsp[0] != TYPE_TCP_ACK || rsp[3] != TYPE_RESPONSE ||
1312         rsp[4] != COMMAND_START_UPDATE) {
1313         debug("Not expected ack");
1314         return LC_ERROR;
1315     }
1316     cb(LC_CB_STAGE_INITIALIZE_UPDATE, cb_count++, 3, 4,
1317        LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
1318 
1319     /* write update-header */
1320     debug("UPDATE_HEADER");
1321     uint32_t nlen = len;
1322     unsigned char *size_ptr = (unsigned char *)&nlen;
1323     for (int i = 0; i < 4; i++) {
1324         cmd[i] = size_ptr[i];
1325     }
1326     cmd[4] = 0x04;
1327     if ((err = TCPSendAndCheck(COMMAND_WRITE_UPDATE_HEADER, 5, cmd))) {
1328         return err;
1329     }
1330     cb(LC_CB_STAGE_INITIALIZE_UPDATE, cb_count++, 4, 4,
1331        LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
1332     cb_count = 0;
1333 
1334     /* write data */
1335     debug("UPDATE_DATA");
1336     int pkt_len;
1337     int tlen = len;
1338     uint8_t *wr_ptr = const_cast<uint8_t*>(wr);
1339     while (tlen) {
1340         pkt_len = 58;
1341         if (tlen < pkt_len) {
1342             pkt_len = tlen;
1343         }
1344         tlen -= pkt_len;
1345 
1346         debug("DATA %d, sending %d bytes, %d bytes left", cb_count,
1347               pkt_len, tlen);
1348 
1349         if ((err = TCPSendAndCheck(COMMAND_WRITE_UPDATE_DATA, pkt_len,
1350             wr_ptr, true))) {
1351             return err;
1352         }
1353         wr_ptr += pkt_len;
1354 
1355         if (cb) {
1356             cb(LC_CB_STAGE_WRITE_CONFIG, cb_count++, (int)(wr_ptr - wr), len,
1357                LC_CB_COUNTER_TYPE_BYTES, cb_arg, NULL);
1358         }
1359     }
1360 
1361     /* write update-done */
1362     cb_count = 0;
1363     cb(LC_CB_STAGE_FINALIZE_UPDATE, cb_count++, 0, 6, LC_CB_COUNTER_TYPE_STEPS,
1364        cb_arg, NULL);
1365     debug("UPDATE_DATA_DONE");
1366     if ((err = TCPSendAndCheck(COMMAND_WRITE_UPDATE_DATA_DONE))) {
1367         return err;
1368     }
1369     cb(LC_CB_STAGE_FINALIZE_UPDATE, cb_count++, 1, 6, LC_CB_COUNTER_TYPE_STEPS,
1370        cb_arg, NULL);
1371 
1372     /* Funky ACK exchange - part 1 */
1373     debug("FUNKY-ACK");
1374     if ((err = TCP_Ack(false, false))) {
1375         debug("Failed to send funky-ack");
1376         return LC_ERROR_WRITE;
1377     }
1378 
1379     if ((err = TCP_Read(status, rlen, rsp))) {
1380         debug("Failed to read from remote");
1381         return LC_ERROR_READ;
1382     }
1383 
1384     /* Funky ACK exchange - part 2 */
1385     debug("FUNKY-ACK");
1386     if ((err = TCP_Ack(false, false))) {
1387         debug("Failed to send funky-ack");
1388         return LC_ERROR_WRITE;
1389     }
1390 
1391     if ((err = TCP_Read(status, rlen, rsp))) {
1392         debug("Failed to read from remote");
1393         return LC_ERROR_READ;
1394     }
1395     cb(LC_CB_STAGE_FINALIZE_UPDATE, cb_count++, 2, 6, LC_CB_COUNTER_TYPE_STEPS,
1396        cb_arg, NULL);
1397 
1398     /* send get-cheksum */
1399     debug("GET_CHECKSUM");
1400     cmd[0] = 0xFF;
1401     cmd[1] = 0xFF;
1402     cmd[2] = 0x04;
1403     if ((err = TCPSendAndCheck(COMMAND_GET_UPDATE_CHECKSUM, 3, cmd))) {
1404         return err;
1405     }
1406     cb(LC_CB_STAGE_FINALIZE_UPDATE, cb_count++, 3, 6, LC_CB_COUNTER_TYPE_STEPS,
1407        cb_arg, NULL);
1408 
1409     /* send finish-update */
1410     debug("FINISH_UPDATE");
1411     cmd[0] = 0x01;
1412     cmd[1] = 0x04;
1413     /*
1414      * OK, this is a bit weird. We will eventually get a response to the
1415      * FINISH_UPDATE, but first we get an "empty" ack, do another funky-ack
1416      * exchange, and then we'll get the real response to this FINISH_UPDATE.
1417      */
1418     if ((err = TCPSendAndCheck(COMMAND_FINISH_UPDATE, 2, cmd, true))) {
1419         return err;
1420     }
1421     cb(LC_CB_STAGE_FINALIZE_UPDATE, cb_count++, 4, 6, LC_CB_COUNTER_TYPE_STEPS,
1422        cb_arg, NULL);
1423 
1424     /* Funky ACK exchange */
1425     debug("FUNKY-ACK");
1426     if ((err = TCP_Ack(false, false))) {
1427         debug("Failed to send funky-ack");
1428         return LC_ERROR_WRITE;
1429     }
1430 
1431     /* Read their empty ack */
1432     if ((err = TCP_Read(status, rlen, rsp))) {
1433         debug("Failed to read from remote");
1434         return LC_ERROR_READ;
1435     }
1436     if (rsp[0] != TYPE_TCP_ACK) {
1437         debug("Failed to read ack");
1438         return LC_ERROR;
1439     }
1440 
1441     /* And then we should have the response we want. */
1442     if ((err = TCP_Read(status, rlen, rsp))) {
1443         debug("Failed to read from remote");
1444         return LC_ERROR_READ;
1445     }
1446 
1447     /* make sure we got an ack */
1448     if (rsp[0] != TYPE_TCP_ACK || rsp[3] != TYPE_RESPONSE ||
1449         rsp[4] != COMMAND_FINISH_UPDATE) {
1450         debug("Failed to read finish-update ack");
1451         return LC_ERROR;
1452     }
1453     cb(LC_CB_STAGE_FINALIZE_UPDATE, cb_count++, 5, 6, LC_CB_COUNTER_TYPE_STEPS,
1454        cb_arg, NULL);
1455 
1456     /* FIN-ACK */
1457     debug("FIN-ACK");
1458     if ((err = TCP_Ack(false, true))) {
1459         debug("Failed to send fin-ack");
1460         return LC_ERROR_WRITE;
1461     }
1462 
1463     if ((err = TCP_Read(status, rlen, rsp))) {
1464         debug("Failed to read from remote");
1465         return LC_ERROR_READ;
1466     }
1467 
1468     /* Make sure we got an ack */
1469     if (rsp[0] != (TYPE_TCP_ACK | TYPE_TCP_FIN)) {
1470         debug("Failed to read finish-update ack");
1471         return LC_ERROR;
1472     }
1473 
1474     if ((err = TCP_Ack(true, false))) {
1475         debug("Failed to ack the ack of our fin-ack");
1476         return LC_ERROR_WRITE;
1477     }
1478     cb(LC_CB_STAGE_FINALIZE_UPDATE, cb_count++, 6, 6, LC_CB_COUNTER_TYPE_STEPS,
1479        cb_arg, NULL);
1480 
1481     /*
1482      * Official traces seem to show a final ack to the above ack, but for us
1483      * it never comes... so we don't bother trying to read it.
1484      */
1485 
1486     /* Return TCP state to initial conditions */
1487     SYN_ACKED = false;
1488 
1489     return 0;
1490 }
1491 
LearnIR(uint32_t * freq,uint32_t ** ir_signal,uint32_t * ir_signal_length,lc_callback cb,void * cb_arg,uint32_t cb_stage)1492 int CRemoteZ_HID::LearnIR(uint32_t *freq, uint32_t **ir_signal,
1493                           uint32_t *ir_signal_length, lc_callback cb,
1494                           void *cb_arg, uint32_t cb_stage)
1495 {
1496     return LC_ERROR_UNSUPP;
1497 }
1498 
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)1499 int CRemoteZ_Base::ReadFile(const char *filename, uint8_t *rd,
1500                             const uint32_t rdlen, uint32_t *data_read,
1501                             uint8_t start_seq, lc_callback cb, void *cb_arg,
1502                             uint32_t cb_stage)
1503 {
1504     return LC_ERROR_UNSUPP;
1505 }
1506 
WriteFile(const char * filename,uint8_t * wr,const uint32_t wrlen)1507 int CRemoteZ_Base::WriteFile(const char *filename, uint8_t *wr,
1508                              const uint32_t wrlen)
1509 {
1510     return LC_ERROR_UNSUPP;
1511 }
1512