概述

蓝牙是一种工作在免费的ISM频段的短距离无线通信技术,在各种设备之间实现灵活、安全、低成本、低功耗的语音和数据通信。它采用自适应跳频技术,可以和多种无线通信共存于ISM频段,与同用于短距离无线通信的Zigbee和UWB相比,蓝牙协议和标准更加完善,设备间一致性和互连通性好,而且以Profile的形式定义了具体应用的实现方式,从而保证了兼容性。

蓝牙通讯原理

蓝牙通讯分为三个阶段:

  • 1)设备发现和连接
  • 2)鉴权
  • 3)应用层信息服务

第一阶段,设备发现与连接。

在这个阶段,TBox定期广播蓝牙设备的地址。主设备搜索到此前用户通过TSP绑定的TBox蓝牙MAC地址列表中的其中一个后,主动请求蓝牙设备进行连接。蓝牙主设备根据信号TBox广播的信号强度,连接TBox并且建立数据通道。

第二阶段, 鉴权。

这个阶段,使主设备与TBox相互确认身份。

第三阶段,请求服务。

这个阶段,允许通过蓝牙通信请求服务。

TBOX有两路数据通道:通道1用于主设备与TBOX蓝牙模块的一级鉴权,通道2用于主设备与TBOX的MCU通讯。

Tbox的BLE模组和主设备交互流程图:

蓝牙广播的内容为蓝牙名称和服务的UUID,广播周期为2s。

主设备通过通道1发送Booking信息,TBox收到通道1主设备的BookingID后,如果ID号在白名单列表中,则认为通道一级鉴权,需要在通道1回复主设备信息并开始执行二级鉴权。

TBox收到通道1主设备的BookingID后,如果ID号在不在白名单中列表中,则认为一级鉴权失败,需要在通道1回复主设备信息,然后断开连接。

车载蓝牙通信实现

蓝牙电话

蓝牙电话主要用到BluetoothHeadsetClient这个类里面定义了很多广播意图,最有用的是这个action

/**\* Intent sent whenever state of a call changes.**It includes:\* {@link #EXTRA_CALL},\* with value of {@link BluetoothHeadsetClientCall} instance,\* representing actual call state.*/public static final String ACTION_CALL_CHANGED ="android.bluetooth.headsetclient.profile.action.AG_CALL_CHANGED";

它监听来电,接听来电,去电,通话中等状态,要想在车载设备中操作电话需要知道这些状态。

private final BroadcastReceiver mReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {if (null != intent) {String action = intent.getAction();Log.i(TAG, "BTService receiver action == "+action);//监听来电if (BluetoothHeadsetClient.ACTION_CALL_CHANGED.equals(action)) {BluetoothHeadsetClientCall mCall = (BluetoothHeadsetClientCall) intent.getExtra(BluetoothHeadsetClient.EXTRA_CALL, null);if (mCall != null) {int callState = mCall.getState();Log.d(TAG, "when call status changes: mConnStat is " + mConnStat+" number == "+mCall.getNumber());if (callState == BluetoothHeadsetClientCall.CALL_STATE_INCOMING) {//来电} else if (callState == BluetoothHeadsetClientCall.CALL_STATE_DIALING) {//去电} else if (callState == BluetoothHeadsetClientCall.CALL_STATE_ACTIVE) {//接听中} else if (callState == BluetoothHeadsetClientCall.CALL_STATE_TERMINATED) {//结束}}}看下它的构造方法BluetoothHeadsetClient(Context context, ServiceListener l) {mContext = context;mServiceListener = l;mAdapter = BluetoothAdapter.getDefaultAdapter();IBluetoothManager mgr = mAdapter.getBluetoothManager();if (mgr != null) {try {mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);} catch (RemoteException e) {Log.e(TAG,"",e);}}doBind();}

mBluetoothStateChangeCallback监听蓝牙打开或关闭状态,重点看下doBind方法

boolean doBind() {Intent intent = new Intent(IBluetoothHeadsetClient.class.getName());ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);intent.setComponent(comp);if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,android.os.Process.myUserHandle())) {Log.e(TAG, "Could not bind to Bluetooth Headset Client Service with " + intent);return false;}return true;}其实就是去绑定一个serviceprivate final ServiceConnection mConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName className, IBinder service) {if (DBG) Log.d(TAG, "Proxy object connected");mService = IBluetoothHeadsetClient.Stub.asInterface(Binder.allowBlocking(service));if (mServiceListener != null) {mServiceListener.onServiceConnected(BluetoothProfile.HEADSET_CLIENT,BluetoothHeadsetClient.this);}}@Overridepublic void onServiceDisconnected(ComponentName className) {if (DBG) Log.d(TAG, "Proxy object disconnected");mService = null;if (mServiceListener != null) {mServiceListener.onServiceDisconnected(BluetoothProfile.HEADSET_CLIENT);}}};

