此文使用的ibeacon模块是april beacon,至于什么是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 +
"\nMac:"
+ mac
+
" \nUUID:"
+ uuid +
"\nMajor:"
+ major +
"\nMinor:"
+ minor +
"\nTxPower:"
+ txPower +
"\nrssi:"
+ 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