zoukankan      html  css  js  c++  java
  • android蓝牙4.0(BLE)开发之ibeacon初步

    一个april beacon里携带的信息如下

    1
    <code class=" hljs ">0201061AFF4C0002159069BDB88C11416BAC3F33468C2788A3044B0378C60C09417072696C426561636F6E051250002003020A0000000000000000000000</code>

    具体是什么意思呢

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    <code class=" hljs vhdl">02  Number of bytes that follow in first AD structure
    01  Flags AD type
    06
        Flags value 0x1A = 000011010
           bit 0 (OFF) LE Limited Discoverable Mode
           bit 1 (ON) LE General Discoverable Mode
           bit 2 (OFF) BR/EDR Not Supported
           bit 3 (ON) Simultaneous LE and BR/EDR to Same Device Capable (controller)
           bit 4 (ON) Simultaneous LE and BR/EDR to Same Device Capable (Host)
    1a Number of bytes that follow in second (and last) AD structure
    前面是常规智能硬件广播包部分
     
    ff (FF代表后面是Manufacture Data)
     
     
    4c 00   (组织标识,0x4c00苹果公司标识,https://www.bluetooth.org/en-us/specification/assigned-numbers/company-identifiers)
    02 0x02 ibeacon标识位)
    15 0x15,22个字节标识长度,uuid,major,minor总和的长度)
    90 69 bd b8-8c 11-41 6b-ac 3f-33 46 8c 27 88 a3 (Proximity UUID)
    04 4b(1099,major)
    03 78(888,minor)
    c6  (切记这里是补码,转化为原码就是-58,iBeacon的信号发出强度值,用来作为和RSSI一起测距的基准 ,txPower)
            计算
                C6
                1100 0110 补码
                1100 0101 反码
                1011 1010 原码
                -(32+16+8+2
                -58
    0c09    (未知)
    417072696c426561636f6e(AprilBeacon字符串对应的十六进制)
    051250002003020a0000000000000000000000(未知)
    </code>

    Proximity UUID :这是将你所有的beacon与其他人的beacon设备区别开的id!例如,目前在商店里某个区域分布着多个beacon形成一条“链带”,用于为顾客提供特定的服务,那么归属于同一条“链带”的beacon将分配到相同的proximity UUID。为这条“链带”设计的专用应用程序将会在后台使用这个UUID扫描到这条“链带”中的beacon设备。

    major 编号:用于将相关的beacon标识为一组。例如,一个商店中的所有beacon将会分配到相同的major编号。通过这种方式,应用程序就能够知道顾客位于哪一家商店。

    minor 标号:用于标识特定的beacon设备。例如一个商店中的每一个beacon设备都拥有唯一的minor编号,这样你才能够知道顾客位于商店中的哪个位置。

    Measuring distance(测量距离) 
    最后一个值, TX power ,用于确定你和beacon之间距离有多近。根据这个值不但可以获得粗略的信息(比如靠近/远离/不在范围内等),也可以获取精确到米的距离(当然你也可以转换为以步为单位的距离)。那么如何实现?

    TX power (上面例子中为0xC6=198,根据2的补码测得256-198=-58dBm)是距离设备1米测得的信号强度值(RSSI- Received Signal Strength Indication,接收到的信号强弱指标)。假如接收到的信号强度减弱了,那么我们可能在远离。只要知道1米距离的RSSI,以及当前的RSSI(我们可以从接收到的信号中一块获取到这些信息),那么计算出当前的距离是可能的。IOS已经实现了个这个功能,对于其它平台需要自己手动编码计算 。

    一个简单的测距函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <code class="language-java hljs ">protected static double calculateAccuracy(int txPower, double rssi) {
            if (rssi == 0) {
                return -1.0; // if we cannot determine accuracy, return -1.
            }
     
            double ratio = rssi * 1.0 / txPower;
            if (ratio < 1.0) {
                return Math.pow(ratio, 10);
            } else {
                double accuracy = (0.89976) * Math.pow(ratio, 7.7095) + 0.111;
                return accuracy;
            }
        }</code>

    在使用蓝牙时需要加权限

    1
    2
    3
    4
    <code class="language-xml hljs "> <uses-permission android:name="android.permission.BLUETOOTH">
        <uses-permission android:name="android.permission.BLUETOOTH_ADMIN">
        <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED">
    </uses-permission></uses-permission></uses-permission></code>

    关键代码如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    <code class="language-java hljs ">package cn.edu.zafu.ble;
     
    import android.app.Activity;
    import android.bluetooth.BluetoothAdapter;
    import android.bluetooth.BluetoothDevice;
    import android.bluetooth.BluetoothManager;
    import android.content.Context;
    import android.content.Intent;
    import android.os.Bundle;
    import android.util.Log;
     
    public class MainActivity extends Activity {
        private BluetoothAdapter mBluetoothAdapter;
     
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
     
            BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
            mBluetoothAdapter = bluetoothManager.getAdapter();
            if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
                Intent enableBluetooth = new Intent(
                        BluetoothAdapter.ACTION_REQUEST_ENABLE);
                startActivityForResult(enableBluetooth, 1);
            }
            mBluetoothAdapter.startLeScan(mLeScanCallback);
     
        }
     
        private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
            @Override
            public void onLeScan(final BluetoothDevice device, final int rssi,
                    final byte[] scanRecord) {
                int startByte = 2;
                boolean patternFound = false;
                // 寻找ibeacon
                while (startByte <= 5) {
                    if (((int) scanRecord[startByte + 2] & 0xff) == 0x02 && // Identifies
                                                                            // an
                                                                            // iBeacon
                            ((int) scanRecord[startByte + 3] & 0xff) == 0x15) { // Identifies
                                                                                // correct
                                                                                // data
                                                                                // length
                        patternFound = true;
                        break;
                    }
                    startByte++;
                }
                // 如果找到了的话
                if (patternFound) {
                    // 转换为16进制
                    byte[] uuidBytes = new byte[16];
                    System.arraycopy(scanRecord, startByte + 4, uuidBytes, 0, 16);
                    String hexString = bytesToHex(uuidBytes);
     
                    // ibeacon的UUID值
                    String uuid = hexString.substring(0, 8) + "-"
                            + hexString.substring(8, 12) + "-"
                            + hexString.substring(12, 16) + "-"
                            + hexString.substring(16, 20) + "-"
                            + hexString.substring(20, 32);
     
                    // ibeacon的Major值
                    int major = (scanRecord[startByte + 20] & 0xff) * 0x100
                            + (scanRecord[startByte + 21] & 0xff);
     
                    // ibeacon的Minor值
                    int minor = (scanRecord[startByte + 22] & 0xff) * 0x100
                            + (scanRecord[startByte + 23] & 0xff);
     
                    String ibeaconName = device.getName();
                    String mac = device.getAddress();
                    int txPower = (scanRecord[startByte + 24]);
                    Log.d("BLE",bytesToHex(scanRecord));
                    Log.d("BLE", "Name:" + ibeaconName + " Mac:" + mac
                            + " UUID:" + uuid + " Major:" + major + " Minor:"
                            + minor + " TxPower:" + txPower + " rssi:" + rssi);
     
                    Log.d("BLE","distance:"+calculateAccuracy(txPower,rssi));
                }
            }
        };
        static final char[] hexArray = "0123456789ABCDEF".toCharArray();
     
        private static String bytesToHex(byte[] bytes) {
            char[] hexChars = new char[bytes.length * 2];
            for (int j = 0; j < bytes.length; j++) {
                int v = bytes[j] & 0xFF;
                hexChars[j * 2] = hexArray[v >>> 4];
                hexChars[j * 2 + 1] = hexArray[v & 0x0F];
            }
            return new String(hexChars);
        }
     
        protected static double calculateAccuracy(int txPower, double rssi) {
            if (rssi == 0) {
                return -1.0; // if we cannot determine accuracy, return -1.
            }
     
            double ratio = rssi * 1.0 / txPower;
            if (ratio < 1.0) {
                return Math.pow(ratio, 10);
            } else {
                double accuracy = (0.89976) * Math.pow(ratio, 7.7095) + 0.111;
                return accuracy;
            }
        }
    }
    </code>

    至此,本文也就结束,所谓初步,就是获取ibeacon模块的基本信息。

    源码下载 
    http://download.csdn.net/detail/sbsujjbcy/8503507

  • 相关阅读:
    Putty远程登录VMware虚拟机Linux(Ubuntu12.04)
    boost库在工作(39)网络UDP异步服务端之九
    UVA 1401 Remember the Word
    Windbg调试命令详解(1)
    数学之路(3)-机器学习(3)-机器学习算法-余弦相似度(1)
    2012-2013年度总结
    重建二叉树---根据前序和中序遍历结果重建二叉树
    Windbg调试命令详解(2)
    时间操作(JavaScript版)—最简单比較两个时间格式数据的大小
    WO+开放平台:API调用开发手记(话费计费接口2.0)
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/5560433.html
Copyright © 2011-2022 走看看