当服务连接时返回IBluetoothHeadsetClient并通知协议请求成功,这是aidl的客户端,不了解aidl的去查看一下android跨进程通信相关知识。

/**\* Connects to remote device.*\* Currently, the system supports only 1 connection. So, in case of the\* second connection, this implementation will disconnect already connected\* device automatically and will process the new one.*\* @param device a remote device we want connect to\* @return true if command has been issued successfully;\* false otherwise;\* upon completion HFP sends {@link #ACTION_CONNECTION_STATE_CHANGED}\* intent.*/public boolean connect(BluetoothDevice device) {if (DBG) log("connect(" + device + ")");final IBluetoothHeadsetClient service = mService;if (service != null && isEnabled() && isValidDevice(device)) {try {return service.connect(device);} catch (RemoteException e) {Log.e(TAG, Log.getStackTraceString(new Throwable()));return false;}}if (service == null) Log.w(TAG, "Proxy not attached to service");return false;}

连接设备就是调用服务端的connect方法。服务端的实现在packages\apps\Bluetooth\src\com\android\bluetooth\hfpclient\HeadsetClientService.java

接听电话/**\* Accepts a call*\* @param device remote device\* @param flag action policy while accepting a call. Possible values\* {@link #CALL_ACCEPT_NONE}, {@link #CALL_ACCEPT_HOLD},\* {@link #CALL_ACCEPT_TERMINATE}\* @return true if command has been issued successfully;\* false otherwise;\* upon completion HFP sends {@link #ACTION_CALL_CHANGED}\* intent.*/public boolean acceptCall(BluetoothDevice device, int flag)拨打电话/**\* Places a call with specified number.*\* @param device remote device\* @param number valid phone number\* @return {@link BluetoothHeadsetClientCall} call if command has been\* issued successfully;\* {@link null} otherwise;\* upon completion HFP sends {@link #ACTION_CALL_CHANGED}\* intent in case of success; {@link #ACTION_RESULT} is sent\* otherwise;*/public BluetoothHeadsetClientCall dial(BluetoothDevice device, String number)拒接接听/**\* Rejects a call.*\* @param device remote device\* @return true if command has been issued successfully;\* false otherwise;\* upon completion HFP sends {@link #ACTION_CALL_CHANGED}\* intent.**Feature required for successful execution is being reported by:\* {@link #EXTRA_AG_FEATURE_REJECT_CALL}.\* This method invocation will fail silently when feature is not supported.*/public boolean rejectCall(BluetoothDevice device)挂断电话/**\* Rejects a call.*\* @param device remote device\* @return true if command has been issued successfully;\* false otherwise;\* upon completion HFP sends {@link #ACTION_CALL_CHANGED}\* intent.**Feature required for successful execution is being reported by:\* {@link #EXTRA_AG_FEATURE_REJECT_CALL}.\* This method invocation will fail silently when feature is not supported.*/public boolean rejectCall(BluetoothDevice device)发送DTMF编码/**\* Sends DTMF code.*\* Possible code values : 0,1,2,3,4,5,6,7,8,9,A,B,C,D,*,#*\* @param device remote device\* @param code ASCII code\* @return true if command has been issued successfully;\* false otherwise;\* upon completion HFP sends {@link #ACTION_RESULT} intent;*/public boolean sendDTMF(BluetoothDevice device, byte code)

根据自己的需求直接调用对应的方法,这里只列举了常用的.

本篇主要介绍车载开发中的基础,了解到车载开发基础的蓝牙通信原理以及举例蓝牙电话通信的示例实现。

Android车载的开发现在很吃香,想入行车载行业也是不错的选择。想学习更多的Android车载技术可以前往《Android车载技术手册》领取;由BYD高级车载开发整理制定的。我这里免费分享出来,能够刷到我这篇文章的可谓是赚到了一笔。

文末

现在的小轿车越来越多,几乎人人都拥有。以至于现在新能源的倡导;以后更换的车辆也会逐渐增多。现在入行车载系统开发来看;确实是很不错的前景。

