为了让CSR867x的开发更容易,现与思度科技联合推出CSR867x学习板【淘宝链接:思度科技CSR开发板】。

技术交流QQ群号:743434463
开发板会员QQ群号:725398389(凭订单号入群,赠PPT、项目源码、视频教程)
——————————正文分割线———————————–

1. 引言

两个通过SPP协议连接的蓝牙设备之间的数据通信如串口通信一般简单方便,遗憾的是ADK中并没有给出简单的例程,使很多初学者难以快速学会使用SPP协议。

本文给出SPP Server和Client的使能示例代码,并给出运行于matlab的Client端测试方法。

2. SPP简介

SPP是Serial Port Profile(串口配置文件)的缩写,其定义了使用蓝牙进行RS232(或类似)串行电缆仿真的设备应使用的协议和过程。简单来说就是在蓝牙设备之间建立虚拟的串口进行数据通信。

先来看一下SPP协议与其他协议之间的关系图:

从上图中可见SPP协议是很多协议的基础协议。蓝牙设备之间通过SDP协议发现彼此的SPP服务。无绳电话和对讲也利用了SPP协议。

接下来看一下协议模型:

SPP协议需要SDP协议和RFCOMM协议作为支撑,分别负责服务的发现和数据的传输。在下文的示例代码中会有体现。通常我们将发起SPP连接请求的设备称为Client,接受SPP请求的设备称为Server。建立SPP连接的消息流如下:

ServerClient注册SDP服务和RFCOMM服务通道查询RFCOMM服务通道加密验证验证通过建立RFCOMM会话双方交换数据ServerClient

3. VM工程中添加SPP协议

ADK中的SPP相关的代码路径如下:

  • src\lib\spp_common\ spp server和spp client共用的代码
  • src\lib\sppc\ spp client代码
  • src\lib\spps\ spp server代码

VM project properties->build system->Libraries添加spps, sppc, spp_common,源代码中包含spps.h, sppc.h, spp_common.h头文件。

3.1. 启用SPP Server

需要启用SPP Server服务并创建消息处理函数:

/* 启用SPP服务 */
void sink_intercom_init(void)
{ITC_DEBUG(("ITC %s\n", __func__));intercom_task.handler = intercom_handle_message;SppStartService(&intercom_task);
}

消息处理函数中对SPP Client发起的连接和断开请求作出响应:

/* SPP连接响应 */
case SPP_CONNECT_IND:
{SPP_CONNECT_IND_T *m = (SPP_CONNECT_IND_T *)message;ITC_DEBUG(("ITC: SPP_CONNECT_IND\n"));intercom_server.addr = m->addr;intercom_server.server_channel = m->server_channel;intercom_server.sink = m->sink;/* 响应Client设备的请求,payload size = 64 */SppConnectResponse(&intercom_task, &intercom_server.addr,TRUE,intercom_server.sink,intercom_server.server_channel,INTERCOM_SPP_MAX_PAYLOAD_SIZE);
}
break;/* SPP断开响应 */
case SPP_DISCONNECT_IND:
{SPP_DISCONNECT_IND_T *m = (SPP_DISCONNECT_IND_T *)message;ITC_DEBUG(("ITC: SPP_DISCONNECT_IND\n"));SppDisconnectResponse(m->spp);
}
break;

在收到SPP Client发来的消息后,原封不动地再发送给Client:

case SPP_MESSAGE_MORE_DATA:
{           /* Move data from source into message */Source src = ((SPP_MESSAGE_MORE_DATA_T*)message)->source;const uint8 *s = SourceMap(src);uint16 len = SourceBoundary(src);uint8 * spp_buf;bool status;uint16 claim_result;spp_buf = SinkMap(intercom_server.sink);claim_result = SinkClaim(intercom_server.sink, len);if (claim_result == 0xFFFF){SourceDrop(src, len);return;}memmove (spp_buf+claim_result, s, len);status = SinkFlush(intercom_server.sink, len);ITC_DEBUG(("ITC: status %d", status));SourceDrop(src, len);
}
break;

3.2. 启用SPP Client

SPP Client不需要注册SDP服务,只需向指定的蓝牙设备直接发起SPP请求:

SppConnectRequest(&bluedongleTask, &addr, 0, 0); /* 0代表默认参数 */

同时需要准备好处理SPP Client库发送给VM的消息:

