diff --git a/src/ble/ctrlm_ble_network.cpp b/src/ble/ctrlm_ble_network.cpp index 57cdb6da..63c1bf51 100644 --- a/src/ble/ctrlm_ble_network.cpp +++ b/src/ble/ctrlm_ble_network.cpp @@ -47,6 +47,7 @@ #include #include #include "ctrlm_rcp_ipc_iarm_thunder.h" +#include "ctrlm_telemetry.h" using namespace std; @@ -310,6 +311,13 @@ ctrlm_obj_network_ble_t::ctrlm_obj_network_ble_t(ctrlm_network_type_t type, ctrl if(rfc) { rfc->add_changed_listener(ctrlm_rfc_t::attrs::BLE, std::bind(&ctrlm_obj_network_ble_t::rfc_retrieved_handler, this, std::placeholders::_1)); } + + #ifdef TELEMETRY_SUPPORT + ctrlm_telemetry_t *telemetry = ctrlm_get_telemetry_obj(); + if(telemetry) { + telemetry->add_listener(ctrlm_telemetry_report_t::RCU, std::bind(&ctrlm_obj_network_ble_t::telemetry_report_handler, this)); + } + #endif } ctrlm_obj_network_ble_t::ctrlm_obj_network_ble_t() { @@ -370,6 +378,9 @@ ctrlm_hal_result_t ctrlm_obj_network_ble_t::hal_init_request(GThread *ctrlm_main ble_rcu_interface_->addRcuKeypressHandler(Slot(is_alive_, std::bind(&ctrlm_obj_network_ble_t::ind_keypress, this, std::placeholders::_1))); + ble_rcu_interface_->addRcuPairingOutcomeHandler(Slot(is_alive_, + std::bind(&ctrlm_obj_network_ble_t::ind_rcu_pairing_outcome, this, std::placeholders::_1))); + ble_rcu_interface_->startKeyMonitorThread(); @@ -1657,6 +1668,61 @@ void ctrlm_obj_network_ble_t::req_process_unpair(void *data, int size) { // BEGIN - Process Indications from HAL to the network in CTRLM Main thread context // ------------------------------------------------------------------------------------------------------------------------------------------------------------------ +void ctrlm_obj_network_ble_t::ind_rcu_pairing_outcome(const BleRcuPairingOutcome &outcome) { + // Queue to the ctrlm main thread for duration computation and telemetry emission + auto copy = std::make_shared(outcome); + ctrlm_main_queue_handler_push_new( + CTRLM_HANDLER_NETWORK, + (ctrlm_msg_handler_network_t)&ctrlm_obj_network_ble_t::ind_process_rcu_pairing_outcome, + copy, + NULL, + id_); +} + +void ctrlm_obj_network_ble_t::ind_process_rcu_pairing_outcome(void *data, int size) { + THREAD_ID_VALIDATE(); + const BleRcuPairingOutcome *outcome = static_cast(data); + if (sizeof(BleRcuPairingOutcome) != size) { + XLOGD_ERROR("Invalid size!"); + return; + } + if (!outcome) { + XLOGD_ERROR("pairing outcome data is NULL"); + return; + } + +#ifdef TELEMETRY_SUPPORT + // Serialize to array for ctrlm.rcu.pairing.attempt T2 marker + std::stringstream ss; + ss << "["; + ss << MARKER_RCU_PAIRING_ATTEMPT_VERSION << ","; + ss << "\"" << name_get() << "\","; + ss << outcome->method << ","; + ss << outcome->result << ","; + ss << outcome->discovered << ","; + ss << "\"" << outcome->name << "\","; + ss << outcome->bluezRetries << ","; + + for (uint8_t i = 0; i < outcome->maxBluezRetries; i++) { + if (i >= outcome->bluezRetries || i >= outcome->bluezError.size()) { + ss << "\"null\""; + } else { + std::string msg = outcome->bluezError.at(i); + auto pos = msg.rfind(": "); + msg = (pos != std::string::npos) ? msg.substr(pos + 2) : msg; + ss << "\"" << msg << "\""; + } + if (i != (outcome->maxBluezRetries-1)) { + ss << ","; + } + } + ss << "]"; + + ctrlm_telemetry_event_t ev(MARKER_RCU_PAIRING_ATTEMPT, ss.str()); + ctrlm_telemetry_t::get_instance()->event(ctrlm_telemetry_report_t::RCU, ev); +#endif // TELEMETRY_SUPPORT +} + void ctrlm_obj_network_ble_t::ind_rcu_status(ctrlm_hal_ble_RcuStatusData_t *params) { // push to the main queue and process it synchronously there @@ -2662,3 +2728,9 @@ void ctrlm_obj_network_ble_t::start_controller_audio_streaming(ctrlm_voice_start bool ctrlm_obj_network_ble_t::is_managed_by_network(ctrlm_controller_id_t id) { return (id >= BLE_RCU_ID_RANGE_MIN && id < BLE_RCU_ID_RANGE_MAX); } + +void ctrlm_obj_network_ble_t::telemetry_report_handler() { + #ifndef TELEMETRY_SUPPORT + XLOGD_WARN("telemetry is not enabled"); + #endif +} diff --git a/src/ble/ctrlm_ble_network.h b/src/ble/ctrlm_ble_network.h index 1182889a..da606682 100644 --- a/src/ble/ctrlm_ble_network.h +++ b/src/ble/ctrlm_ble_network.h @@ -134,11 +134,13 @@ class ctrlm_obj_network_ble_t : public ctrlm_obj_network_t { void ind_rcu_paired(ctrlm_hal_ble_IndPaired_params_t *params); void ind_rcu_unpaired(ctrlm_hal_ble_IndUnPaired_params_t *params); void ind_keypress(ctrlm_hal_ble_IndKeypress_params_t *params); + void ind_rcu_pairing_outcome(const BleRcuPairingOutcome &outcome); void ind_process_rcu_status(void *data, int size); void ind_process_paired(void *data, int size); void ind_process_unpaired(void *data, int size); void ind_process_keypress(void *data, int size); + void ind_process_rcu_pairing_outcome(void *data, int size); virtual void req_process_network_status(void *data, int size); virtual void req_process_controller_status(void *data, int size); @@ -195,6 +197,7 @@ class ctrlm_obj_network_ble_t : public ctrlm_obj_network_t { std::shared_ptr getConfigSettings(); virtual void start_controller_audio_streaming(ctrlm_voice_start_audio_params_t *params); + void telemetry_report_handler(); protected: virtual bool is_managed_by_network(ctrlm_controller_id_t id); diff --git a/src/ble/ctrlm_ble_rcu_interface.cpp b/src/ble/ctrlm_ble_rcu_interface.cpp index f90cdc67..8d1d0e1a 100644 --- a/src/ble/ctrlm_ble_rcu_interface.cpp +++ b/src/ble/ctrlm_ble_rcu_interface.cpp @@ -185,6 +185,12 @@ void ctrlm_ble_rcu_interface_t::initialize() m_rcuUnpairedSlots.invoke(¶ms); }; m_controller->addManagedDeviceRemovedSlot(Slot(m_isAlive, deviceRemovedSlot)); + + auto pairingOutcomeSlot = [this](const BleRcuPairingOutcome &outcome) + { + m_rcuPairingOutcomeSlots.invoke(outcome); + }; + m_controller->addPairingOutcomeSlot(Slot(m_isAlive, pairingOutcomeSlot)); } voice_params_par_t params; diff --git a/src/ble/ctrlm_ble_rcu_interface.h b/src/ble/ctrlm_ble_rcu_interface.h index c9209c6f..e29c7fc8 100644 --- a/src/ble/ctrlm_ble_rcu_interface.h +++ b/src/ble/ctrlm_ble_rcu_interface.h @@ -145,12 +145,17 @@ class ctrlm_ble_rcu_interface_t { m_rcuKeypressSlots.addSlot(func); } + inline void addRcuPairingOutcomeHandler(const Slot &func) + { + m_rcuPairingOutcomeSlots.addSlot(func); + } Slots m_rcuStatusChangedSlots; Slots m_rcuPairedSlots; Slots m_rcuUnpairedSlots; Slots m_rcuKeypressSlots; + Slots m_rcuPairingOutcomeSlots; private: std::shared_ptr m_isAlive; diff --git a/src/ble/hal/blercu/blercuadapter.h b/src/ble/hal/blercu/blercuadapter.h index cd9fc9e8..3407c25e 100644 --- a/src/ble/hal/blercu/blercuadapter.h +++ b/src/ble/hal/blercu/blercuadapter.h @@ -72,7 +72,7 @@ class BleRcuAdapter virtual bool isDevicePaired(const BleAddress &address) const = 0; virtual bool isDeviceConnected(const BleAddress &address) const = 0; - virtual bool addDevice(const BleAddress &address) = 0; + virtual bool addDevice(const BleAddress &address, int retries) = 0; virtual bool removeDevice(const BleAddress &address) = 0; virtual bool setConnectionParams(BleAddress address, double minInterval, double maxInterval, @@ -107,7 +107,7 @@ class BleRcuAdapter { m_deviceNameChangedSlots.addSlot(func); } - inline void addDevicePairingErrorSlot(const Slot &func) + inline void addDevicePairingErrorSlot(const Slot &func) { m_devicePairingErrorSlots.addSlot(func); } @@ -135,7 +135,7 @@ class BleRcuAdapter Slots m_deviceFoundSlots; Slots m_deviceRemovedSlots; Slots m_deviceNameChangedSlots; - Slots m_devicePairingErrorSlots; + Slots m_devicePairingErrorSlots; Slots m_devicePairingChangedSlots; Slots m_deviceReadyChangedSlots; diff --git a/src/ble/hal/blercu/blercucontroller.cpp b/src/ble/hal/blercu/blercucontroller.cpp index 9924c9df..deb59392 100644 --- a/src/ble/hal/blercu/blercucontroller.cpp +++ b/src/ble/hal/blercu/blercucontroller.cpp @@ -41,7 +41,6 @@ using namespace std; - class BleRcuController_userdata { public: BleRcuController_userdata(shared_ptr isAlive_, BleRcuControllerImpl* controller_) @@ -607,6 +606,16 @@ void BleRcuControllerImpl::onFinishedPairing() m_state = Complete; m_stateChangedSlots.invoke(m_state); + + // emit pairing outcome telemetry + BleRcuPairingOutcome outcome; + outcome.method = m_pairingStateMachine.pairingMethod(); + outcome.result = BleRcuPairingStateMachine::SUCCESS; + outcome.bluezRetries = m_pairingStateMachine.bluezRetries(); + outcome.maxBluezRetries = MAX_PAIRING_RETRIES; + outcome.name = m_pairingStateMachine.pairedName(); + outcome.discovered = m_pairingStateMachine.discoveredDevices(); + m_pairingOutcomeSlots.invoke(outcome); } // ----------------------------------------------------------------------------- @@ -646,6 +655,17 @@ void BleRcuControllerImpl::onFailedPairing() m_state = Failed; m_stateChangedSlots.invoke(m_state); + + // emit pairing outcome telemetry + BleRcuPairingOutcome outcome; + outcome.method = m_pairingStateMachine.pairingMethod(); + outcome.result = m_pairingStateMachine.failureReason(); + outcome.bluezRetries = m_pairingStateMachine.bluezRetries(); + outcome.maxBluezRetries = MAX_PAIRING_RETRIES; + outcome.bluezError = m_pairingStateMachine.bluezError(); + outcome.discovered = m_pairingStateMachine.discoveredDevices(); + outcome.name = ""; + m_pairingOutcomeSlots.invoke(outcome); } diff --git a/src/ble/hal/blercu/blercucontroller.h b/src/ble/hal/blercu/blercucontroller.h index 770d4d07..b4eab730 100644 --- a/src/ble/hal/blercu/blercucontroller.h +++ b/src/ble/hal/blercu/blercucontroller.h @@ -36,10 +36,23 @@ #include #include +#include +#include +#include class BleRcuDevice; +struct BleRcuPairingOutcome +{ + int method; // numeric enum value for PairingMethod + int result; // numeric enum value for FailureReason + int discovered; // number of discovered devices + int bluezRetries; // number of bluez retries attempted + int maxBluezRetries; // max number of retries + std::string name; // empty on failure + std::vector bluezError; // bluez error messages +}; class BleRcuController { @@ -101,12 +114,17 @@ class BleRcuController { m_stateChangedSlots.addSlot(func); } + inline void addPairingOutcomeSlot(const Slot &func) + { + m_pairingOutcomeSlots.addSlot(func); + } protected: Slots m_managedDeviceAddedSlots; Slots m_managedDeviceRemovedSlots; Slots m_pairingStateChangedSlots; Slots m_stateChangedSlots; + Slots m_pairingOutcomeSlots; }; #endif // !defined(BLERCUCONTROLLER_H) diff --git a/src/ble/hal/blercu/blercudevice.h b/src/ble/hal/blercu/blercudevice.h index 8ab7cc44..ef297db7 100644 --- a/src/ble/hal/blercu/blercudevice.h +++ b/src/ble/hal/blercu/blercudevice.h @@ -187,17 +187,18 @@ class BleRcuDevice { m_readyChangedSlots.addSlot(func); } - inline void addPairingErrorSlot(const Slot &func) + inline void addPairingErrorSlot(const Slot &func) { m_pairingErrorSlots.addSlot(func); } + protected: Slots m_connectedChangedSlots; Slots m_pairedChangedSlots; Slots m_nameChangedSlots; Slots m_readyChangedSlots; - Slots m_pairingErrorSlots; + Slots m_pairingErrorSlots; }; diff --git a/src/ble/hal/blercu/blercupairingstatemachine.cpp b/src/ble/hal/blercu/blercupairingstatemachine.cpp index e23c6939..0779fb69 100644 --- a/src/ble/hal/blercu/blercupairingstatemachine.cpp +++ b/src/ble/hal/blercu/blercupairingstatemachine.cpp @@ -52,6 +52,9 @@ BleRcuPairingStateMachine::BleRcuPairingStateMachine(const shared_ptraddPoweredChangedSlot(Slot(m_isAlive, std::bind(&BleRcuPairingStateMachine::onAdapterPoweredChanged, this, std::placeholders::_1))); - m_adapter->addDevicePairingErrorSlot(Slot(m_isAlive, - std::bind(&BleRcuPairingStateMachine::onDevicePairingError, this, std::placeholders::_1, std::placeholders::_2))); + m_adapter->addDevicePairingErrorSlot(Slot(m_isAlive, + std::bind(&BleRcuPairingStateMachine::onDevicePairingError, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4))); } BleRcuPairingStateMachine::~BleRcuPairingStateMachine() @@ -206,6 +209,37 @@ bool BleRcuPairingStateMachine::isScanningForAutoPair() const return isRunning() && m_isAutoPairing && m_stateMachine.inState(DiscoverySuperState); } +BleRcuPairingStateMachine::PairingMethod BleRcuPairingStateMachine::pairingMethod() const +{ + return m_pairingMethod; +} + +BleRcuPairingStateMachine::FailureReason BleRcuPairingStateMachine::failureReason() const +{ + return m_failureReason; +} + +int BleRcuPairingStateMachine::discoveredDevices() const +{ + return m_discoveredDevices.size(); +} + +int BleRcuPairingStateMachine::bluezRetries() const +{ + return m_bluezRetries; +} + +std::string BleRcuPairingStateMachine::pairedName() const +{ + auto it = m_discoveredDevices.find(m_pairedMac); + return (it != m_discoveredDevices.end()) ? it->second : ""; +} + +std::vector BleRcuPairingStateMachine::bluezError() const +{ + return m_bluezErrorMsg; +} + // ----------------------------------------------------------------------------- /*! @@ -239,6 +273,14 @@ void BleRcuPairingStateMachine::startAutoWithTimeout(int timeoutMs) m_targetedPairingNames.push_back(name); } + // reset telemetry tracking state + m_pairingMethod = AUTO_TIMEOUT; + m_failureReason = SUCCESS; + m_discoveredDevices.clear(); + m_bluezRetries = 0; + m_pairedMac.clear(); + m_bluezErrorMsg.clear(); + // start the state machine m_stateMachine.start(); @@ -289,6 +331,14 @@ void BleRcuPairingStateMachine::startWithCode(uint8_t pairingCode) m_targetedPairingNames.push_back(std::regex(nameWithCode, std::regex_constants::ECMAScript)); } + // reset telemetry tracking state + m_pairingMethod = IR_CODE; + m_failureReason = SUCCESS; + m_discoveredDevices.clear(); + m_bluezRetries = 0; + m_pairedMac.clear(); + m_bluezErrorMsg.clear(); + // start the state machine m_stateMachine.start(); @@ -321,6 +371,14 @@ void BleRcuPairingStateMachine::startWithMacList(const std::vector & // set the list of addresses to filter for m_pairingMacList = macList; + // reset telemetry tracking state + m_pairingMethod = MAC_LIST; + m_failureReason = SUCCESS; + m_discoveredDevices.clear(); + m_bluezRetries = 0; + m_pairedMac.clear(); + m_bluezErrorMsg.clear(); + // start the state machine m_stateMachine.start(); @@ -353,6 +411,9 @@ void BleRcuPairingStateMachine::stop() XLOGD_INFO("cancelling pairing"); + // record the cancellation reason before posting the event + m_failureReason = FAIL_CANCELLED; + // post a cancel event and let the state-machine clean up m_stateMachine.postEvent(CancelRequestEvent); } @@ -432,15 +493,21 @@ void BleRcuPairingStateMachine::onStateExit(int state) */ void BleRcuPairingStateMachine::onStateTransition(int oldState, int newState) { + FailureReason newFailureReason = SUCCESS; + if (newState == FinishedState) { if (oldState == UnpairingState) { XLOGD_AUTOMATION_WARN("timed-out in un-pairing phase (failed rcu may be left paired)"); + newFailureReason = FAIL_PAIRING_TIMEOUT; } else if (oldState == StartingDiscoveryState) { XLOGD_AUTOMATION_ERROR("timed-out waiting for discovery started signal"); + newFailureReason = FAIL_DISCOVERY_TIMEOUT; } else if (oldState == DiscoveringState) { XLOGD_AUTOMATION_ERROR("timed-out in discovery phase (didn't find target rcu device to pair to)"); + newFailureReason = FAIL_TARGET_RCU_NOT_FOUND; } else if (oldState == StoppingDiscoveryState) { XLOGD_AUTOMATION_ERROR("timed-out waiting for discovery to stop (suggesting something has gone wrong inside bluez)"); + newFailureReason = FAIL_DISCOVERY_STOP_TIMEOUT; } } else if (newState == UnpairingState) { if (oldState == EnablePairableState || oldState == PairingState) { @@ -449,6 +516,11 @@ void BleRcuPairingStateMachine::onStateTransition(int oldState, int newState) XLOGD_AUTOMATION_WARN("timed-out in setup phase (rcu didn't response to all requests within %dms)", m_setupTimeout); } } + + // Change the failure reason only if it hasn't already been set elsewhere + if (newFailureReason != SUCCESS && m_failureReason == SUCCESS) { + m_failureReason = newFailureReason; + } } void BleRcuPairingStateMachine::onEnteredStoppingDiscoveryStartedExternally() @@ -521,6 +593,9 @@ void BleRcuPairingStateMachine::onDiscoveryChanged(bool discovering) if (discovering) { m_stateMachine.postEvent(DiscoveryStartedEvent); } else { + if (m_stateMachine.inState(DiscoverySuperState)) { + m_failureReason = FAIL_DISCOVERY_STOPPED; + } m_stateMachine.postEvent(DiscoveryStoppedEvent); } } @@ -543,6 +618,7 @@ void BleRcuPairingStateMachine::onEnteredDiscoveringState() map::const_iterator it = deviceNames.begin(); for (; it != deviceNames.end(); ++it) { processDevice(it->first, it->second); + m_discoveredDevices.emplace(it->first, it->second); } } @@ -660,7 +736,7 @@ void BleRcuPairingStateMachine::onEnteredPairingState() m_pairingSlots.invoke(); // request the manager to pair with the device - m_adapter->addDevice(m_targetAddress); + m_adapter->addDevice(m_targetAddress, MAX_PAIRING_RETRIES); } // ----------------------------------------------------------------------------- @@ -714,6 +790,7 @@ void BleRcuPairingStateMachine::onEnteredUnpairingState() // remove (unpair) the target device because we've failed :-( if (m_adapter->removeDevice(m_targetAddress) == false) { + m_failureReason = FAIL_PAIRING_TIMEOUT; m_stateMachine.postEvent(DeviceUnpairedEvent); } } @@ -883,6 +960,7 @@ void BleRcuPairingStateMachine::onDeviceFound(const BleAddress &address, XLOGD_DEBUG("device added %s %s (target %s)", address.toString().c_str(), name.c_str(), m_targetAddress.toString().c_str()); + m_discoveredDevices.emplace(address, name); processDevice(address, name); } @@ -905,6 +983,11 @@ void BleRcuPairingStateMachine::onDeviceRemoved(const BleAddress &address) // check if the device removed is the one we're targeting if (!m_targetAddress.isNull() && (m_targetAddress == address)) { + if (m_stateMachine.inState(UnpairingState)) { + m_failureReason = FAIL_PAIRING_TIMEOUT; + } else { + m_failureReason = FAIL_DEVICE_REMOVED; + } m_stateMachine.postEvent(DeviceRemovedEvent); } } @@ -927,6 +1010,7 @@ void BleRcuPairingStateMachine::onDeviceNameChanged(const BleAddress &address, XLOGD_DEBUG("device name changed %s %s (target %s)", address.toString().c_str(), name.c_str(), m_targetAddress.toString().c_str()); + m_discoveredDevices[address] = name; processDevice(address, name); } @@ -941,12 +1025,23 @@ void BleRcuPairingStateMachine::onDeviceNameChanged(const BleAddress &address, */ void BleRcuPairingStateMachine::onDevicePairingError(const BleAddress &address, - const string &error) + const string &error, + int retryCnt, + bool finalRetry) { if (!m_stateMachine.isRunning()) { return; } + m_failureReason = FAIL_BLUEZ_ERROR; + m_bluezRetries = retryCnt; + m_bluezErrorMsg.push_back(error); + + if (!finalRetry) { + // Still retrying so don't stop pairing and timers yet + return; + } + XLOGD_ERROR("Device (%s) pairing failed, shutting down state machine...", address.toString().c_str()); // stop the pairing and setup timeout timers @@ -979,6 +1074,11 @@ void BleRcuPairingStateMachine::onDevicePairingChanged(const BleAddress &address if (paired) { m_stateMachine.postEvent(DevicePairedEvent); } else { + if (m_stateMachine.inState(UnpairingState)) { + m_failureReason = FAIL_PAIRING_TIMEOUT; + } else { + m_failureReason = FAIL_DEVICE_UNPAIRED; + } m_stateMachine.postEvent(DeviceUnpairedEvent); } } @@ -1006,6 +1106,7 @@ void BleRcuPairingStateMachine::onDeviceReadyChanged(const BleAddress &address, if (ready) { m_pairingSuccesses++; m_pairingSucceeded = true; + m_pairedMac = address; m_stateMachine.postEvent(DeviceReadyEvent); } } @@ -1027,6 +1128,7 @@ void BleRcuPairingStateMachine::onAdapterPoweredChanged(bool powered) } if (!powered) { + m_failureReason = FAIL_ADAPTER_OFF; m_stateMachine.postEvent(AdapterPoweredOffEvent); } } diff --git a/src/ble/hal/blercu/blercupairingstatemachine.h b/src/ble/hal/blercu/blercupairingstatemachine.h index cfb15c31..1886f3a7 100644 --- a/src/ble/hal/blercu/blercupairingstatemachine.h +++ b/src/ble/hal/blercu/blercupairingstatemachine.h @@ -40,13 +40,34 @@ #include #include - class BleRcuAdapter; class ConfigSettings; +#define MAX_PAIRING_RETRIES 3 class BleRcuPairingStateMachine { +public: + enum PairingMethod { + AUTO_TIMEOUT, + MAC_LIST, + IR_CODE, + }; + + enum FailureReason { + SUCCESS = 0, + FAIL_DISCOVERY_TIMEOUT, + FAIL_DISCOVERY_STOPPED, + FAIL_DISCOVERY_STOP_TIMEOUT, + FAIL_PAIRING_TIMEOUT, + FAIL_TARGET_RCU_NOT_FOUND, + FAIL_BLUEZ_ERROR, + FAIL_ADAPTER_OFF, + FAIL_DEVICE_UNPAIRED, + FAIL_DEVICE_REMOVED, + FAIL_CANCELLED + }; + public: enum State { RunningSuperState, @@ -73,6 +94,14 @@ class BleRcuPairingStateMachine bool isScanningForAutoPair() const; int pairingCode() const; +// Pairing outcome getters (valid after the state machine stops) + PairingMethod pairingMethod() const; + FailureReason failureReason() const; + int discoveredDevices() const; + int bluezRetries() const; + std::string pairedName() const; + std::vector bluezError() const; + // public slots: void startAutoWithTimeout(int timeoutMs); void startWithCode(uint8_t pairingCode); @@ -114,7 +143,7 @@ class BleRcuPairingStateMachine void onDeviceNameChanged(const BleAddress &address, const std::string &name); void onDevicePairingChanged(const BleAddress &address, bool paired); void onDeviceReadyChanged(const BleAddress &address, bool ready); - void onDevicePairingError(const BleAddress &address, const std::string &error); + void onDevicePairingError(const BleAddress &address, const std::string &error, int retryCnt, bool finalRetry); void onAdapterPoweredChanged(bool powered); @@ -172,6 +201,14 @@ class BleRcuPairingStateMachine int m_pairingSuccesses; bool m_pairingSucceeded; + // Pairing outcome tracking + PairingMethod m_pairingMethod; + FailureReason m_failureReason; + std::map m_discoveredDevices; + int m_bluezRetries; + BleAddress m_pairedMac; + std::vector m_bluezErrorMsg; + BtrMgrAdapter m_btrMgrAdapter; bool discoveryStartedExternally = false; BtrMgrAdapter::OperationType lastOperationType = BtrMgrAdapter::unknownOperation; diff --git a/src/ble/hal/blercu/bluez/blercuadapter.cpp b/src/ble/hal/blercu/bluez/blercuadapter.cpp index 56949f40..ea05fbc4 100644 --- a/src/ble/hal/blercu/bluez/blercuadapter.cpp +++ b/src/ble/hal/blercu/bluez/blercuadapter.cpp @@ -1216,10 +1216,10 @@ bool BleRcuAdapterBluez::isDeviceConnected(const BleAddress &address) const // ----------------------------------------------------------------------------- /*! - \fn void BleRcuManager::addDevice(const BleAddress &address) + \fn void BleRcuManager::addDevice(const BleAddress &address, int retries) Sends a request to the bluez daemon to pair the device with the given - \a address. The request is sent even if the device is already paired, + \a address and \a retries. The request is sent even if the device is already paired, this is to handle the case where a pending unpair notification is sitting in the dbus queue but not yet processed. @@ -1227,7 +1227,7 @@ bool BleRcuAdapterBluez::isDeviceConnected(const BleAddress &address) const \sa isDevicePaired(), removeDevice() */ -bool BleRcuAdapterBluez::addDevice(const BleAddress &address) +bool BleRcuAdapterBluez::addDevice(const BleAddress &address, int retries) { if (!m_stateMachine.inState(AdapterPoweredOnState)) { return false; @@ -1245,10 +1245,10 @@ bool BleRcuAdapterBluez::addDevice(const BleAddress &address) XLOGD_INFO("requesting bluez pair %s", device->address().toString().c_str()); - device->addPairingErrorSlot(Slot(m_isAlive, - std::bind(&BleRcuAdapterBluez::onDevicePairingError, this, address, std::placeholders::_1))); + device->addPairingErrorSlot(Slot(m_isAlive, + std::bind(&BleRcuAdapterBluez::onDevicePairingError, this, address, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3))); - device->pair(0); + device->pair(0, retries); return true; } @@ -1688,9 +1688,11 @@ void BleRcuAdapterBluez::onDeviceNameChanged(const BleAddress &address, */ void BleRcuAdapterBluez::onDevicePairingError(const BleAddress &address, - const std::string &error) + const std::string &error, + int retryCnt, + bool finalRetry) { - m_devicePairingErrorSlots.invoke(address, error); + m_devicePairingErrorSlots.invoke(address, error, retryCnt, finalRetry); } // ----------------------------------------------------------------------------- diff --git a/src/ble/hal/blercu/bluez/blercuadapter_p.h b/src/ble/hal/blercu/bluez/blercuadapter_p.h index aeb35f5c..33a2e48d 100644 --- a/src/ble/hal/blercu/bluez/blercuadapter_p.h +++ b/src/ble/hal/blercu/bluez/blercuadapter_p.h @@ -94,7 +94,7 @@ class BleRcuAdapterBluez : public BleRcuAdapter bool isDevicePaired(const BleAddress &address) const override; bool isDeviceConnected(const BleAddress &address) const override; - bool addDevice(const BleAddress &address) override; + bool addDevice(const BleAddress &address, int retries) override; bool removeDevice(const BleAddress &address) override; bool setConnectionParams(BleAddress address, double minInterval, double maxInterval, @@ -113,7 +113,7 @@ class BleRcuAdapterBluez : public BleRcuAdapter const std::vector &interfaces); void onDeviceNameChanged(const BleAddress &address, const std::string &name); - void onDevicePairingError(const BleAddress &address, const std::string &error); + void onDevicePairingError(const BleAddress &address, const std::string &error, int retryCnt, bool finalRetry); void onDevicePairedChanged(const BleAddress &address, bool paired); void onDeviceReadyChanged(const BleAddress &address, bool ready); diff --git a/src/ble/hal/blercu/bluez/blercudevice.cpp b/src/ble/hal/blercu/bluez/blercudevice.cpp index 08aa0287..575c8a5f 100644 --- a/src/ble/hal/blercu/bluez/blercudevice.cpp +++ b/src/ble/hal/blercu/bluez/blercudevice.cpp @@ -98,7 +98,7 @@ BleRcuDeviceBluez::BleRcuDeviceBluez(const BleAddress &bdaddr, , m_lastServicesResolvedState(false) , m_isPairing(false) , m_pairingRetryCnt(0) - , m_maxPairingRetries(3) + , m_maxPairingRetries(0) , m_timeSinceReady(0) , m_recoveryAttempts(0) , m_maxRecoveryAttempts(100) @@ -242,8 +242,9 @@ static gboolean getInitialDeviceProperties(gpointer user_data) request then the \a pairingError signal will be emitted. */ -void BleRcuDeviceBluez::pair(int timeout) +void BleRcuDeviceBluez::pair(int timeout, int retries) { + m_maxPairingRetries = retries; m_deviceProxy->Pair( PendingReply<>(m_isAlive, std::bind(&BleRcuDeviceBluez::onPairRequestReply, this, std::placeholders::_1))); @@ -269,10 +270,11 @@ void BleRcuDeviceBluez::onPairRequestReply(PendingReply<> *reply) if (m_pairingRetryCnt < m_maxPairingRetries) { m_pairingRetryCnt++; XLOGD_INFO("Retrying pairing, attempt %d out of %d ", m_pairingRetryCnt, m_maxPairingRetries); - pair(0); + m_pairingErrorSlots.invoke(reply->errorMessage(), m_pairingRetryCnt, false); + pair(0, m_maxPairingRetries); } else { + m_pairingErrorSlots.invoke(reply->errorMessage(), m_pairingRetryCnt, true); m_pairingRetryCnt = 0; - m_pairingErrorSlots.invoke(reply->errorMessage()); } } else { XLOGD_DEBUG("%s pairing request successful", m_address.toString().c_str()); diff --git a/src/ble/hal/blercu/bluez/blercudevice_p.h b/src/ble/hal/blercu/bluez/blercudevice_p.h index 39ecd86c..0700b227 100644 --- a/src/ble/hal/blercu/bluez/blercudevice_p.h +++ b/src/ble/hal/blercu/bluez/blercudevice_p.h @@ -92,7 +92,7 @@ class BleRcuDeviceBluez : public BleRcuDevice public: std::string bluezObjectPath() const; - void pair(int timeout); + void pair(int timeout, int retries); void cancelPairing(); void connect(); diff --git a/src/ctrlm_tr181.h b/src/ctrlm_tr181.h index 8fdb0b34..d04ea769 100644 --- a/src/ctrlm_tr181.h +++ b/src/ctrlm_tr181.h @@ -59,8 +59,7 @@ #define CTRLM_TR181_VOICE_PARAMS_VSDK_CONFIGURATION "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.Voice.VSDKConfiguration" #define CTRLM_TR181_VOICE_PARAMS_KEYWORD_SENSITIVITY "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.Voice.KeywordSensitivity" #define CTRLM_TR181_TELEMETRY_REPORT_GLOBAL "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.ctrlm.telemetry_report.global" -#define CTRLM_TR181_TELEMETRY_REPORT_RF4CE "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.ctrlm.telemetry_report.rf4ce" -#define CTRLM_TR181_TELEMETRY_REPORT_BLE "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.ctrlm.telemetry_report.ble" +#define CTRLM_TR181_TELEMETRY_REPORT_RCU "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.ctrlm.telemetry_report.rcu" #define CTRLM_TR181_TELEMETRY_REPORT_IP "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.ctrlm.telemetry_report.ip" #define CTRLM_TR181_TELEMETRY_REPORT_VOICE "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.ctrlm.telemetry_report.voice" #define CTRLM_RT181_POWER_RFC_PWRMGR2 "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.Power.PwrMgr2.Enable" diff --git a/src/telemetry/ctrlm_telemetry.cpp b/src/telemetry/ctrlm_telemetry.cpp index 3918444f..32a6f946 100644 --- a/src/telemetry/ctrlm_telemetry.cpp +++ b/src/telemetry/ctrlm_telemetry.cpp @@ -60,8 +60,7 @@ ctrlm_telemetry_t::ctrlm_telemetry_t() { this->timeout_id = 0; this->set_duration(this->reporting_interval); this->event_reported[ctrlm_telemetry_report_t::GLOBAL] = false; - this->event_reported[ctrlm_telemetry_report_t::RF4CE] = false; - this->event_reported[ctrlm_telemetry_report_t::BLE] = false; + this->event_reported[ctrlm_telemetry_report_t::RCU] = false; this->event_reported[ctrlm_telemetry_report_t::IP] = false; this->event_reported[ctrlm_telemetry_report_t::VOICE] = false; } @@ -112,8 +111,7 @@ void ctrlm_telemetry_t::report() { const char *ctrlm_telemetry_t::get_report_trigger(ctrlm_telemetry_report_t report) { switch(report) { case ctrlm_telemetry_report_t::GLOBAL: return(CTRLM_TR181_TELEMETRY_REPORT_GLOBAL); - case ctrlm_telemetry_report_t::RF4CE: return(CTRLM_TR181_TELEMETRY_REPORT_RF4CE); - case ctrlm_telemetry_report_t::BLE: return(CTRLM_TR181_TELEMETRY_REPORT_BLE); + case ctrlm_telemetry_report_t::RCU: return(CTRLM_TR181_TELEMETRY_REPORT_RCU); case ctrlm_telemetry_report_t::IP: return(CTRLM_TR181_TELEMETRY_REPORT_IP); case ctrlm_telemetry_report_t::VOICE: return(CTRLM_TR181_TELEMETRY_REPORT_VOICE); } @@ -123,8 +121,7 @@ const char *ctrlm_telemetry_t::get_report_trigger(ctrlm_telemetry_report_t repor const char *ctrlm_telemetry_t::get_report_str(ctrlm_telemetry_report_t report) { switch(report) { case ctrlm_telemetry_report_t::GLOBAL: return("GLOBAL"); - case ctrlm_telemetry_report_t::RF4CE: return("RF4CE"); - case ctrlm_telemetry_report_t::BLE: return("BLE"); + case ctrlm_telemetry_report_t::RCU: return("RCU"); case ctrlm_telemetry_report_t::IP: return("IP"); case ctrlm_telemetry_report_t::VOICE: return("VOICE"); } diff --git a/src/telemetry/ctrlm_telemetry.h b/src/telemetry/ctrlm_telemetry.h index 8b5db4fb..9024ebe2 100644 --- a/src/telemetry/ctrlm_telemetry.h +++ b/src/telemetry/ctrlm_telemetry.h @@ -28,8 +28,7 @@ */ typedef enum { GLOBAL, - RF4CE, - BLE, + RCU, IP, VOICE } ctrlm_telemetry_report_t; diff --git a/src/telemetry/ctrlm_telemetry_event.cpp b/src/telemetry/ctrlm_telemetry_event.cpp index 6ca82571..f6bda2d1 100644 --- a/src/telemetry/ctrlm_telemetry_event.cpp +++ b/src/telemetry/ctrlm_telemetry_event.cpp @@ -34,6 +34,14 @@ bool ctrlm_telemetry_event_t::event() const { template <> bool ctrlm_telemetry_event_t::event() const { - XLOGD_TELEMETRY("telemetry event <%s, %s>", this->marker.c_str(), this->value.c_str()); - return(t2_event_s((char *)this->marker.c_str(), (char *)this->value.c_str()) == T2ERROR_SUCCESS); + if (value.length() > CTRLM_TELEMETRY_MAX_EVENT_SIZE_BYTES) { + XLOGD_ERROR("telemetry event <%s> dropped: value length <%zu> exceeds maximum <%d> bytes", + this->marker.c_str(), + this->value.length(), + CTRLM_TELEMETRY_MAX_EVENT_SIZE_BYTES); + return false; + } else { + XLOGD_TELEMETRY("telemetry event <%s, %s>", this->marker.c_str(), this->value.c_str()); + return(t2_event_s((char *)this->marker.c_str(), (char *)this->value.c_str()) == T2ERROR_SUCCESS); + } } diff --git a/src/telemetry/ctrlm_telemetry_event.h b/src/telemetry/ctrlm_telemetry_event.h index 1628afb1..b83ca853 100644 --- a/src/telemetry/ctrlm_telemetry_event.h +++ b/src/telemetry/ctrlm_telemetry_event.h @@ -26,6 +26,8 @@ #include #endif +#define CTRLM_TELEMETRY_MAX_EVENT_SIZE_BYTES 4536 // Maximum size of event list in bytes (there are limitations in the T2 implementation that restrict the maximum size of an event string. This value should be within the limits of the T2 implementation) + template class ctrlm_telemetry_event_t { static_assert(std::is_same::value || std::is_same::value || std::is_same::value, "Invalid telemetry event type"); diff --git a/src/telemetry/ctrlm_telemetry_markers.h b/src/telemetry/ctrlm_telemetry_markers.h index 23c0f775..684ec2b3 100644 --- a/src/telemetry/ctrlm_telemetry_markers.h +++ b/src/telemetry/ctrlm_telemetry_markers.h @@ -125,4 +125,28 @@ // End Voice Markers // +// +// RCU Markers +// + +// BLE RCU Pairing Attempt Marker +// Value format: Array of comma separated integers or string with the fields below. +// [,,,,,,,,,] +// - version of the marker format. +// - type of network the marker is coming from +// - enum representing pairing method (see PairingMethod) +// - enum that represents "success" or failure reason (see FailureReason) +// - number of discovered devices from pairing attempt +// - name of paired remote, empty string on failure +// - number of bluez pair() retries made before success or final error +// - error message 1 from bluez layer or null if no error +// - error message 2 from bluez layer or null if no error +// - error message 3 from bluez layer or null if no error +#define MARKER_RCU_PAIRING_ATTEMPT "ctrlm.rcu.pairing.attempt_accum" +#define MARKER_RCU_PAIRING_ATTEMPT_VERSION 1 + +// +// End RCU Markers +// + #endif diff --git a/src/voice/telemetry/ctrlm_voice_telemetry_events.h b/src/voice/telemetry/ctrlm_voice_telemetry_events.h index adadfde6..93badb20 100644 --- a/src/voice/telemetry/ctrlm_voice_telemetry_events.h +++ b/src/voice/telemetry/ctrlm_voice_telemetry_events.h @@ -79,7 +79,7 @@ class ctrlm_voice_telemetry_session_t : public ctrlm_telemetry_event_t