@@ -48,6 +48,37 @@ class BluetoothControl : public PluginHost::IPlugin
4848 public:
4949 class Config : public Core ::JSON::Container {
5050 public:
51+ class LowEnergyConfig : public Core ::JSON::Container {
52+ public:
53+ // Default settings for LE connections
54+ LowEnergyConfig ()
55+ : Core::JSON::Container()
56+ , MinInterval(8 )
57+ , MaxInterval(8 )
58+ , Timeout(3000 /* ms */ )
59+ , Latency(0 )
60+ {
61+ Add (_T (" mininterval" ), &MinInterval);
62+ Add (_T (" maxinterval" ), &MaxInterval);
63+ Add (_T (" timeout" ), &Timeout);
64+ Add (_T (" latency" ), &Latency);
65+ }
66+ ~LowEnergyConfig ()
67+ {
68+ }
69+
70+ LowEnergyConfig (const LowEnergyConfig&) = delete ;
71+ LowEnergyConfig (LowEnergyConfig&&) = delete ;
72+ LowEnergyConfig& operator =(const LowEnergyConfig&) = delete ;
73+ LowEnergyConfig& operator =(LowEnergyConfig&&) = delete ;
74+
75+ public:
76+ Core::JSON::DecUInt16 MinInterval;
77+ Core::JSON::DecUInt16 MaxInterval;
78+ Core::JSON::DecUInt16 Timeout;
79+ Core::JSON::DecUInt16 Latency;
80+ };
81+
5182 class UUIDConfig : public Core ::JSON::Container {
5283 public:
5384 UUIDConfig& operator =(const UUIDConfig&) = delete ;
@@ -106,6 +137,7 @@ class BluetoothControl : public PluginHost::IPlugin
106137 Add (_T (" autopasskeyconfirm" ), &AutoPasskeyConfirm);
107138 Add (_T (" persistmac" ), &PersistMAC);
108139 Add (_T (" uuids" ), &UUIDs);
140+ Add (_T (" lowenergy" ), &LowEnergy);
109141 }
110142 ~Config () = default ;
111143
@@ -119,6 +151,7 @@ class BluetoothControl : public PluginHost::IPlugin
119151 Core::JSON::Boolean AutoPasskeyConfirm;
120152 Core::JSON::Boolean PersistMAC;
121153 Core::JSON::ArrayType<UUIDConfig> UUIDs;
154+ LowEnergyConfig LowEnergy;
122155 }; // class Config
123156
124157 class Data : public Core ::JSON::Container {
@@ -716,8 +749,13 @@ class BluetoothControl : public PluginHost::IPlugin
716749 }
717750 }
718751
719- TRACE (ControlFlow, (_T (" %s background scan..." ), (start? " Restarting" : " Stopping" )));
720- HCISocket::Discovery (start);
752+ TRACE (ControlFlow, (_T (" %s background scan..." ), (start? _T (" Restarting" ) : _T (" Stopping" ))));
753+
754+ uint32_t result = HCISocket::Discovery (start);
755+
756+ if ((result != Core::ERROR_NONE) && (result != Core::ERROR_ILLEGAL_STATE)) {
757+ TRACE (Trace::Error, (_T (" BLE discovery %s failed" ), _T (" start" ), _T (" stop" )));
758+ }
721759 }
722760#endif // !defined(USE_KERNEL_CONNECTION_CONTROL)
723761 }
@@ -1515,9 +1553,6 @@ class BluetoothControl : public PluginHost::IPlugin
15151553 , _capabilities(~0 )
15161554 , _authentication(~0 )
15171555 , _oobData(~0 )
1518- , _interval(0 )
1519- , _latency(0 )
1520- , _timeout(0 )
15211556#if defined(USE_KERNEL_CONNECTION_CONTROL)
15221557 , _autoConnectionSubmitted(false )
15231558#endif
@@ -1645,19 +1680,22 @@ class BluetoothControl : public PluginHost::IPlugin
16451680 case HCI_NO_CONNECTION:
16461681 result = Core::ERROR_ALREADY_RELEASED;
16471682 TRACE (ControlFlow, (_T (" Device not connected" )));
1648- BackgroundScan (true );
16491683 break ;
16501684 default :
16511685 result = Core::ERROR_ASYNC_FAILED;
16521686 TRACE (ControlFlow, (_T (" Disconnect command failed [%d]" ), disconnect.Result ()));
16531687 break ;
16541688 }
1655- ClearState (DISCONNECTING);
16561689 }
1657- } else {
1658- TRACE (ControlFlow, (_T (" Failed to disconnect [%d]" ), result));
1659- ClearState (DISCONNECTING);
16601690 }
1691+
1692+ BackgroundScan (true );
1693+
1694+ if (result != Core::ERROR_NONE) {
1695+ TRACE (ControlFlow, (_T (" Unable to disconnect [%d]" ), result));
1696+ }
1697+
1698+ ClearState (DISCONNECTING);
16611699 } else {
16621700 TRACE (Trace::Information, (_T (" Device is currently busy" )));
16631701 }
@@ -1669,6 +1707,7 @@ class BluetoothControl : public PluginHost::IPlugin
16691707 uint32_t result = Core::ERROR_INPROGRESS;
16701708
16711709 if (SetState (PAIRING) == Core::ERROR_NONE) {
1710+ BackgroundScan (false );
16721711 result = _parent->Connector ().Pair (Address (), AddressType (), static_cast <Bluetooth::ManagementSocket::capabilities>(capabilities));
16731712 if (result == Core::ERROR_INPROGRESS) {
16741713 UpdateListener ();
@@ -1677,6 +1716,7 @@ class BluetoothControl : public PluginHost::IPlugin
16771716 _abortPairingJob.Schedule ([this ](){
16781717 TRACE (Trace::Information, (_T (" Timeout! Aborting pairing!" ), RemoteId ().c_str ()));
16791718 AbortPairing ();
1719+ BackgroundScan (true );
16801720 }, (1000L * timeout));
16811721 result = Core::ERROR_NONE;
16821722 } else {
@@ -1685,7 +1725,10 @@ class BluetoothControl : public PluginHost::IPlugin
16851725 } else if (result != Core::ERROR_NONE) {
16861726 TRACE (Trace::Error, (_T (" Failed to pair device %s [%d]" ), RemoteId ().c_str (), result));
16871727 }
1728+ }
16881729
1730+ if (result != Core::ERROR_REQUEST_SUBMITTED) {
1731+ BackgroundScan (true );
16891732 ClearState (PAIRING);
16901733 }
16911734 } else {
@@ -1705,12 +1748,14 @@ class BluetoothControl : public PluginHost::IPlugin
17051748 } else if (result != Core::ERROR_NONE) {
17061749 TRACE (Trace::Error, (_T (" Failed to abort pairing [%d]" ), result));
17071750 }
1751+
1752+ if (result != Core::ERROR_INPROGRESS) {
1753+ ClearState (PAIRING);
1754+ }
17081755 } else {
17091756 TRACE (Trace::Information, (_T (" Not currently pairing to this device" )));
17101757 }
17111758
1712- ClearState (PAIRING);
1713-
17141759 return (result);
17151760 }
17161761 uint32_t Unpair () override
@@ -1730,7 +1775,6 @@ class BluetoothControl : public PluginHost::IPlugin
17301775 }
17311776
17321777 ClearState (UNPAIRING);
1733- UpdateListener ();
17341778 } else {
17351779 TRACE (Trace::Information, (_T (" Device is currently busy" )));
17361780 }
@@ -1746,7 +1790,7 @@ class BluetoothControl : public PluginHost::IPlugin
17461790 }
17471791 void ConfirmPasskey (const bool confirm) override
17481792 {
1749- TRACE (Trace::Information, (_T (" Passkey confirmation reply: %s" ), confirm? " YES" : " NO" ));
1793+ TRACE (Trace::Information, (_T (" Passkey confirmation reply: %s" ), confirm? _T ( " YES" ) : _T ( " NO" ) ));
17501794 _userReplyJob.Submit ([this , confirm]() {
17511795 _parent->Connector ().PasskeyConfirmReply (Address (), AddressType (), confirm);
17521796 });
@@ -1904,7 +1948,7 @@ class BluetoothControl : public PluginHost::IPlugin
19041948 TRACE (Trace::Information, (_T (" Pairing with device %s; confirm passkey %06d? (YES/NO)" ), RemoteId ().c_str (), passkey));
19051949
19061950 // Request passkey confirmation from client or, if auto confirm is enabled, reply already.
1907- if (_parent->AutoConfirmPasskey () == true ) {
1951+ if (_parent->Configuration (). AutoPasskeyConfirm . Value () == true ) {
19081952 TRACE (Trace::Information, (_T (" Auto-confirm enabled, accepting the passkey!" )));
19091953 ConfirmPasskey (true );
19101954 } else {
@@ -1965,14 +2009,14 @@ class BluetoothControl : public PluginHost::IPlugin
19652009
19662010 _state.Unlock ();
19672011
1968- _autoConnectJob.Submit ([this ]() {
1969- // Each time a device connects evalute whether background scan is needed.
1970- BackgroundScan (true );
1971- });
1972-
19732012 if (updated == true ) {
19742013 UpdateListener ();
19752014 DeviceStateChanged (JBluetoothControl::devicestate::CONNECTED);
2015+
2016+ _autoConnectJob.Submit ([this ]() {
2017+ // Each time a device connects evalute whether background scan is needed.
2018+ BackgroundScan (true );
2019+ });
19762020 }
19772021 }
19782022 void Disconnection (const uint8_t reason)
@@ -2225,9 +2269,6 @@ class BluetoothControl : public PluginHost::IPlugin
22252269 uint8_t _capabilities;
22262270 uint8_t _authentication;
22272271 uint8_t _oobData;
2228- uint16_t _interval;
2229- uint16_t _latency;
2230- uint16_t _timeout;
22312272#if defined(USE_KERNEL_CONNECTION_CONTROL)
22322273 bool _autoConnectionSubmitted;
22332274#endif
@@ -2303,14 +2344,20 @@ class BluetoothControl : public PluginHost::IPlugin
23032344 Connection (handle);
23042345 } else {
23052346 TRACE (ControlFlow, (_T (" Connect command failed [%d]" ), connect.Result ()));
2347+ result = Core::ERROR_ASYNC_FAILED;
23062348 }
23072349 } else {
23082350 if (result == Core::ERROR_TIMEDOUT) {
2309- TRACE (Trace::Information, (_T (" Waiting for connection... [%d] " ), result ));
2351+ TRACE (Trace::Information, (_T (" Waiting for connection... " ) ));
23102352 result = Core::ERROR_REQUEST_SUBMITTED;
23112353 }
2312- else {
2313- TRACE (Trace::Error, (_T (" Failed to connect [%d]" ), result));
2354+ }
2355+
2356+ if (result != Core::ERROR_NONE) {
2357+ BackgroundScan (true );
2358+
2359+ if (result != Core::ERROR_REQUEST_SUBMITTED) {
2360+ TRACE (Trace::Error, (_T (" Unable to connect [%d]" ), result));
23142361 }
23152362 }
23162363 } else {
@@ -2535,6 +2582,8 @@ class BluetoothControl : public PluginHost::IPlugin
25352582 if (IsPaired () == true ) {
25362583 BackgroundScan (false );
25372584
2585+ const BluetoothControl::Config& config = _parent->Configuration ();
2586+
25382587 Bluetooth::HCISocket::Command::ConnectLE connect;
25392588 connect.Clear ();
25402589 connect->interval = htobs (4 *0x0010 );
@@ -2543,20 +2592,20 @@ class BluetoothControl : public PluginHost::IPlugin
25432592 connect->peer_bdaddr_type = LE_PUBLIC_ADDRESS;
25442593 connect->peer_bdaddr = *(Locator ().Data ());
25452594 connect->own_bdaddr_type = LE_PUBLIC_ADDRESS;
2546- connect->min_interval = htobs (0x000F );
2547- connect->max_interval = htobs (0x000F );
2548- connect->latency = htobs (0x0000 );
2549- connect->supervision_timeout = htobs (8000 / 10 ); // in centiseconds
2550- connect->min_ce_length = htobs (0x0001 );
2551- connect->max_ce_length = htobs (0x0001 );
2595+ connect->min_interval = htobs (config. LowEnergy . MinInterval . Value () );
2596+ connect->max_interval = htobs (config. LowEnergy . MaxInterval . Value () );
2597+ connect->latency = htobs (config. LowEnergy . Latency . Value () );
2598+ connect->supervision_timeout = htobs (config. LowEnergy . Timeout . Value () / 10 ); // in centiseconds
2599+ connect->min_ce_length = htobs (0 );
2600+ connect->max_ce_length = htobs (0 );
25522601
25532602 result = Connector ().Exchange (MAX_ACTION_TIMEOUT, connect, connect);
25542603 if (result == Core::ERROR_NONE) {
25552604 if (connect.Result () == 0 ) {
25562605 Connection (btohs (connect.Response ().handle ));
25572606 } else {
25582607 TRACE (ControlFlow, (_T (" ConnectLE command failed [%d]" ), connect.Result ()));
2559- AutoConnect ( false ) ;
2608+ result = Core::ERROR_ASYNC_FAILED ;
25602609 }
25612610 }
25622611 else {
@@ -2574,13 +2623,16 @@ class BluetoothControl : public PluginHost::IPlugin
25742623 TRACE (Trace::Information, (_T (" Canceled connection attempt" )));
25752624 }
25762625
2577- TRACE (Trace::Information, (_T (" Waiting for connection... [%d]" ), result));
2578-
2626+ TRACE (Trace::Information, (_T (" Waiting for connection..." )));
25792627 result = Core::ERROR_REQUEST_SUBMITTED;
2580- BackgroundScan (true );
2581- } else {
2582- TRACE (Trace::Error, (_T (" Failed to connect [%d]" ), result));
2583- AutoConnect (false );
2628+ }
2629+ }
2630+
2631+ if (result != Core::ERROR_NONE) {
2632+ BackgroundScan (true ); // also when waiting for BLE connection
2633+
2634+ if (result != Core::ERROR_REQUEST_SUBMITTED) {
2635+ TRACE (Trace::Error, (_T (" Unable to connect [%d]" ), result));
25842636 }
25852637 }
25862638 } else {
@@ -3250,7 +3302,7 @@ class BluetoothControl : public PluginHost::IPlugin
32503302 details.id = _parent.InterfaceID ();
32513303 details.address = info.Address ().ToString ();
32523304 details.interface = (" hci" + Core::ToString (_parent.InterfaceID ()));
3253- details.type = _parent.AdapterType ();
3305+ details.type = _parent.Configuration (). Type . Value ();
32543306 details.version = info.Version ();
32553307
32563308 if (info.Manufacturer () != 0 ) {
@@ -3687,19 +3739,13 @@ POP_WARNING()
36873739 uint32_t SaveDevice (const DeviceImpl* device) const ;
36883740
36893741 private:
3690- bool AutoConfirmPasskey () const
3691- {
3692- return (_config.AutoPasskeyConfirm .Value ());
3742+ const Config& Configuration () const {
3743+ return _config;
36933744 }
36943745 JSONRPCImplementation& JSONRPC ()
36953746 {
36963747 return (_jsonrpcImplementation);
36973748 }
3698- JBluetoothControl::adaptertype AdapterType () const
3699- {
3700- return (_config.Type .Value ());
3701- }
3702-
37033749
37043750 private:
37053751 Core::ProxyType<Web::Response> GetMethod (Core::TextSegmentIterator& index);
0 commit comments