Beacon一開始制定的封包格式如下圖:

「beacon packet format」的圖片搜尋結果

在接收到藍芽封包後可以根據以上格是進行解析,最終得到個欄位的資料。

 

以下使用Java實作封包解析並將其封裝成物件,程式碼中的 package_parser 為專門解析 beacon 封包之函數。

  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
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
public class Beacon {
    private String prefix;
    private String uuid;
    private int major;
    private int minor;
    private int tx_power;
    private String macAddress;
    private int rssi;

    static {
        hexArray = "0123456789ABCDEF".toCharArray();
    }

    public Beacon(String uuid,int major,int minor,int txPower,int rssi){
        this.uuid = uuid;
        this.major = major;
        this.minor = minor;
        this.tx_power = txPower;
        this.rssi = rssi;
    }
    public Beacon(String uuid,int major,int minor,int txPower,int rssi,String mac){
        this.uuid = uuid;
        this.major = major;
        this.minor = minor;
        this.tx_power = txPower;
        this.rssi = rssi;
        this.macAddress = mac;
    }

    public Beacon(byte[] package_raw, BluetoothDevice device,int rssi) throws BeaconFormateNotFoundException {
        this.rssi = rssi;
        this.macAddress = device.getAddress();
        package_parser(package_raw);
    }

    private void package_parser(byte[] package_raw) throws BeaconFormateNotFoundException {
        int startByte = 2;
        boolean patternFound = false;
        // 尋找ibeacon
        // 先依序尋找第2到第8陣列的元素
        while (startByte <= 5) {
            // Identifies an iBeacon
            if (((int) package_raw[startByte + 2] & 0xff) == 0x02 &&
                    // Identifies correct data length
                    ((int) package_raw[startByte + 3] & 0xff) == 0x15) {

                patternFound = true;
                break;
            }
            startByte++;
        }

        if (patternFound) {
            byte[] uuidBytes = new byte[16];
            // 來源、起始位置
            System.arraycopy(package_raw, startByte + 4, uuidBytes, 0, 16);
            String hexString = Beacon.bytesToHex(uuidBytes);

            // UUID
            this.uuid = hexString.substring(0, 8) + "-"
                    + hexString.substring(8, 12) + "-"
                    + hexString.substring(12, 16) + "-"
                    + hexString.substring(16, 20) + "-"
                    + hexString.substring(20, 32);

            // Major
            this.major = (package_raw[startByte + 20] & 0xff) * 0x100
                    + (package_raw[startByte + 21] & 0xff);

            // Minor
            this.minor = (package_raw[startByte + 22] & 0xff) * 0x100
                    + (package_raw[startByte + 23] & 0xff);

            // txPower
            this.tx_power = (package_raw[startByte + 24]);
        }else {
            throw new BeaconFormateNotFoundException("patternFound");
        }
    }

    private final static char[] hexArray;

    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);
    }

    private static double calculateAccuracy(int txPower, double rssi) {
        if (rssi == 0)
            return -1.0;

        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;
        }
    }

    public double distance(){
        return calculateAccuracy(this.tx_power,this.rssi);
    }

    public String getUuid() {
        return uuid;
    }

    public int getMajor() {
        return major;
    }

    public int getMinor() {
        return minor;
    }

    public String getMacAddress() {
        return macAddress;
    }
    public int getRssi(){
        return rssi;
    }

    public int getTxPower(){
        return tx_power;
    }

    public int getX() {
        return this.major;
    }

    public int getY() {
        return this.minor;
    }

    public static List<Beacon> getSamples(){
        List<Beacon> list = new ArrayList<>();
        Beacon b1 = new Beacon("00910-412f-4124-1245",5,2,-35,12);
        list.add(b1);
        Beacon b2 = new Beacon("00910-412f-4124-1245",1,5,-45,12);
        list.add(b2);
        Beacon b3 = new Beacon("00910-412f-4124-1245",8,6,-25,12);
        list.add(b3);
        return list;
    }

}

 

關於如何使用,可以參考 Android Ble - 掃描beacon裝置 該文章有接收藍芽封包並進行解析完整說明,而範例專案則可點此 連結 參考

 

​​​​

arrow
arrow
    文章標籤
    beacon
    全站熱搜
    創作者介紹
    創作者 Lung-Yu,Tsai 的頭像
    Lung-Yu,Tsai

    Lung-Yu,Tsai 的部落格

    Lung-Yu,Tsai 發表在 痞客邦 留言(0) 人氣()