传统蓝牙API实现扫描的核心代码

   本人对蓝牙协议栈也算是个小白,以前都没有接触过蓝牙协议栈这块,来到现公司后还是接触,有些客户的蓝牙协议栈在遥控器向主机端发送连接参数更新请求后被拒绝,或者更新成功后发给遥控的又是另外一个数值,之前老大让我改了三个宏定义就可以,BTM_BLE_CONN_INT_MIN_DEF设成6,BTM_BLE_CONN_INT_MAX_DEF设成40,BTM_BLE_CONN_INT_MIN_LIMIT设成0x0006.之前一直不知道为什么这么改下就可以了。后面碰到一个问题,终于找到连接参数是怎么更新的,当然这里只是一部分。有大神看到可以帮忙补充。

        因为遥控器发给主机的的更新连接参数的packet是acl data,所以必定会在l2c_rcv_acl_data处理该patcket。该函数是专门处理ACL 类型的数据包的。根据解析出来的rcv_cid为L2CAP_BLE_SIGNALLING_CID,即可找到具体的处理函数l2cble_process_sig_cmd,在该函数中会去解析出packet包中的min_interval,max_interval,latency以及timeout。然后给t_l2c_linkcb这个结构中对应的值更新。
————————————————
版权声明:本文为CSDN博主「张伟字益达」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/linux_c_language/article/details/79803263

传统蓝牙API的扫描时长,系统默认是12秒左右,但可以主动停止,可以根据业务需求,设置一个扫描超时时间
传统蓝牙API实现扫描的核心代码

[Asm] 纯文本查看 复制代码

?

001

002

003

004

005

006

007

008

009

010

011

012

013

014

015

016

017

018

019

020

021

022

023

024

025

026

027

028

029

030

031

032

033

034

035

036

037

038

039

040

041

042

043

044

045

046

047

048

049

050

051

052

053

054

055

056

057

058

059

060

061

062

063

064

065

066

067

068

069

070

071

072

073

074

075

076

077

078

079

080

081

082

083

084

085

086

087

088

089

090

091

092

093

094

095

096

097

098

099

100

101

102

103

104

105

106

107

    /**

     * 查找蓝牙,包括传统蓝牙和低功耗蓝牙

     *

     * 注:

     * 1.该方式在查找低功耗蓝牙上效率较低

     * 2.若只需要查找低功耗蓝牙,应该使用“低功耗蓝牙API”,即 findBluetoothLE() 方法

     *

     * [url=home.php?mod=space&uid=952169]@Param[/url] scanInterval 扫描时长,单位:秒

     * @param bluetoothAdapter

     * @param btScanCallback 扫描结果回调

     */

    public static void findBluetoothLEAndClassic(int scanInterval, final BluetoothAdapter bluetoothAdapter, final BtScanCallback btScanCallback) {

        try {

            if (DeviceUtils.getInstance(context).checkPermission("android.permission.BLUETOOTH")

            && DeviceUtils.getInstance(context).checkPermission("android.permission.BLUETOOTH_ADMIN")) {

                if (!bluetoothAdapter.isEnabled()) {

                    // 若蓝牙未打开,直接返回

                    btScanCallback.onScan(new ArrayList<HashMap<String, Object>>());

                    return;

                }

                if (mScanning) {

                    // 正在扫描中,直接返回

                    btScanCallback.onScan(new ArrayList<HashMap<String, Object>>());

                    return;

                }

                // 默认扫描6秒,若scanInterval不合法,则使用默认值

                final int defaultInterval = 6;

                if (scanInterval <= 0) {

                    scanInterval = defaultInterval;

                }

                // 通过bluetoothAdapter.startDiscovery()实现的扫描,系统会在扫描结束(通常是12秒)后自动停止,

                // 而cancelDiscovery()可以提前终止扫描。 所以这里的控制逻辑,相当于设置一个最大时间,限制扫描不得超出这个时间,

                // 但是很可能提前完成扫描(比如scanInterval > 12秒)

                // 设置一段时间后停止扫描(以防系统未正常停止扫描)

                final Handler handler = HandlerThread.newHandler(new Handler.Callback() {

                    @Override

                    public boolean handleMessage(Message msg) {

                        Log.d(TAG, "Cancel bluetooth scan");

                        // 若已经停止扫描(系统扫描结束/通过cancelDiscovery取消扫描),则再次调用该方法不会触发ACTION_DISCOVERY_FINISHED

                        bluetoothAdapter.cancelDiscovery();

                        return false;

                    }

                });

                handler.sendEmptyMessageDelayed(0, scanInterval * 1000);

                // 准备开始扫描

                final ArrayList<HashMap<String, Object>> scanResult = new ArrayList<>();

                btScanReceiver = new BroadcastReceiver() {

                    public void onReceive(Context context, Intent intent) {

                        String action = intent.getAction();

                        if (action.equals(BluetoothDevice.ACTION_FOUND)) { //found device

                            BluetoothDevice device = intent

                                    .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

                            HashMap<String, Object> map = parseBtDevice2Map(device);

                            // 该extra取值与BluetoothDevice对象中getName()取值一致,因此不需要通过它获取name

//                          String name = intent.getStringExtra(BluetoothDevice.EXTRA_NAME);

                            short defaultValue = 0;

                            short rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, defaultValue);

                            map.put("rssi", rssi);

                            scanResult.add(map);

                            Log.d(TAG, "onScanResult: " + device.getAddress() + ", " + device.getName());

                        } else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_STARTED)) {

                            Log.d(TAG, "正在扫描");

                        } else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {

                            Log.d(TAG, "扫描完成");

                            mScanning = false;

                            btScanCallback.onScan(scanResult);

                            // 若系统先扫描完,不需要再通过代码主动停止扫描

                            handler.removeMessages(0);

                            // 注销接收器

                            unRegisterBtScanReceiver();

                        }

                    }

                };

                IntentFilter filter = new IntentFilter();

                // 用BroadcastReceiver来取得搜索结果

                filter.addAction(BluetoothDevice.ACTION_FOUND);

                filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);

                // 两种情况会触发ACTION_DISCOVERY_FINISHED:1.系统结束扫描(约12秒);2.调用cancelDiscovery()方法主动结束扫描

                filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);

                context.registerReceiver(btScanReceiver, filter);

                // 开始扫描

                mScanning = true;

                bluetoothAdapter.startDiscovery();

            } else {

                // 缺少权限,直接返回

                btScanCallback.onScan(new ArrayList<HashMap<String, Object>>());

            }

        } catch (Throwable t) {

            t.printStackTrace();

            btScanCallback.onScan(new ArrayList<HashMap<String, Object>>());

        }

    }

    public static void unRegisterBtScanReceiver() {

        if (btScanReceiver != null) {

            context.unregisterReceiver(btScanReceiver);

            btScanReceiver = null;

        }

    }

     

    public interface BtScanCallback {

        void onScan(ArrayList<HashMap<String, Object>> result);

    }



