GAP层协议浅析

overview

为什么这篇博文GAP协议不加一个ble修饰?因为这个协议太重要了,有必要从蓝牙整体面详细整理一下相关东西。

记得之前一个前辈,新人培训时,用到了三个词总结什么是GAP?
发现连接安全” 太深刻。

引用core spec一张图,无论br/edr何时还是ble 都绕不开GAP协议。
全球蓝牙设备都需遵守GAP协议,才能够正常被发现和连接。
在这里插入图片描述

Role

BR/EDR

  • 在传统蓝牙中,主要分为两种角色,initiator(发起连接的一端) 和acceptor(接受连接的一段)。
  • 需要注意的是,同一个设备既可以作为initiator,也可以作为acceptor,这种角色并不是固定的,只是针对一次连接过程中的角色定义。
  • 同一个设备,同一时间,可以接受连接,也可以发起连接。

BLE

  • 在ble中,GAP定义了四种角色:广播者 broadcast;监听者observer;外围设备peripheral;中央设备central。
  • 连接过程仅有两个设备参与,这四种角色也并不是每个设备一个角色。可以成对来看,broadcast-observer,peripheral-central。针对同一次连接的不同时期。在扫描阶段,顾名思义,广播者发送广播,监听者扫描监听周围设备的广播。
  • 举例说明,蓝牙鼠标与电脑连接,这个过程中,mouse 发送adv,所以是broadcast;pc 进入scan mode 所以是observer;pc 主动发起的连接,作为master,也是central; 鼠标接受连接,并且提供自己定义的service,是slave ,也是peripheral。
  • 同传统蓝牙一样,根据设备的使用环境,可以自定义实现相关的profile,并不是所有设备都需要实现四种角色。如鼠标,就不需要实现observer 角色,它没有显示能力,也发现不了对端设备的名字,所以无法主动发起连接。
  • 也有很多多协议的复杂设备,例如我们使用的手机,四种角色都需要实现

用户接口

主要是蓝牙设备呈现给用户的一些参数

蓝牙地址

  • BD_ADDR,规定是一个48bit大小,主要分为public 和random 。 SIG对蓝牙地址的各个位段都有详细规定。
  • random address 又可以分为 static address和 private address private address
    可以分为 non-resolvable 和resolvable
  • 后续会另起一篇,详细介绍bt address及RPA

设备名

  • 蓝牙设备理论上最长可达248字节(UTF-8),但是在ui层次一般被限制在62个字符以内。
  • 另外需要注意的是,可能对端设备对名字长度有限制,只会显示前20个字节
  • 一般在adv 中会携带device name 信息,br/edr中会remote name request 拿到对端设备名字, ble
    中一般会通过ATT 读到对端设备名字的characteristic

密钥

  • passkey应用在smp或者传统配对过程中,可能会呈现给用户,这个需要视设备IO能力而定
  • 在smp过程中,passkey是一个6位整数,范围是000000-999999
  • 在legacy pairing过程中,PIN有不同的级别
  • ble 主要是smp

设备类型

class of device (COD)

  • 在发现设备阶段,会得到对端设备的cod,决定对端设备支持的服务
  • 同一个设备可能支持多个不同设备类型的服务,但是可能会显示一种,最期待被对端设备发现的设备类型

图标

  • 一个16bit的数字,能够映射成一个图标或字符串
  • 属于GATT里面的一个特征,可以查阅sepc,选择需要显示的图标

广播码

  • broadcast_code用来加密BIS
  • 在UI层字符串一般在4个字节到16字节之间
  • 在其他所有层,都会转换为128bit,不足前面补零

Modes – BR/EDR physical transport

Discoverability modes

Connectability modes

Bondable modes

Synchronizability modes

Security aspects – BR/EDR physical transport

Authentication

Security modes

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,可以使用 PyTorch 中的 Hook 机制来获取 VGG19 模型的 GAP 的输出。Hook 是在模型前向计算过程中的一种操作,它可以在指定的计算完后,获取该的输出。具体操作如下: 首先,加载 VGG19 模型: ```python import torch import torchvision.models as models vgg19 = models.vgg19(pretrained=True) ``` 然后,我们可以查看 VGG19 模型的结构,以便确定 GAP 的位置: ```python print(vgg19) ``` 输出的模型结构如下: ``` VGG( (features): Sequential( (0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (1): ReLU(inplace=True) (2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (3): ReLU(inplace=True) (4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) (5): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (6): ReLU(inplace=True) (7): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (8): ReLU(inplace=True) (9): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) (10): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (11): ReLU(inplace=True) (12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (13): ReLU(inplace=True) (14): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (15): ReLU(inplace=True) (16): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (17): ReLU(inplace=True) (18): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) (19): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (20): ReLU(inplace=True) (21): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (22): ReLU(inplace=True) (23): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (24): ReLU(inplace=True) (25): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (26): ReLU(inplace=True) (27): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) (28): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (29): ReLU(inplace=True) (30): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (31): ReLU(inplace=True) (32): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (33): ReLU(inplace=True) (34): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (35): ReLU(inplace=True) (36): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) ) (avgpool): AdaptiveAvgPool2d(output_size=(7, 7)) (classifier): Sequential( (0): Linear(in_features=25088, out_features=4096, bias=True) (1): ReLU(inplace=True) (2): Dropout(p=0.5, inplace=False) (3): Linear(in_features=4096, out_features=4096, bias=True) (4): ReLU(inplace=True) (5): Dropout(p=0.5, inplace=False) (6): Linear(in_features=4096, out_features=1000, bias=True) ) ) ``` 可以看到,VGG19 模型的 GAP 是 AdaptiveAvgPool2d ,所以我们可以在该上注册一个 Hook: ```python def hook_fn(module, input, output): global gap_output gap_output = output vgg19.avgpool.register_forward_hook(hook_fn) ``` 在该 Hook 函数中,我们将该的输出保存在全局变量 gap_output 中。 现在,我们可以使用 VGG19 模型来处理一张图片,并获取 GAP 的输出: ```python from PIL import Image import torchvision.transforms as transforms # 加载图片 img = Image.open('test.jpg') # 对图片进行预处理 preprocess = transforms.Compose([ transforms.Resize(256), transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ]) img_tensor = preprocess(img) img_tensor = torch.unsqueeze(img_tensor, 0) # 在模型上进行前向计算 vgg19.eval() with torch.no_grad(): output = vgg19(img_tensor) # 获取 GAP 的输出 print(gap_output) ``` 输出的结果即为 GAP 的输出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值