现在的位置: 首页 > 综合 > 正文

hciattach 分析

2018年01月10日 ⁄ 综合 ⁄ 共 2931字 ⁄ 字号 评论关闭
hciattach的功能是:建立串口和蓝牙协议层的数据连接通道。
源代码参考 tools/hciattach.c
先看hciattach的用法
hciattach [-n] [-p] [-b] [-r] [-t timeout] [-s initial_speed] <tty> <type | id> [speed] [flow|noflow] [bdaddr]
hciattach -l
hciattach的结构体
struct uart_t {
char *type;
int  m_id;
int  p_id;
int  proto;
int  init_speed;
int  speed;
int  flags;
char *bdaddr;
int  (*init) (int fd, struct uart_t *u, struct termios *ti);
int  (*post) (int fd, struct uart_t *u, struct termios *ti);
};
从main 函数开始,
while ((opt=getopt(argc, argv, "bnpt:s:lr")) != EOF)   //为什么,请看上面的用法
解析main函数的参数,然后switch(opt) 进入选择。
init_speed = atoi(optarg);
……
n = argc - optind;
if (n < 2) {
usage();
exit(1);
}
这是参数不对,调用使用方法
for (n = 0; optind < argc; n++, optind++) {
char *opt;
opt = argv[optind];
switch(n) {
case 0:
dev[0] = 0;
if (!strchr(opt, '/'))    //查找opt中首次出现/的地方  
strcpy(dev, "/dev/");
strcat(dev, opt);    //opt追加到dev后
break;
                case 1:
                        if (strchr(argv[optind], ',')) {
int m_id, p_id;
sscanf(argv[optind], "%x,%x", &m_id, &p_id);
u = get_by_id(m_id, p_id);    //获取uart_t,返回uart[],对应其中的初始化函数等。假如是uart[1]就是bcsp
} else {
u = get_by_type(opt);
}
                ……
前面都是对hciattach用法的解析。
struct uart_t uart[] = {
{ "any",        0x0000, 0x0000, HCI_UART_H4,   115200, 115200, FLOW_CTL, NULL, NULL     },
{ "bcsp",       0x0000, 0x0000, HCI_UART_BCSP, 115200, 115200, 0,        NULL, bcsp     },
        ……
上面粗体标注  对应u->init,u->post。这里蓝牙供应商会添加自己的配置和通讯方式。
设置好了通讯方式,在初始化串口调用。
init_uart函数分析
static int init_uart(char *dev, struct uart_t *u, int send_break, int raw)
{
struct termios ti;
int fd, i;
unsigned long flags = 0;
if (raw)
flags |= 1 << HCI_UART_RAW_DEVICE;
fd = open(dev, O_RDWR | O_NOCTTY);     //可进行读写,不将此设备分配作为此进程的控制终端,即Ctrl+C 不能结束此进程
if (fd < 0) {
perror("Can't open serial port");
return -1;
}
tcflush(fd, TCIOFLUSH);    //清空数据线
if (tcgetattr(fd, &ti) < 0) {        //获得串口设置
perror("Can't get port settings");
return -1;
}
cfmakeraw(&ti);    //将终端设置为原始模式控制终端
ti.c_cflag |= CLOCAL;
if (u->flags & FLOW_CTL)    //设置流控
ti.c_cflag |= CRTSCTS;
else
ti.c_cflag &= ~CRTSCTS;    //本地连接,无调制解调器控制
if (tcsetattr(fd, TCSANOW, &ti) < 0) {    //设置串口
perror("Can't set port settings");
return -1;
}
/* Set initial baudrate */
if (set_speed(fd, &ti, u->init_speed) < 0) {    
perror("Can't set initial baud rate");
return -1;
}
tcflush(fd, TCIOFLUSH);
if (send_break) {
tcsendbreak(fd, 0);    //在串口线上发送0值
usleep(500000);    //0.5s发送一个break
}
if (u->init && u->init(fd, u, &ti) < 0)    
//所有bluez支持的蓝牙串口设备类型构成了一个uart结构数组,通过查找对应的uart类型,并调用这个uart的init成员函数。
return -1;
tcflush(fd, TCIOFLUSH);
/* Set actual baudrate */        //设置实际的波特率
if (set_speed(fd, &ti, u->speed) < 0) {
perror("Can't set baud rate");
return -1;
}
/* Set TTY to N_HCI line discipline */
i = N_HCI;
if (ioctl(fd, TIOCSETD, &i) < 0) {        //调用内核的tty_ioctl,采用ldisc机制改变hci行规
perror("Can't set line discipline");
return -1;
}
if (flags && ioctl(fd, HCIUARTSETFLAGS, flags) < 0) {    //设置串口参数
perror("Can't set UART flags");
return -1;
}
if (ioctl(fd, HCIUARTSETPROTO, u->proto) < 0) {   
 //调用内核的tty_ioctl,注册一个hci设备,设置proto为hci设备的proto操作函数集
perror("Can't set device");
return -1;
}
if (u->post && u->post(fd, u, &ti) < 0)    //调用这个uart的post成员函数
return -1;
return fd;
}
其中TIOCSETD,HCIUARTSETPROTO需要内核处理
重新回到main(),后面信号处理  
恢复行规
ld = N_TTY;
if (ioctl(n, TIOCSETD, &ld) < 0) {
perror("Can't restore line discipline");
exit(1);
}
 
到此为止,hciattach的工作介绍完毕。
 
 
 
【上篇】
【下篇】

抱歉!评论已关闭.