CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
orangepi-xunlong

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.

GitHub Repository: orangepi-xunlong/orangepi-build
Path: blob/next/external/cache/sources/hcitools/hciattach_xr.c
Views: 3959
1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <unistd.h>
4
#include <errno.h>
5
#include <fcntl.h>
6
#include <string.h>
7
#include <signal.h>
8
#include <time.h>
9
#include <stdint.h>
10
#include <sys/termios.h>
11
#include <sys/ioctl.h>
12
#include <limits.h>
13
#include "hciattach.h"
14
15
/******************************************************************************
16
** Constants & Macros
17
******************************************************************************/
18
#define LOG_STR "XRADIO Bluetooth"
19
#define DBG_ON 1
20
21
#define XR_DBG(fmt, arg...) \
22
do { \
23
if (DBG_ON) \
24
fprintf(stderr, "%s: " fmt "\n" , LOG_STR, ##arg); \
25
} while(0)
26
27
#define XR_ERR(fmt, arg...) \
28
do { \
29
fprintf(stderr, "%s ERROR: " fmt "\n", LOG_STR, ##arg);\
30
perror(LOG_STR" ERROR reason"); \
31
} while(0)
32
33
#define XR_DUMP(buffer, len) \
34
fprintf(stderr, "%s: ", LOG_STR); \
35
do { \
36
for (int i = 0; i < len; i++) { \
37
if (i && !(i % 16)) { \
38
fprintf(stderr, "\n"); \
39
fprintf(stderr, "%s: ", LOG_STR); \
40
} \
41
fprintf(stderr, "%02x ", buffer[i]); \
42
} \
43
fprintf(stderr, "\n"); \
44
} while (0)
45
46
#define BT_FW_PATH_NAME "/system/vendor/etc/firmware/fw_xr829_bt.bin"
47
#define BT_FW_LOAD_ADDR 0x0000
48
#define BT_FW_JUMP_ADDR 0x0000
49
#define AW1722 1
50
#define AW1732 2
51
#define CHIP_NAME AW1722
52
53
#define SZ_1K (0x00000400U )
54
#define SZ_16K (0x00004000U )
55
56
#define SWAP16(d) (((d & 0xff) << 8) | ((d & 0xff00) >> 8))
57
#define SWAP32(d) (((d & 0xff) << 24) | ((d & 0xff00) << 8) \
58
| ((d & 0xff0000) >> 8) | ((d & 0xff000000) >> 24))
59
60
#define CMD_ID(group, key) (((group) << 3) | (key))
61
62
/*----------------------------*/
63
/* COMMANDS FORM PC TO MCU */
64
/*----------------------------*/
65
#define CMD_ID_MEMRW 0x00
66
#define CMD_ID_SEQRQ 0x01
67
#define CMD_ID_SYSCTL 0x02
68
#define CMD_ID_FLASH 0x03
69
70
#define CMD_ID_SEQRD CMD_ID(CMD_ID_SEQRQ, 0)
71
#define CMD_ID_SEQWR CMD_ID(CMD_ID_SEQRQ, 1)
72
/* uart commands */
73
#define CMD_ID_SETUART CMD_ID(CMD_ID_SYSCTL, 0)
74
#define CMD_ID_SETPC CMD_ID(CMD_ID_SYSCTL, 3)
75
76
#define CMD_WRITEN 0
77
#define CMD_WRITESEQ 1
78
#define CMD_SETBAUD 2
79
#define CMD_SETPC 3
80
#define DATA_RAW 4
81
82
/******************************************************************************
83
** Type definitions
84
******************************************************************************/
85
86
/* vendor serial control block */
87
typedef struct
88
{
89
int fd; /* fd to Bluetooth device */
90
struct termios *ti; /* serial terminal of BT port */
91
} vnd_userial_cb_t;
92
93
#pragma pack(1)
94
/* command header
95
*
96
* byte 0 byte 1 byte 2 byte 3 byte 4 byte 5 byte 6 -7 byte 8-11
97
* ___________________________________________________________________________________________________
98
* | | | | | | | | |
99
* | 'B' | 'R' | 'O' | 'M' | Flags |Reserved | Checksum | Playload Length |
100
* |_________|_________|_________|_________|_________|_________|__________ ________|___________________|
101
*/
102
typedef struct {
103
uint8_t magic[4]; // magic "BROM"
104
#define CMD_BROM_MAGIC "BROM"
105
uint8_t flags;
106
#define CMD_HFLAG_ERROR (0x1U << 0)
107
#define CMD_HFLAG_ACK (0x1U << 1)
108
#define CMD_HFLAG_CHECK (0x1U << 2)
109
#define CMD_HFLAG_RETRY (0x1U << 3)
110
#define CMD_HFLAG_EXE (0x1U << 4)
111
uint8_t version:4;
112
uint8_t reserved:4;
113
uint16_t checksum;
114
uint32_t payload_len;
115
} __attribute__((packed)) cmd_header_t;
116
#define MB_CMD_HEADER_SIZE (sizeof(cmd_header_t))
117
118
/* acknownledge structure */
119
typedef struct {
120
cmd_header_t h;
121
uint8_t err;
122
} __attribute__((packed)) cmd_ack_t;
123
124
/* sequence read/write command structure */
125
typedef struct {
126
cmd_header_t h;
127
uint8_t cmdid;
128
uint32_t addr;
129
uint32_t dlen;
130
uint16_t dcs;
131
} __attribute__((packed)) cmd_seq_wr_t;
132
133
/* io change command structure */
134
typedef struct {
135
cmd_header_t h;
136
uint8_t cmdid;
137
uint32_t val;
138
} __attribute__((packed)) cmd_sys_t;
139
140
typedef struct {
141
cmd_header_t h;
142
uint8_t cmdid;
143
uint32_t lcr;
144
} __attribute__((packed)) cmd_sys_setuart_t;
145
146
#pragma pack()
147
148
static const uint8_t hci_reset[] = { 0x01, 0x03, 0x0c, 0x00 };
149
static const uint8_t hci_update_baud_rate[] = { 0x01, 0x18, 0xfc, 0x04, 0x60, 0xE3, 0x16, 0x00};
150
static vnd_userial_cb_t vnd_userial;
151
152
static int32_t cmd_sync_uart(void);
153
static int32_t cmd_sync_baud(uint32_t lcr);
154
static int32_t cmd_write_seq(uint32_t addr, uint32_t len, uint8_t *data);
155
static int32_t cmd_set_pc(uint32_t pc);
156
static void userial_set_hw_fctrl(uint8_t hw_fctrl);
157
static uint32_t userial_read(uint8_t *p_buffer, uint32_t len, uint32_t timeout);
158
static uint32_t userial_write(const uint8_t *p_data, uint32_t len);
159
160
/******************************************************************************
161
** Functions
162
******************************************************************************/
163
static uint16_t CheckSum16(uint8_t *data, uint32_t len)
164
{
165
uint16_t cs = 0;
166
uint16_t *p = (uint16_t *)data;
167
168
while(len > 1) {
169
cs += *p++;
170
len -= 2;
171
}
172
if (len) {
173
cs += *(uint8_t *)p;
174
}
175
return cs;
176
}
177
178
static uint64_t time_gettimeofday_us(void)
179
{
180
struct timeval tv;
181
gettimeofday(&tv, NULL);
182
return (uint64_t)tv.tv_sec * 1000000ULL + (uint64_t)tv.tv_usec;
183
}
184
185
static uint8_t *memsearch(uint8_t *haystack, uint32_t hlen, uint8_t *needle, uint32_t nlen)
186
{
187
while (hlen-- >= nlen) {
188
if (!memcmp(haystack, needle, nlen)) {
189
return haystack;
190
}
191
haystack++;
192
}
193
return NULL;
194
}
195
196
static int32_t xr_raw_write(int type, uint8_t *data, uint32_t len)
197
{
198
uint8_t buffer[MB_CMD_HEADER_SIZE + 13] = {'B', 'R', 'O', 'M', 0, 0, 0, 0, 0, 0, 0, 0};
199
uint8_t *psend = data;
200
uint32_t lsend = len;
201
cmd_header_t *hdr = (cmd_header_t *)buffer;;
202
cmd_ack_t *ack = (cmd_ack_t *)buffer;
203
204
if (type != DATA_RAW) {
205
psend = buffer;
206
lsend = MB_CMD_HEADER_SIZE + len;
207
memcpy(buffer + MB_CMD_HEADER_SIZE, data, len);
208
hdr->payload_len = len;
209
#if ENABLE_DCS
210
hdr->flags = CMD_HFLAG_CHECK;
211
#endif
212
hdr->checksum = ~CheckSum16(buffer, MB_CMD_HEADER_SIZE + len);
213
hdr->payload_len = SWAP32(hdr->payload_len);
214
hdr->checksum = SWAP16(hdr->checksum);
215
switch (type) {
216
case CMD_WRITESEQ:
217
{
218
cmd_seq_wr_t *cmd = (cmd_seq_wr_t *)buffer;
219
cmd->addr = SWAP32(cmd->addr);
220
cmd->dlen = SWAP32(cmd->dlen);
221
cmd->dcs = SWAP16(cmd->dcs);
222
}
223
break;
224
case CMD_SETBAUD:
225
{
226
cmd_sys_setuart_t *cmd = (cmd_sys_setuart_t*)buffer;
227
cmd->lcr = SWAP32(cmd->lcr);
228
}
229
break;
230
case CMD_SETPC:
231
{
232
cmd_sys_t *cmd = (cmd_sys_t*)buffer;
233
cmd->val = SWAP32(cmd->val);
234
}
235
break;
236
default:
237
XR_ERR("%s: Unsupport type %d", __func__, type);
238
return -1;
239
}
240
}
241
242
ssize_t ret_w, ret_r;
243
uint64_t t0, t1, t2, t3;
244
245
tcflush(vnd_userial.fd, TCIOFLUSH);
246
247
t0 = time_gettimeofday_us();
248
ret_w = userial_write(psend, lsend);
249
t1 = time_gettimeofday_us();
250
251
memset(buffer, 0, MB_CMD_HEADER_SIZE + 1);
252
253
t2 = time_gettimeofday_us();
254
ret_r = userial_read(buffer, MB_CMD_HEADER_SIZE, 100000);
255
t3 = time_gettimeofday_us();
256
257
XR_DBG("%s, type: %d, write len: %5d, ret: %5d, time: %6lluus, read len: %2d, ret: %2d, %6lluus",
258
__func__, type, lsend, ret_w, t1 - t0, MB_CMD_HEADER_SIZE, ret_r, t3 - t2);
259
260
uint8_t *p = (uint8_t *)memsearch(buffer, MB_CMD_HEADER_SIZE, (uint8_t *)"BROM", 4);
261
if (p != buffer) {
262
if (p == NULL) {
263
XR_ERR("%s: invalid response", __func__);
264
return -1;
265
}
266
uint32_t nowread = buffer + MB_CMD_HEADER_SIZE - p;
267
uint32_t needread = p - buffer;
268
XR_DBG("%s: Index error, re-find header magic", __func__);
269
memcpy(buffer, p, nowread);
270
memset(buffer + nowread, 0x0, needread);
271
userial_read(buffer + nowread, needread, 100000);
272
}
273
274
/* check response */
275
if (ack->h.flags & CMD_HFLAG_ERROR) {
276
userial_read(buffer + MB_CMD_HEADER_SIZE, 1, 100000);
277
XR_ERR("%s: resp error flag, type %d", __func__, ack->err);
278
return -ack->err;
279
}
280
281
if (ack->h.flags & CMD_HFLAG_ACK) {
282
/* convert network byte order to host byte order */
283
ack->h.payload_len = SWAP32(ack->h.payload_len);
284
ack->h.checksum = SWAP16(ack->h.checksum);
285
if (ack->h.payload_len != 0) {
286
XR_ERR("%s: data payload len %d != 0", __func__, ack->h.payload_len);
287
return -1;
288
}
289
}
290
291
if (ack->h.flags & CMD_HFLAG_CHECK) {
292
if (CheckSum16(buffer, MB_CMD_HEADER_SIZE) != 0xffff) {
293
XR_ERR("%s: write data response 0 checksum error", __func__);
294
return -1;
295
}
296
}
297
return 0;
298
}
299
300
static int32_t cmd_sync_uart(void)
301
{
302
uint8_t sync = 0x55;
303
uint8_t ack[3] = {0};
304
ssize_t ret = -1;
305
uint32_t cnt = 0;
306
307
do {
308
XR_DBG("uart sync count:%d.", cnt);
309
tcflush(vnd_userial.fd, TCIOFLUSH);
310
userial_write(&sync, 1);
311
ret = userial_read(ack, 2, 2000);
312
if (ret == 2 && ((ack[0] == 'O' && ack[1] == 'K') || (ack[0] == 'K' && ack[1] == 'O'))) {
313
XR_DBG("Receive %s, uart Sync done.", ack);
314
return 0;
315
}
316
} while (cnt++ < 50);
317
318
XR_DBG("uart sync fail.");
319
return -1;
320
}
321
322
static int32_t cmd_sync_baud(uint32_t lcr)
323
{
324
uint8_t buffer[MB_CMD_HEADER_SIZE + 5];
325
cmd_sys_setuart_t *cmd = (cmd_sys_setuart_t*)buffer;
326
327
cmd->cmdid = CMD_ID_SETUART;
328
cmd->lcr = lcr;
329
330
uint8_t cnt = 0;
331
int ret = -1;
332
333
do {
334
XR_DBG("%s count:%d.", __func__, cnt);
335
ret = xr_raw_write(CMD_SETBAUD, buffer + MB_CMD_HEADER_SIZE, 5);
336
if (ret == 0) {
337
set_speed(vnd_userial.fd, vnd_userial.ti, lcr & 0xffffff);
338
return cmd_sync_uart();
339
}
340
} while (cnt++ < 3);
341
342
XR_DBG("cmd_sync_baud fail.");
343
return -1;
344
}
345
346
static int32_t cmd_write_seq(uint32_t addr, uint32_t len, uint8_t *data)
347
{
348
int ret = -1;
349
uint8_t buffer[MB_CMD_HEADER_SIZE + 13];
350
cmd_seq_wr_t *cmd = (cmd_seq_wr_t *)buffer;
351
352
cmd->cmdid = CMD_ID_SEQWR;
353
cmd->addr = addr;
354
cmd->dlen = len;
355
#if ENABLE_DCS
356
cmd->dcs = ~CheckSum16(data, len);
357
#endif
358
359
ret = xr_raw_write(CMD_WRITESEQ, buffer + MB_CMD_HEADER_SIZE, 11);
360
if (ret == 0) {
361
return xr_raw_write(DATA_RAW, data, len);
362
}
363
return ret;
364
}
365
366
static int32_t cmd_set_pc(uint32_t pc)
367
{
368
uint8_t buffer[MB_CMD_HEADER_SIZE + 5];
369
cmd_sys_t *cmd = (cmd_sys_t*)buffer;
370
371
cmd->cmdid = CMD_ID_SETPC;
372
cmd->val = pc;
373
XR_DBG("set pc %x, val %x", pc, cmd->val);
374
375
return xr_raw_write(CMD_SETPC, buffer + MB_CMD_HEADER_SIZE, 5);
376
}
377
378
static void userial_set_hw_fctrl(uint8_t hw_fctrl)
379
{
380
if (vnd_userial.fd == -1) {
381
XR_ERR("vnd_userial.fd is -1");
382
return;
383
}
384
385
if (hw_fctrl) {
386
XR_DBG("Set HW FlowControl On");
387
vnd_userial.ti->c_cflag |= CRTSCTS;
388
} else {
389
XR_DBG("Set HW FlowControl Off");
390
vnd_userial.ti->c_cflag &= ~CRTSCTS;
391
}
392
tcsetattr(vnd_userial.fd, TCSANOW, vnd_userial.ti);
393
tcflush(vnd_userial.fd, TCIOFLUSH);
394
}
395
396
static uint32_t userial_read(uint8_t *buffer, uint32_t len, uint32_t timeout)
397
{
398
fd_set set;
399
struct timeval tv;
400
int rv;
401
402
FD_ZERO(&set); /* clear the set */
403
FD_SET(vnd_userial.fd, &set); /* add our file descriptor to the set */
404
405
/* there was data to read */
406
ssize_t r;
407
uint8_t *pos = (uint8_t*)buffer;
408
409
while (len > 0) {
410
tv.tv_sec = 0;
411
tv.tv_usec = timeout;
412
413
rv = select(vnd_userial.fd + 1, &set, NULL, NULL, &tv);
414
if(rv == -1) {
415
XR_ERR("select error"); /* an error accured */
416
break;
417
} else if(rv == 0) {
418
XR_ERR("read timeout"); /* a timeout occured */
419
break;
420
}
421
422
r = read(vnd_userial.fd, pos, len);
423
if (r < 1)
424
break;
425
426
len -= r;
427
pos += r;
428
}
429
430
return pos - buffer;
431
}
432
433
static uint32_t userial_write(const uint8_t *buffer, uint32_t len)
434
{
435
ssize_t r;
436
uint8_t *pos = (uint8_t*)buffer;
437
438
while (len > 0) {
439
r = write(vnd_userial.fd, pos, len);
440
if (r < 1)
441
break;
442
443
len -= r;
444
pos += r;
445
}
446
447
return pos - buffer;
448
}
449
450
static int32_t load_btfirmware(void)
451
{
452
FILE *fwfile_fd = NULL;
453
uint32_t len;
454
uint8_t *data = NULL;
455
uint32_t addr = BT_FW_LOAD_ADDR;
456
uint32_t section = SZ_16K;
457
458
fwfile_fd = fopen(BT_FW_PATH_NAME, "rb");
459
XR_DBG("BT firmware: %s", BT_FW_PATH_NAME);
460
if(!fwfile_fd) {
461
XR_ERR("Unable to open BT firmware %s", BT_FW_PATH_NAME);
462
return -1;
463
}
464
465
data = (uint8_t*)malloc(section);
466
if (data == NULL) {
467
XR_DBG("failed to alloc %d byte memory.", section);
468
fclose(fwfile_fd);
469
return -1;
470
}
471
472
XR_DBG("load bt firmware starting.");
473
while ((len = fread(data, 1, section, fwfile_fd)) > 0) {
474
cmd_write_seq(addr, len, data);
475
addr += len;
476
}
477
478
free(data);
479
fclose(fwfile_fd);
480
XR_DBG("load firmware done.");
481
482
XR_DBG("Firmware run from address 0x%08X", BT_FW_JUMP_ADDR);
483
cmd_set_pc(BT_FW_JUMP_ADDR);
484
485
if (CHIP_NAME == AW1732) {
486
XR_DBG("second time sync starting....");
487
if (cmd_sync_uart() < 0)
488
return -1;
489
cmd_set_pc(BT_FW_JUMP_ADDR);
490
}
491
return addr;
492
}
493
494
static int hci_cmd_handle(const uint8_t *cmd, uint32_t cmd_len, uint32_t event_len)
495
{
496
uint8_t buffer[256];
497
498
XR_DBG("send hci command");
499
userial_write(cmd, cmd_len);
500
XR_DUMP(cmd, cmd_len);
501
502
if (read_hci_event(vnd_userial.fd, buffer, event_len) != event_len) {
503
XR_ERR("Event read error");
504
return -1;
505
}
506
XR_DBG("Received event");
507
XR_DUMP(buffer, event_len);
508
return 0;
509
}
510
511
int xr_init(int fd, struct uart_t *u, struct termios *ti)
512
{
513
vnd_userial.fd = fd;
514
vnd_userial.ti = ti;
515
516
XR_DBG("uart sync starting....");
517
if (cmd_sync_uart() < 0)
518
goto END;
519
XR_DBG("set bandrate to %d.", u->speed);
520
if (cmd_sync_baud(((u->speed) | (3<<24))) < 0)
521
goto END;
522
if (load_btfirmware() < 0)
523
goto END;
524
XR_DBG("bt firmware is running....");
525
526
XR_DBG("set baudrate to %d", u->init_speed);
527
set_speed(vnd_userial.fd, vnd_userial.ti, u->init_speed);
528
userial_set_hw_fctrl(1);
529
usleep(50000);
530
531
XR_DBG("process hci reset...");
532
if (hci_cmd_handle(hci_reset, sizeof(hci_reset), 7) < 0)
533
goto END;
534
535
XR_DBG("process hci update baud...");
536
if (hci_cmd_handle(hci_update_baud_rate, sizeof(hci_update_baud_rate), 7) < 0)
537
goto END;
538
539
usleep(100000);
540
541
return 0;
542
543
END:
544
XR_DBG("device fd = %d close", fd);
545
close(vnd_userial.fd);
546
vnd_userial.fd = -1;
547
vnd_userial.ti = NULL;
548
549
return -1;
550
}
551
552
int xr_post(int fd, struct uart_t *u, struct termios *ti)
553
{
554
XR_DBG("Done setting line discpline");
555
return 0;
556
}
557
558
559