上篇博客中已经对BTStack框架进行了较为详细的说明,本篇博客将进一步总结一下(由韦大仙笔记所得)。

可以从5个方面来理解BTStack的框架:

1.硬件操作:hci_transport_t

BTStack支持多种接口的蓝牙模块,比如USB口、3线串口、5线串口。

对于这些接口,会抽象出对应的hci_transport_t结构体。

该结构体成员如下:

里面有init、open、send_packet等重要成员。

对于3线串口、5线串口,它们在init、open设备时,不需要写两套代码。因为它们都是串口设备,只不过前者不使用硬件流控、后者使用硬件流控。

对串口硬件的操作,再抽象出一个btstack_uart_block_t结构体:

2. 操作系统相关代码:btstack_run_loop

BTStack支持多种操作系统,比如Windows、Linux、IOS。

不同的操作系统,操作设备的函数不一样,比如:

① Windows使用WaitForMultipleObjects函数来等待数据

② Linux使用select函数来等待数据

BTStack针对不同的运行环境,抽象出了对应的btstack_run_loop结构体,共同成员为:

比如其中的execute成员很重要,它是一个循环,在循环中等待、读取、处理函数。

3. 循环体中,怎么读取、处理数据

BTStack可以同时支持多个蓝牙设备,每一个蓝牙设备被open时都会返回一个文件句柄,Windows/Linux就是通过监视这些文件句柄来等待数据的。

显然,循环体从句柄A得到了数据,应该调用句标A对应的处理函数:句柄和处理函数是绑定的。

所以,BTStack里抽象出了btstack_data_source_t结构体,里面含有句柄、处理函数:

打开硬件设备时,

1)要设置对应的btstack_data_source_t结构体:句柄、处理函数

2)  并调用btstack_run_loop_add_data_source把这个结构体告诉btstack_run_loop,

3)  btstack_run_loop的execute循环中,就监视该句标,获得数据后调用对应的处理函数

对于各种btstack_data_source_t结构体,都有自己的处理函数:

1)对于UART

UART有两种:

  3线串口(其数据传输协议被称为H5),

  5线串口(其数据传输协议被称为H4)。

使用H4、H5协议时它的处理函数都是btstack_uart_windows_process_read:

这个函数会调用block_received()来处理,block_received是函数指针。

对于H4协议,它指向:hci_transport_h4_block_read;

对于H5协议,它指向:hci_transport_h5_block_received:

所以:

对于H4协议,uart data source的process函数最终是hci_transport_h4_block_read;

对于H5协议,uart data source的process函数最终是hci_transport_h5_block_read。

2)对于USB

每一个endpoint都有对应的btstack_data_source_t结构体,也都有对应的process函数,比如:

可以看到,对于不同的接口,即对于H2、H4、H5,都分别有自己的处理函数。

各个句柄对应的处理函数,是该句柄数据的处理起点,它将会调用上面各层提供的处理函数。这些处理函数,最终都会通过以下调用,把数据上报给各层:

packet_handler(packet_type, packet, size);   // h2,h4,h5中的packet_handler指针

这个packet_handler是hci.c提供的。hci.c文件中hci_init函数它通过以下调用,把hci.c的packet_handler函数传给hci_transport_t结构体,用来设置H2、H4或H5文件中的packet_handler指针:

4. 上面各层如何处理数据

hci.c提供的packet_handler函数,根据packet_type的不同,分别处理。

有3类packet_type:event、acl data、soc data。

btstack_data_source_t结构体中的process函数是数据处理的起点,该“起点”会调用hci.c中的packet_handler函数。

那么hci.c中的packet_handler可以认为是数据处理的分发站。

HCI层可以处理这些数据时,就由HCI层来处理,处理不了就上报。

L2CAP、SM、GATT、GAP、APP等等,都可以提供处理函数。

1)对于EVENT数据:

hci.c中的event_handler函数用来处理这些数据,

在HCI层能处理的数据将被用来设置hci_stack结构体;

有必要上报的数据,通过hci_emit_event函数上报。