BLE API实现扫描的核心代码
 

[Asm] 纯文本查看 复制代码

?

001

002

003

004

005

006

007

008

009

010

011

012

013

014

015

016

017

018

019

020

021

022

023

024

025

026

027

028

029

030

031

032

033

034

035

036

037

038

039

040

041

042

043

044

045

046

047

048

049

050

051

052

053

054

055

056

057

058

059

060

061

062

063

064

065

066

067

068

069

070

071

072

073

074

075

076

077

078

079

080

081

082

083

084

085

086

087

088

089

090

091

092

093

094

095

096

097

098

099

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

    /**

     * 查找低功耗蓝牙,该方法在4.3(API 18)以上,无法查找“传统蓝牙”

     *

     * @param scanInterval 扫描时长,单位:秒

     * @param bluetoothAdapter

     * @param btScanCallback 扫描结果回调

     */

    public static void findBluetoothLE(int scanInterval, final BluetoothAdapter bluetoothAdapter, final BtScanCallback btScanCallback) {

        try {

            if (DeviceUtils.getInstance(context).checkPermission("android.permission.BLUETOOTH")

                    && DeviceUtils.getInstance(context).checkPermission("android.permission.BLUETOOTH_ADMIN")) {

                if (!bluetoothAdapter.isEnabled()) {

                    // 若蓝牙未打开,直接返回

                    btScanCallback.onScan(new ArrayList<HashMap<String, Object>>());

                    return;

                }

                if (mScanning) {

                    // 正在扫描中,直接返回

                    btScanCallback.onScan(new ArrayList<HashMap<String, Object>>());

                    return;

                }

                // 默认扫描6秒,若scanInterval不合法,则使用默认值

                final int defaultInterval = 6;

                if (scanInterval <= 0) {

                    scanInterval = defaultInterval;

                }

                // 4.3的低功耗蓝牙API

                if (Build.VERSION.SDK_INT >= 18) {

                    final ArrayList<HashMap<String, Object>> scanResult = new ArrayList<>();

                    // 5.0又引入了新的蓝牙API(4.3版本的API仍然可用)

                    if (Build.VERSION.SDK_INT < 21) {

                        // 定义扫描结果回调

                        final BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() {

                            /**

                             *

                             * @param device 扫描到的设备实例,可从实例中获取到相应的信息。如:名称,mac地址

                             * @param rssi 可理解成设备的信号值。该数值是一个负数,越大则信号越强

                             * @param scanRecord 远程设备提供的广播数据的内容

                             */

                            @Override

                            public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {

                                HashMap<String, Object> map = parseBtDevice2Map(device);

                                map.put("rssi", rssi);

//                      map.put("scanRecord", Data.byteToHex(scanRecord));

                                scanResult.add(map);

                            }

                        };

                        // 开始扫描

                        mScanning = true;

                        bluetoothAdapter.startLeScan(leScanCallback);

                        // 设置一段时间后停止扫描

                        Handler handler = HandlerThread.newHandler(new Handler.Callback() {

                            @Override

                            public boolean handleMessage(Message msg) {

                                mScanning = false;

                                bluetoothAdapter.stopLeScan(leScanCallback);

                                btScanCallback.onScan(scanResult);

                                return false;

                            }

                        });

                        handler.sendEmptyMessageDelayed(0, scanInterval * 1000);

                    } else {

                        // 定义扫描结果回调

                        final ScanCallback mScanCallback = new ScanCallback() {

                            //当一个蓝牙ble广播被发现时回调

                            @Override

                            public void onScanResult(int callbackType, ScanResult result) {

                                Log.d(TAG, "onScanResult: " + result.getDevice().getAddress() + ", " + result.getDevice().getName());

                                super.onScanResult(callbackType, result);

                                //扫描类型有开始扫描时传入的ScanSettings相关

                                //对扫描到的设备进行操作。如:获取设备信息。

                                if (result != null) {

                                    HashMap<String, Object> map = new HashMap<>();

                                    BluetoothDevice device = result.getDevice();

                                    if (device != null) {

                                        map = parseBtDevice2Map(device);

                                    }

                                    map.put("rssi", result.getRssi());

                                    ScanRecord scanRecord = result.getScanRecord();

                                    scanResult.add(map);

                                }

                            }

                            // 批量返回扫描结果。一般蓝牙设备对象都是通过onScanResult(int,ScanResult)返回,

                            // 而不会在onBatchScanResults(List)方法中返回,除非手机支持批量扫描模式并且开启了批量扫描模式。

                            // 批处理的开启请查看ScanSettings。

                            //@param results 以前扫描到的扫描结果列表。

                            @Override

                            public void onBatchScanResults(List<ScanResult> results) {

                                super.onBatchScanResults(results);

                                Log.d(TAG, "onBatchScanResults");

                            }

                            //当扫描不能开启时回调

                            @Override

                            public void onScanFailed(int errorCode) {

                                super.onScanFailed(errorCode);

                                //扫描太频繁会返回ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED,表示app无法注册,无法开始扫描。

                                Log.d(TAG, "onScanFailed. errorCode: " + errorCode);

                            }

                        };

                        //开始扫描

                        final BluetoothLeScanner mBLEScanner = bluetoothAdapter.getBluetoothLeScanner();

                        mScanning = true;

/** 也可指定过滤条件和扫描配置

                         //创建ScanSettings的build对象用于设置参数

                         ScanSettings.Builder builder = new ScanSettings.Builder()

                         //设置高功耗模式

                         .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY);

                         //android 6.0添加设置回调类型、匹配模式等

                         if(android.os.Build.VERSION.SDK_INT >= 23) {

                         //定义回调类型

                         builder.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES);

                         //设置蓝牙LE扫描滤波器硬件匹配的匹配模式

                         builder.setMatchMode(ScanSettings.MATCH_MODE_STICKY);

                         }

                         // 若设备支持批处理扫描,可以选择使用批处理,但此时扫描结果仅触发onBatchScanResults()

                         //             if (bluetoothAdapter.isOffloadedScanBatchingSupported()) {

                         //                 //设置蓝牙LE扫描的报告延迟的时间(以毫秒为单位)

                         //                 //设置为0以立即通知结果

                         //                 builder.setReportDelay(0L);

                         //             }

                         ScanSettings scanSettings = builder.build();

                         //可设置过滤条件,在第一个参数传入,但一般不设置过滤。

                         mBLEScanner.startScan(null, scanSettings, mScanCallback);

 */

                        mBLEScanner.startScan(mScanCallback);

                        // 设置一段时间后停止扫描

                        Handler handler = HandlerThread.newHandler(new Handler.Callback() {

                            @Override

                            public boolean handleMessage(Message msg) {

                                mScanning = false;

                                mBLEScanner.stopScan((mScanCallback));

                                btScanCallback.onScan(scanResult);

                                return false;

                            }

                        });

                        handler.sendEmptyMessageDelayed(0, scanInterval * 1000);

                    }

                } else {

                    findBluetoothLEAndClassic(scanInterval, bluetoothAdapter, btScanCallback);

                }

            } else {

                // 缺少权限,直接返回

                btScanCallback.onScan(new ArrayList<HashMap<String, Object>>());

            }

        } catch (Throwable t) {

            t.printStackTrace();

            btScanCallback.onScan(new ArrayList<HashMap<String, Object>>());

        }

    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值