herald  2.0.0
ble_device.h
1 // Copyright 2020-2021 Herald Project Contributors
2 // SPDX-License-Identifier: Apache-2.0
3 //
4 
5 #ifndef HERALD_BLE_DEVICE_H
6 #define HERALD_BLE_DEVICE_H
7 
8 #include "ble_tx_power.h"
9 #include "ble_mac_address.h"
10 #include "ble_sensor_configuration.h"
11 
12 #include "../device.h"
13 
14 #include "../datatype/payload_data.h"
15 #include "../datatype/payload_sharing_data.h"
16 #include "../datatype/immediate_send_data.h"
17 #include "../datatype/target_identifier.h"
18 #include "../datatype/time_interval.h"
19 #include "../datatype/date.h"
20 #include "../datatype/uuid.h"
21 #include "filter/ble_advert_parser.h"
22 
23 #include <variant>
24 #include <vector>
25 #include <optional>
26 #include <bitset>
27 
28 namespace herald {
29 namespace ble {
30 
31 using namespace herald::datatype;
32 using namespace herald::ble::filter;
33 
34 class BLEDeviceDelegate; // fwd decl
35 
36 enum class BLEDeviceAttribute : int {
37  peripheral, state, operatingSystem, payloadData, rssi, txPower, immediateSendData
38 };
39 
40 enum class BLEDeviceOperatingSystem : int {
41  android_tbc, android, ios_tbc, ios, ignore, shared, unknown
42 };
43 
45 enum class BLEDeviceState : int {
46  uninitialised, /* Uninitialised state only seen within Herald, not seen by those listing devices in a DB */
47  connecting, connected, disconnected
48 };
49 
51 enum class BLEInternalState : short {
53  discovered,
55  filtered,
57  has_potential,
59  relevant,
61  identified,
63  timed_out
64 };
65 
66 enum class BLELegacyService : short {
67  NotApplicable, // i.e. Herald
68  Unknown, // i.e. other
69  OpenTrace,
70  AustraliaCovidSafe
71  // TODO others later (up to 7 values plus Unknown and NotApplicable)
72 };
73 
74 namespace SignalCharacteristicType {
75  constexpr bool SpecCompliant = true;
76  constexpr bool NotSpecCompliant = false;
77 }
78 
81 public:
83  ~BLEDeviceFlags() = default;
84 
85  void reset();
86 
87  BLEInternalState internalState() const;
88  void internalState(BLEInternalState newInternalState);
89 
90  BLEDeviceState state() const;
91  void state(BLEDeviceState newState);
92 
93  BLEDeviceOperatingSystem operatingSystem() const;
94  void operatingSystem(BLEDeviceOperatingSystem newOS);
95 
96  bool hasHeraldService() const;
97  void hasHeraldService(bool newValue);
98  bool hasLegacyService() const;
99  BLELegacyService legacyService() const;
100  void legacyService(BLELegacyService newValue);
101  bool hasPayloadCharacteristic() const;
102  void hasPayloadCharacteristic(bool newValue);
103  bool signalCharacteristic() const;
104  void signalCharacteristic(bool newValue);
105  bool hasSecureCharacteristic() const;
106  void hasSecureCharacteristic(bool newValue);
107  bool hasEverConnected() const;
108  void hasEverConnected(bool newValue);
109 
110 private:
111  // Note: Bit fields merged into a single class
112  //unsigned short int bitfields; // at least 16 bits (usually always 16 bits)
113  std::bitset<16> bitFields; // will always consume sets of 8 bits, so round up
114  // 0 = BLEInternalState field 1
115  // 1 = BLEInternalState field 2
116  // 2 = BLEInternalState field 3
117  // 3 = BLEDeviceState field 1
118  // 4 = BLEDeviceState field 2
119  // 5 = BLEDeviceOperatingSystem field 1
120  // 6 = BLEDeviceOperatingSystem field 2
121  // 7 = BLEDeviceOperatingSystem field 3
122  // 8 = hasHeraldService
123  // 9 = hasLegacyService field 1
124  // 10 = hasLegacyService field 2
125  // 11 = hasLegacyService field 3
126  // 12 = hasPayloadChar
127  // 13 = hasSignalChar
128  // 14 = hasSecureChar
129  // 15 = hasEverConnected
130 };
131 
133  std::vector<BLEAdvertSegment> segments; // TODO change to fixed size containers
134 };
135 
136 using FilteredState = std::monostate;
137 
138 // struct HasPotentialState {
139 // BLEDeviceState state;
140 // BLEDeviceOperatingSystem os;
141 // BLETxPower txPower;
142 
143 // TimeInterval ignoreForDuration; // QN isn't this used in fetch payload stage?
144 // Date ignoreUntil; // QN isn't this used in fetch payload stage?
145 
146 // std::vector<UUID> services; // TODO can we not just make this ephemeral?
147 // bool hasEverConnected;
148 // int connectRepeatedFailures;
149 // };
150 
152  RelevantState()
153  : txPower(0),
154  ignoreForDuration(0),
155  ignoreUntil(0),
156  pseudoAddress(),
157  connectRepeatedFailures(0),
158  payloadUpdated(0)
159  {}
160 
161  BLETxPower txPower;
162 
163  TimeInterval ignoreForDuration; // Isn't this TIME^connectRepeatedFailures?
164  Date ignoreUntil;
165 
166  BLEMacAddress pseudoAddress; // all zeros if unset (also OS is not Android)
167 
168  unsigned short int connectRepeatedFailures;
169 
170  Date payloadUpdated; // Note only use if state is Identified, not just Relevant
171 };
172 
173 // struct IdentifiedState {
174 // BLETxPower txPower;
175 // BLEMacAddress pseudoAddress; // QN Isn't this available from advert stage?
176 
177 // unsigned short connectRepeatedFailures;
178 // };
179 
180 
181 class BLEDevice : public Device {
182 public:
183  BLEDevice(); // Used for array initialisation, uses dummy static config ONLY
185  BLEDevice(BLESensorConfiguration& config,BLEDeviceDelegate& delegate, const Date& created = Date()); // default (uninitialised state) constructor
186  BLEDevice(BLESensorConfiguration& config,TargetIdentifier identifier, BLEDeviceDelegate& delegate, const Date& created = Date());
187  BLEDevice(const BLEDevice& other); // copy ctor
188  BLEDevice(BLEDevice&& other) = delete; // remove move constructor
189  ~BLEDevice();
190 
192  void reset(const TargetIdentifier& newID, BLEDeviceDelegate& newDelegate);
193 
194  BLEDevice& operator=(const BLEDevice& other); // copy assign
195  BLEDevice operator=(BLEDevice && other) = delete; // remove mode assign
196 
197  bool operator==(const BLEDevice& other) const noexcept;
198  bool operator!=(const BLEDevice& other) const noexcept;
199 
201  const BLESensorConfiguration& configuration() const noexcept;
202 
203  const TargetIdentifier& identifier() const override; // MAC ADDRESS OR PSEUDO DEVICE ADDRESS
204  void identifier(const TargetIdentifier&) override; // MAC ADDRESS OR PSEUDO DEVICE ADDRESS
205  // Date created() const override; // TODO unused, consider removing
206 
207  // basic descriptors
208  std::string description() const;
209  operator std::string() const;
210 
211  // GENERAL BLUETOOTH STATE
212  TimeInterval timeIntervalSinceLastUpdate() const override;
213  // TimeInterval timeIntervalSinceConnected() const; // TODO unused, consider removing
214 
215  // TODO add in generic Advert and GATT handle number information caching here
216 
217  // bool hasAdvertData() const; // TODO unused, consider removing
218  void advertData(std::vector<BLEAdvertSegment> segments); // TODO getter unused, so consider removing
219  // const std::vector<BLEAdvertSegment>& advertData() const; // TODO unused, consider removing
220 
222  // bool hasServicesSet() const; // TODO unused, consider removing
224  void services(std::vector<UUID> services);
226  bool hasService(const UUID& serviceUUID) const;
227 
228  BLEDeviceState state() const;
229  void state(BLEDeviceState newState);
230 
231  // TODO decide if operatingSystem is relevant anymore??? - change it to BluetoothComplianceFlag?
232  BLEDeviceOperatingSystem operatingSystem() const;
233  void operatingSystem(BLEDeviceOperatingSystem newOS);
234 
235  RSSI rssi() const;
236  void rssi(RSSI newRSSI);
237 
238  std::optional<BLETxPower> txPower() const;
239  void txPower(BLETxPower newPower);
240 
241  // NOTE May need a herald specific version of this, as we may wish a herald device to only receive or transmit
242  // bool receiveOnly() const;
243  // void receiveOnly(bool newReceiveOnly);
244 
245 
246 
247 
248  // HERALD PROTOCOL SPECIFIC STATE - TODO HIDE THESE FROM SENSOR/EXTERNAL CALLS
249 
250  // timing related getters
251  TimeInterval timeIntervalSinceLastPayloadDataUpdate() const; // TODO unused, consider removing
252  TimeInterval timeIntervalSinceLastWritePayloadSharing() const; // TODO unused, consider removing
253  TimeInterval timeIntervalSinceLastWritePayload() const; // TODO unused, consider removing
254  TimeInterval timeIntervalSinceLastWriteRssi() const; // TODO unused, consider removing
255  TimeInterval timeIntervalUntilIgnoreExpired() const; // TODO unused, consider removing
256 
257  std::optional<UUID> signalCharacteristic() const;
258  void signalCharacteristic(UUID newChar);
259 
260  std::optional<UUID> payloadCharacteristic() const; // TODO unused, consider removing (Needed for interop?)
261  void payloadCharacteristic(UUID newChar); // TODO unused, consider removing (Needed for interop?)
262 
263  std::optional<BLEMacAddress> pseudoDeviceAddress() const;
264  void pseudoDeviceAddress(BLEMacAddress newAddress);
265 
266  PayloadData payloadData() const;
267  void payloadData(PayloadData newPayloadData);
268 
269  // std::optional<ImmediateSendData> immediateSendData() const;
270  // void immediateSendData(ImmediateSendData toSend);
271  // void clearImmediateSendData();
272 
273  // State engine methods - Herald specific
274  bool ignore() const;
275  void ignore(bool newIgnore);
276  void invalidateCharacteristics();
277  void registerDiscovery(Date at); // ALWAYS externalise time (now())
278  // void registerWritePayload(Date at); // ALWAYS externalise time (now())
279  // void registerWritePayloadSharing(Date at); // ALWAYS externalise time (now())
280  // void registerWriteRssi(Date at); // ALWAYS externalise time (now())
281 
282 private:
283  static BLESensorConfiguration staticConfig; // Used by empty constructor for array construction ONLY
284  BLESensorConfiguration& conf; // allows this class to minimise its memory storage space
285 
286  std::optional<std::reference_wrapper<BLEDeviceDelegate>> delegate; // Optional to avoid catch-22
287  TargetIdentifier id; // Mac address // TODO replace this here with a hash
288 
289  BLEDeviceFlags flags; // merging of several enums and fields to save memory
290  // BLEInternalState internalState; // used for selection of union below
291  // BLEDeviceOperatingSystem os;
292  // BLEDeviceState state;
293 
294  // Data holders
295  // Date mCreated;
296  // std::optional<Date> lastUpdated;
297  Date lastUpdated; // Merges mCreated and lastUpdated
298 
299 
300  // \brief RelevantState is used for hasPotential, relevant and identified
301  std::variant<DiscoveredState, FilteredState, RelevantState> stateData;
302 
303  // std::optional<BLEDeviceState> mState; // hasPotential, relevant, identified
304  // std::optional<BLEDeviceOperatingSystem> os; // hasPotential, relevant, identified
305  PayloadData payload; // TODO make ephemeral (other than ID portion) - identified
306  // std::optional<ImmediateSendData> mImmediateSendData; // TODO make ephemeral - identified
307  RSSI mRssi; // TODO make ephemeral - all
308  // std::optional<BLETxPower> mTxPower; // hasPotential, relevant, identified
309  // bool mReceiveOnly; // TODO make convenience method based on other settings
310 
311  // // TODO simplify these three into their own state option (union)
312  // bool mIgnore; // filtered
313  // std::optional<TimeInterval> ignoreForDuration; // hasPotential
314  // std::optional<Date> ignoreUntil; // hasPotential
315 
316  // // TODO key these to an external limited list of characteristics
317  // std::optional<UUID> mPayloadCharacteristic; // relevant
318  // std::optional<UUID> mSignalCharacteristic; // relevant
319  // std::optional<BLEMacAddress> pseudoAddress; // relevant, identified
320 
321  // // Remove these as we don't support writing from C++ (there's no need - read works solidly)
322  // std::optional<Date> lastWriteRssiAt;
323  // std::optional<Date> lastWritePayloadAt;
324  // std::optional<Date> lastWritePayloadSharingAt;
325 
326  // // std::optional<Date> lastDiscoveredAt; // TODO remove - This is always the same as the last RSSI (i.e. lastUpdated) date
327  // std::optional<Date> connected; // merge with hasEverConnected
328  // std::optional<Date> payloadUpdated;
329 
330  // // TODO make this ephemeral
331  // std::optional<std::vector<BLEAdvertSegment>> segments; // discovered
332  // // TODO limit this to a key to the detected service ID (Herald or other. Prefer Herald)
333  // std::optional<std::vector<UUID>> mServices; // hasPotential, relevant
334 
335  // bool hasEverConnected; // hasPotential, relevant
336  // int connectRepeatedFailures; // hasPotential, relevant
337 };
338 
339 } // end namespace
340 } // end namespace
341 
342 #endif
Generic abstraction of a particular local proximate device type.
Definition: device.h:27
Definition: ble_device_delegate.h:13
INTERNAL Herald class used to minimise the memory footprint with hundreds of devices nearby.
Definition: ble_device.h:80
Definition: ble_device.h:181
const BLESensorConfiguration & configuration() const noexcept
Returns the BLESensorConfiguration reference relating to this instance.
void reset(const TargetIdentifier &newID, BLEDeviceDelegate &newDelegate)
Resets the device to what it's state would be if just constructed. Allows re-use in fixed size contai...
Definition: ble_mac_address.h:18
Definition: date.h:18
Definition: payload_data.h:13
Definition: rssi.h:14
Definition: target_identifier.h:17
Definition: time_interval.h:19
Definition: uuid.h:18
Contains all low-level Herald datatype implementations.
Definition: base64_string.h:14
Acts as a non-global memory arena for arbitrary classes.
Definition: aggregates.h:15
Definition: data.h:562
Defines BLE sensor configuration data, e.g. service and characteristic UUIDs.
Definition: ble_sensor_configuration.h:23
Definition: ble_device.h:132
Definition: ble_device.h:151
Definition: ble_advert_types.h:55