hci_emit_event函数会调用hci_stack->event_handlers链表中的各个callback函数。该链表中的函数,来自上面各层,它们通过hci_add_event_handler注册这些callback函数。

调用hci_add_event_handler的文件有:

le_data_channel_client.c属于APP,即APP可以处理感兴趣的数据;

main.c中注册的函数没什么用处,就是在蓝牙模块初始化完毕后,打印一个提示信息:“BTstack up and running at …”;

gatt_client.c这个文件,在le_data_channel_client.c这个APP中没被使用;

att_Server.c这个文件是用于ATT Server的,在le_data_channel_client.c这个APP中没被使用;

btstack_crypto.c、sm.c都是用于安全管理;

l2cap.c,这很重要,ATT、GATT、GAP、SM各层都要使用L2CAP来收、发数据。

2)对于ACL数据:

hci.c中的acl_handler函数用来处理这些数据,

在HCI能处理的数据将被用来设置对应的hci_connection_t结构体,

有必要上报的数据,通过hci_emit_acl_packet函数上报。

hci_emit_acl_packet函数会调用hci_stack->acl_packet_handler来处理。

在l2cap.c中,通过如下调用设置hci_stack->acl_packet_handler:

hci_register_acl_packet_handler(&l2cap_acl_handler);

即:上报的ACL数据,将由L2CAP的l2cap_acl_handler函数来处理。

3)对于SCO数据:

hci.c中的sco_handler函数用来处理这些数据,

在HCI能处理的数据将被用来设置对应的hci_connection_t结构体,

有必要上报的数据,通过hci_stack->sco_packet_handler函数上报。

APP如果要处理SCO数据,可以通过hci_register_sco_packet_handler提供自己的处理函数。hci_register_sco_packet_handler就是真接设置hci_stack->sco_packet_handler。

5. 谁触发了数据的传输?

之前我们说过主循环里在等待数据,只有我们给蓝牙模块发送命令之后,它才会回送数据。

那么,在哪里给蓝牙模块发送了第1个命令?在APP代码中,必有如下语句:

// turn on!

hci_power_control(HCI_POWER_ON);

这会导致给蓝牙模块发送一系列的初始化命令,

初始化成功后,APP通过hci_add_event_handler注册的函数就会被调用,在这个函数里就可以执行我们自己的代码,比如发起scan、发起connection等等。

附:3线串口上H5协议

SLIP协议最好文章:

SLIP—串行线路上传输数据报的非标准协议

https://blog.csdn.net/pushilong/article/details/80358485

https://wenku.baidu.com/view/809a8a8e8bd63186bcebbcae.html

第07节-开源蓝牙协议BTStack框架代码阅读(下)的更多相关文章

  1. 第07节-开源蓝牙协议BTStack框架代码阅读(上)

    首先来看一下,对于硬件操作,它是如何来进行处理的.在上篇文章中曾说过,在main函数里面它会调用硬件相关的代码,调用操作系统相关的代码.在BTStack中,可以搜索一下main.c,将会发现有很多ma ...

  2. 第06节-开源蓝牙协议BTStack框架分析

    本篇博客根据韦东山的视频,整理所得. 本篇博客讲解BTStack的框架,首先来看一下硬件的结构: 蓝牙模块接在电脑上,或是接在开发板上.不论接在哪,我们都需要编写程序来控制这个蓝牙模块. . 我们需要 ...

  3. 第08节-开源蓝牙协议栈BTStack数据处理

    本篇博客根据韦东山的视频整理所得. 在上篇博客,通过阅读BTStack的源码,大体了解了其框架,对于任何一个BTStack的应用程序都有一个main函数,这个main函数是统一的.这个main函数做了 ...

  4. [转]FFMpeg框架代码阅读

    简介 FFmpeg是一个集录制.转换.音/视频编码解码功能为一体的完整的开源解决方案. FFmpeg的开发是基于Linux操作系统,但是可以在大多数操作系统中编译和使用.FFmpeg支持MPEG.Di ...

  5. FFMpeg框架代码阅读

    http://blog.csdn.net/wstarx/article/details/1572393 FFMPEG源码分析(二) http://www.cnblogs.com/qingquan/ar ...

  6. Deepctr框架代码阅读

    DeepCtr是一个简易的CTR模型框架,集成了深度学习流行的所有模型,适合学推荐系统模型的人参考. 我在参加比赛中用到了这个框架,但是效果一般,为了搞清楚原因从算法和框架两方面入手.在读代码的过程中 ...

  7. 蓝牙协议分析(5)_BLE广播通信相关的技术分析

    1. 前言 大家都知道,相比传统蓝牙,蓝牙低功耗(BLE)最大的突破就是加大了对广播通信(Advertising)的支持和利用.关于广播通信,通过“玩转BLE(1)_Eddystone beacon” ...

  8. 蓝牙协议(bluetooth spec)

    1.概述:   蓝牙协议规范遵循开放系统互连参考模型(OSI/RM),从低到高地定义了蓝牙协议堆栈的各个层次. SIG(Session Initiation Protocol)所定义的蓝牙技术规范的目 ...

  9. 介绍开源的.net通信框架NetworkComms框架之二 传递类

    原文网址: http://www.cnblogs.com/csdev Networkcomms 是一款C# 语言编写的TCP/UDP通信框架  作者是英国人  以前是收费的 目前作者已经开源  开源地 ...

