1 /*
2 * Copyright (C) 2018 Alberto Irurueta Carro (alberto@irurueta.com)
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package com.irurueta.navigation.indoor;
17
18 import java.io.Serializable;
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.List;
22
23 /**
24 * The <code>Beacon</code> class represents a single hardware Beacon detected by
25 * an Android device.
26 *
27 * <pre>A Beacon is identified by a unique multi-part identifier, with the first of the ordered
28 * identifiers being more significant for the purposes of grouping beacons.
29 *
30 * A Beacon sends a Bluetooth Low Energy (BLE) advertisement that contains these
31 * three identifiers, along with the calibrated tx power (in RSSI) of the Beacon's
32 * Bluetooth transmitter.
33 * </pre>
34 * <p>
35 * Based on:
36 * <a href="https://github.com/AltBeacon/android-beacon-library/blob/master/src/main/java/org/altbeacon/beacon/Beacon.java">
37 * https://github.com/AltBeacon/android-beacon-library/blob/master/src/main/java/org/altbeacon/beacon/Beacon.java
38 * </a>
39 */
40 public class Beacon implements Serializable, RadioSource {
41
42 /**
43 * Default frequency used by a Beacon when none is specified (expressed in Hz).
44 */
45 public static final double DEFAULT_FREQUENCY = 2.4e9;
46
47 /**
48 * The list of the multipart identifiers of the beacon. Together, these identifiers signify
49 * a unique beacon. The identifiers are ordered by significance for the purpose of grouping
50 * beacons.
51 */
52 private ArrayList<BeaconIdentifier> identifiers;
53
54 /**
55 * The calibrated measured Tx power of the Beacon in RSSI (expressed in dBm's).
56 * This value is baked into a Beacon when it is manufactured, and it is
57 * transmitted with each packet to aid in the distance estimate.
58 */
59 private double transmittedPower;
60
61 /**
62 * The Bluetooth mac address.
63 */
64 private String bluetoothAddress;
65
66 /**
67 * The two byte value indicating the type of beacon that this is, which is used for figuring
68 * out the byte layout of the beacon advertisement.
69 */
70 private int beaconTypeCode;
71
72 /**
73 * A two byte code indicating the beacon manufacturer. A list of registered manufacturer codes
74 * may be found here:
75 * <a href="https://www.bluetooth.org/en-us/specification/assigned-numbers/company-identifiers">
76 * https://www.bluetooth.org/en-us/specification/assigned-numbers/company-identifiers
77 * </a>
78 * <p>
79 * If the beacon is a GATT-based beacon, this field will be set to -1.
80 */
81 private int manufacturer;
82
83 /**
84 * A 32 bit service uuid for the beacon.
85 * This is valid only for GATT-based beacons. If the beacon is a manufacturer data-based
86 * beacon, this field will be -1
87 */
88 private int serviceUuid = -1;
89
90 /**
91 * The Bluetooth device name. This is a field transmitted by the remote beacon device separate
92 * from the advertisement data
93 */
94 private String bluetoothName;
95
96 /**
97 * Frequency used by this Beacon(expressed in Hz).
98 */
99 private double frequency = DEFAULT_FREQUENCY;
100
101 /**
102 * Constructor.
103 *
104 * @param identifiers list of the multipart identifiers of the beacon.
105 * @param transmittedPower calibrated measured Tx power of the Beacon in RSSI (expressed in dBm's).
106 * @throws IllegalArgumentException if identifiers is null.
107 */
108 public Beacon(final List<BeaconIdentifier> identifiers, final double transmittedPower) {
109 if (identifiers == null) {
110 throw new IllegalArgumentException();
111 }
112
113 this.identifiers = new ArrayList<>(identifiers);
114 this.transmittedPower = transmittedPower;
115 }
116
117 /**
118 * Constructor.
119 *
120 * @param identifiers list of the multipart identifiers of the beacon.
121 * @param transmittedPower calibrated measured Tx power of the Beacon in RSSI (expressed in dBm's).
122 * @param bluetoothAddress the bluetooth mac address.
123 * @param beaconTypeCode the two byte value indicating the type of beacon.
124 * @param manufacturer a two byte code indicating the beacon manufacturer.
125 * @param serviceUuid a 32 bit service uuid for the beacon.
126 * @param bluetoothName the bluetooth device name.
127 * @throws IllegalArgumentException if identifiers is null.
128 */
129 public Beacon(final List<BeaconIdentifier> identifiers, final double transmittedPower,
130 final String bluetoothAddress, final int beaconTypeCode, final int manufacturer,
131 final int serviceUuid, final String bluetoothName) {
132 this(identifiers, transmittedPower);
133
134 this.bluetoothAddress = bluetoothAddress;
135 this.beaconTypeCode = beaconTypeCode;
136 this.manufacturer = manufacturer;
137 this.serviceUuid = serviceUuid;
138 this.bluetoothName = bluetoothName;
139 }
140
141 /**
142 * Constructor.
143 *
144 * @param identifiers list of the multipart identifiers of the beacon.
145 * @param transmittedPower calibrated measured Tx power of the Beacon in RSSI (expressed in dBm's).
146 * @param frequency frequency used by this Beacon.
147 * @throws IllegalArgumentException if identifiers is null or frequency is negative.
148 */
149 public Beacon(final List<BeaconIdentifier> identifiers, final double transmittedPower, final double frequency) {
150 this(identifiers, transmittedPower);
151
152 if (frequency < 0.0) {
153 throw new IllegalArgumentException();
154 }
155
156 this.frequency = frequency;
157 }
158
159 /**
160 * Constructor.
161 *
162 * @param identifiers list of the multipart identifiers of the beacon.
163 * @param transmittedPower calibrated measured Tx power of the Beacon in RSSI (expressed in dBm's).
164 * @param frequency frequency used by this Beacon.
165 * @param bluetoothAddress the bluetooth mac address.
166 * @param beaconTypeCode the two byte value indicating the type of beacon.
167 * @param manufacturer a two byte code indicating the beacon manufacturer.
168 * @param serviceUuid a 32 bit service uuid for the beacon.
169 * @param bluetoothName the bluetooth device name.
170 * @throws IllegalArgumentException if identifiers is null.
171 */
172 public Beacon(final List<BeaconIdentifier> identifiers, final double transmittedPower, final double frequency,
173 final String bluetoothAddress, final int beaconTypeCode, final int manufacturer,
174 final int serviceUuid, final String bluetoothName) {
175 this(identifiers, transmittedPower, bluetoothAddress, beaconTypeCode, manufacturer, serviceUuid, bluetoothName);
176
177 if (frequency < 0.0) {
178 throw new IllegalArgumentException();
179 }
180
181 this.frequency = frequency;
182 }
183
184 /**
185 * Empty constructor.
186 */
187 protected Beacon() {
188 }
189
190 /**
191 * Returns the specified identifier - 0 indexed.
192 * Note: to read id1, call getIdentifier(0);
193 *
194 * @param i index identifier.
195 * @return identifier or null if not available.
196 */
197 public BeaconIdentifier getIdentifier(final int i) {
198 if (i < 0 || identifiers == null || identifiers.size() <= i) {
199 return null;
200 }
201 return identifiers.get(i);
202 }
203
204 /**
205 * Convenience method to get the first identifier.
206 *
207 * @return first identifier or null if not available.
208 */
209 public BeaconIdentifier getId1() {
210 if (identifiers == null || identifiers.isEmpty()) {
211 return null;
212 }
213 return identifiers.get(0);
214 }
215
216 /**
217 * Convenience method to get the second identifier.
218 *
219 * @return second identifier or null if not available.
220 */
221 public BeaconIdentifier getId2() {
222 if (identifiers == null || identifiers.size() < 2) {
223 return null;
224 }
225 return identifiers.get(1);
226 }
227
228 /**
229 * Convenience method to get the third identifier.
230 *
231 * @return third identifier or null if not available.
232 */
233 public BeaconIdentifier getId3() {
234 if (identifiers == null || identifiers.size() < 3) {
235 return null;
236 }
237 return identifiers.get(2);
238 }
239
240 /**
241 * Gets the list of the multipart identifiers of the beacon. Together, these identifiers signify
242 * a unique beacon. The identifiers are ordered by significance for the purpose of grouping
243 * beacons.
244 *
245 * @return list of identifiers of the beacon or null if not available.
246 */
247 public List<BeaconIdentifier> getIdentifiers() {
248 return identifiers != null ? Collections.unmodifiableList(identifiers) : null;
249 }
250
251 /**
252 * Returns the calibrated measured Tx power of the Beacon in RSSI (expressed in dBm's).
253 * This value is baked into a Beacon when it is manufactured, and it is
254 * transmitted with each packet to aid in the distance estimate.
255 *
256 * @return the calibrated measured Tx power.
257 */
258 public double getTransmittedPower() {
259 return transmittedPower;
260 }
261
262 /**
263 * Gets the bluetooth mac address.
264 *
265 * @return bluetooth mac address.
266 */
267 public String getBluetoothAddress() {
268 return bluetoothAddress;
269 }
270
271 /**
272 * Gets the two byte value indicating the type of beacon that this is, which is used for figuring
273 * out the byte layout of the beacon advertisement.
274 *
275 * @return two byte value indicating the type of beacon.
276 */
277 public int getBeaconTypeCode() {
278 return beaconTypeCode;
279 }
280
281
282 /**
283 * Gets the Bluetooth device name. This is a field transmitted by the remote beacon device separate
284 * from the advertisement data.
285 *
286 * @return bluetooth device name.
287 */
288 public String getBluetoothName() {
289 return bluetoothName;
290 }
291
292 /**
293 * Gets a two byte code indicating the beacon manufacturer. A list of registered manufacturer codes
294 * may be found here:
295 * <a href="https://www.bluetooth.org/en-us/specification/assigned-numbers/company-identifiers">
296 * https://www.bluetooth.org/en-us/specification/assigned-numbers/company-identifiers
297 * </a>
298 * <p>
299 * If the beacon is a GATT-based beacon, this field will be set to -1.
300 *
301 * @return a two byte code indicating the beacon manufacturer.
302 */
303 public int getManufacturer() {
304 return manufacturer;
305 }
306
307 /**
308 * Gets a 32 bit service uuid for the beacon.
309 * This is valid only for GATT-based beacons. If the beacon is a manufacturer data-based
310 * beacon, this field will be -1
311 *
312 * @return service uuid.
313 */
314 public int getServiceUuid() {
315 return serviceUuid;
316 }
317
318 /**
319 * Gets frequency used by this radio source (expressed in Hz).
320 *
321 * @return frequency used by this radio source (expressed in Hz).
322 */
323 @Override
324 public double getFrequency() {
325 return frequency;
326 }
327
328 /**
329 * Checks whether two beacons are considered equal if they share the same identifiers.
330 *
331 * @param that beacon to be compared.
332 * @return true if both beacons are considered equal, false otherwise.
333 */
334 @Override
335 public boolean equals(final Object that) {
336 if (!(that instanceof Beacon thatBeacon)) {
337 return false;
338 }
339
340 return identifiers != null && identifiers.equals(thatBeacon.identifiers);
341 }
342
343 /**
344 * Computes hash code for this instance.
345 *
346 * @return this instance hash code.
347 */
348 @Override
349 public int hashCode() {
350 return identifiers.hashCode();
351 }
352
353 /**
354 * Gets radio source type, which can be either a Wi-Fi Access point or a bluetooth Beacon.
355 *
356 * @return radio source type.
357 */
358 @Override
359 public RadioSourceType getType() {
360 return RadioSourceType.BEACON;
361 }
362 }