Android车载开发基础学习——蓝牙通信是如何实现的?相关推荐

  1. 车载开发中,蓝牙通信需要学习那些核心技术点?

    车载蓝牙通信是指在汽车内部或车辆与外部设备之间使用蓝牙技术进行数据传输和通信.蓝牙5.0是现代蓝牙技术的最新版本,它引入了一系列新功能和改进,提供了更快的数据传输速度.更长的传输距离.更稳定的连接和更 ...

  2. 2022 最新 Android 基础教程,从开发入门到项目实战【b站动脑学院】学习笔记——第二章:Android App 开发基础

    第 2 章 Android App开发基础 本章介绍基于Android系统的App开发常识,包括以下几个方面:App开发与其他软件开发有什么不一 样,App工程是怎样的组织结构又是怎样配置的,App开 ...

  3. 都快2023年了,想从事Android车载开发的还没看过这些吗?

    说在前面的话 近几年的Android开发岗位就业环境想必大家也都有所耳闻,许多Android开发工程师都找不到自己满意的工作,于是纷纷另谋出路- 刚好这几年随着Android车载开发的兴起,就有许多A ...

  4. Android App开发基础

    Android App开发基础 App的开发特点 (1)App的运行环境 1.使用数据线把手机连到电脑上 2.在电脑上安装手机的驱动程序 3.打开手机的开发者选项并启用USB调试 4.将连接的手机设为 ...

  5. Android视频开发基础(二)

    Android视频开发基础(二) https://blog.csdn.net/goodlixueyong/article/details/62447452 前一篇文章详细介绍了视频的一些基本概念,这些 ...

  6. Android App开发基础篇—数据存储(SQLite数据库)

    Android App开发基础篇-数据存储(SQLite数据库) 前言:Android中提供了对SQLite数据库的支持.开发人员可以在应用中创建和操作自己的数据库来存储数据,并对数据进行操作. 一. ...

  7. 浅谈Android游戏开发基础和经验

    Android游戏开发基础和经验是本文要介绍的内容,主要是来了解并学习Android游戏开发的内容实例,具体关于Android游戏开发内容的详解来看本文. 做一个类似俄罗斯方块的android游戏开发 ...

  8. 虚幻引擎虚拟现实开发基础学习教程

    流派:电子学习| MP4 |视频:h264,1280×720 |音频:AAC,44.1 KHz 语言:英语+中英文字幕(根据原英文字幕机译更准确)|大小解压后:3.93 GB |时长:5h 15m 了 ...

  9. android界面数据存储,Android应用开发基础之数据存储和界面展现(二)

    Android应用开发基础之数据存储和界面展现(二) 常见布局 相对布局 RelativeLayout 组件默认左对齐.顶部对齐 设置组件在指定组件的右边 android:layout_toRight ...

  10. ASP.Net MVC开发基础学习笔记(5):区域、模板页与WebAPI初步

    http://blog.jobbole.com/85008/ ASP.Net MVC开发基础学习笔记(5):区域.模板页与WebAPI初步 2015/03/17 · IT技术 · .Net, Asp. ...

最新文章

  1. python字典用法(创建、添加、删除(del()、clear()、pop()、popitem())、修改、查找(get()、keys()、values()、items())、更新update、遍历)
  2. 在线作图|如何绘制一张星图
  3. Microsoft COCO 数据集
  4. “365算法每日学计划”:05打卡-图解冒泡排序(多解法)
  5. Zabbix的架构配置选项
  6. VTK:图片之ImageGradientMagnitude
  7. 河南彩民中奖3亿5千万
  8. How to identify the product settype and attribute in a given list
  9. 1970“变种”bug连WiFi热点iOS设备会变砖?
  10. android lua loadluafile 相对路径,Lua中的loadfile、dofile、require详解
  11. 移动端业务数据管理平台+健康管理平台+banner管理+图标管理+订单管理+门店内容管理+用户信息管理+版本更新管理Axure通用web端高保真交互app业务数据管理平台
  12. 三星oneui主屏幕费电_这或许是单手握持手感最佳的手机 三星Galaxy S20上手体验...
  13. WIN10专业版激活后变成教育版怎么解决
  14. php 统计uv,简单网站统计功能的实现 PV IP 真实访客数(UV) | 学步园
  15. 手机作为显示器及键鼠控制电脑棒(by quqi99)
  16. Android CameraX 仿一甜相机(录像、拍照、可调节尺寸、聚焦、照明、网格线),最全的CameraX教程
  17. 论文阅读:CCX-RAYNET: A CLASS CONDITIONED CONVOLUTIONAL NEURAL NETWORK FOR BIPLANAR X-RAYS TO CT VOLUME
  18. 系统崩溃分析 - vmcore 加载到 Trace32
  19. java如何调用pyramid函数_讲解:ICM、Pyramid、JAVA,PYTHON、PYTHON ,C++SPSS| Statis
  20. 比较Perl、PHP、Python、Java和Ruby

热门文章

  1. 【技术讨论】从弹弹堂说起,如何用2D物理引擎编写一个游戏一2011-11-05 10:36...
  2. live555源码分析(七)播放过程
  3. php解析psd图层,PSD解析工具实现(七)
  4. PHP网页页脚咋设计,50个网页头部与网页页脚设计欣赏
  5. Unity动画系统-配置Avatar
  6. Android设备远程控制工具AVDTools使用
  7. 强大如斯的Bunch类
  8. 使用python进行数据清洗常用的库_用于格式化和数据清理的便捷Python库
  9. 什么是SCSI硬盘?
  10. Linux中将多块新硬盘合并成一个,挂载到/data目录下