随机推荐

  1. java的GUI之SWT框架 配置开发环境(包含但不限于WindowBuilder完整教程,解决Unknown GUI toolkit报错,解决导入SWT包错误)

    官网(资料挺多的,API文档截图以及示例都有):https://www.eclipse.org/swt/ 克隆官方仓库 git clone --depth=1 git://git.eclipse.or ...

  2. C++中vector小学习,顺便查了下<stdio.h>(或<cstdio>)

    今天看书,邻桌在看<C++ Primer>,拿过来看了一会儿.以前比较少用vector容器,看了下后,瞬间觉得好腻害的样子,就想试一下.嗯,就是试一下而已.(代码可能网上都差不多,有参考) ...

  3. Java 性能调优小技巧

    1.在知道必要之前不要优化系统 这可能是最重要的性能调整技巧之一.你应该遵循常见的最佳实践做法并尝试高效地实现用例.但是,这并不意味着在你证明必要之前,你应该更换任何标准库或构建复杂的优化. 在大多数 ...

  4. Beta冲刺(7/7)——2019.5.29

    作业描述 课程 软件工程1916|W(福州大学) 团队名称 修!咻咻! 作业要求 项目Alpha冲刺(团队) 团队目标 切实可行的计算机协会维修预约平台 开发工具 Eclipse 团队信息 队员学号 ...

  5. ant-design自定义FormItem--上传文件组件

    自定义上传组件,只需要在内部的值变化之后调用props中的onChange方法就可以托管在From组件中, 此外为了保证,初始化值发生变化后组件也发生变化,需要检测initialValue 变化,这是 ...

  6. 集合类源码(五)Collection之BlockingQueue(LinkedTransferQueue, PriorityBlockingQueue, SynchronousQueue)

    LinkedTransferQueue 功能 全名 public class LinkedTransferQueue<E> extends AbstractQueue<E> i ...

  7. ['1', '2', '3'].map(parseInt) 输出答案和解析

    根据题目可以了解到这道题主要考我们的是对map函数和parseInt函数的熟悉程序,所以我们先来了解这两个函数 map 根据MDN上对于map的解释:map() 方法创建一个新数组,其结果是该数组中的 ...

  8. Python转义序列

    正则表达式参考:https://www.cnblogs.com/huxi/archive/2010/07/04/1771073.html

  9. R数据挖掘 第一篇:聚类分析(划分)

    聚类是把一个数据集划分成多个子集的过程,每一个子集称作一个簇(Cluster),聚类使得簇内的对象具有很高的相似性,但与其他簇中的对象很不相似,由聚类分析产生的簇的集合称作一个聚类.在相同的数据集上, ...

  10. sql 简单分页查询(ror_number() over)

    SELECT * FROM ( SELECT *, ROW_NUMBER() OVER (ORDER BY ID DESC ) AS r_num FROM (select * from #table ...