1 /* HM-MOD-UART/HM-LGW-O-TW-W-EU driver
3 * Copyright (c) 2016 Michael Gernoth <michael@gernoth.net>
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to
7 * deal in the Software without restriction, including without limitation the
8 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 * sell copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
32 #include <sys/types.h>
38 #include "hmuartlgw.h"
40 #define HMUARTLGW_INIT_TIMEOUT 10000
42 #define HMUARTLGW_SETTLE_TIME 1
46 enum hmuartlgw_state
{
47 HMUARTLGW_QUERY_APPSTATE
,
48 HMUARTLGW_ENTER_BOOTLOADER
,
49 HMUARTLGW_ENTER_BOOTLOADER_ACK
,
51 HMUARTLGW_ENTER_APPLICATION
,
52 HMUARTLGW_ENTER_APPLICATION_ACK
,
53 HMUARTLGW_APPLICATION
,
57 enum hmuartlgw_state state
;
61 #define CRC16_POLY 0x8005
63 static uint16_t crc16(uint8_t* buf
, int length
)
65 uint16_t crc
= 0xd77f;
70 for (i
= 0; i
< 8; i
++) {
83 static int hmuartlgw_init_parse(enum hmuartlgw_dst dst
, uint8_t *buf
, int buf_len
, void *data
)
85 struct recv_data
*rdata
= data
;
89 printf("Length: %d\n", buf_len
);
90 hexdump(buf
, buf_len
, "INIT > ");
94 if (dst
!= HMUARTLGW_OS
)
97 if ((buf_len
== 10) && (buf
[0] == 0x00) && !strncmp(((char*)buf
)+1, "Co_CPU_BL", 9)) {
98 rdata
->state
= HMUARTLGW_BOOTLOADER
;
102 if ((buf_len
== 11) && (buf
[0] == 0x00) && !strncmp(((char*)buf
)+1, "Co_CPU_App", 10)) {
103 rdata
->state
= HMUARTLGW_APPLICATION
;
107 switch(rdata
->state
) {
108 case HMUARTLGW_QUERY_APPSTATE
:
109 if ((buf
[0] == HMUARTLGW_OS_ACK
) && (buf
[1] == 0x02)) {
110 if (!strncmp(((char*)buf
)+2, "Co_CPU_BL", 9)) {
111 rdata
->state
= HMUARTLGW_BOOTLOADER
;
112 } else if (!strncmp(((char*)buf
)+2, "Co_CPU_App", 10)) {
113 rdata
->state
= HMUARTLGW_APPLICATION
;
117 case HMUARTLGW_ENTER_BOOTLOADER
:
118 if ((buf_len
== 2) &&
119 (buf
[0] == HMUARTLGW_OS_ACK
) &&
121 rdata
->state
= HMUARTLGW_ENTER_BOOTLOADER_ACK
;
124 case HMUARTLGW_ENTER_BOOTLOADER_ACK
:
125 rdata
->state
= HMUARTLGW_ENTER_BOOTLOADER
;
127 case HMUARTLGW_ENTER_APPLICATION
:
128 if ((buf_len
== 2) &&
129 (buf
[0] == HMUARTLGW_OS_ACK
) &&
131 rdata
->state
= HMUARTLGW_ENTER_APPLICATION_ACK
;
134 case HMUARTLGW_ENTER_APPLICATION_ACK
:
135 rdata
->state
= HMUARTLGW_ENTER_APPLICATION
;
145 struct hmuartlgw_dev
*hmuart_init(char *device
, hmuartlgw_cb_fn cb
, void *data
, int app
)
147 struct hmuartlgw_dev
*dev
= NULL
;
148 struct termios oldtio
, tio
;
150 dev
= malloc(sizeof(struct hmuartlgw_dev
));
152 perror("malloc(struct hmuartlgw_dev)");
156 memset(dev
, 0, sizeof(struct hmuartlgw_dev
));
158 dev
->fd
= open(device
, O_RDWR
| O_NOCTTY
);
160 perror("open(hmuartlgw)");
165 fprintf(stderr
, "%s opened\n", device
);
168 if (tcgetattr(dev
->fd
, &oldtio
) == -1) {
173 memset(&tio
, 0, sizeof(tio
));
175 tio
.c_cflag
= B115200
| CS8
| CLOCAL
| CREAD
;
176 tio
.c_iflag
= IGNPAR
;
182 tcflush(dev
->fd
, TCIFLUSH
);
183 if (tcsetattr(dev
->fd
, TCSANOW
, &tio
) == -1) {
189 fprintf(stderr
, "serial parameters set\n");
192 hmuartlgw_flush(dev
);
195 hmuartlgw_enter_app(dev
);
197 hmuartlgw_enter_bootloader(dev
);
212 struct hmuartlgw_dev
*hmlgw_init(char *device
, hmuartlgw_cb_fn cb
, void *data
)
214 struct hmuartlgw_dev
*dev
= NULL
;
219 void hmuartlgw_enter_bootloader(struct hmuartlgw_dev
*dev
)
221 hmuartlgw_cb_fn cb_old
= dev
->cb
;
222 void *cb_data_old
= dev
->cb_data
;
223 struct recv_data rdata
= { 0 };
224 uint8_t buf
[128] = { 0 };
227 fprintf(stderr
, "Entering bootloader\n");
230 buf
[0] = HMUARTLGW_OS_CHANGE_APP
;
232 dev
->cb
= hmuartlgw_init_parse
;
233 dev
->cb_data
= &rdata
;
235 rdata
.state
= HMUARTLGW_QUERY_APPSTATE
;
236 buf
[0] = HMUARTLGW_OS_GET_APP
;
237 hmuartlgw_send(dev
, buf
, 1, HMUARTLGW_OS
);
239 hmuartlgw_poll(dev
, HMUARTLGW_INIT_TIMEOUT
);
240 } while (rdata
.state
== HMUARTLGW_QUERY_APPSTATE
);
242 if (rdata
.state
!= HMUARTLGW_BOOTLOADER
) {
243 rdata
.state
= HMUARTLGW_ENTER_BOOTLOADER
;
244 buf
[0] = HMUARTLGW_OS_CHANGE_APP
;
245 hmuartlgw_send(dev
, buf
, 1, HMUARTLGW_OS
);
247 hmuartlgw_poll(dev
, HMUARTLGW_INIT_TIMEOUT
);
248 } while (rdata
.state
!= HMUARTLGW_BOOTLOADER
);
250 printf("Waiting for bootloader to settle...\n");
251 sleep(HMUARTLGW_SETTLE_TIME
);
255 dev
->cb_data
= cb_data_old
;
258 void hmuartlgw_enter_app(struct hmuartlgw_dev
*dev
)
260 hmuartlgw_cb_fn cb_old
= dev
->cb
;
261 void *cb_data_old
= dev
->cb_data
;
262 struct recv_data rdata
= { 0 };
263 uint8_t buf
[128] = { 0 };
266 fprintf(stderr
, "Entering application\n");
269 dev
->cb
= hmuartlgw_init_parse
;
270 dev
->cb_data
= &rdata
;
272 rdata
.state
= HMUARTLGW_QUERY_APPSTATE
;
273 buf
[0] = HMUARTLGW_OS_GET_APP
;
274 hmuartlgw_send(dev
, buf
, 1, HMUARTLGW_OS
);
276 hmuartlgw_poll(dev
, HMUARTLGW_INIT_TIMEOUT
);
277 } while (rdata
.state
== HMUARTLGW_QUERY_APPSTATE
);
279 if (rdata
.state
!= HMUARTLGW_APPLICATION
) {
280 rdata
.state
= HMUARTLGW_ENTER_APPLICATION
;
281 buf
[0] = HMUARTLGW_OS_CHANGE_APP
;
282 hmuartlgw_send(dev
, buf
, 1, HMUARTLGW_OS
);
284 hmuartlgw_poll(dev
, HMUARTLGW_INIT_TIMEOUT
);
285 } while (rdata
.state
!= HMUARTLGW_APPLICATION
);
287 printf("Waiting for application to settle...\n");
288 sleep(HMUARTLGW_SETTLE_TIME
);
292 dev
->cb_data
= cb_data_old
;
295 static int hmuartlgw_escape(uint8_t *frame
, int framelen
)
299 for (i
= 1; i
< framelen
; i
++) {
300 if (frame
[i
] == 0xfc || frame
[i
] == 0xfd) {
301 memmove(frame
+ i
+ 1, frame
+ i
, framelen
- i
);
310 int hmuartlgw_send_raw(struct hmuartlgw_dev
*dev
, uint8_t *frame
, int framelen
)
316 hexdump(frame
, framelen
, "UARTLGW < ");
319 framelen
= hmuartlgw_escape(frame
, framelen
);
322 ret
= write(dev
->fd
, frame
+ w
, framelen
- w
);
328 } while (w
< framelen
);
333 int hmuartlgw_send(struct hmuartlgw_dev
*dev
, uint8_t *cmd
, int cmdlen
, enum hmuartlgw_dst dst
)
335 static uint8_t cnt
= 0;
336 uint8_t frame
[4096] = { 0 };
340 frame
[1] = ((cmdlen
+ 2) >> 8) & 0xff;
341 frame
[2] = (cmdlen
+ 2) & 0xff;
343 dev
->last_send_cnt
= cnt
;
345 memcpy(&(frame
[5]), cmd
, cmdlen
);
346 crc
= crc16(frame
, cmdlen
+ 5);
347 frame
[cmdlen
+ 5] = (crc
>> 8) & 0xff;
348 frame
[cmdlen
+ 6] = crc
& 0xff;
350 return hmuartlgw_send_raw(dev
, frame
, cmdlen
+ 7);
353 int hmuartlgw_poll(struct hmuartlgw_dev
*dev
, int timeout
)
355 struct pollfd pfds
[1];
362 memset(pfds
, 0, sizeof(struct pollfd
) * 1);
364 pfds
[0].fd
= dev
->fd
;
365 pfds
[0].events
= POLLIN
;
367 ret
= poll(pfds
, 1, timeout
);
377 if (!(pfds
[0].revents
& POLLIN
)) {
382 r
= read(dev
->fd
, dev
->buf
+dev
->pos
, 1);
393 if (dev
->buf
[0] != 0xfd) {
394 memset(dev
->buf
, 0, sizeof(dev
->buf
));
396 dev
->unescape_next
= 0;
400 if (dev
->unescape_next
) {
401 dev
->buf
[dev
->pos
-1] |= 0x80;
402 dev
->unescape_next
= 0;
403 } else if (dev
->buf
[dev
->pos
-1] == 0xfc) {
404 dev
->unescape_next
= 1;
412 len
= ((dev
->buf
[1] << 8) & 0xff00) | (dev
->buf
[2] & 0xff);
414 if (dev
->pos
< len
+ 5)
420 crc
= crc16(dev
->buf
, dev
->pos
);
423 hexdump(dev
->buf
, dev
->pos
, "UARTLGW > ");
425 dev
->cb(dev
->buf
[3], dev
->buf
+ 5 , dev
->pos
- 7, dev
->cb_data
);
427 memset(dev
->buf
, 0, sizeof(dev
->buf
));
429 dev
->unescape_next
= 0;
431 fprintf(stderr
, "Invalid checksum received!\n");
432 hexdump(dev
->buf
, dev
->pos
, "ERR> ");
433 printf("calculated: %04x\n", crc
);
435 memset(dev
->buf
, 0, sizeof(dev
->buf
));
437 dev
->unescape_next
= 0;
444 void hmuartlgw_close(struct hmuartlgw_dev
*dev
)
449 void hmuartlgw_flush(struct hmuartlgw_dev
*dev
)
451 struct pollfd pfds
[1];
456 tcflush(dev
->fd
, TCIOFLUSH
);
459 memset(pfds
, 0, sizeof(struct pollfd
) * 1);
461 pfds
[0].fd
= dev
->fd
;
462 pfds
[0].events
= POLLIN
;
464 ret
= poll(pfds
, 1, 100);
468 if (!(pfds
[0].revents
& POLLIN
))
471 memset(buf
, 0, sizeof(buf
));
472 r
= read(dev
->fd
, buf
, sizeof(buf
));
480 void hmuartlgw_set_debug(int d
)