herald  2.0.0
concrete_ble_transmitter.h
1 // Copyright 2020-2021 Herald Project Contributors
2 // SPDX-License-Identifier: Apache-2.0
3 //
4 
5 #ifndef HERALD_BLE_CONCRETE_TRANSMITTER_H
6 #define HERALD_BLE_CONCRETE_TRANSMITTER_H
7 
8 #include "../ble_database.h"
9 #include "../ble_receiver.h"
10 #include "../ble_sensor.h"
11 #include "../ble_transmitter.h"
12 #include "../ble_protocols.h"
13 #include "../bluetooth_state_manager.h"
14 #include "../ble_device_delegate.h"
15 #include "../filter/ble_advert_parser.h"
16 #include "../../payload/payload_data_supplier.h"
17 #include "../../context.h"
18 #include "../../data/sensor_logger.h"
19 #include "../ble_sensor_configuration.h"
20 #include "../ble_coordinator.h"
21 #include "../../datatype/bluetooth_state.h"
22 
23 // nRF Connect SDK includes
24 #include <bluetooth/bluetooth.h>
25 #include <bluetooth/hci.h>
26 #include <bluetooth/hci_vs.h>
27 #include <sys/util.h>
28 #include <sys/byteorder.h>
29 #include <bluetooth/conn.h>
30 #include <bluetooth/uuid.h>
31 #include <bluetooth/gatt.h>
32 
33 // C++17 includes
34 #include <algorithm>
35 #include <optional>
36 #include <cstring>
37 
38 namespace herald {
39 namespace ble {
40 
41 using namespace herald::datatype;
42 using namespace herald::ble::filter;
43 using namespace herald::payload;
44 
45 
46 // zephyr internal functions called by template
47 
48 
49 namespace zephyrinternal {
50 
51  typedef std::function<PayloadData(const PayloadTimestamp)> GetPayloadFunction;
52 
53  GetPayloadFunction getPayloadDataSupplier();
54 
55  void setPayloadDataSupplier(GetPayloadFunction pds);
56 
57 
58  struct bt_data* getAdvertData();
59  std::size_t getAdvertDataSize();
60 
61  struct bt_le_adv_param* getAdvertParams();
62 
63  void get_tx_power(uint8_t handle_type, uint16_t handle, int8_t *tx_pwr_lvl);
64 
65  ssize_t read_vnd(struct bt_conn *conn, const struct bt_gatt_attr *attr,
66  void *buf, uint16_t len, uint16_t offset);
67  ssize_t write_vnd(struct bt_conn *conn, const struct bt_gatt_attr *attr,
68  const void *buf, uint16_t len, uint16_t offset,
69  uint8_t flags);
70  ssize_t read_payload(struct bt_conn *conn, const struct bt_gatt_attr *attr,
71  void *buf, uint16_t len, uint16_t offset);
72  ssize_t write_payload(struct bt_conn *conn, const struct bt_gatt_attr *attr,
73  const void *buf, uint16_t len, uint16_t offset,
74  uint8_t flags);
75 }
76 
77 
78 
79 template <typename ContextT, typename PayloadDataSupplierT, typename BLEDatabaseT, typename SensorDelegateSetT>
81 public:
82  ConcreteBLETransmitter(ContextT& ctx, BluetoothStateManager& bluetoothStateManager,
83  PayloadDataSupplierT& payloadDataSupplier, BLEDatabaseT& bleDatabase, SensorDelegateSetT& dels)
84  : m_context(ctx),
85  m_stateManager(bluetoothStateManager),
86  m_pds(payloadDataSupplier),
87  m_db(bleDatabase),
88  delegates(dels),
89  isAdvertising(false)
90 
91  HLOGGERINIT(ctx,"Sensor","BLE.ConcreteBLETransmitter")
92  {
93  zephyrinternal::setPayloadDataSupplier([this](const PayloadTimestamp pts) -> PayloadData {
94  return m_pds.payload(pts);
95  });
96  }
97 
98  ConcreteBLETransmitter(const ConcreteBLETransmitter& from) = delete;
100 
102  {
103  stop();
104  // zephyrinternal::setPayloadDataSupplier(NULL);
105  }
106 
107  // Coordination overrides - Since v1.2-beta3
108  std::optional<std::reference_wrapper<CoordinationProvider>> coordinationProvider() {
109  return {};
110  }
111 
112  // Sensor overrides
113  void start() {
114  HTDBG("ConcreteBLETransmitter::start");
115  if (!m_context.getSensorConfiguration().advertisingEnabled) {
116  HTDBG("Sensor Configuration has advertising disabled. Returning.");
117  return;
118  }
119  m_context.getPlatform().getAdvertiser().registerStopCallback([this] () -> void {
120  stopAdvertising();
121  });
122  m_context.getPlatform().getAdvertiser().registerStartCallback([this] () -> void {
123  startAdvertising();
124  });
125  HTDBG("Advertising callbacks registered");
126 
127  // Ensure our zephyr context has bluetooth ready
128  m_context.getPlatform().startBluetooth();
129 
130  HTDBG("Bluetooth started. Requesting start of adverts");
131 
132  startAdvertising();
133  }
134 
135  void stop() {
136  HTDBG("ConcreteBLETransmitter::stop");
137  if (!m_context.getSensorConfiguration().advertisingEnabled) {
138  HTDBG("Sensor Configuration has advertising disabled. Returning.");
139  return;
140  }
141  stopAdvertising();
142  }
143 
144 private:
145  ContextT& m_context;
146  BluetoothStateManager& m_stateManager;
147  PayloadDataSupplierT& m_pds;
148  BLEDatabaseT& m_db;
149 
150  SensorDelegateSetT& delegates;
151 
152  bool isAdvertising;
153 
154  HLOGGER(ContextT);
155 
156  // Internal methods
157  void startAdvertising()
158  {
159  // HTDBG("startAdvertising called");
160  if (!m_context.getSensorConfiguration().advertisingEnabled) {
161  HTDBG("Sensor Configuration has advertising disabled. Returning.");
162  return;
163  }
164  if (isAdvertising) {
165  // HTDBG("Already advertising. Returning.");
166  return;
167  }
168 
169  // Note: TxPower currently disabled due to restricted advert space and the need to include Herald's service.
170  // See https://github.com/theheraldproject/herald-for-cpp/issues/26
171  // Get current TxPower and alter advert accordingly:-
172  // int8_t txp_get = 0;
173  // zephyrinternal::get_tx_power(BT_HCI_VS_LL_HANDLE_TYPE_ADV,0, &txp_get);
174  // HTDBG("Zephyr tx power:-");
175  // HTDBG(std::to_string(txp_get));
176  // herald::ble::ad[1] = bt_data{
177  // .type=BT_DATA_TX_POWER,
178  // .data_len=sizeof(txp_get),
179  // .data=(const uint8_t *)uint8_t(txp_get)
180  // };
181 
182  // Now start advertising
183  // See https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/zephyr/reference/bluetooth/gap.html#group__bt__gap_1gac45d16bfe21c3c38e834c293e5ebc42b
184  int success = bt_le_adv_start(zephyrinternal::getAdvertParams(), zephyrinternal::getAdvertData(), zephyrinternal::getAdvertDataSize(), NULL, 0);
185  if (0 != success) {
186  HTDBG("Start advertising failed");
187  return;
188  }
189 
190  // zephyrinternal::get_tx_power(BT_HCI_VS_LL_HANDLE_TYPE_ADV,0, &txp_get);
191  // HTDBG("Zephyr tx power post advertising starting:-");
192  // HTDBG(std::to_string(txp_get));
193 
194  HTDBG("Start advertising completed successfully");
195  isAdvertising = true;
196  }
197 
198  void stopAdvertising()
199  {
200  // HTDBG("stopAdvertising called");
201  if (!m_context.getSensorConfiguration().advertisingEnabled) {
202  HTDBG("Sensor Configuration has advertising disabled. Returning.");
203  return;
204  }
205  if (!isAdvertising) {
206  // HTDBG("Not advertising already. Returning.");
207  return;
208  }
209  isAdvertising = false;
210  int success = bt_le_adv_stop();
211  if (0 != success) {
212  HTDBG("Stop advertising failed");
213  return;
214  }
215  // Don't stop Bluetooth altogether - this is done by the ZephyrContext->stopBluetooth() function only
216  HTDBG("Stop advertising completed successfully");
217  }
218 
219 };
220 
221 }
222 }
223 
224 #endif
Definition: bluetooth_state_manager.h:19
Dummy implementation of a ConcreteBLETransmitter that does nothing (used for testing)
Definition: concrete_ble_transmitter.h:39
Definition: payload_data.h:13
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: payload_timestamp.h:13