/* SPP连接成功,保存sink留作发送数据时用 */
case SPP_CLIENT_CONNECT_CFM:
{SPP_CLIENT_CONNECT_CFM_T *m = (SPP_CLIENT_CONNECT_CFM_T *) message;/* bool success = m->status == spp_connect_success; */spp_sink = m->sink;BD_DEBUG(("BD: SPP_CLIENT_CONNECT_CFM: %u, payload size: %d\n", m->status, m->payload_size));
}
break;/* 断开SPP响应 */
case SPP_DISCONNECT_IND:
{SPP_DISCONNECT_IND_T *m = (SPP_DISCONNECT_IND_T *) message;spp_sink = NULL;BD_DEBUG(("BD: SPP_DISCONNECT_IND: %u\n", m->status));SppDisconnectResponse(m->spp);
}
break;

处理接收到的SPP Server的数据:

case SPP_MESSAGE_MORE_DATA:
{Source src = ((SPP_MESSAGE_MORE_DATA_T*)message)->source;const uint8 *s = SourceMap(src);uint16 len = SourceBoundary(src);spp_server_data_process((const char *)s, len);SourceDrop(src, len);
}
break;

我们可以在spp_server_data_process里添加程序以处理SPP Server发送来的数据,也可以将数据通过stream机制直接传送给DSP,作为两个蓝牙设备之间DSP数据的透传通道。

4. matlab环境验证SPP收发数据

matlab提供了两种工具可用来验证目标设备的SPP Server是否工作正常。一是虚拟串口,二是蓝牙SPP。

4.1. 虚拟串口

当蓝牙设备与PC机通过蓝牙适配器连接后,如果蓝牙设备支持SPP协议,PC机在扫描到此协议后会虚拟出串口:

此时我们需要在matlab中通过访问串口的方式与蓝牙设备建立通信:

spp_uart = serial('COM7');  % 获取串口句柄
fopen(spp_uart);  % 打开串口
fwrite(spp_uart,'111'); % 发送字符串111
recv = fread(spp_uart,9); % 阻塞在此函数直到读取到9个字节
fprintf('%s\n',recv);
fclose(spp_uart); % 关闭串口
delete(spp_uart); % 删除句柄

此方式的优点是连接建立速度较快,缺点是有些设备不能在PC端虚拟出串口(如CSR8670)。

4.2. 蓝牙SPP

matlab支持通过调用蓝牙SPP连接蓝牙设备的SPP Server,此方式支持不能正常枚举出虚拟串口的蓝牙设备,前提是用户已经知道目标设备的SPP server channel并已与其完成配对。示例代码如下:

r=instrhwinfo('Bluetooth');  % 搜索附近的蓝牙设备
d=r.RemoteNames; % 获取这些设备的名称
[m,n] = listdlg('PromptString','Select Your Bluetooth device:','SelectionMode','single','ListString',d); % 列表选择目标蓝牙设备
dn=cell2mat(d(m));
dev = Bluetooth(dn, 2) % 通过SPP server channel(此处是2)获取目标蓝牙设备的SPP连接句柄
fopen(dev);  % 建立蓝牙SPP连接
fwrite(dev,'1'); % 发送字符1
fread(dev, 5); % 阻塞等待接收满5字节数据
fclose(dev); % 断开蓝牙SPP连接

5. 总结

在掌握了SPP Server和Client的使能和验证方法后,可以基于SPP协议定制上层协议,开发各种独特应用。这里要注意SPP协议在与安卓设备通信时不受限制,但与iOS设备通信的前提条件是蓝牙设备支持MFi协议。此处可见苹果对任何能够穿透iOS操作系统直达应用的连接技术都是严格管控的,明面上是增加系统稳定性,实质是通过切断客户与终端用户的直接联系,强收过路费。

6. 参考文档

  • Serial Port Profile.pdf

