5 #ifndef HERALD_BLE_CONCRETE_RECEIVER_H
6 #define HERALD_BLE_CONCRETE_RECEIVER_H
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 #include "../ble_mac_address.h"
23 #include "../../zephyr_context.h"
26 #include <bluetooth/bluetooth.h>
27 #include <bluetooth/conn.h>
28 #include <bluetooth/uuid.h>
29 #include <bluetooth/gatt.h>
30 #include <bluetooth/gatt_dm.h>
31 #include <bluetooth/addr.h>
32 #include <bluetooth/scan.h>
34 #include <zephyr/types.h>
49 using namespace herald::ble::filter;
50 using namespace herald::payload;
55 uint32_t waitWithTimeout(uint32_t timeoutMillis, k_timeout_t period, std::function<
bool()> keepWaiting);
59 : target(
id), state(BLEDeviceState::disconnected), connection(NULL), address(),
60 readPayload(), immediateSend(), remoteInstigated(
false), inDiscovery(
false), isReading(
false)
72 bool remoteInstigated;
77 namespace zephyrinternal {
79 struct bt_uuid_128* getHeraldUUID();
80 struct bt_uuid_128* getHeraldSignalAndroidCharUUID();
81 struct bt_uuid_128* getHeraldSignalIOSCharUUID();
82 struct bt_uuid_128* getHeraldPayloadCharUUID();
85 void resetReceiverInstance();
87 struct bt_conn_le_create_param* getDefaultCreateParam();
88 struct bt_le_conn_param* getDefaultConnParam();
90 struct bt_le_scan_param* getDefaultScanParam();
91 struct bt_scan_init_param* getScanInitParam();
93 struct bt_gatt_read_params* getReadParams();
99 uint8_t gatt_read_cb(
struct bt_conn *conn, uint8_t err,
100 struct bt_gatt_read_params *params,
101 const void *data, uint16_t length);
134 void connected(
struct bt_conn *conn, uint8_t err);
137 void disconnected(
struct bt_conn *conn, uint8_t reason);
140 void le_param_updated(
struct bt_conn *conn, uint16_t interval,
141 uint16_t latency, uint16_t timeout);
143 struct bt_conn_cb* getConnectionCallbacks();
148 void scan_cb(
const bt_addr_le_t *addr, int8_t rssi, uint8_t adv_type,
149 struct net_buf_simple *buf);
208 void discovery_completed_cb(
struct bt_gatt_dm *dm,
211 void discovery_service_not_found_cb(
struct bt_conn *conn,
214 void discovery_error_found_cb(
struct bt_conn *conn,
218 const struct bt_gatt_dm_cb* getDiscoveryCallbacks();
221 template <
typename ContextT,
typename PayloadDataSupplierT,
typename BLEDatabaseT,
typename SensorDelegateSetT>
225 PayloadDataSupplierT& payloadDataSupplier, BLEDatabaseT& bleDatabase, SensorDelegateSetT& dels)
227 m_stateManager(bluetoothStateManager),
228 m_pds(payloadDataSupplier),
233 HLOGGERINIT(ctx,
"Sensor",
"BLE.ConcreteBLEReceiver")
246 std::optional<std::reference_wrapper<CoordinationProvider>> coordinationProvider()
263 HTDBG(
"ConcreteBLEReceiver::start");
264 if (!m_context.getSensorConfiguration().scanningEnabled) {
265 HTDBG(
"Sensor Configuration has scanning disabled. Returning.");
268 herald::ble::zephyrinternal::setReceiverInstance(*
this);
272 HTDBG(
"calling start bluetooth");
273 int startOk = m_context.getPlatform().startBluetooth();
274 HTDBG(
"start bluetooth done");
276 HTDBG(
"ERROR starting context bluetooth:-");
277 HTDBG(std::to_string(startOk));
280 HTDBG(
"Calling conn cb register");
281 bt_conn_cb_register(zephyrinternal::getConnectionCallbacks());
282 HTDBG(
"conn cb register done");
284 HTDBG(
"calling bt scan start");
287 HTDBG(
"ConcreteBLEReceiver::start completed successfully");
292 HTDBG(
"ConcreteBLEReceiver::stop");
293 if (!m_context.getSensorConfiguration().scanningEnabled) {
294 HTDBG(
"Sensor Configuration has scanning disabled. Returning.");
298 herald::ble::zephyrinternal::resetReceiverInstance();
304 HTDBG(
"ConcreteBLEReceiver::stop completed successfully");
319 HTDBG(
"openConnection");
323 uint8_t val[6] = {0,0,0,0,0,0};
324 Data addrData = toTarget.underlyingData();
326 bool cok = addrData.
uint8(0,t);
329 cok = addrData.
uint8(1,t);
332 cok = addrData.
uint8(2,t);
335 cok = addrData.
uint8(3,t);
338 cok = addrData.
uint8(4,t);
341 cok = addrData.
uint8(5,t);
347 bt_addr_le_t tempAddress{1, {{val[0],val[1],val[2],val[3],val[4],val[5]}}};
349 bt_addr_le_copy(&state.address, &tempAddress);
350 HTDBG(
"Address copied. Constituted as:-");
352 Data newAddr(state.address.a.val,6);
354 HTDBG((std::string)newMac);
389 m_context.getPlatform().getAdvertiser().stopAdvertising();
395 if (NULL == state.connection) {
396 HTDBG(
" - No existing connection. Attempting to connect");
418 char addr_str[BT_ADDR_LE_STR_LEN];
419 bt_addr_le_to_str(&state.address, addr_str,
sizeof(addr_str));
420 HTDBG(
"ADDR AS STRING in openConnection:-");
423 state.state = BLEDeviceState::connecting;
424 state.remoteInstigated =
false;
425 int success = bt_conn_le_create(
427 zephyrinternal::getDefaultCreateParam(),
428 zephyrinternal::getDefaultConnParam(),
431 HTDBG(
" - post connection attempt");
434 if (-EINVAL == success) {
435 HTDBG(
" - ERROR in passed in parameters");
436 }
else if (-EAGAIN == success) {
437 HTDBG(
" - bt device not ready");
438 }
else if (-EALREADY == success) {
439 HTDBG(
" - bt device initiating")
440 }
else if (-ENOMEM == success) {
441 HTDBG(
" - bt connect attempt failed with default BT ID. Trying again later.");
444 }
else if (-ENOBUFS == success) {
445 HTDBG(
" - bt_hci_cmd_create has no buffers free");
446 }
else if (-ECONNREFUSED == success) {
447 HTDBG(
" - Connection refused");
448 }
else if (-EIO == success) {
449 HTDBG(
" - Low level BT HCI opcode IO failure");
451 HTDBG(
" - Unknown error code...");
452 HTDBG(std::to_string(success));
461 auto& device = db.device(newMac);
462 device.state(BLEDeviceState::disconnected);
470 HTDBG(
"Zephyr waitWithTimeout for new connection");
482 uint32_t timedOut = waitWithTimeout(5'000, K_MSEC(25), [&state] {
483 return state.state == BLEDeviceState::connecting;
486 HTDBG(
"ZEPHYR WAIT TIMED OUT. Is connected?");
487 HTDBG((state.state == BLEDeviceState::connected) ?
"true" :
"false");
488 HTDBG(std::to_string(timedOut));
492 return state.state == BLEDeviceState::connected;
495 HTDBG(
" - Existing connection exists! Reusing.");
504 HTDBG(
"closeConnection call for ADDR:-");
506 char addr_str[BT_ADDR_LE_STR_LEN];
507 bt_addr_le_to_str(&state.address, addr_str,
sizeof(addr_str));
513 if (NULL != state.connection) {
514 if (state.remoteInstigated) {
515 HTDBG(
"Connection remote instigated - not forcing close");
516 }
else if (state.inDiscovery) {
517 HTDBG(
"Connection in-use for service discovery - not forcing close");
518 }
else if (state.isReading) {
519 HTDBG(
"Connection in-use for characteristic read - not forcing close");
521 bt_conn_disconnect(state.connection, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
526 HTDBG(
"State connections is null - assuming it is closed");
528 state.remoteInstigated =
false;
532 if (!state.remoteInstigated && !state.inDiscovery && !state.isReading) {
533 HTDBG(
"Removing old state connection cache object");
534 removeState(toTarget);
537 HTDBG(
"Not removed state cache for connection. Notifying caller connection is not yet closed.");
546 if (!connectionStates.empty()) {
547 HTDBG(
"Current connection states cached:-");
548 for (
auto& [key,value] : connectionStates) {
549 std::string ci =
" - ";
550 ci += value.target.underlyingData().hexEncodedString();
552 switch (value.state) {
553 case BLEDeviceState::connected:
556 case BLEDeviceState::disconnected:
557 ci +=
"disconnected";
562 ci +=
", connection is null: ";
563 ci += (NULL == value.connection ?
"true" :
"false");
567 bool nullBefore = (NULL == value.connection);
568 char addr_str[BT_ADDR_LE_STR_LEN];
569 bt_addr_le_to_str(&value.address, addr_str,
sizeof(addr_str));
571 HTDBG(
"Looking up connection object for address just printed");
572 value.connection = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &value.address);
573 if (!nullBefore && (NULL == value.connection)) {
574 HTDBG(
" WARNING connection was not null, but is now we've tried to look it up again - WHY? Zephyr could not find connection by address?");
579 if (BLEDeviceState::disconnected == value.state) {
580 HTDBG(
"Connection is in disconnected state. Setting state cache connection to NULL");
581 value.connection = NULL;
584 if (NULL != value.connection && value.remoteInstigated) {
585 HTDBG(
"REMOTELY INSTIGATED OR CONNECTED DEVICE TIMED OUT");
586 auto& device = db.device(value.target);
590 if (device.timeIntervalSinceLastUpdate() < TimeInterval::never() &&
591 device.timeIntervalSinceLastUpdate() > TimeInterval::seconds(30)) {
593 bt_conn_disconnect(value.connection, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
594 bt_conn_unref(value.connection);
595 value.connection = NULL;
601 for (
auto iter = connectionStates.begin();connectionStates.end() != iter; ++iter) {
603 if (NULL != iter->second.connection) {
605 auto& device = db.device(iter->second.target);
608 if (device.timeIntervalSinceLastUpdate() > TimeInterval::seconds(30)) {
609 bt_conn_disconnect(iter->second.connection, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
610 bt_conn_unref(iter->second.connection);
611 iter->second.connection = NULL;
615 if (NULL == iter->second.connection) {
616 connectionStates.erase(iter);
624 m_context.getPlatform().getAdvertiser().startAdvertising();
627 std::optional<Activity> serviceDiscovery(
Activity activity)
override
629 auto currentTargetOpt = std::get<1>(activity.
prerequisites.front());
630 if (!currentTargetOpt.has_value()) {
631 HTDBG(
"No target specified for serviceDiscovery activity. Returning.");
635 auto& state = findOrCreateState(currentTargetOpt.value());
636 if (state.state != BLEDeviceState::connected) {
637 HTDBG(
"Not connected to target of activity. Returning.");
640 if (NULL == state.connection) {
641 HTDBG(
"State for activity does not have a connection. Returning.");
645 auto& device = db.device(currentTargetOpt.value());
646 state.inDiscovery =
true;
648 gatt_discover(state.connection);
650 HTDBG(
"Zephyr waitWithTimeout for serviceDiscovery");
651 uint32_t timedOut = waitWithTimeout(5'000, K_MSEC(25), [&state] () ->
bool {
653 return state.inDiscovery || state.isReading;
655 HTDBG(
"Zephyr waitWithTimeout completed for serviceDiscovery");
657 state.inDiscovery =
false;
660 HTDBG(
"service discovery timed out for device");
661 HTDBG(std::to_string(timedOut));
667 std::optional<Activity> readPayload(
Activity activity)
override
719 void scan_cb(
const bt_addr_le_t *addr, int8_t rssi, uint8_t adv_type,
720 struct net_buf_simple *buf)
override
724 Data advert(buf->data,buf->len);
725 auto& device = db.device(bleMacAddress,advert);
728 if (device.ignore()) {
734 if (device.rssi().intValue() == 0) {
735 char addr_str[BT_ADDR_LE_STR_LEN];
736 bt_addr_le_to_str(addr, addr_str,
sizeof(addr_str));
737 std::string addrStr(addr_str);
738 HTDBG(
"New address FROM SCAN:-");
743 device.rssi(
RSSI(rssi));
746 void le_param_updated(
struct bt_conn *conn, uint16_t interval,
747 uint16_t latency, uint16_t timeout)
override
749 HTDBG(
"le param updated called");
752 void connected(
struct bt_conn *conn, uint8_t err)
override
754 HTDBG(
"**************** Zephyr connection callback. Mac of connected:");
756 auto addr = bt_conn_get_dst(conn);
757 char addr_str[BT_ADDR_LE_STR_LEN];
758 bt_addr_le_to_str(addr, addr_str,
sizeof(addr_str));
759 std::string addrStr(addr_str);
761 HTDBG((std::string)bleMacAddress);
764 auto& device = db.device(bleMacAddress);
770 HTDBG(
"Connected: Error value:-");
771 HTDBG(std::to_string(err));
776 state.state = BLEDeviceState::disconnected;
777 state.connection = NULL;
780 device.state(BLEDeviceState::disconnected);
788 state.connection = conn;
789 bt_addr_le_copy(&state.address,addr);
790 state.state = BLEDeviceState::connected;
793 device.state(BLEDeviceState::connected);
802 void disconnected(
struct bt_conn *conn, uint8_t reason)
override
804 HTDBG(
"********** Zephyr disconnection callback. Mac of disconnected:");
806 auto addr = bt_conn_get_dst(conn);
807 char addr_str[BT_ADDR_LE_STR_LEN];
808 bt_addr_le_to_str(addr, addr_str,
sizeof(addr_str));
809 std::string addrStr(addr_str);
811 HTDBG((std::string)bleMacAddress);
814 HTDBG(
"Disconnection: Reason value:-");
815 HTDBG(std::to_string(reason));
825 state.state = BLEDeviceState::disconnected;
826 state.connection = NULL;
829 auto& device = db.device(bleMacAddress);
830 device.state(BLEDeviceState::disconnected);
833 void discovery_completed_cb(
struct bt_gatt_dm *dm,
void *context)
override
835 HTDBG(
"The GATT discovery procedure succeeded");
836 const struct bt_gatt_dm_attr *prev = NULL;
839 auto& device = db.device(state.target);
841 prev = bt_gatt_dm_char_next(dm,prev);
844 struct bt_gatt_chrc *chrc = bt_gatt_dm_attr_chrc_val(prev);
846 int matches = bt_uuid_cmp(chrc->uuid, &zephyrinternal::getHeraldPayloadCharUUID()->uuid);
848 HTDBG(
" - FOUND Herald read characteristic. Reading.");
849 device.payloadCharacteristic(m_context.getSensorConfiguration().payloadCharacteristicUUID);
851 state.readPayload.clear();
852 state.isReading =
true;
860 zephyrinternal::getReadParams()->single.handle = chrc->value_handle;
861 zephyrinternal::getReadParams()->single.offset = 0x0000;
862 int readErr = bt_gatt_read(bt_gatt_dm_conn_get(dm), zephyrinternal::getReadParams());
864 HTDBG(
"GATT read error: TBD");
870 matches = bt_uuid_cmp(chrc->uuid, &zephyrinternal::getHeraldSignalAndroidCharUUID()->uuid);
872 HTDBG(
" - FOUND Herald android signal characteristic. logging.");
873 device.signalCharacteristic(m_context.getSensorConfiguration().androidSignalCharacteristicUUID);
874 device.operatingSystem(BLEDeviceOperatingSystem::android);
878 matches = bt_uuid_cmp(chrc->uuid, &zephyrinternal::getHeraldSignalIOSCharUUID()->uuid);
880 HTDBG(
" - FOUND Herald ios signal characteristic. logging.");
881 device.signalCharacteristic(m_context.getSensorConfiguration().iosSignalCharacteristicUUID);
882 device.operatingSystem(BLEDeviceOperatingSystem::ios);
888 bt_uuid_to_str(chrc->uuid,uuid_str,
sizeof(uuid_str));
889 HTDBG(
" - Char doesn't match any herald char uuid:-");
892 }
while (NULL != prev);
893 state.inDiscovery =
false;
896 HTDBG(
"Herald read payload char not found in herald service (weird...). Ignoring device.");
902 int err = bt_gatt_dm_data_release(dm);
904 HTDBG(
"Could not release the discovery data, error code: TBD");
909 std::vector<UUID> serviceList;
910 serviceList.push_back(m_context.getSensorConfiguration().serviceUUID);
911 device.services(serviceList);
914 void discovery_service_not_found_cb(
struct bt_conn *conn,
void *context)
override
916 HTDBG(
"The service could not be found during the discovery. Ignoring device:");
918 HTDBG((std::string)state.target);
920 auto& device = db.device(state.target);
921 std::vector<UUID> serviceList;
922 device.services(serviceList);
926 void discovery_error_found_cb(
struct bt_conn *conn,
int err,
void *context)
override
928 HTDBG(
"The discovery procedure failed with ");
929 HTDBG(std::to_string(err));
933 uint8_t gatt_read_cb(
struct bt_conn *conn, uint8_t err,
934 struct bt_gatt_read_params *params,
935 const void *data, uint16_t length)
override
937 HTDBG(
"In gatt_read_cb");
941 HTDBG(
"Finished reading CHAR read payload:-");
942 HTDBG(state.readPayload.hexEncodedString());
945 db.device(state.target).payloadData(state.readPayload);
948 state.readPayload.clear();
950 state.isReading =
false;
955 state.readPayload.append((
const uint8_t*)data,0,length);
963 auto iter = connectionStates.find(forTarget);
964 if (connectionStates.end() != iter) {
967 return connectionStates.emplace(forTarget, forTarget).first->second;
971 ConnectedDeviceState& findOrCreateStateByConnection(
struct bt_conn *conn,
bool remoteInstigated =
false)
973 for (
auto& [key, value] : connectionStates) {
974 if (value.connection == conn) {
979 auto addr = bt_conn_get_dst(conn);
982 auto result = connectionStates.emplace(target, target);
983 bt_addr_le_copy(&result.first->second.address,addr);
984 result.first->second.remoteInstigated = remoteInstigated;
985 return result.first->second;
990 auto iter = connectionStates.find(forTarget);
991 if (connectionStates.end() != iter) {
992 connectionStates.erase(iter);
1002 int err = bt_le_scan_start(zephyrinternal::getDefaultScanParam(), &zephyrinternal::scan_cb);
1005 HTDBG(
"Starting scanning failed");
1019 void gatt_discover(
struct bt_conn *conn)
1021 HTDBG(
"Attempting GATT service discovery");
1025 err = bt_gatt_dm_start(conn, &zephyrinternal::getHeraldUUID()->uuid, zephyrinternal::getDiscoveryCallbacks(), NULL);
1027 HTDBG(
"could not start the discovery procedure, error code")
1028 HTDBG(
std::to_string(err));
1029 bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
1032 HTDBG("Service discovery succeeded... now do something with it in the callback!");
1035 ContextT& m_context;
1037 PayloadDataSupplierT& m_pds;
1040 SensorDelegateSetT& delegates;
Definition: ble_mac_address.h:18
Definition: bluetooth_state_manager.h:19
Dummy implementation of a ConcreteBLEReceiver that does nothing (used for testing)
Definition: concrete_ble_receiver.h:24
bool closeConnection(const TargetIdentifier &toTarget) override
Definition: concrete_ble_receiver.h:502
void restartScanningAndAdvertising() override
Definition: concrete_ble_receiver.h:543
bool openConnection(const TargetIdentifier &toTarget) override
Definition: concrete_ble_receiver.h:317
Definition: ble_protocols.h:22
The main data workhorse class of the Herald API.
Definition: data.h:33
bool uint8(std::size_t fromIndex, uint8_t &into) const noexcept
Returns whether reading a single uint8_t to into at fromIndex was successful.
Definition: data.h:324
Definition: payload_data.h:13
Definition: target_identifier.h:17
INTERNAL utility class to allow Zephyr C API to call callbacks in the Zephyr internal Context Impl cl...
Definition: zephyr_context.h:96
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: concrete_ble_receiver.h:57
An activity that needs to be performed due to some state being achieved in a Sensor.
Definition: activities.h:75
std::vector< Prerequisite > prerequisites
A list of non-prioritised pre-requisities (priority is taken from the priority field in Activity).
Definition: activities.h:82