2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.bluetooth.bluegiga.internal.eir;
15 import java.util.ArrayList;
16 import java.util.Arrays;
17 import java.util.Collections;
18 import java.util.List;
20 import java.util.UUID;
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.eclipse.jdt.annotation.Nullable;
26 * Defines an EIR record used in the BLE advertisement packets.
28 * @author Chris Jackson - Initial contribution
32 public class EirRecord {
33 private EirDataType type = EirDataType.UNKNOWN;
34 private Object record = new Object();
36 EirRecord(int @Nullable [] data) {
37 if (data == null || data.length == 0) {
41 type = EirDataType.getEirPacketType(data[0]);
44 record = processFlags(data);
46 case EIR_MANUFACTURER_SPECIFIC:
47 record = processManufacturer(data);
49 case EIR_SVC_UUID16_COMPLETE:
50 case EIR_SVC_UUID16_INCOMPLETE:
51 record = processUuid16(data);
53 case EIR_SVC_UUID32_COMPLETE:
54 case EIR_SVC_UUID32_INCOMPLETE:
55 record = processUuid32(data);
57 case EIR_SVC_UUID128_COMPLETE:
58 case EIR_SVC_UUID128_INCOMPLETE:
59 record = processUuid128(data);
63 record = processString(data);
66 record = processUInt8(data);
68 case EIR_SLAVEINTERVALRANGE:
69 record = processUInt16List(data);
71 case EIR_DEVICE_CLASS:
72 record = processUInt8(data);
74 case EIR_SVC_DATA_UUID16:
75 record = processUUID16ServiceData(data);
77 case EIR_SVC_DATA_UUID32:
78 record = processUUID32ServiceData(data);
80 case EIR_SVC_DATA_UUID128:
81 record = processUUID128ServiceData(data);
84 record = processUnknown(data);
89 private Map<Short, int[]> processManufacturer(int[] data) {
90 short manufacturer = (short) (((data[2] & 0xFFFF) << 8) | (data[1] & 0xFFFF));
91 return Collections.singletonMap(manufacturer, Arrays.copyOfRange(data, 3, data.length));
94 private Map<UUID, int[]> processUUID16ServiceData(int[] data) {
95 return Collections.singletonMap(process16BitUUID(data, 1), Arrays.copyOfRange(data, 3, data.length));
98 private Map<UUID, int[]> processUUID32ServiceData(int[] data) {
99 return Collections.singletonMap(process32BitUUID(data, 1), Arrays.copyOfRange(data, 5, data.length));
102 private Map<UUID, int[]> processUUID128ServiceData(int[] data) {
103 return Collections.singletonMap(process128BitUUID(data, 1), Arrays.copyOfRange(data, 17, data.length));
106 private List<UUID> processUuid16(int[] data) {
107 List<UUID> uuidList = new ArrayList<>();
109 for (int cnt = 1; cnt < data.length - 1; cnt += 2) {
110 uuidList.add(process16BitUUID(data, cnt));
116 private List<UUID> processUuid32(int[] data) {
117 List<UUID> uuidList = new ArrayList<>();
119 for (int cnt = 1; cnt < data.length - 1; cnt += 4) {
120 uuidList.add(process32BitUUID(data, cnt));
126 private List<UUID> processUuid128(int[] data) {
127 List<UUID> uuidList = new ArrayList<>();
129 for (int cnt = 1; cnt < data.length - 1; cnt += 16) {
130 uuidList.add(process128BitUUID(data, cnt));
136 private UUID process16BitUUID(int[] data, int index) {
137 // 0000xxxx-0000-1000-8000-00805F9B34FB
138 long high = ((long) data[index] << 32) + ((long) data[index + 1] << 40) + 0x00001000L;
139 return new UUID(high, 0x800000805f9b34fbL);
142 private UUID process32BitUUID(int[] data, int index) {
143 // xxxxxxxx-0000-1000-8000-00805F9B34FB
144 long high = ((long) data[index] << 32) + ((long) data[index + 1] << 40) + ((long) data[index + 2] << 48)
145 + ((long) data[index + 3] << 56) + 0x00001000L;
146 return new UUID(high, 0x800000805f9b34fbL);
149 private UUID process128BitUUID(int[] data, int index) {
150 long low = (data[index]) + ((long) data[index + 1] << 8) + ((long) data[index + 2] << 16)
151 + ((long) data[index + 3] << 24) + ((long) data[index + 4] << 32) + ((long) data[index + 5] << 40)
152 + ((long) data[index + 6] << 48) + ((long) data[index + 7] << 56);
153 long high = (data[index + 8]) + ((long) data[index + 9] << 8) + ((long) data[index + 10] << 16)
154 + ((long) data[index + 11] << 24) + ((long) data[index + 12] << 32) + ((long) data[index + 13] << 40)
155 + ((long) data[index + 14] << 48) + ((long) data[index + 15] << 56);
156 return new UUID(high, low);
159 private List<Integer> processUInt16List(int[] data) {
160 List<Integer> intList = new ArrayList<>();
162 for (int cnt = 1; cnt < data.length - 1; cnt += 2) {
163 intList.add(Integer.valueOf(data[cnt] + (data[cnt + 1] << 8)));
169 private List<EirFlags> processFlags(int[] data) {
170 List<EirFlags> flags = new ArrayList<>();
172 for (int cnt = 1; cnt < data.length; cnt++) {
173 for (int bitcnt = 0; bitcnt < 8; bitcnt++) {
174 if ((data[cnt] & (1 << bitcnt)) != 0) {
175 flags.add(EirFlags.getEirFlag(flagBit));
184 private String processString(int[] data) {
185 StringBuilder builder = new StringBuilder();
186 for (int cnt = 1; cnt < data.length; cnt++) {
187 builder.append((char) data[cnt]);
189 return builder.toString();
192 private int processUInt8(int[] data) {
194 return data[1] - 256;
200 private String processUnknown(int[] data) {
201 StringBuilder builder = new StringBuilder();
202 for (int cnt = 0; cnt < data.length; cnt++) {
203 builder.append(String.format("%02X", data[cnt]));
205 return builder.toString();
208 public EirDataType getType() {
212 public Object getRecord() {
217 public String toString() {
218 final StringBuilder builder = new StringBuilder();
219 builder.append("EirRecord [type=");
220 builder.append(type);
221 builder.append(", record=");
222 builder.append(record);
224 return builder.toString();