CSR867x学习笔记:SPP Server and Client相关推荐

  1. Go语学习笔记 - grpc server/client protobuf | 从零开始Go语言

    目录 创建Proto文件 生成proto文件对应的go文件 创建服务结构体 创建客户端测试 小结 学习笔记,写到哪是哪. 上一篇是写的redis操作来着,最近主要研究了一下grpc. 在玩grpc的过 ...

  2. CSR867x学习笔记:低音炮音频传输协议(SWAT)

    为了让CSR867x的开发更容易,现与思度科技联合推出CSR867x学习板[淘宝链接:思度科技CSR开发板]. 技术交流QQ群号:743434463 开发板会员QQ群号:725398389(凭订单号入 ...

  3. 【运维学习笔记】在 vSphere Client上创建新的虚拟机

    具体步骤如下: 1. 创建新的虚拟机 打开vSphere Client(可以是客户端也可以是网页端) 如果是网页端仅能使用火狐浏览器或者谷歌浏览器打开,输入网址:192.168.22.22,进入如下界 ...

  4. Go语学习笔记 - websocket gorilla(附测试代码) | 从零开始Go语言

    目录 项目结构 消息结构 服务端代码 定义客户端行为 服务启动 测试代码 总结 学习笔记,写到哪是哪. websocket也是常用的协议了,在上一篇中主要测试使用了一下grpc. 下面我会把代码贴出来 ...

  5. python word 操作 doc 文件格式转docx 格式 学习笔记

    python word 操作 doc 文件格式转docx 格式 学习笔记 from win32com import client as wc import time # TODO file_0 = & ...

  6. ROS 学习笔记(三):自定义服务数据srv+server+client 示例运行

    ROS 学习笔记(三):自定义服务数据srv+Server+Client 示例运行 一.自定义服务数据: 1.向功能包添加自定义服务文件(AddTwoInts.srv) cd ~/catkin_ws/ ...

  7. mysql数据实时同步:Canal安装部署、kafka安装、zk安装、mysql安装、Canal Server+Canal Client HA,Canal+mysql+Kafka,相关验证(学习笔记)

    目录 Canal安装部署 1.1. 服务器准备 1.2. 设置主机名并配置hosts 1.3. 免密设置 1.4. 设置ntp时间 1.5. 关闭防火墙 1.6. 关闭selinux 1.7. 安装J ...

  8. ASP.NET Core分布式项目实战(oauth2 + oidc 实现 client部分)--学习笔记

    任务16:oauth2 + oidc 实现 client部分 实现 client 之前启动一下上一节的 server,启动之前需要清除一些代码 注释 Program 的 MigrateDbContex ...

  9. ASP.NET Core分布式项目实战(oauth2 + oidc 实现 server部分)--学习笔记

    任务15:oauth2 + oidc 实现 server部分 基于之前快速入门的项目(MvcCookieAuthSample): ASP.NET Core快速入门(第5章:认证与授权)--学习笔记 A ...

最新文章

  1. 一本书带你入门商业数据科学
  2. flask从服务器获取html页面,flask的ajax、获取服务器数据、放到前端页面、如果数据存在显示标签、如果不存在不显示标签...
  3. 免焊vga3加6接线图_计数器和接近开关两线怎么接,计数器接近开关接线图
  4. sqlserver shiwu
  5. 山东联通中兴B860 AV1.1机顶盒 刷机问题解决
  6. SpreadJS 15.1 ~【SpreadJS 15.0】
  7. TeamTalk服务器编译与部署
  8. linux下制作dos启动u盘启动,linux dos启动盘怎样做
  9. android学习code3 布局上
  10. Xcode 报错及解决办法汇总
  11. UIView Animation 动画学习总结
  12. WFP之关联上下文数据以及注意事项
  13. kodi linux版本,Linux下安装多媒体中心 Kodi 18.8 新版本并设置中文界面
  14. 数字图像处理-DFTDCTWHT小波变换分解重构(Matlab)
  15. 显示远程计算机或设备将不接受连接的解决办法
  16. Excel全自动项目管理甘特图
  17. 南卫理公会大学 计算机排名,南卫理公会大学全球排名及其优秀校友
  18. gitBash快速清屏,git命令行操作,快速清屏,清屏
  19. Android果冻效果(阻尼动画)
  20. 什么是IP Core?

热门文章

  1. IOS 公司开发者账号申请详细教程-13810208661
  2. 曾做erp开发工程师,谈下自己的经验
  3. 在进行原理图编译的时候提示警告:Net has no driving source
  4. 纯JS实现房贷利率报表对比
  5. 团队RESTful 风格API规范
  6. Tesseract训练识别数字
  7. python爬取lol所有英雄信息
  8. 基于LBS的六边形热力图算法
  9. UC伯克利教授Stuart Russell人工智能基础概念与34个误区 (公号回复“AI基础概念”可下载PDF资料)
  10. 爬取链家所有房源信息(在售、成交、租房)