Coverage Report

Created: 2021-08-28 18:14

D:\git\skunkworks\herald-for-cpp\herald\include\herald\ble\ble_device.h
Line
Count
Source
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
44
/// \brief Low-level Bluetooth status
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
50
/// \brief Internal discovery BLE state to aid efficient memory use in BLEDevice.
51
enum class BLEInternalState : short {
52
  /// \brief Discovered via Advert, but advert not assessed yet
53
  discovered,
54
  /// \brief Advert assessed, but device filtered as irrelevant
55
  filtered,
56
  /// \brief Advert assessed, and device requires further inspection (via connect and list services/characteristics)
57
  has_potential,
58
  /// \brief Determined to be a relevant device (Herald, or other relevant protocol)
59
  relevant,
60
  /// \brief Payload has been retrieved
61
  identified,
62
  /// \brief Not seen in a while, memory slot eligible for reallocation
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
79
/// \brief INTERNAL Herald class used to minimise the memory footprint with hundreds of devices nearby
80
class BLEDeviceFlags {
81
public:
82
  BLEDeviceFlags();
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
132
struct DiscoveredState {
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
151
struct RelevantState {
152
  RelevantState()
153
   : txPower(0), 
154
     ignoreForDuration(0),
155
     ignoreUntil(0),
156
     pseudoAddress(),
157
     connectRepeatedFailures(0),
158
     payloadUpdated(0)
159
21
  {}
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
184
  BLEDevice(BLESensorConfiguration& config);
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
191
  /// \brief Resets the device to what it's state would be if just constructed. Allows re-use in fixed size containers
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
200
  /// \brief Returns the BLESensorConfiguration reference relating to this instance
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
221
  /** Have we set the service list for this device yet? (i.e. done GATT service discover) **/
222
  // bool hasServicesSet() const; // TODO unused, consider removing
223
  /** Set services found on this device (set, not append) **/
224
  void services(std::vector<UUID> services);
225
  /** Does the service list contain a service UUID? **/
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