diff options
-rw-r--r-- | api/direct_bt/BTAdapter.hpp | 17 | ||||
-rw-r--r-- | api/direct_bt/BTDevice.hpp | 5 | ||||
-rw-r--r-- | api/direct_bt/BTTypes0.hpp | 17 | ||||
-rw-r--r-- | java/jau/direct_bt/DBTAdapter.java | 13 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTAdapter.cxx | 22 | ||||
-rw-r--r-- | java/org/direct_bt/BTAdapter.java | 21 | ||||
-rw-r--r-- | java/org/direct_bt/BTDevice.java | 10 | ||||
-rw-r--r-- | java/org/direct_bt/BTRole.java | 75 | ||||
-rw-r--r-- | src/direct_bt/BTAdapter.cpp | 11 | ||||
-rw-r--r-- | src/direct_bt/BTTypes0.cpp | 9 |
10 files changed, 190 insertions, 10 deletions
diff --git a/api/direct_bt/BTAdapter.hpp b/api/direct_bt/BTAdapter.hpp index 40317cd3..d1058738 100644 --- a/api/direct_bt/BTAdapter.hpp +++ b/api/direct_bt/BTAdapter.hpp @@ -240,11 +240,19 @@ namespace direct_bt { /** * BTAdapter represents one Bluetooth Controller. * <p> + * BTAdapter roles: + * + * - ::BTRole::Master when discovery is enabled via startDiscovery(), but also per default at construction. + * - ::BTRole::Slave once advertising is enabled via startAdvertising(), explicit until next startDiscovery(). + * </p> + * <p> * Controlling Environment variables: * <pre> * - 'direct_bt.debug.adapter.event': Debug messages about events, see debug_events * </pre> * </p> + * + * @see [Bluetooth Specification](https://www.bluetooth.com/specifications/bluetooth-core-specification/) */ class BTAdapter : public BTObject { @@ -260,7 +268,7 @@ namespace direct_bt { bool hci_uses_ext_conn; /** - * Either the adapter's initially reported public address or a random address setup via HCI before scanning / discovery. + * Either the adapter's initially reported public address or a random address setup via HCI before discovery or advertising. */ BDAddressAndType visibleAddressAndType; @@ -274,6 +282,7 @@ namespace direct_bt { const uint16_t dev_id; private: + std::atomic<BTRole> btRole; // = BTRole::Master (default) HCIHandler hci; std::atomic<AdapterSetting> old_settings; @@ -494,6 +503,12 @@ namespace direct_bt { } /** + * Return the current BTRole of this adapter. + * @since 2.4.0 + */ + BTRole getRole() const noexcept { return btRole; } + + /** * Returns the current BTMode of this adapter. */ BTMode getBTMode() const noexcept { return adapterInfo.getCurrentBTMode(); } diff --git a/api/direct_bt/BTDevice.hpp b/api/direct_bt/BTDevice.hpp index 7a0c0785..7385d786 100644 --- a/api/direct_bt/BTDevice.hpp +++ b/api/direct_bt/BTDevice.hpp @@ -53,6 +53,11 @@ namespace direct_bt { class BTAdapter; // forward class AdapterStatusListener; // forward + /** + * BTDevice represents one Bluetooth device. + * + * @see [Bluetooth Specification](https://www.bluetooth.com/specifications/bluetooth-core-specification/) + */ class BTDevice : public BTObject { friend BTAdapter; // managing us: ctor and update(..) during discovery diff --git a/api/direct_bt/BTTypes0.hpp b/api/direct_bt/BTTypes0.hpp index 8eee5bf4..92045b0d 100644 --- a/api/direct_bt/BTTypes0.hpp +++ b/api/direct_bt/BTTypes0.hpp @@ -51,6 +51,23 @@ namespace direct_bt { /** + * Bluetooth device roles from the perspective of the link layer (connection initiator). + * @since 2.4.0 + */ + enum class BTRole : uint8_t { + /** Undefined role. */ + None = 0, + /** Master or *central* role, discovering remote devices and initiating connection. This is a GATT client. */ + Master = 1, + /** Slave or *peripheral* role, advertising and waiting for connections to accept. This is a GATT server. */ + Slave = 2 + }; + constexpr uint8_t number(const BTRole rhs) noexcept { + return static_cast<uint8_t>(rhs); + } + std::string to_string(const BTRole v) noexcept; + + /** * Bluetooth adapter operating mode */ enum class BTMode : uint8_t { diff --git a/java/jau/direct_bt/DBTAdapter.java b/java/jau/direct_bt/DBTAdapter.java index 440b4f8e..edf97e24 100644 --- a/java/jau/direct_bt/DBTAdapter.java +++ b/java/jau/direct_bt/DBTAdapter.java @@ -46,6 +46,7 @@ import org.direct_bt.BTGattService; import org.direct_bt.BTManager; import org.direct_bt.BTMode; import org.direct_bt.BTObject; +import org.direct_bt.BTRole; import org.direct_bt.BTType; import org.direct_bt.BTUtils; import org.direct_bt.EIRDataTypeSet; @@ -104,6 +105,18 @@ public class DBTAdapter extends DBTObject implements BTAdapter public final BTManager getManager() { return DBTManager.getManager(); } @Override + public final BTRole getRole() { + return BTRole.get(getRoleImpl()); + } + private native byte getRoleImpl(); + + @Override + public final BTMode getBTMode() { + return BTMode.get(getBTModeImpl()); + } + private native byte getBTModeImpl(); + + @Override public void close() { final DBTManager mngr = (DBTManager)DBTManager.getManager(); if( !isValid() ) { diff --git a/java/jni/direct_bt/DBTAdapter.cxx b/java/jni/direct_bt/DBTAdapter.cxx index 8f4ad701..b5bd1083 100644 --- a/java/jni/direct_bt/DBTAdapter.cxx +++ b/java/jni/direct_bt/DBTAdapter.cxx @@ -789,6 +789,28 @@ jbyte Java_jau_direct_1bt_DBTAdapter_stopDiscoveryImpl(JNIEnv *env, jobject obj) return (jbyte) number(HCIStatusCode::INTERNAL_FAILURE); } +jbyte Java_jau_direct_1bt_DBTAdapter_getRoleImpl(JNIEnv *env, jobject obj) +{ + try { + BTAdapter *adapter = jau::getJavaUplinkObject<BTAdapter>(env, obj); + return (jbyte) number( adapter->getRole() ); + } catch(...) { + rethrow_and_raise_java_exception(env); + } + return (jbyte) number( BTRole::None ); +} + +jbyte Java_jau_direct_1bt_DBTAdapter_getBTModeImpl(JNIEnv *env, jobject obj) +{ + try { + BTAdapter *adapter = jau::getJavaUplinkObject<BTAdapter>(env, obj); + return (jbyte) number( adapter->getBTMode() ); + } catch(...) { + rethrow_and_raise_java_exception(env); + } + return (jbyte) number( BTMode::NONE ); +} + jobject Java_jau_direct_1bt_DBTAdapter_getDiscoveredDevicesImpl(JNIEnv *env, jobject obj) { try { diff --git a/java/org/direct_bt/BTAdapter.java b/java/org/direct_bt/BTAdapter.java index 442d9f4e..6e4e5875 100644 --- a/java/org/direct_bt/BTAdapter.java +++ b/java/org/direct_bt/BTAdapter.java @@ -31,10 +31,15 @@ package org.direct_bt; import java.util.List; /** - * Provides access to Bluetooth adapters. + * BTAdapter represents one Bluetooth Controller. + * <p> + * BTAdapter roles: + * + * - {@link BTRole#Master} discovery is enabled via {@link #startDiscovery(boolean, boolean, short, short, byte) startDiscovery(..)}, but also per default at construction. + * - {@link BTRole#Slave} once advertising is enabled via {@link #startAdvertising(short, short, byte, byte, byte) startAdvertising(..)}, explicit until next {@link #startDiscovery(boolean, boolean, short, short, byte) startDiscovery(..)}. + * </p> * * @see [Bluetooth Specification](https://www.bluetooth.com/specifications/bluetooth-core-specification/) - * @see [BlueZ adapter API](http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/adapter-api.txt) */ public interface BTAdapter extends BTObject { @@ -43,6 +48,18 @@ public interface BTAdapter extends BTObject */ public BTManager getManager(); + /** + * Return the current {@link BTRole} of this adapter. + * @since 2.4.0 + */ + public BTRole getRole(); + + /** + * Returns the current {@link BTMode} of this adapter. + * @since 2.4.0 + */ + public BTMode getBTMode(); + /** Find a BluetoothDevice. If parameters name and address are not null, * the returned object will have to match them. * It will first check for existing objects. It will not turn on discovery diff --git a/java/org/direct_bt/BTDevice.java b/java/org/direct_bt/BTDevice.java index 70cfdba8..03d4150f 100644 --- a/java/org/direct_bt/BTDevice.java +++ b/java/org/direct_bt/BTDevice.java @@ -32,12 +32,10 @@ import java.util.List; import java.util.Map; /** - * Provides access to Bluetooth adapters. - * - * @see [Bluetooth Specification](https://www.bluetooth.com/specifications/bluetooth-core-specification/) - * @see [BlueZ device API](http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt) - * - */ + * BTDevice represents one Bluetooth device. + * + * @see [Bluetooth Specification](https://www.bluetooth.com/specifications/bluetooth-core-specification/) + */ public interface BTDevice extends BTObject { /** Find a BluetoothGattService. If parameter UUID is not null, diff --git a/java/org/direct_bt/BTRole.java b/java/org/direct_bt/BTRole.java new file mode 100644 index 00000000..ac50fa18 --- /dev/null +++ b/java/org/direct_bt/BTRole.java @@ -0,0 +1,75 @@ +/** + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2021 Gothel Software e.K. + * Copyright (c) 2021 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package org.direct_bt; + +/** + * Bluetooth device roles from the perspective of the link layer (connection initiator). + * <p> + * See {@link #get(byte)} for its native integer mapping. + * </p> + * @since 2.4.0 + */ +public enum BTRole { + /** Undefined role. */ + None ((byte)0), + /** Master or *central* role, discovering remote devices and initiating connection. This is a GATT client. */ + Master ((byte)1), + /** Slave or *peripheral* role, advertising and waiting for connections to accept. This is a GATT server. */ + Slave ((byte)2); + + public final byte value; + + /** + * Maps the specified name to a constant of BTRole. + * <p> + * Implementation simply returns {@link #valueOf(String)}. + * This maps the constant names itself to their respective constant. + * </p> + * @param name the string name to be mapped to a constant of this enum type. + * @return the corresponding constant of this enum type. + * @throws IllegalArgumentException if the specified name can't be mapped to a constant of this enum type + * as described above. + */ + public static BTRole get(final String name) throws IllegalArgumentException { + return valueOf(name); + } + + /** + * Maps the specified integer value to a constant of {@link BTRole}. + * @param value the integer value to be mapped to a constant of this enum type. + * @return the corresponding constant of this enum type, using {@link #None} if not supported. + */ + public static BTRole get(final byte value) { + switch(value) { + case (byte)0x01: return Master; + case (byte)0x02: return Slave; + default: return None; + } + } + + BTRole(final byte v) { + value = v; + } +} diff --git a/src/direct_bt/BTAdapter.cpp b/src/direct_bt/BTAdapter.cpp index bc671ea4..b588e5a0 100644 --- a/src/direct_bt/BTAdapter.cpp +++ b/src/direct_bt/BTAdapter.cpp @@ -160,6 +160,7 @@ bool BTAdapter::updateDataFromAdapterInfo() noexcept { bool BTAdapter::initialSetup() noexcept { bool ok = false; currentMetaScanType = ScanType::NONE; + btRole = BTRole::Master; keep_le_scan_alive = false; if( !mgmt.isOpen() ) { @@ -240,6 +241,7 @@ BTAdapter::BTAdapter(const BTAdapter::ctor_cookie& cc, BTManager& mgmt_, const A le_features( LE_Features::NONE ), visibleAddressAndType( adapterInfo_.addressAndType ), dev_id( adapterInfo.dev_id ), + btRole (BTRole::Master), hci( dev_id ) { (void)cc; @@ -330,6 +332,7 @@ void BTAdapter::poweredOff(const bool active) noexcept { hci.resetAllStates(false); currentMetaScanType = ScanType::NONE; + btRole = BTRole::Master; if( active ) { unlockConnectAny(); @@ -745,6 +748,7 @@ HCIStatusCode BTAdapter::startDiscovery(const bool keepAlive, const bool le_scan if( hasScanType(currentNativeScanType, ScanType::LE) ) { removeDiscoveredDevices(); + btRole = BTRole::Master; if( keep_le_scan_alive == keepAlive ) { DBG_PRINT("BTAdapter::startDiscovery: Already discovering, unchanged keepAlive %d -> %d, currentScanType[native %s, meta %s] ...\n- %s", keep_le_scan_alive.load(), keepAlive, @@ -1054,6 +1058,8 @@ HCIStatusCode BTAdapter::startAdvertising(const uint16_t adv_interval_min, const adv_interval_min, adv_interval_max, adv_type, adv_chan_map, filter_policy); if( HCIStatusCode::SUCCESS != status ) { ERR_PRINT("BTAdapter::stopAdvertising: le_start_adv failed: %s - %s", to_string(status).c_str(), toString(true).c_str()); + } else { + btRole = BTRole::Slave; } return status; } @@ -1093,7 +1099,7 @@ HCIStatusCode BTAdapter::stopAdvertising() noexcept { std::string BTAdapter::toString(bool includeDiscoveredDevices) const noexcept { std::string random_address_info = adapterInfo.addressAndType != visibleAddressAndType ? " ("+visibleAddressAndType.toString()+")" : ""; - std::string out("Adapter[BTMode "+to_string(getBTMode())+", "+adapterInfo.addressAndType.toString()+random_address_info+ + std::string out("Adapter[BTMode "+to_string(getBTMode())+", "+to_string(getRole())+", "+adapterInfo.addressAndType.toString()+random_address_info+ ", '"+getName()+"', id "+std::to_string(dev_id)+ ", curSettings"+to_string(adapterInfo.getCurrentSettingMask())+ ", valid "+std::to_string(isValid())+ @@ -1218,6 +1224,9 @@ bool BTAdapter::mgmtEvDeviceDiscoveringAny(const MgmtEvent& e, const bool hciSou event.toString().c_str()); } currentMetaScanType = nextMetaScanType; + if( isDiscovering() ) { + btRole = BTRole::Master; + } checkDiscoveryState(); diff --git a/src/direct_bt/BTTypes0.cpp b/src/direct_bt/BTTypes0.cpp index e3687835..a47a3248 100644 --- a/src/direct_bt/BTTypes0.cpp +++ b/src/direct_bt/BTTypes0.cpp @@ -347,6 +347,15 @@ static inline const int8_t * const_uint8_to_const_int8_ptr(const uint8_t* p) noe return static_cast<const int8_t *>( static_cast<void *>( const_cast<uint8_t*>( p ) ) ); } +std::string direct_bt::to_string(const BTRole v) noexcept { + switch(v) { + case BTRole::None: return "None"; + case BTRole::Master: return "Master"; + case BTRole::Slave: return "Slave"; + } + return "Unknown BTRole "+jau::to_hexstring(number(v)); +} + std::string direct_bt::to_string(const BTMode v) noexcept { switch(v) { case BTMode::NONE: return "NONE"; |