summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2022-05-05 22:55:52 +0200
committerSven Gothel <[email protected]>2022-05-05 22:55:52 +0200
commitb3d62d2336744481bc83377d780d9ac79f534207 (patch)
treeb608ab8dc98fabf1b14ab4515a070dcc856f40aa
parent53159c09d953475e1816f1c0c5be6c3cdb76b545 (diff)
Trial (Java + C++): DBTEndpoint, DBTClientTest, DBTServerTest: Add abstraction to plug-in any client/server instance into DBTClientServer1x
Further add TestDBTProvokeClientServer_i470 (java trial, copied from native trial)
-rw-r--r--trial/direct_bt/dbt_client00.hpp60
-rw-r--r--trial/direct_bt/dbt_client01.hpp50
-rw-r--r--trial/direct_bt/dbt_client_server1x.hpp62
-rw-r--r--trial/direct_bt/dbt_client_test.hpp24
-rw-r--r--trial/direct_bt/dbt_constants.hpp6
-rw-r--r--trial/direct_bt/dbt_endpoint.hpp6
-rw-r--r--trial/direct_bt/dbt_server00.hpp32
-rw-r--r--trial/direct_bt/dbt_server01.hpp63
-rw-r--r--trial/direct_bt/test_client_server00.cpp2
-rw-r--r--trial/direct_bt/test_client_server10_NoEnc.cpp12
-rw-r--r--trial/direct_bt/test_client_server12_NoEnc.cpp12
-rw-r--r--trial/direct_bt/test_client_server20_SC0.cpp12
-rw-r--r--trial/direct_bt/test_client_server22_SC0.cpp12
-rw-r--r--trial/direct_bt/test_client_server30_SC1.cpp12
-rw-r--r--trial/direct_bt/test_client_server32_SC1.cpp12
-rw-r--r--trial/direct_bt/test_provoke_client_server_i470.cpp221
-rw-r--r--trial/java/trial/org/direct_bt/DBTClient00.java103
-rw-r--r--trial/java/trial/org/direct_bt/DBTClient01.java679
-rw-r--r--trial/java/trial/org/direct_bt/DBTClientServer1x.java61
-rw-r--r--trial/java/trial/org/direct_bt/DBTClientTest.java25
-rw-r--r--trial/java/trial/org/direct_bt/DBTEndpoint.java7
-rw-r--r--trial/java/trial/org/direct_bt/DBTServer00.java50
-rw-r--r--trial/java/trial/org/direct_bt/DBTServer01.java842
-rw-r--r--trial/java/trial/org/direct_bt/ExpectedPairing.java31
-rw-r--r--trial/java/trial/org/direct_bt/TestDBTClientServer00.java2
-rw-r--r--trial/java/trial/org/direct_bt/TestDBTClientServer10_NoEnc.java12
-rw-r--r--trial/java/trial/org/direct_bt/TestDBTClientServer12_NoEnc.java12
-rw-r--r--trial/java/trial/org/direct_bt/TestDBTClientServer20_SC0.java12
-rw-r--r--trial/java/trial/org/direct_bt/TestDBTClientServer22_SC0.java12
-rw-r--r--trial/java/trial/org/direct_bt/TestDBTClientServer30_SC1.java12
-rw-r--r--trial/java/trial/org/direct_bt/TestDBTClientServer32_SC1.java12
-rw-r--r--trial/java/trial/org/direct_bt/TestDBTProvokeClientServer_i470.java69
32 files changed, 2098 insertions, 441 deletions
diff --git a/trial/direct_bt/dbt_client00.hpp b/trial/direct_bt/dbt_client00.hpp
index abf56906..047a8f3b 100644
--- a/trial/direct_bt/dbt_client00.hpp
+++ b/trial/direct_bt/dbt_client00.hpp
@@ -30,7 +30,7 @@
#include "dbt_client_test.hpp"
class DBTClient00;
-typedef std::shared_ptr<DBTClient00> DBTClientRef;
+typedef std::shared_ptr<DBTClient00> DBTClient00Ref;
using namespace jau;
using namespace jau::fractions_i64_literals;
@@ -39,22 +39,9 @@ using namespace jau::fractions_i64_literals;
* This central BTRole::Master participant works with DBTServer00.
*/
class DBTClient00 : public DBTClientTest {
- public:
- /**
- * Disconnect after processing.
- *
- * Default is `false`.
- */
+ private:
bool KEEP_CONNECTED = false;
- /**
- * Remove device when disconnecting.
- *
- * This removes the device from all instances within adapter
- * and hence all potential side-effects of the current instance.
- *
- * Default is `false`, since it is good to test whether such side-effects exists.
- */
bool REMOVE_DEVICE = false;
DiscoveryPolicy discoveryPolicy = DiscoveryPolicy::PAUSE_CONNECTED_UNTIL_READY; // default value
@@ -64,13 +51,14 @@ class DBTClient00 : public DBTClientTest {
jau::sc_atomic_int deviceReadyCount = 0;
+ jau::sc_atomic_int disconnectCount = 0;
jau::sc_atomic_int notificationsReceived = 0;
jau::sc_atomic_int indicationsReceived = 0;
jau::sc_atomic_int completedGATTCommands = 0;
- jau::sc_atomic_int completedMeasurements = 0;
+ jau::sc_atomic_int completedMeasurementsTotal = 0;
+ jau::sc_atomic_int completedMeasurementsSuccess = 0;
jau::sc_atomic_int measurementsLeft = 0;
- private:
const uint64_t timestamp_t0 = getCurrentMilliseconds();
// const fraction_i64 timestamp_t0 = jau::getMonotonicMicroseconds();
@@ -228,6 +216,8 @@ class DBTClient00 : public DBTClientTest {
to_hexstring(handle).c_str(), device->toString(true).c_str());
(void)timestamp;
+ parent.disconnectCount++;
+
std::thread dc(&DBTClient00::removeDevice, &parent, device); // @suppress("Invalid arguments")
dc.detach();
}
@@ -296,6 +286,32 @@ class DBTClient00 : public DBTClientTest {
BTAdapterRef getAdapter() override { return clientAdapter; }
+ void setProtocolSessionsLeft(const int v) override {
+ measurementsLeft = v;
+ }
+ int getProtocolSessionsLeft() override {
+ return measurementsLeft;
+ }
+ int getProtocolSessionsDoneTotal() override {
+ return completedMeasurementsTotal;
+ }
+ int getProtocolSessionsDoneSuccess() override {
+ return completedMeasurementsSuccess;
+ }
+ int getDisconnectCount() override {
+ return disconnectCount;
+ }
+
+ void setDiscoveryPolicy(const DiscoveryPolicy v) override {
+ discoveryPolicy = v;
+ }
+ void setKeepConnected(const bool v) override {
+ KEEP_CONNECTED = v;
+ }
+ void setRemoveDevice(const bool v) override {
+ REMOVE_DEVICE = v;
+ }
+
private:
void resetLastProcessingStats() {
completedGATTCommands = 0;
@@ -489,7 +505,7 @@ class DBTClient00 : public DBTClientTest {
const fraction_i64 td = ( getMonotonicTime() - t0 ).to_fraction_i64();
timeout = 3_s < td;
if( !timeout ) {
- std::this_thread::sleep_for(std::chrono::milliseconds(17));
+ jau::sleep_for( 17_ms );
}
}
} while( !success && !timeout );
@@ -524,9 +540,6 @@ class DBTClient00 : public DBTClientTest {
}
// cmd.close(); // done via dtor
}
-
- std::this_thread::sleep_for(std::chrono::milliseconds(1000));
- success = true;
} catch ( std::exception & e ) {
fprintf_td(stderr, "****** Client Processing Ready Device: Exception.2 caught for %s: %s\n", device->toString().c_str(), e.what());
}
@@ -557,8 +570,9 @@ class DBTClient00 : public DBTClientTest {
}
}
+ completedMeasurementsTotal++;
if( success ) {
- completedMeasurements++;
+ completedMeasurementsSuccess++;
}
if( 0 < measurementsLeft ) {
measurementsLeft--;
@@ -566,7 +580,7 @@ class DBTClient00 : public DBTClientTest {
fprintf_td(stderr, "****** Client Processing Ready Device: Success %d; Measurements completed %d"
", left %d; Received notitifications %d, indications %d"
"; Completed GATT commands %d: %s\n",
- success, completedMeasurements.load(),
+ success, completedMeasurementsSuccess.load(),
measurementsLeft.load(), notificationsReceived.load(), indicationsReceived.load(),
completedGATTCommands.load(), device->getAddressAndType().toString().c_str());
}
diff --git a/trial/direct_bt/dbt_client01.hpp b/trial/direct_bt/dbt_client01.hpp
index 7795bdb0..ce05e392 100644
--- a/trial/direct_bt/dbt_client01.hpp
+++ b/trial/direct_bt/dbt_client01.hpp
@@ -22,15 +22,15 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#ifndef DBT_CLIENT00_HPP_
-#define DBT_CLIENT00_HPP_
+#ifndef DBT_CLIENT01_HPP_
+#define DBT_CLIENT01_HPP_
#include "dbt_constants.hpp"
#include "dbt_client_test.hpp"
class DBTClient01;
-typedef std::shared_ptr<DBTClient01> DBTClientRef;
+typedef std::shared_ptr<DBTClient01> DBTClient01Ref;
using namespace jau;
using namespace jau::fractions_i64_literals;
@@ -64,10 +64,12 @@ class DBTClient01 : public DBTClientTest {
jau::sc_atomic_int deviceReadyCount = 0;
+ jau::sc_atomic_int disconnectCount = 0;
jau::sc_atomic_int notificationsReceived = 0;
jau::sc_atomic_int indicationsReceived = 0;
jau::sc_atomic_int completedGATTCommands = 0;
- jau::sc_atomic_int completedMeasurements = 0;
+ jau::sc_atomic_int completedMeasurementsTotal = 0;
+ jau::sc_atomic_int completedMeasurementsSuccess = 0;
jau::sc_atomic_int measurementsLeft = 0;
private:
@@ -214,6 +216,8 @@ class DBTClient01 : public DBTClientTest {
to_hexstring(handle).c_str(), device->toString(true).c_str());
(void)timestamp;
+ parent.disconnectCount++;
+
std::thread dc(&DBTClient01::removeDevice, &parent, device); // @suppress("Invalid arguments")
dc.detach();
}
@@ -282,6 +286,32 @@ class DBTClient01 : public DBTClientTest {
BTAdapterRef getAdapter() override { return clientAdapter; }
+ void setProtocolSessionsLeft(const int v) override {
+ measurementsLeft = v;
+ }
+ int getProtocolSessionsLeft() override {
+ return measurementsLeft;
+ }
+ int getProtocolSessionsDoneTotal() override {
+ return completedMeasurementsTotal;
+ }
+ int getProtocolSessionsDoneSuccess() override {
+ return completedMeasurementsSuccess;
+ }
+ int getDisconnectCount() override {
+ return disconnectCount;
+ }
+
+ void setDiscoveryPolicy(const DiscoveryPolicy v) override {
+ discoveryPolicy = v;
+ }
+ void setKeepConnected(const bool v) override {
+ KEEP_CONNECTED = v;
+ }
+ void setRemoveDevice(const bool v) override {
+ REMOVE_DEVICE = v;
+ }
+
private:
void resetLastProcessingStats() {
completedGATTCommands = 0;
@@ -475,7 +505,7 @@ class DBTClient01 : public DBTClientTest {
const fraction_i64 td = ( getMonotonicTime() - t0 ).to_fraction_i64();
timeout = 3_s < td;
if( !timeout ) {
- std::this_thread::sleep_for(std::chrono::milliseconds(17));
+ jau::sleep_for( 17_ms );
}
}
} while( !success && !timeout );
@@ -510,9 +540,6 @@ class DBTClient01 : public DBTClientTest {
}
// cmd.close(); // done via dtor
}
-
- std::this_thread::sleep_for(std::chrono::milliseconds(1000));
- success = true;
} catch ( std::exception & e ) {
fprintf_td(stderr, "****** Client Processing Ready Device: Exception.2 caught for %s: %s\n", device->toString().c_str(), e.what());
}
@@ -538,8 +565,9 @@ class DBTClient01 : public DBTClientTest {
}
}
+ completedMeasurementsTotal++;
if( success ) {
- completedMeasurements++;
+ completedMeasurementsSuccess++;
}
if( 0 < measurementsLeft ) {
measurementsLeft--;
@@ -547,7 +575,7 @@ class DBTClient01 : public DBTClientTest {
fprintf_td(stderr, "****** Client Processing Ready Device: Success %d; Measurements completed %d"
", left %d; Received notitifications %d, indications %d"
"; Completed GATT commands %d: %s\n",
- success, completedMeasurements.load(),
+ success, completedMeasurementsSuccess.load(),
measurementsLeft.load(), notificationsReceived.load(), indicationsReceived.load(),
completedGATTCommands.load(), device->getAddressAndType().toString().c_str());
}
@@ -652,4 +680,4 @@ class DBTClient01 : public DBTClientTest {
}
};
-#endif /* DBT_CLIENT00_HPP_ */
+#endif /* DBT_CLIENT01_HPP_ */
diff --git a/trial/direct_bt/dbt_client_server1x.hpp b/trial/direct_bt/dbt_client_server1x.hpp
index 045e9328..4ed2a0cc 100644
--- a/trial/direct_bt/dbt_client_server1x.hpp
+++ b/trial/direct_bt/dbt_client_server1x.hpp
@@ -54,10 +54,22 @@ class DBTClientServer1x {
public:
void test8x_fullCycle(const std::string& suffix, const int protocolSessionCount, const bool server_client_order,
- const bool serverSC, const BTSecurityLevel secLevelServer, const bool serverShallHaveKeys,
- const BTSecurityLevel secLevelClient, const bool clientShallHaveKeys)
+ const bool serverSC, const BTSecurityLevel secLevelServer, const ExpectedPairing serverExpPairing,
+ const BTSecurityLevel secLevelClient, const ExpectedPairing clientExpPairing)
{
- (void)serverShallHaveKeys;
+ std::shared_ptr<DBTServer00> server = std::make_shared<DBTServer00>("S-"+suffix, EUI48::ALL_DEVICE, BTMode::DUAL, serverSC, secLevelServer);
+ std::shared_ptr<DBTClient00> client = std::make_shared<DBTClient00>("C-"+suffix, EUI48::ALL_DEVICE, BTMode::DUAL);
+ test8x_fullCycle(suffix, protocolSessionCount, server_client_order,
+ server, secLevelServer, serverExpPairing,
+ client, secLevelClient, clientExpPairing);
+ }
+
+ void test8x_fullCycle(const std::string& suffix, const int protocolSessionCount, const bool server_client_order,
+ std::shared_ptr<DBTServerTest> server, const BTSecurityLevel secLevelServer, const ExpectedPairing serverExpPairing,
+ std::shared_ptr<DBTClientTest> client, const BTSecurityLevel secLevelClient, const ExpectedPairing clientExpPairing)
+ {
+ (void)secLevelServer;
+ (void)serverExpPairing;
const jau::fraction_timespec t0 = jau::getMonotonicTime();
@@ -72,10 +84,12 @@ class DBTClientServer1x {
REQUIRE( adapters.size() >= 2 );
}
- std::shared_ptr<DBTServer00> server = std::make_shared<DBTServer00>("S-"+suffix, EUI48::ALL_DEVICE, BTMode::DUAL, serverSC, secLevelServer);
- server->servingProtocolSessionsLeft = protocolSessionCount;
+ server->setProtocolSessionsLeft(protocolSessionCount);
- std::shared_ptr<DBTClient00> client = std::make_shared<DBTClient00>("C-"+suffix, EUI48::ALL_DEVICE, BTMode::DUAL);
+ client->setProtocolSessionsLeft( protocolSessionCount );
+ client->setKeepConnected( false ); // default, auto-disconnect after work is done
+ client->setRemoveDevice( false ); // default, test side-effects
+ client->setDiscoveryPolicy( DiscoveryPolicy::PAUSE_CONNECTED_UNTIL_DISCONNECTED );
ChangedAdapterSetCallback myChangedAdapterSetFunc = DBTEndpoint::initChangedAdapterSetListener(manager,
server_client_order ? std::vector<DBTEndpointRef>{ server, client } : std::vector<DBTEndpointRef>{ client, server } );
@@ -86,10 +100,6 @@ class DBTClientServer1x {
BTSecurityRegistry::Entry * sec = BTSecurityRegistry::getOrCreate(serverName);
sec->sec_level = secLevelClient;
}
- client->KEEP_CONNECTED = false; // default, auto-disconnect after work is done
- client->REMOVE_DEVICE = false; // default, test side-effects
- client->measurementsLeft = protocolSessionCount;
- client->discoveryPolicy = DiscoveryPolicy::PAUSE_CONNECTED_UNTIL_DISCONNECTED;
{
const std::lock_guard<std::mutex> lock(mtx_sync); // RAII-style acquire and relinquish via destructor
@@ -140,12 +150,12 @@ class DBTClientServer1x {
do {
{
const std::lock_guard<std::mutex> lock(mtx_sync); // RAII-style acquire and relinquish via destructor
- done = ! ( protocolSessionCount > server->servedProtocolSessionsTotal ||
- protocolSessionCount > client->completedMeasurements ||
+ done = ! ( protocolSessionCount > server->getProtocolSessionsDoneSuccess() ||
+ protocolSessionCount > client->getProtocolSessionsDoneSuccess() ||
nullptr == lastCompletedDevice ||
lastCompletedDevice->getConnected() );
}
- max_connections_hit = ( protocolSessionCount * DBTConstants::max_connections_per_session ) <= server->disconnectCount;
+ max_connections_hit = ( protocolSessionCount * DBTConstants::max_connections_per_session ) <= server->getDisconnectCount();
test_duration = ( jau::getMonotonicTime() - t0 ).to_fraction_i64();
timeout = 0_s < timeout_value && timeout_value <= test_duration + 500_ms; // let's timeout here before our timeout timer
if( !done && !max_connections_hit && !timeout ) {
@@ -158,23 +168,25 @@ class DBTClientServer1x {
fprintf_td(stderr, "****** Test Stats: duration %" PRIi64 " ms, timeout[hit %d, value %s sec], max_connections hit %d\n",
test_duration.to_ms(), timeout, timeout_value.to_string(true).c_str(), max_connections_hit);
fprintf_td(stderr, " Server ProtocolSessions[success %d/%d total, requested %d], disconnects %d of %d max\n",
- server->servedProtocolSessionsSuccess.load(), server->servedProtocolSessionsTotal.load(), protocolSessionCount,
- server->disconnectCount.load(), ( protocolSessionCount * DBTConstants::max_connections_per_session ));
- fprintf_td(stderr, " Client ProtocolSessions success %d \n",
- client->completedMeasurements.load());
+ server->getProtocolSessionsDoneSuccess(), server->getProtocolSessionsDoneTotal(), protocolSessionCount,
+ server->getDisconnectCount(), ( protocolSessionCount * DBTConstants::max_connections_per_session ));
+ fprintf_td(stderr, " Client ProtocolSessions[success %d/%d total, requested %d], disconnects %d of %d max\n",
+ client->getProtocolSessionsDoneSuccess(), client->getProtocolSessionsDoneTotal(), protocolSessionCount,
+ client->getDisconnectCount(), ( protocolSessionCount * DBTConstants::max_connections_per_session ));
fprintf_td(stderr, "\n\n");
REQUIRE( false == max_connections_hit );
REQUIRE( false == timeout );
{
const std::lock_guard<std::mutex> lock(mtx_sync); // RAII-style acquire and relinquish via destructor
- REQUIRE( protocolSessionCount == server->servedProtocolSessionsTotal );
- REQUIRE( protocolSessionCount == server->servedProtocolSessionsSuccess );
- REQUIRE( protocolSessionCount == client->completedMeasurements );
+ REQUIRE( protocolSessionCount <= server->getProtocolSessionsDoneTotal() );
+ REQUIRE( protocolSessionCount == server->getProtocolSessionsDoneSuccess() );
+ REQUIRE( protocolSessionCount <= client->getProtocolSessionsDoneTotal() );
+ REQUIRE( protocolSessionCount == client->getProtocolSessionsDoneSuccess() );
REQUIRE( nullptr != lastCompletedDevice );
REQUIRE( EIRDataType::NONE != lastCompletedDeviceEIR.getEIRDataMask() );
REQUIRE( false == lastCompletedDevice->getConnected() );
- REQUIRE( ( protocolSessionCount * DBTConstants::max_connections_per_session ) > server->disconnectCount );
+ REQUIRE( ( protocolSessionCount * DBTConstants::max_connections_per_session ) > server->getDisconnectCount() );
}
//
@@ -197,15 +209,19 @@ class DBTClientServer1x {
const BTSecurityLevel clientKeysSecLevel = clientKeys.getSecLevel();
REQUIRE( secLevelClient == clientKeysSecLevel);
{
- if( clientShallHaveKeys ) {
+ if( ExpectedPairing::PREPAIRED == clientExpPairing && BTSecurityLevel::NONE < secLevelClient ) {
// Using encryption: pre-paired
REQUIRE( PairingMode::PRE_PAIRED == lastCompletedDevicePairingMode );
REQUIRE( BTSecurityLevel::ENC_ONLY == lastCompletedDeviceSecurityLevel ); // pre-paired fixed level, no auth
- } else if( BTSecurityLevel::NONE < secLevelClient ) {
+ } else if( ExpectedPairing::NEW_PAIRING == clientExpPairing && BTSecurityLevel::NONE < secLevelClient ) {
// Using encryption: Newly paired
REQUIRE( PairingMode::PRE_PAIRED != lastCompletedDevicePairingMode );
REQUIRE_MSG( "PairingMode client "+to_string(lastCompletedDevicePairingMode)+" not > NONE", PairingMode::NONE < lastCompletedDevicePairingMode );
REQUIRE_MSG( "SecurityLevel client "+to_string(lastCompletedDeviceSecurityLevel)+" not >= "+to_string(secLevelClient), secLevelClient <= lastCompletedDeviceSecurityLevel );
+ } else if( ExpectedPairing::DONT_CARE == clientExpPairing && BTSecurityLevel::NONE < secLevelClient ) {
+ // Any encryption, any pairing
+ REQUIRE_MSG( "PairingMode client "+to_string(lastCompletedDevicePairingMode)+" not > NONE", PairingMode::NONE < lastCompletedDevicePairingMode );
+ REQUIRE_MSG( "SecurityLevel client "+to_string(lastCompletedDeviceSecurityLevel)+" not >= "+to_string(secLevelClient), secLevelClient <= lastCompletedDeviceSecurityLevel );
} else {
// No encryption: No pairing
REQUIRE( PairingMode::NONE == lastCompletedDevicePairingMode );
diff --git a/trial/direct_bt/dbt_client_test.hpp b/trial/direct_bt/dbt_client_test.hpp
index 5671180b..d97bb3b3 100644
--- a/trial/direct_bt/dbt_client_test.hpp
+++ b/trial/direct_bt/dbt_client_test.hpp
@@ -33,6 +33,30 @@ typedef std::shared_ptr<DBTClientTest> DBTClientTestRef;
class DBTClientTest : public DBTEndpoint {
public:
+ /**
+ * Set DiscoveryPolicy
+ *
+ * Default is {@link DiscoveryPolicy#PAUSE_CONNECTED_UNTIL_READY}
+ */
+ virtual void setDiscoveryPolicy(const DiscoveryPolicy v) = 0;
+
+ /**
+ * Set disconnect after processing.
+ *
+ * Default is `false`.
+ */
+ virtual void setKeepConnected(const bool v) = 0;
+
+ /**
+ * Set remove device when disconnecting.
+ *
+ * This removes the device from all instances within adapter
+ * and hence all potential side-effects of the current instance.
+ *
+ * Default is `false`, since it is good to test whether such side-effects exists.
+ */
+ virtual void setRemoveDevice(const bool v) = 0;
+
virtual HCIStatusCode startDiscovery(const std::string& msg) = 0;
virtual HCIStatusCode stopDiscovery(const std::string& msg) = 0;
diff --git a/trial/direct_bt/dbt_constants.hpp b/trial/direct_bt/dbt_constants.hpp
index 2dff7285..0218d21f 100644
--- a/trial/direct_bt/dbt_constants.hpp
+++ b/trial/direct_bt/dbt_constants.hpp
@@ -62,6 +62,12 @@ class DBTConstants {
static const std::vector<uint8_t> FailHandshakeCommandData;
};
+enum class ExpectedPairing {
+ DONT_CARE,
+ NEW_PAIRING,
+ PREPAIRED
+};
+
const jau::uuid128_t DBTConstants::DataServiceUUID = jau::uuid128_t("d0ca6bf3-3d50-4760-98e5-fc5883e93712");
const jau::uuid128_t DBTConstants::StaticDataUUID = jau::uuid128_t("d0ca6bf3-3d51-4760-98e5-fc5883e93712");
const jau::uuid128_t DBTConstants::CommandUUID = jau::uuid128_t("d0ca6bf3-3d52-4760-98e5-fc5883e93712");
diff --git a/trial/direct_bt/dbt_endpoint.hpp b/trial/direct_bt/dbt_endpoint.hpp
index 3d7c352c..4146ceb6 100644
--- a/trial/direct_bt/dbt_endpoint.hpp
+++ b/trial/direct_bt/dbt_endpoint.hpp
@@ -68,6 +68,12 @@ class DBTEndpoint {
virtual void close(const std::string& msg) = 0;
+ virtual void setProtocolSessionsLeft(const int v) = 0;
+ virtual int getProtocolSessionsLeft() = 0;
+ virtual int getProtocolSessionsDoneTotal() = 0;
+ virtual int getProtocolSessionsDoneSuccess() = 0;
+ virtual int getDisconnectCount() = 0;
+
/**
* Initialize the given adapter for this endpoint.
*
diff --git a/trial/direct_bt/dbt_server00.hpp b/trial/direct_bt/dbt_server00.hpp
index 362b0141..9565e0b1 100644
--- a/trial/direct_bt/dbt_server00.hpp
+++ b/trial/direct_bt/dbt_server00.hpp
@@ -70,9 +70,11 @@ class DBTServer00 : public DBTServerTest {
bool use_SC = true;
BTSecurityLevel adapterSecurityLevel = BTSecurityLevel::UNSET;
- // DBGattServerRef dbGattServer = std::make_shared<DBGattServer>(
- // DBGattServerRef dbGattServer = new DBGattServer(
- // DBGattServerRef dbGattServer( new DBGattServer(
+ jau::sc_atomic_int disconnectCount = 0;
+ jau::sc_atomic_int servedProtocolSessionsTotal = 0;
+ jau::sc_atomic_int servedProtocolSessionsSuccess = 0;
+ jau::sc_atomic_int servingProtocolSessionsLeft = 1;
+
DBGattServerRef dbGattServer = std::make_shared<DBGattServer>(
/* services: */
jau::make_darray( // DBGattService
@@ -152,14 +154,6 @@ class DBTServer00 : public DBTServerTest {
std::mutex mtx_sync;
BTDeviceRef connectedDevice;
- public:
- jau::sc_atomic_int disconnectCount = 0;
- jau::sc_atomic_int servedProtocolSessionsTotal = 0;
- jau::sc_atomic_int servedProtocolSessionsSuccess = 0;
- jau::sc_atomic_int servingProtocolSessionsLeft = 1;
-
- private:
-
void setDevice(BTDeviceRef cd) {
const std::lock_guard<std::mutex> lock(mtx_sync); // RAII-style acquire and relinquish via destructor
connectedDevice = cd;
@@ -618,6 +612,22 @@ class DBTServer00 : public DBTServerTest {
fprintf_td(stderr, "****** Server Close.X: %s\n", msg.c_str());
}
+ void setProtocolSessionsLeft(const int v) override {
+ servingProtocolSessionsLeft = v;
+ }
+ int getProtocolSessionsLeft() override {
+ return servingProtocolSessionsLeft;
+ }
+ int getProtocolSessionsDoneTotal() override {
+ return servedProtocolSessionsTotal;
+ }
+ int getProtocolSessionsDoneSuccess() override {
+ return servedProtocolSessionsSuccess;
+ }
+ int getDisconnectCount() override {
+ return disconnectCount;
+ }
+
private:
HCIStatusCode stopAdvertising(std::string msg) {
HCIStatusCode status = serverAdapter->stopAdvertising();
diff --git a/trial/direct_bt/dbt_server01.hpp b/trial/direct_bt/dbt_server01.hpp
index 33e34807..911aaf4d 100644
--- a/trial/direct_bt/dbt_server01.hpp
+++ b/trial/direct_bt/dbt_server01.hpp
@@ -22,15 +22,15 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#ifndef DBT_SERVER00_HPP_
-#define DBT_SERVER00_HPP_
+#ifndef DBT_SERVER01_HPP_
+#define DBT_SERVER01_HPP_
#include "dbt_constants.hpp"
#include "dbt_server_test.hpp"
class DBTServer01;
-typedef std::shared_ptr<DBTServer01> DBTServer00Ref;
+typedef std::shared_ptr<DBTServer01> DBTServer01Ref;
using namespace jau;
@@ -70,9 +70,11 @@ class DBTServer01 : public DBTServerTest {
bool use_SC = true;
BTSecurityLevel adapterSecurityLevel = BTSecurityLevel::UNSET;
- // DBGattServerRef dbGattServer = std::make_shared<DBGattServer>(
- // DBGattServerRef dbGattServer = new DBGattServer(
- // DBGattServerRef dbGattServer( new DBGattServer(
+ jau::sc_atomic_int disconnectCount = 0;
+ jau::sc_atomic_int servedProtocolSessionsTotal = 0;
+ jau::sc_atomic_int servedProtocolSessionsSuccess = 0;
+ jau::sc_atomic_int servingProtocolSessionsLeft = 1;
+
DBGattServerRef dbGattServer = std::make_shared<DBGattServer>(
/* services: */
jau::make_darray( // DBGattService
@@ -152,14 +154,6 @@ class DBTServer01 : public DBTServerTest {
std::mutex mtx_sync;
BTDeviceRef connectedDevice;
- public:
- jau::sc_atomic_int disconnectCount = 0;
- jau::sc_atomic_int servedProtocolSessionsTotal = 0;
- jau::sc_atomic_int servedProtocolSessionsSuccess = 0;
- jau::sc_atomic_int servingProtocolSessionsLeft = 1;
-
- private:
-
void setDevice(BTDeviceRef cd) {
const std::lock_guard<std::mutex> lock(mtx_sync); // RAII-style acquire and relinquish via destructor
connectedDevice = cd;
@@ -387,6 +381,17 @@ class DBTServer01 : public DBTServerTest {
}
}
+ bool onceDisconnect = true;
+
+ void disconnectDevice() {
+ jau::sleep_for( 300_ms );
+ BTDeviceRef connectedDevice_ = parent.getDevice();
+ fprintf_td(stderr, "****** Server GATT::disconnectDevice(sessions [%d ok / %d total], left %d): client %s\n",
+ parent.servedProtocolSessionsSuccess.load(), parent.servedProtocolSessionsTotal.load(), parent.servingProtocolSessionsLeft.load(),
+ connectedDevice_->toString().c_str());
+ connectedDevice_->disconnect();
+ }
+
public:
MyGATTServerListener(DBTServer01& p)
@@ -418,17 +423,7 @@ class DBTServer01 : public DBTServerTest {
}
}
- bool onceDisconnect = true;
-
- void disconnectDevice() {
- jau::sleep_for( 300_ms );
- BTDeviceRef connectedDevice_ = parent.getDevice();
- fprintf_td(stderr, "****** Server GATT::disconnectDevice(sessions [%d ok / %d total], left %d): client %s\n",
- parent.servedProtocolSessionsSuccess.load(), parent.servedProtocolSessionsTotal.load(), parent.servingProtocolSessionsLeft.load(),
- connectedDevice_->toString().c_str());
- connectedDevice_->disconnect();
- }
-
+ public:
void connected(BTDeviceRef device, const uint16_t initialMTU) override {
const bool match = parent.matches(device);
fprintf_td(stderr, "****** Server GATT::connected(match %d): initMTU %d, %s\n",
@@ -637,6 +632,22 @@ class DBTServer01 : public DBTServerTest {
fprintf_td(stderr, "****** Server Close.X: %s\n", msg.c_str());
}
+ void setProtocolSessionsLeft(const int v) override {
+ servingProtocolSessionsLeft = v;
+ }
+ int getProtocolSessionsLeft() override {
+ return servingProtocolSessionsLeft;
+ }
+ int getProtocolSessionsDoneTotal() override {
+ return servedProtocolSessionsTotal;
+ }
+ int getProtocolSessionsDoneSuccess() override {
+ return servedProtocolSessionsSuccess;
+ }
+ int getDisconnectCount() override {
+ return disconnectCount;
+ }
+
private:
HCIStatusCode stopAdvertising(std::string msg) {
HCIStatusCode status = serverAdapter->stopAdvertising();
@@ -789,4 +800,4 @@ class DBTServer01 : public DBTServerTest {
}
};
-#endif // DBT_SERVER00_HPP_
+#endif // DBT_SERVER01_HPP_
diff --git a/trial/direct_bt/test_client_server00.cpp b/trial/direct_bt/test_client_server00.cpp
index 2c342cbf..e4d39908 100644
--- a/trial/direct_bt/test_client_server00.cpp
+++ b/trial/direct_bt/test_client_server00.cpp
@@ -97,7 +97,7 @@ TEST_CASE( "Server StartStop and SwitchRole Trial 10", "[trial][startstop][switc
const std::string serverName = "TestDBTCS00-S-T10";
std::shared_ptr<DBTServer00> server = std::make_shared<DBTServer00>(serverName, EUI48::ALL_DEVICE, BTMode::DUAL, true /* SC */, BTSecurityLevel::NONE);
- server->servingProtocolSessionsLeft = 1;
+ server->setProtocolSessionsLeft(1);
ChangedAdapterSetCallback myChangedAdapterSetFunc = DBTEndpoint::initChangedAdapterSetListener(manager, { server });
diff --git a/trial/direct_bt/test_client_server10_NoEnc.cpp b/trial/direct_bt/test_client_server10_NoEnc.cpp
index 51b4dca8..ada2271a 100644
--- a/trial/direct_bt/test_client_server10_NoEnc.cpp
+++ b/trial/direct_bt/test_client_server10_NoEnc.cpp
@@ -53,10 +53,10 @@ class TestDBTClientServer10_NoEnc : public DBTClientServer1x {
void test00_FullCycle_EncNone() {
base_test_framework.setupTest( 20_s );
{
- const bool serverShallHaveKeys = false;
- const bool clientShallHaveKeys = false;
+ const ExpectedPairing serverExpPairing = ExpectedPairing::DONT_CARE;
+ const ExpectedPairing clientExpPairing = ExpectedPairing::DONT_CARE;
test8x_fullCycle("10", 1 /* protocolSessionCount */, true /* server_client_order */, serverSC,
- BTSecurityLevel::NONE, serverShallHaveKeys, BTSecurityLevel::NONE, clientShallHaveKeys);
+ BTSecurityLevel::NONE, serverExpPairing, BTSecurityLevel::NONE, clientExpPairing);
}
base_test_framework.cleanupTest();
}
@@ -64,10 +64,10 @@ class TestDBTClientServer10_NoEnc : public DBTClientServer1x {
void test01_FullCycle_EncNone() {
base_test_framework.setupTest( 30_s );
{
- const bool serverShallHaveKeys = false;
- const bool clientShallHaveKeys = false;
+ const ExpectedPairing serverExpPairing = ExpectedPairing::DONT_CARE;
+ const ExpectedPairing clientExpPairing = ExpectedPairing::DONT_CARE;
test8x_fullCycle("11", 2 /* protocolSessionCount */, true /* server_client_order */, serverSC,
- BTSecurityLevel::NONE, serverShallHaveKeys, BTSecurityLevel::NONE, clientShallHaveKeys);
+ BTSecurityLevel::NONE, serverExpPairing, BTSecurityLevel::NONE, clientExpPairing);
}
base_test_framework.cleanupTest();
}
diff --git a/trial/direct_bt/test_client_server12_NoEnc.cpp b/trial/direct_bt/test_client_server12_NoEnc.cpp
index 37c5b4d5..37c49964 100644
--- a/trial/direct_bt/test_client_server12_NoEnc.cpp
+++ b/trial/direct_bt/test_client_server12_NoEnc.cpp
@@ -53,10 +53,10 @@ class TestDBTClientServer12_NoEnc : public DBTClientServer1x {
void test02_FullCycle_EncNone() {
base_test_framework.setupTest( 20_s );
{
- const bool serverShallHaveKeys = false;
- const bool clientShallHaveKeys = false;
+ const ExpectedPairing serverExpPairing = ExpectedPairing::DONT_CARE;
+ const ExpectedPairing clientExpPairing = ExpectedPairing::DONT_CARE;
test8x_fullCycle("12", 1 /* protocolSessionCount */, false /* server_client_order */, serverSC,
- BTSecurityLevel::NONE, serverShallHaveKeys, BTSecurityLevel::NONE, clientShallHaveKeys);
+ BTSecurityLevel::NONE, serverExpPairing, BTSecurityLevel::NONE, clientExpPairing);
}
base_test_framework.cleanupTest();
}
@@ -64,10 +64,10 @@ class TestDBTClientServer12_NoEnc : public DBTClientServer1x {
void test03_FullCycle_EncNone() {
base_test_framework.setupTest( 30_s );
{
- const bool serverShallHaveKeys = false;
- const bool clientShallHaveKeys = false;
+ const ExpectedPairing serverExpPairing = ExpectedPairing::DONT_CARE;
+ const ExpectedPairing clientExpPairing = ExpectedPairing::DONT_CARE;
test8x_fullCycle("13", 2 /* protocolSessionCount */, false /* server_client_order */, serverSC,
- BTSecurityLevel::NONE, serverShallHaveKeys, BTSecurityLevel::NONE, clientShallHaveKeys);
+ BTSecurityLevel::NONE, serverExpPairing, BTSecurityLevel::NONE, clientExpPairing);
}
base_test_framework.cleanupTest();
}
diff --git a/trial/direct_bt/test_client_server20_SC0.cpp b/trial/direct_bt/test_client_server20_SC0.cpp
index cadb0040..29e1c7c3 100644
--- a/trial/direct_bt/test_client_server20_SC0.cpp
+++ b/trial/direct_bt/test_client_server20_SC0.cpp
@@ -53,10 +53,10 @@ class TestDBTClientServer20_SC0 : public DBTClientServer1x {
void test10_FullCycle_EncOnlyNo1() {
base_test_framework.setupTest( 40_s );
{
- const bool serverShallHaveKeys = false;
- const bool clientShallHaveKeys = false;
+ const ExpectedPairing serverExpPairing = ExpectedPairing::NEW_PAIRING;
+ const ExpectedPairing clientExpPairing = ExpectedPairing::NEW_PAIRING;
test8x_fullCycle("20", 1 /* protocolSessionCount */, true /* server_client_order */, serverSC,
- BTSecurityLevel::ENC_ONLY, serverShallHaveKeys, BTSecurityLevel::ENC_ONLY, clientShallHaveKeys);
+ BTSecurityLevel::ENC_ONLY, serverExpPairing, BTSecurityLevel::ENC_ONLY, clientExpPairing);
}
base_test_framework.cleanupTest();
}
@@ -64,10 +64,10 @@ class TestDBTClientServer20_SC0 : public DBTClientServer1x {
void test20_FullCycle_EncOnlyNo2() {
base_test_framework.setupTest( 40_s );
{
- const bool serverShallHaveKeys = true;
- const bool clientShallHaveKeys = true;
+ const ExpectedPairing serverExpPairing = ExpectedPairing::PREPAIRED;
+ const ExpectedPairing clientExpPairing = ExpectedPairing::PREPAIRED;
test8x_fullCycle("21", 2 /* protocolSessionCount */, true /* server_client_order */, serverSC,
- BTSecurityLevel::ENC_ONLY, serverShallHaveKeys, BTSecurityLevel::ENC_ONLY, clientShallHaveKeys);
+ BTSecurityLevel::ENC_ONLY, serverExpPairing, BTSecurityLevel::ENC_ONLY, clientExpPairing);
}
base_test_framework.cleanupTest();
}
diff --git a/trial/direct_bt/test_client_server22_SC0.cpp b/trial/direct_bt/test_client_server22_SC0.cpp
index e08ea4d4..8cddf1b0 100644
--- a/trial/direct_bt/test_client_server22_SC0.cpp
+++ b/trial/direct_bt/test_client_server22_SC0.cpp
@@ -53,10 +53,10 @@ class TestDBTClientServer22_SC0 : public DBTClientServer1x {
void test11_FullCycle_EncOnlyNo1() {
base_test_framework.setupTest( 40_s );
{
- const bool serverShallHaveKeys = false;
- const bool clientShallHaveKeys = false;
+ const ExpectedPairing serverExpPairing = ExpectedPairing::NEW_PAIRING;
+ const ExpectedPairing clientExpPairing = ExpectedPairing::NEW_PAIRING;
test8x_fullCycle("22", 1 /* protocolSessionCount */, false /* server_client_order */, serverSC,
- BTSecurityLevel::ENC_ONLY, serverShallHaveKeys, BTSecurityLevel::ENC_ONLY, clientShallHaveKeys);
+ BTSecurityLevel::ENC_ONLY, serverExpPairing, BTSecurityLevel::ENC_ONLY, clientExpPairing);
}
base_test_framework.cleanupTest();
}
@@ -64,10 +64,10 @@ class TestDBTClientServer22_SC0 : public DBTClientServer1x {
void test21_FullCycle_EncOnlyNo2() {
base_test_framework.setupTest( 40_s );
{
- const bool serverShallHaveKeys = true;
- const bool clientShallHaveKeys = true;
+ const ExpectedPairing serverExpPairing = ExpectedPairing::PREPAIRED;
+ const ExpectedPairing clientExpPairing = ExpectedPairing::PREPAIRED;
test8x_fullCycle("23", 2 /* protocolSessionCount */, false /* server_client_order */, serverSC,
- BTSecurityLevel::ENC_ONLY, serverShallHaveKeys, BTSecurityLevel::ENC_ONLY, clientShallHaveKeys);
+ BTSecurityLevel::ENC_ONLY, serverExpPairing, BTSecurityLevel::ENC_ONLY, clientExpPairing);
}
base_test_framework.cleanupTest();
}
diff --git a/trial/direct_bt/test_client_server30_SC1.cpp b/trial/direct_bt/test_client_server30_SC1.cpp
index 09eb07fe..a60b7d95 100644
--- a/trial/direct_bt/test_client_server30_SC1.cpp
+++ b/trial/direct_bt/test_client_server30_SC1.cpp
@@ -53,10 +53,10 @@ class TestDBTClientServer30_SC1 : public DBTClientServer1x {
void test10_FullCycle_EncOnlyNo1() {
base_test_framework.setupTest( 40_s );
{
- const bool serverShallHaveKeys = false;
- const bool clientShallHaveKeys = false;
+ const ExpectedPairing serverExpPairing = ExpectedPairing::NEW_PAIRING;
+ const ExpectedPairing clientExpPairing = ExpectedPairing::NEW_PAIRING;
test8x_fullCycle("30", 1 /* protocolSessionCount */, true /* server_client_order */, serverSC,
- BTSecurityLevel::ENC_ONLY, serverShallHaveKeys, BTSecurityLevel::ENC_ONLY, clientShallHaveKeys);
+ BTSecurityLevel::ENC_ONLY, serverExpPairing, BTSecurityLevel::ENC_ONLY, clientExpPairing);
}
base_test_framework.cleanupTest();
}
@@ -64,10 +64,10 @@ class TestDBTClientServer30_SC1 : public DBTClientServer1x {
void test20_FullCycle_EncOnlyNo2() {
base_test_framework.setupTest( 40_s );
{
- const bool serverShallHaveKeys = true;
- const bool clientShallHaveKeys = true;
+ const ExpectedPairing serverExpPairing = ExpectedPairing::PREPAIRED;
+ const ExpectedPairing clientExpPairing = ExpectedPairing::PREPAIRED;
test8x_fullCycle("31", 2 /* protocolSessionCount */, true /* server_client_order */, serverSC,
- BTSecurityLevel::ENC_ONLY, serverShallHaveKeys, BTSecurityLevel::ENC_ONLY, clientShallHaveKeys);
+ BTSecurityLevel::ENC_ONLY, serverExpPairing, BTSecurityLevel::ENC_ONLY, clientExpPairing);
}
base_test_framework.cleanupTest();
}
diff --git a/trial/direct_bt/test_client_server32_SC1.cpp b/trial/direct_bt/test_client_server32_SC1.cpp
index 30b2f2d0..6ff7221b 100644
--- a/trial/direct_bt/test_client_server32_SC1.cpp
+++ b/trial/direct_bt/test_client_server32_SC1.cpp
@@ -53,10 +53,10 @@ class TestDBTClientServer32_SC1 : public DBTClientServer1x {
void test10_FullCycle_EncOnlyNo1() {
base_test_framework.setupTest( 40_s );
{
- const bool serverShallHaveKeys = false;
- const bool clientShallHaveKeys = false;
+ const ExpectedPairing serverExpPairing = ExpectedPairing::NEW_PAIRING;
+ const ExpectedPairing clientExpPairing = ExpectedPairing::NEW_PAIRING;
test8x_fullCycle("32", 1 /* protocolSessionCount */, false /* server_client_order */, serverSC,
- BTSecurityLevel::ENC_ONLY, serverShallHaveKeys, BTSecurityLevel::ENC_ONLY, clientShallHaveKeys);
+ BTSecurityLevel::ENC_ONLY, serverExpPairing, BTSecurityLevel::ENC_ONLY, clientExpPairing);
}
base_test_framework.cleanupTest();
}
@@ -64,10 +64,10 @@ class TestDBTClientServer32_SC1 : public DBTClientServer1x {
void test20_FullCycle_EncOnlyNo2() {
base_test_framework.setupTest( 40_s );
{
- const bool serverShallHaveKeys = true;
- const bool clientShallHaveKeys = true;
+ const ExpectedPairing serverExpPairing = ExpectedPairing::PREPAIRED;
+ const ExpectedPairing clientExpPairing = ExpectedPairing::PREPAIRED;
test8x_fullCycle("33", 2 /* protocolSessionCount */, false /* server_client_order */, serverSC,
- BTSecurityLevel::ENC_ONLY, serverShallHaveKeys, BTSecurityLevel::ENC_ONLY, clientShallHaveKeys);
+ BTSecurityLevel::ENC_ONLY, serverExpPairing, BTSecurityLevel::ENC_ONLY, clientExpPairing);
}
base_test_framework.cleanupTest();
}
diff --git a/trial/direct_bt/test_provoke_client_server_i470.cpp b/trial/direct_bt/test_provoke_client_server_i470.cpp
index d081e57a..e393182f 100644
--- a/trial/direct_bt/test_provoke_client_server_i470.cpp
+++ b/trial/direct_bt/test_provoke_client_server_i470.cpp
@@ -27,7 +27,8 @@
#include <catch2/catch_amalgamated.hpp>
#include <jau/test/catch2_ext.hpp>
-#include "dbt_base_client_server.hpp"
+// #include "dbt_base_client_server.hpp"
+#include "dbt_client_server1x.hpp"
#include "dbt_server01.hpp"
#include "dbt_client01.hpp"
@@ -43,210 +44,30 @@ static BaseDBTClientServer& base_test_framework = BaseDBTClientServer::get();
* In other words, relying on BTAdapter to filter out:
* - already discovered devices
* - already connected devices
+ *
+ * Further, the server will issue a disconnect once only 300 ms after 1st MTU exchange,
+ * disrupting the client's getGATTServices().
*/
-class TestDBTClientServer_i470 {
- private:
- std::mutex mtx_sync;
- BTDeviceRef lastCompletedDevice = nullptr;
- PairingMode lastCompletedDevicePairingMode = PairingMode::NONE;
- BTSecurityLevel lastCompletedDeviceSecurityLevel = BTSecurityLevel::NONE;
- EInfoReport lastCompletedDeviceEIR;
-
+class TestDBTClientServer_i470 : public DBTClientServer1x {
public:
void test_i470() {
- const bool serverSC = true;
- const std::string suffix = "i470";
- const int protocolSessionCount = 2;
- const bool server_client_order = true;
- const BTSecurityLevel secLevelServer = BTSecurityLevel::ENC_ONLY;
- const BTSecurityLevel secLevelClient = BTSecurityLevel::ENC_ONLY;
-
base_test_framework.setupTest( 20_s );
{
-
- const jau::fraction_timespec t0 = jau::getMonotonicTime();
-
- BTManager & manager = BTManager::get();
- {
- jau::darray<BTAdapterRef> adapters = manager.getAdapters();
- jau::fprintf_td(stderr, "Adapter: Count %u\n", adapters.size());
-
- for(jau::nsize_t i=0; i<adapters.size(); i++) {
- jau::fprintf_td(stderr, "%u: %s\n", i, adapters[i]->toString().c_str());
- }
- REQUIRE( adapters.size() >= 2 );
- }
-
- std::shared_ptr<DBTServer01> server = std::make_shared<DBTServer01>("S-"+suffix, EUI48::ALL_DEVICE, BTMode::DUAL, serverSC, secLevelServer);
- server->servingProtocolSessionsLeft = 2* protocolSessionCount;
-
- std::shared_ptr<DBTClient01> client = std::make_shared<DBTClient01>("C-"+suffix, EUI48::ALL_DEVICE, BTMode::DUAL);
-
- ChangedAdapterSetCallback myChangedAdapterSetFunc = DBTEndpoint::initChangedAdapterSetListener(manager,
- server_client_order ? std::vector<DBTEndpointRef>{ server, client } : std::vector<DBTEndpointRef>{ client, server } );
-
- const std::string serverName = server->getName();
- BTDeviceRegistry::addToWaitForDevices( serverName );
- {
- BTSecurityRegistry::Entry * sec = BTSecurityRegistry::getOrCreate(serverName);
- sec->sec_level = secLevelClient;
- }
- client->KEEP_CONNECTED = false; // default, auto-disconnect after work is done
- client->REMOVE_DEVICE = false; // default, test side-effects
- client->measurementsLeft = protocolSessionCount;
- client->discoveryPolicy = DiscoveryPolicy::PAUSE_CONNECTED_UNTIL_DISCONNECTED;
-
- {
- const std::lock_guard<std::mutex> lock(mtx_sync); // RAII-style acquire and relinquish via destructor
- lastCompletedDevice = nullptr;
- lastCompletedDevicePairingMode = PairingMode::NONE;
- lastCompletedDeviceSecurityLevel = BTSecurityLevel::NONE;
- lastCompletedDeviceEIR.clear();
- }
- class MyAdapterStatusListener : public AdapterStatusListener {
- private:
- TestDBTClientServer_i470& parent;
- public:
- MyAdapterStatusListener(TestDBTClientServer_i470& p) : parent(p) {}
-
- void deviceReady(BTDeviceRef device, const uint64_t timestamp) override {
- (void)timestamp;
- const std::lock_guard<std::mutex> lock(parent.mtx_sync); // RAII-style acquire and relinquish via destructor
- parent.lastCompletedDevice = device;
- parent.lastCompletedDevicePairingMode = device->getPairingMode();
- parent.lastCompletedDeviceSecurityLevel = device->getConnSecurityLevel();
- parent.lastCompletedDeviceEIR = *device->getEIR();
- fprintf_td(stderr, "XXXXXX Client Ready: %s\n", device->toString(true).c_str());
- }
-
- std::string toString() const override { return "DBTClientServer1x::Client"; }
- };
- std::shared_ptr<AdapterStatusListener> clientAdapterStatusListener = std::make_shared<MyAdapterStatusListener>(*this);
- REQUIRE( true == client->getAdapter()->addStatusListener(clientAdapterStatusListener) );
-
- //
- // Server start
- //
- DBTEndpoint::checkInitializedState(server);
- DBTServerTest::startAdvertising(server, false /* current_exp_advertising_state */, "test"+suffix+"_startAdvertising");
-
- //
- // Client start
- //
- DBTEndpoint::checkInitializedState(client);
- DBTClientTest::startDiscovery(client, false /* current_exp_discovering_state */, "test"+suffix+"_startDiscovery");
-
- BaseDBTClientServer& framework = BaseDBTClientServer::get();
- const jau::fraction_i64 timeout_value = framework.get_timeout_value();
- jau::fraction_i64 test_duration = 0_s;
- bool done = false;
- bool timeout = false;
- bool max_connections_hit = false;
- do {
- {
- const std::lock_guard<std::mutex> lock(mtx_sync); // RAII-style acquire and relinquish via destructor
- done = ! ( protocolSessionCount > server->servedProtocolSessionsTotal ||
- protocolSessionCount > client->completedMeasurements ||
- nullptr == lastCompletedDevice ||
- lastCompletedDevice->getConnected() );
- }
- max_connections_hit = ( protocolSessionCount * DBTConstants::max_connections_per_session ) <= server->disconnectCount;
- test_duration = ( jau::getMonotonicTime() - t0 ).to_fraction_i64();
- timeout = 0_s < timeout_value && timeout_value <= test_duration + 500_ms; // let's timeout here before our timeout timer
- if( !done && !max_connections_hit && !timeout ) {
- jau::sleep_for( 88_ms );
- }
- } while( !done && !max_connections_hit && !timeout );
- test_duration = ( jau::getMonotonicTime() - t0 ).to_fraction_i64();
-
- fprintf_td(stderr, "\n\n");
- fprintf_td(stderr, "****** Test Stats: duration %" PRIi64 " ms, timeout[hit %d, value %s sec], max_connections hit %d\n",
- test_duration.to_ms(), timeout, timeout_value.to_string(true).c_str(), max_connections_hit);
- fprintf_td(stderr, " Server ProtocolSessions[success %d/%d total, requested %d], disconnects %d of %d max\n",
- server->servedProtocolSessionsSuccess.load(), server->servedProtocolSessionsTotal.load(), protocolSessionCount,
- server->disconnectCount.load(), ( protocolSessionCount * DBTConstants::max_connections_per_session ));
- fprintf_td(stderr, " Client ProtocolSessions success %d \n",
- client->completedMeasurements.load());
- fprintf_td(stderr, "\n\n");
-
- REQUIRE( false == max_connections_hit );
- REQUIRE( false == timeout );
- {
- const std::lock_guard<std::mutex> lock(mtx_sync); // RAII-style acquire and relinquish via destructor
- REQUIRE( protocolSessionCount == server->servedProtocolSessionsTotal );
- REQUIRE( protocolSessionCount == server->servedProtocolSessionsSuccess );
- REQUIRE( protocolSessionCount == client->completedMeasurements );
- REQUIRE( nullptr != lastCompletedDevice );
- REQUIRE( EIRDataType::NONE != lastCompletedDeviceEIR.getEIRDataMask() );
- REQUIRE( false == lastCompletedDevice->getConnected() );
- REQUIRE( ( protocolSessionCount * DBTConstants::max_connections_per_session ) > server->disconnectCount );
- }
-
- //
- // Client stop
- //
- DBTClientTest::stopDiscovery(client, true /* current_exp_discovering_state */, "test"+suffix+"_stopDiscovery");
- client->close("test"+suffix+"_close");
-
- //
- // Server stop
- //
- DBTServerTest::stop(server, true /* current_exp_advertising_state */, "test"+suffix+"_stopAdvertising");
- server->close("test"+suffix+"_close");
-
- //
- // Validating Security Mode
- //
- SMPKeyBin clientKeys = SMPKeyBin::read(DBTConstants::CLIENT_KEY_PATH, *lastCompletedDevice, true /* verbose */);
- REQUIRE( true == clientKeys.isValid() );
- const BTSecurityLevel clientKeysSecLevel = clientKeys.getSecLevel();
- REQUIRE( secLevelClient == clientKeysSecLevel);
- {
- if( PairingMode::PRE_PAIRED == lastCompletedDevicePairingMode ) {
- // Using encryption: pre-paired
- REQUIRE( BTSecurityLevel::ENC_ONLY == lastCompletedDeviceSecurityLevel ); // pre-paired fixed level, no auth
- } else if( BTSecurityLevel::NONE < secLevelClient ) {
- // Using encryption: Newly paired
- REQUIRE( PairingMode::PRE_PAIRED != lastCompletedDevicePairingMode );
- REQUIRE_MSG( "PairingMode client "+to_string(lastCompletedDevicePairingMode)+" not > NONE", PairingMode::NONE < lastCompletedDevicePairingMode );
- REQUIRE_MSG( "SecurityLevel client "+to_string(lastCompletedDeviceSecurityLevel)+" not >= "+to_string(secLevelClient), secLevelClient <= lastCompletedDeviceSecurityLevel );
- } else {
- // No encryption: No pairing
- REQUIRE( PairingMode::NONE == lastCompletedDevicePairingMode );
- REQUIRE( BTSecurityLevel::NONE == lastCompletedDeviceSecurityLevel );
- }
- }
-
- //
- // Validating EIR
- //
- {
- const std::lock_guard<std::mutex> lock(mtx_sync); // RAII-style acquire and relinquish via destructor
- fprintf_td(stderr, "lastCompletedDevice.connectedEIR: %s\n", lastCompletedDeviceEIR.toString().c_str());
- REQUIRE( EIRDataType::NONE != lastCompletedDeviceEIR.getEIRDataMask() );
- REQUIRE( true == lastCompletedDeviceEIR.isSet(EIRDataType::FLAGS) );
- REQUIRE( true == lastCompletedDeviceEIR.isSet(EIRDataType::SERVICE_UUID) );
- REQUIRE( true == lastCompletedDeviceEIR.isSet(EIRDataType::NAME) );
- REQUIRE( true == lastCompletedDeviceEIR.isSet(EIRDataType::CONN_IVAL) );
- REQUIRE( serverName == lastCompletedDeviceEIR.getName() );
- }
-
- //
- // Now reuse adapter for client mode -> Start discovery + Stop Discovery
- //
- {
- const BTAdapterRef adapter = server->getAdapter();
- { // if( false ) {
- adapter->removeAllStatusListener();
- }
-
- DBTEndpoint::startDiscovery(adapter, false /* current_exp_discovering_state */);
-
- DBTEndpoint::stopDiscovery(adapter, true /* current_exp_discovering_state */);
- }
-
- const int count = manager.removeChangedAdapterSetCallback(myChangedAdapterSetFunc);
- fprintf_td(stderr, "****** EOL Removed ChangedAdapterSetCallback %d\n", count);
+ const bool serverSC = true;
+ const std::string suffix = "i470";
+ const int protocolSessionCount = 2;
+ const bool server_client_order = true;
+ const BTSecurityLevel secLevelServer = BTSecurityLevel::ENC_ONLY;
+ const BTSecurityLevel secLevelClient = BTSecurityLevel::ENC_ONLY;
+ const ExpectedPairing serverExpPairing = ExpectedPairing::DONT_CARE;
+ const ExpectedPairing clientExpPairing = ExpectedPairing::DONT_CARE;
+
+ // std::shared_ptr<DBTServerTest> server = std::make_shared<DBTServer01>("S-"+suffix, EUI48::ALL_DEVICE, BTMode::DUAL, serverSC, secLevelServer);
+ std::shared_ptr<DBTServerTest> server = std::make_shared<DBTServer00>("S-"+suffix, EUI48::ALL_DEVICE, BTMode::DUAL, serverSC, secLevelServer);
+ std::shared_ptr<DBTClientTest> client = std::make_shared<DBTClient01>("C-"+suffix, EUI48::ALL_DEVICE, BTMode::DUAL);
+ test8x_fullCycle(suffix, protocolSessionCount, server_client_order,
+ server, secLevelServer, serverExpPairing,
+ client, secLevelClient, clientExpPairing);
}
base_test_framework.cleanupTest();
}
diff --git a/trial/java/trial/org/direct_bt/DBTClient00.java b/trial/java/trial/org/direct_bt/DBTClient00.java
index 56d69bee..91aa9029 100644
--- a/trial/java/trial/org/direct_bt/DBTClient00.java
+++ b/trial/java/trial/org/direct_bt/DBTClient00.java
@@ -56,48 +56,41 @@ import org.direct_bt.SMPPairingState;
import org.direct_bt.ScanType;
import org.jau.net.EUI48;
+import trial.org.direct_bt.DBTClient01.MyAdapterStatusListener;
+
/**
* This central BTRole::Master participant works with DBTServer00.
*/
public class DBTClient00 implements DBTClientTest {
- /**
- * Disconnect after processing.
- *
- * Default is `false`.
- */
- boolean KEEP_CONNECTED = false;
-
- /**
- * Remove device when disconnecting.
- *
- * This removes the device from all instances within adapter
- * and hence all potential side-effects of the current instance.
- *
- * Default is `false`, since it is good to test whether such side-effects exists.
- */
- boolean REMOVE_DEVICE = false;
-
- final boolean GATT_VERBOSE = false;
- final boolean SHOW_UPDATE_EVENTS = false;
-
- final long timestamp_t0 = BTUtils.startupTimeMillis();
-
- final String adapterShortName = "TDev2Clt";
- String adapterName = "TestDev2_Clt";
- EUI48 useAdapter = EUI48.ALL_DEVICE;
- BTMode btMode = BTMode.DUAL;
- BTAdapter clientAdapter = null;
+ private final boolean GATT_VERBOSE = false;
+
+ private final long timestamp_t0 = BTUtils.startupTimeMillis();
+
+ private final String adapterShortName = "TDev2Clt";
+
private final MyAdapterStatusListener myAdapterStatusListener = new MyAdapterStatusListener();
- AtomicInteger deviceReadyCount = new AtomicInteger(0);
+ private final byte cmd_arg = (byte)0x44;
+
+ private String adapterName = "TestDev2_Clt";
+ private EUI48 useAdapter = EUI48.ALL_DEVICE;
+ private BTMode btMode = BTMode.DUAL;
+ private BTAdapter clientAdapter = null;
+
+ private boolean KEEP_CONNECTED = false;
+
+ private boolean REMOVE_DEVICE = false;
- AtomicInteger notificationsReceived = new AtomicInteger(0);
- AtomicInteger indicationsReceived = new AtomicInteger(0);
- AtomicInteger completedGATTCommands = new AtomicInteger(0);
- AtomicInteger completedMeasurements = new AtomicInteger(0);
- AtomicInteger measurementsLeft = new AtomicInteger(1);
+ private DiscoveryPolicy discoveryPolicy = DiscoveryPolicy.PAUSE_CONNECTED_UNTIL_READY; // default value
- final byte cmd_arg = (byte)0x44;
+ private final AtomicInteger disconnectCount = new AtomicInteger(0);
+ private final AtomicInteger measurementsLeft = new AtomicInteger(1);
+ private final AtomicInteger deviceReadyCount = new AtomicInteger(0);
+ private final AtomicInteger notificationsReceived = new AtomicInteger(0);
+ private final AtomicInteger indicationsReceived = new AtomicInteger(0);
+ private final AtomicInteger completedGATTCommands = new AtomicInteger(0);
+ private final AtomicInteger completedMeasurementsTotal = new AtomicInteger(0);
+ private final AtomicInteger completedMeasurementsSuccess = new AtomicInteger(0);
public DBTClient00(final String adapterName, final EUI48 useAdapter, final BTMode btMode) {
this.adapterName = adapterName;
@@ -115,6 +108,40 @@ public class DBTClient00 implements DBTClientTest {
@Override
public BTAdapter getAdapter() { return clientAdapter; }
+ @Override
+ public void setProtocolSessionsLeft(final int v) {
+ measurementsLeft.set(v);
+ }
+ @Override
+ public int getProtocolSessionsLeft() {
+ return measurementsLeft.get();
+ }
+ @Override
+ public int getProtocolSessionsDoneTotal() {
+ return completedMeasurementsTotal.get();
+ }
+ @Override
+ public int getProtocolSessionsDoneSuccess() {
+ return completedMeasurementsSuccess.get();
+ }
+ @Override
+ public int getDisconnectCount() {
+ return this.disconnectCount.get();
+ }
+
+ @Override
+ public void setDiscoveryPolicy(final DiscoveryPolicy v) {
+ discoveryPolicy = v;
+ }
+ @Override
+ public void setKeepConnected(final boolean v) {
+ KEEP_CONNECTED = v;
+ }
+ @Override
+ public void setRemoveDevice(final boolean v) {
+ REMOVE_DEVICE = v;
+ }
+
static void executeOffThread(final Runnable runobj, final String threadName, final boolean detach) {
final Thread t = new Thread( runobj, threadName );
if( detach ) {
@@ -269,6 +296,8 @@ public class DBTClient00 implements DBTClientTest {
public void deviceDisconnected(final BTDevice device, final HCIStatusCode reason, final short handle, final long timestamp) {
BTUtils.println(System.err, "****** Client DISCONNECTED: Reason "+reason+", old handle 0x"+Integer.toHexString(handle)+": "+device+" on "+device.getAdapter());
+ disconnectCount.addAndGet(1);
+
executeOffThread( () -> { removeDevice(device); }, "Client DBT-Remove-"+device.getAddressAndType(), true /* detach */);
}
@@ -558,14 +587,15 @@ public class DBTClient00 implements DBTClientTest {
}
}
+ completedMeasurementsTotal.addAndGet(1);
if( success ) {
- completedMeasurements.addAndGet(1);
+ completedMeasurementsSuccess.addAndGet(1);
}
if( 0 < measurementsLeft.get() ) {
measurementsLeft.decrementAndGet();
}
BTUtils.println(System.err, "****** Client Processing Ready Device: Success "+success+
- "; Measurements completed "+completedMeasurements.get()+
+ "; Measurements completed "+completedMeasurementsSuccess.get()+
", left "+measurementsLeft.get()+
"; Received notitifications "+notificationsReceived.get()+", indications "+indicationsReceived.get()+
"; Completed GATT commands "+completedGATTCommands.get()+
@@ -582,7 +612,6 @@ public class DBTClient00 implements DBTClientTest {
}
}
- DiscoveryPolicy discoveryPolicy = DiscoveryPolicy.PAUSE_CONNECTED_UNTIL_READY; // default value
static final boolean le_scan_active = true; // default value
static final short le_scan_interval = (short)24; // 15ms, default value
static final short le_scan_window = (short)24; // 15ms, default value
diff --git a/trial/java/trial/org/direct_bt/DBTClient01.java b/trial/java/trial/org/direct_bt/DBTClient01.java
new file mode 100644
index 00000000..3d53b2ff
--- /dev/null
+++ b/trial/java/trial/org/direct_bt/DBTClient01.java
@@ -0,0 +1,679 @@
+/**
+ * Author: Sven Gothel <[email protected]>
+ * Copyright (c) 2022 Gothel Software e.K.
+ *
+ * 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 trial.org.direct_bt;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.direct_bt.AdapterSettings;
+import org.direct_bt.AdapterStatusListener;
+import org.direct_bt.BTMode;
+import org.direct_bt.BTSecurityLevel;
+import org.direct_bt.BTAdapter;
+import org.direct_bt.BTDevice;
+import org.direct_bt.BTDeviceRegistry;
+import org.direct_bt.BTGattChar;
+import org.direct_bt.BTGattCmd;
+import org.direct_bt.BTGattDesc;
+import org.direct_bt.BTGattService;
+import org.direct_bt.BTSecurityRegistry;
+import org.direct_bt.BTUtils;
+import org.direct_bt.DiscoveryPolicy;
+import org.direct_bt.EIRDataTypeSet;
+import org.direct_bt.EInfoReport;
+import org.direct_bt.GattCharPropertySet;
+import org.direct_bt.HCIStatusCode;
+import org.direct_bt.LE_Features;
+import org.direct_bt.LE_PHYs;
+import org.direct_bt.PairingMode;
+import org.direct_bt.SMPIOCapability;
+import org.direct_bt.SMPKeyBin;
+import org.direct_bt.SMPPairingState;
+import org.direct_bt.ScanType;
+import org.jau.net.EUI48;
+
+/**
+ * This central BTRole::Master participant works with DBTServer00.
+ */
+public class DBTClient01 implements DBTClientTest {
+ private final boolean GATT_VERBOSE = false;
+
+ private final long timestamp_t0 = BTUtils.startupTimeMillis();
+
+ private final String adapterShortName = "TDev2Clt";
+
+ private final MyAdapterStatusListener myAdapterStatusListener = new MyAdapterStatusListener();
+
+ private final byte cmd_arg = (byte)0x44;
+
+ private String adapterName = "TestDev2_Clt";
+ private EUI48 useAdapter = EUI48.ALL_DEVICE;
+ private BTMode btMode = BTMode.DUAL;
+ private BTAdapter clientAdapter = null;
+
+ private boolean KEEP_CONNECTED = false;
+
+ private boolean REMOVE_DEVICE = false;
+
+ private DiscoveryPolicy discoveryPolicy = DiscoveryPolicy.PAUSE_CONNECTED_UNTIL_READY; // default value
+
+ private final AtomicInteger disconnectCount = new AtomicInteger(0);
+ private final AtomicInteger measurementsLeft = new AtomicInteger(1);
+ private final AtomicInteger deviceReadyCount = new AtomicInteger(0);
+ private final AtomicInteger notificationsReceived = new AtomicInteger(0);
+ private final AtomicInteger indicationsReceived = new AtomicInteger(0);
+ private final AtomicInteger completedGATTCommands = new AtomicInteger(0);
+ private final AtomicInteger completedMeasurementsTotal = new AtomicInteger(0);
+ private final AtomicInteger completedMeasurementsSuccess = new AtomicInteger(0);
+
+ public DBTClient01(final String adapterName, final EUI48 useAdapter, final BTMode btMode) {
+ this.adapterName = adapterName;
+ this.useAdapter = useAdapter;
+ this.btMode = btMode;
+ }
+
+ @Override
+ public String getName() { return adapterName; }
+
+ @Override
+ public void setAdapter(final BTAdapter clientAdapter) {
+ this.clientAdapter = clientAdapter;
+ }
+ @Override
+ public BTAdapter getAdapter() { return clientAdapter; }
+
+ @Override
+ public void setProtocolSessionsLeft(final int v) {
+ measurementsLeft.set(v);
+ }
+ @Override
+ public int getProtocolSessionsLeft() {
+ return measurementsLeft.get();
+ }
+ @Override
+ public int getProtocolSessionsDoneTotal() {
+ return completedMeasurementsTotal.get();
+ }
+ @Override
+ public int getProtocolSessionsDoneSuccess() {
+ return completedMeasurementsSuccess.get();
+ }
+ @Override
+ public int getDisconnectCount() {
+ return this.disconnectCount.get();
+ }
+
+ @Override
+ public void setDiscoveryPolicy(final DiscoveryPolicy v) {
+ discoveryPolicy = v;
+ }
+ @Override
+ public void setKeepConnected(final boolean v) {
+ KEEP_CONNECTED = v;
+ }
+ @Override
+ public void setRemoveDevice(final boolean v) {
+ REMOVE_DEVICE = v;
+ }
+
+ static void executeOffThread(final Runnable runobj, final String threadName, final boolean detach) {
+ final Thread t = new Thread( runobj, threadName );
+ if( detach ) {
+ t.setDaemon(true); // detach thread
+ }
+ t.start();
+ }
+ static void execute(final Runnable task, final boolean offThread) {
+ if( offThread ) {
+ final Thread t = new Thread(task);
+ t.setDaemon(true);
+ t.start();
+ } else {
+ task.run();
+ }
+ }
+
+ class MyAdapterStatusListener extends AdapterStatusListener {
+ @Override
+ public void adapterSettingsChanged(final BTAdapter adapter, final AdapterSettings oldmask,
+ final AdapterSettings newmask, final AdapterSettings changedmask, final long timestamp) {
+ final boolean initialSetting = oldmask.isEmpty();
+ if( initialSetting ) {
+ BTUtils.println(System.err, "****** Client SETTINGS: "+oldmask+" -> "+newmask+", initial "+changedmask);
+ } else {
+ BTUtils.println(System.err, "****** Client SETTINGS: "+oldmask+" -> "+newmask+", changed "+changedmask);
+ }
+ BTUtils.println(System.err, "Client Status Adapter:");
+ BTUtils.println(System.err, adapter.toString());
+ }
+
+ @Override
+ public void discoveringChanged(final BTAdapter adapter, final ScanType currentMeta, final ScanType changedType, final boolean changedEnabled, final DiscoveryPolicy policy, final long timestamp) {
+ BTUtils.println(System.err, "****** Client DISCOVERING: meta "+currentMeta+", changed["+changedType+", enabled "+changedEnabled+", policy "+policy+"] on "+adapter);
+ }
+
+ @Override
+ public boolean deviceFound(final BTDevice device, final long timestamp) {
+ if( BTDeviceRegistry.isWaitingForDevice(device.getAddressAndType().address, device.getName()) &&
+ 0 < measurementsLeft.get()
+ )
+ {
+ BTUtils.println(System.err, "****** Client FOUND__-0: Connecting "+device.toString());
+ {
+ final long td = BTUtils.currentTimeMillis() - timestamp_t0; // adapter-init -> now
+ BTUtils.println(System.err, "PERF: adapter-init -> FOUND__-0 " + td + " ms");
+ }
+ executeOffThread( () -> { connectDiscoveredDevice(device); },
+ "Client DBT-Connect-"+device.getAddressAndType(), true /* detach */);
+ return true;
+ } else {
+ BTUtils.println(System.err, "****** Client FOUND__-1: NOP "+device.toString());
+ return false;
+ }
+ }
+
+ @Override
+ public void deviceUpdated(final BTDevice device, final EIRDataTypeSet updateMask, final long timestamp) {
+ }
+
+ @Override
+ public void deviceConnected(final BTDevice device, final short handle, final long timestamp) {
+ BTUtils.println(System.err, "****** Client CONNECTED: "+device.toString());
+ }
+
+ @Override
+ public void devicePairingState(final BTDevice device, final SMPPairingState state, final PairingMode mode, final long timestamp) {
+ BTUtils.println(System.err, "****** Client PAIRING_STATE: state "+state+", mode "+mode+": "+device);
+ switch( state ) {
+ case NONE:
+ // next: deviceReady(..)
+ break;
+ case FAILED: {
+ final boolean res = SMPKeyBin.remove(DBTConstants.CLIENT_KEY_PATH, device);
+ BTUtils.println(System.err, "****** Client PAIRING_STATE: state "+state+"; Remove key file "+SMPKeyBin.getFilename(DBTConstants.CLIENT_KEY_PATH, device)+", res "+res);
+ // next: deviceReady() or deviceDisconnected(..)
+ } break;
+ case REQUESTED_BY_RESPONDER:
+ // next: FEATURE_EXCHANGE_STARTED
+ break;
+ case FEATURE_EXCHANGE_STARTED:
+ // next: FEATURE_EXCHANGE_COMPLETED
+ break;
+ case FEATURE_EXCHANGE_COMPLETED:
+ // next: PASSKEY_EXPECTED... or KEY_DISTRIBUTION
+ break;
+ case PASSKEY_EXPECTED: {
+ final BTSecurityRegistry.Entry sec = BTSecurityRegistry.getStartOf(device.getAddressAndType().address, "");
+ if( null != sec && sec.getPairingPasskey() != BTSecurityRegistry.NO_PASSKEY ) {
+ executeOffThread( () -> { device.setPairingPasskey( sec.getPairingPasskey() ); }, "DBT-SetPasskey-"+device.getAddressAndType(), true /* detach */);
+ } else {
+ executeOffThread( () -> { device.setPairingPasskey( 0 ); }, "DBT-SetPasskey-"+device.getAddressAndType(), true /* detach */);
+ // 3s disconnect: executeOffThread( () -> { device.setPairingPasskeyNegative(); }, "DBT-SetPasskeyNegative-"+device.getAddressAndType(), true /* detach */);
+ }
+ // next: KEY_DISTRIBUTION or FAILED
+ } break;
+ case NUMERIC_COMPARE_EXPECTED: {
+ final BTSecurityRegistry.Entry sec = BTSecurityRegistry.getStartOf(device.getAddressAndType().address, "");
+ if( null != sec ) {
+ executeOffThread( () -> { device.setPairingNumericComparison( sec.getPairingNumericComparison() ); }, "DBT-SetNumericComp-"+device.getAddressAndType(), true /* detach */);
+ } else {
+ executeOffThread( () -> { device.setPairingNumericComparison( false ); }, "DBT-SetNumericCompFalse-"+device.getAddressAndType(), true /* detach */);
+ }
+ // next: KEY_DISTRIBUTION or FAILED
+ } break;
+ case OOB_EXPECTED:
+ // FIXME: ABORT
+ break;
+ case KEY_DISTRIBUTION:
+ // next: COMPLETED or FAILED
+ break;
+ case COMPLETED:
+ // next: deviceReady(..)
+ break;
+ default: // nop
+ break;
+ }
+ }
+
+ @Override
+ public void deviceReady(final BTDevice device, final long timestamp) {
+ {
+ deviceReadyCount.incrementAndGet();
+ BTUtils.println(System.err, "****** Client READY-0: Processing["+deviceReadyCount.get()+"] "+device.toString());
+ {
+ final long td = BTUtils.currentTimeMillis() - timestamp_t0; // adapter-init -> now
+ BTUtils.println(System.err, "PERF: adapter-init -> READY-0 " + td + " ms");
+ }
+
+ // Be nice to Test* case, allowing to reach its own listener.deviceReady() added later
+ executeOffThread( () -> { processReadyDevice(device); },
+ "DBT-Process-"+device.getAddressAndType(), true /* detach */);
+ // processReadyDevice(device); // AdapterStatusListener::deviceReady() explicitly allows prolonged and complex code execution!
+ }
+ }
+
+ @Override
+ public void deviceDisconnected(final BTDevice device, final HCIStatusCode reason, final short handle, final long timestamp) {
+ BTUtils.println(System.err, "****** Client DISCONNECTED: Reason "+reason+", old handle 0x"+Integer.toHexString(handle)+": "+device+" on "+device.getAdapter());
+
+ disconnectCount.addAndGet(1);
+
+ executeOffThread( () -> { removeDevice(device); }, "Client DBT-Remove-"+device.getAddressAndType(), true /* detach */);
+ }
+
+ @Override
+ public String toString() {
+ return "Client AdapterStatusListener[user, per-adapter]";
+ }
+ };
+
+ class MyGATTEventListener implements BTGattChar.Listener {
+ private final int i, j;
+
+ public MyGATTEventListener(final int i_, final int j_) { i=i_; j=j_; }
+
+ @Override
+ public void notificationReceived(final BTGattChar charDecl,
+ final byte[] value, final long timestamp) {
+ if( GATT_VERBOSE ) {
+ final long tR = BTUtils.currentTimeMillis();
+ BTUtils.fprintf_td(System.err, "**[%02d.%02d] Characteristic-Notify: UUID %s, td %d ******\n",
+ i, j, charDecl.getUUID(), (tR-timestamp));
+ BTUtils.fprintf_td(System.err, "**[%02d.%02d] Characteristic: %s ******\n", i, j, charDecl.toString());
+ BTUtils.fprintf_td(System.err, "**[%02d.%02d] Value R: size %d, ro: %s ******\n", i, j, value.length, BTUtils.bytesHexString(value, 0, -1, true));
+ BTUtils.fprintf_td(System.err, "**[%02d.%02d] Value S: %s ******\n", i, j, BTUtils.decodeUTF8String(value, 0, value.length));
+ }
+ notificationsReceived.incrementAndGet();
+ }
+
+ @Override
+ public void indicationReceived(final BTGattChar charDecl,
+ final byte[] value, final long timestamp, final boolean confirmationSent) {
+ if( GATT_VERBOSE ) {
+ final long tR = BTUtils.currentTimeMillis();
+ BTUtils.fprintf_td(System.err, "**[%02d.%02d] Characteristic-Indication: UUID %s, td %d, confirmed %b ******\n",
+ i, j, charDecl.getUUID(), (tR-timestamp), confirmationSent);
+ BTUtils.fprintf_td(System.err, "**[%02d.%02d] Characteristic: %s ******\n", i, j, charDecl.toString());
+ BTUtils.fprintf_td(System.err, "**[%02d.%02d] Value R: size %d, ro: %s ******\n", i, j, value.length, BTUtils.bytesHexString(value, 0, -1, true));
+ BTUtils.fprintf_td(System.err, "**[%02d.%02d] Value S: %s ******\n", i, j, BTUtils.decodeUTF8String(value, 0, value.length));
+ }
+ indicationsReceived.incrementAndGet();
+ }
+ }
+
+ private void resetLastProcessingStats() {
+ completedGATTCommands.set(0);
+ notificationsReceived.set(0);
+ indicationsReceived.set(0);
+ }
+
+ private void connectDiscoveredDevice(final BTDevice device) {
+ BTUtils.println(System.err, "****** Client Connecting Device: Start " + device.toString());
+
+ resetLastProcessingStats();
+
+ final BTSecurityRegistry.Entry sec = BTSecurityRegistry.getStartOf(device.getAddressAndType().address, device.getName());
+ if( null != sec ) {
+ BTUtils.println(System.err, "****** Client Connecting Device: Found SecurityDetail "+sec.toString()+" for "+device.toString());
+ } else {
+ BTUtils.println(System.err, "****** Client Connecting Device: No SecurityDetail for "+device.toString());
+ }
+ final BTSecurityLevel req_sec_level = null != sec ? sec.getSecLevel() : BTSecurityLevel.UNSET;
+ HCIStatusCode res = device.uploadKeys(DBTConstants.CLIENT_KEY_PATH, req_sec_level, true /* verbose_ */);
+ BTUtils.fprintf_td(System.err, "****** Client Connecting Device: BTDevice::uploadKeys(...) result %s\n", res.toString());
+ if( HCIStatusCode.SUCCESS != res ) {
+ if( null != sec ) {
+ if( sec.isSecurityAutoEnabled() ) {
+ final boolean r = device.setConnSecurityAuto( sec.getSecurityAutoIOCap() );
+ BTUtils.println(System.err, "****** Client Connecting Device: Using SecurityDetail.SEC AUTO "+sec+" -> set OK "+r);
+ } else if( sec.isSecLevelOrIOCapSet() ) {
+ final boolean r = device.setConnSecurity(sec.getSecLevel(), sec.getIOCap());
+ BTUtils.println(System.err, "****** Client Connecting Device: Using SecurityDetail.Level+IOCap "+sec+" -> set OK "+r);
+ } else {
+ final boolean r = device.setConnSecurityAuto( SMPIOCapability.KEYBOARD_ONLY );
+ BTUtils.println(System.err, "****** Client Connecting Device: Setting SEC AUTO security detail w/ KEYBOARD_ONLY ("+sec+") -> set OK "+r);
+ }
+ } else {
+ final boolean r = device.setConnSecurityAuto( SMPIOCapability.KEYBOARD_ONLY );
+ BTUtils.println(System.err, "****** Client Connecting Device: Setting SEC AUTO security detail w/ KEYBOARD_ONLY -> set OK "+r);
+ }
+ }
+ final EInfoReport eir = device.getEIR();
+ BTUtils.println(System.err, "Client EIR-1 "+device.getEIRInd().toString());
+ BTUtils.println(System.err, "Client EIR-2 "+device.getEIRScanRsp().toString());
+ BTUtils.println(System.err, "Client EIR-+ "+eir.toString());
+
+ short conn_interval_min = (short)8; // 10ms
+ short conn_interval_max = (short)12; // 15ms
+ final short conn_latency = (short)0;
+ if( eir.isSet(EIRDataTypeSet.DataType.CONN_IVAL) ) {
+ final short[] minmax = new short[2];
+ eir.getConnInterval(minmax);
+ conn_interval_min = minmax[0];
+ conn_interval_max = minmax[1];
+ }
+ final short supervision_timeout = BTUtils.getHCIConnSupervisorTimeout(conn_latency, (int) ( conn_interval_max * 1.25 ) /* ms */);
+ res = device.connectLE(le_scan_interval, le_scan_window, conn_interval_min, conn_interval_max, conn_latency, supervision_timeout);
+ // res = device.connectDefault();
+ BTUtils.println(System.err, "****** Client Connecting Device Command, res "+res+": End result "+res+" of " + device.toString());
+ }
+
+ private void processReadyDevice(final BTDevice device) {
+ BTUtils.println(System.err, "****** Client Processing Ready Device: Start " + device.toString());
+ final long t1 = BTUtils.currentTimeMillis();
+
+ SMPKeyBin.createAndWrite(device, DBTConstants.CLIENT_KEY_PATH, true /* verbose */);
+ final long t2 = BTUtils.currentTimeMillis();
+
+ boolean success = false;
+
+ {
+ final LE_PHYs resTx[] = { new LE_PHYs() };
+ final LE_PHYs resRx[] = { new LE_PHYs() };
+ final HCIStatusCode res = device.getConnectedLE_PHY(resTx, resRx);
+ BTUtils.fprintf_td(System.err, "****** Client Got Connected LE PHY: status %s: Tx %s, Rx %s\n",
+ res.toString(), resTx[0].toString(), resRx[0].toString());
+ }
+ final long t3 = BTUtils.currentTimeMillis();
+
+ //
+ // GATT Service Processing
+ //
+ try {
+ final List<BTGattService> primServices = device.getGattServices();
+ if( null == primServices || 0 == primServices.size() ) {
+ // Cheating the flow, but avoiding: goto, do-while-false and lastly unreadable intendations
+ // And it is an error case nonetheless ;-)
+ throw new RuntimeException("Processing Ready Device: getServices() failed " + device.toString());
+ }
+ final long t5 = BTUtils.currentTimeMillis();
+ {
+ final long td00 = device.getLastDiscoveryTimestamp() - timestamp_t0; // adapter-init to discovered
+ final long td01 = t1 - timestamp_t0; // adapter-init to processing-start
+ final long td05 = t5 - timestamp_t0; // adapter-init -> gatt-complete
+ final long tdc1 = t1 - device.getLastDiscoveryTimestamp(); // discovered to processing-start
+ final long tdc5 = t5 - device.getLastDiscoveryTimestamp(); // discovered to gatt-complete
+ final long td12 = t2 - t1; // SMPKeyBin
+ final long td23 = t3 - t2; // LE_PHY
+ final long td13 = t3 - t1; // SMPKeyBin + LE_PHY
+ final long td35 = t5 - t3; // get-gatt-services
+ BTUtils.println(System.err, System.lineSeparator()+System.lineSeparator());
+ BTUtils.println(System.err, "PERF: GATT primary-services completed"+System.lineSeparator()+
+ "PERF: adapter-init to discovered " + td00 + " ms,"+System.lineSeparator()+
+ "PERF: adapter-init to processing-start " + td01 + " ms,"+System.lineSeparator()+
+ "PERF: adapter-init to gatt-complete " + td05 + " ms,"+System.lineSeparator()+
+ "PERF: discovered to processing-start " + tdc1 + " ms,"+System.lineSeparator()+
+ "PERF: discovered to gatt-complete " + tdc5 + " ms,"+System.lineSeparator()+
+ "PERF: SMPKeyBin + LE_PHY " + td13 + " ms (SMPKeyBin "+td12+"ms, LE_PHY "+td23+"ms), "+System.lineSeparator()+
+ "PERF: get-gatt-services " + td35 + " ms,"+System.lineSeparator());
+ }
+
+ {
+ final BTGattCmd cmd = new BTGattCmd(device, "TestCmd", null /* service_uuid */, DBTConstants.CommandUUID, DBTConstants.ResponseUUID);
+ cmd.setVerbose(true);
+ final boolean cmd_resolved = cmd.isResolved();
+ BTUtils.println(System.err, "Client Command test: "+cmd.toString()+", resolved "+cmd_resolved);
+ final byte[] cmd_data = { cmd_arg };
+ final HCIStatusCode cmd_res = cmd.send(true /* prefNoAck */, cmd_data, 3000 /* timeoutMS */);
+ if( HCIStatusCode.SUCCESS == cmd_res ) {
+ final byte[] resp = cmd.getResponse();
+ if( 1 == resp.length && resp[0] == cmd_arg ) {
+ BTUtils.fprintf_td(System.err, "Client Success: %s -> %s (echo response)\n", cmd.toString(), BTUtils.bytesHexString(resp, 0, resp.length, true /* lsb */));
+ completedGATTCommands.incrementAndGet();
+ } else {
+ BTUtils.fprintf_td(System.err, "Client Failure: %s -> %s (different response)\n", cmd.toString(), BTUtils.bytesHexString(resp, 0, resp.length, true /* lsb */));
+ }
+ } else {
+ BTUtils.fprintf_td(System.err, "Client Failure: %s -> %s\n", cmd.toString(), cmd_res.toString());
+ }
+ cmd.close();
+ }
+
+ try {
+ int i=0;
+ for(final Iterator<BTGattService> srvIter = primServices.iterator(); srvIter.hasNext(); i++) {
+ final BTGattService primService = srvIter.next();
+ if( GATT_VERBOSE ) {
+ BTUtils.fprintf_td(System.err, " [%02d] Service UUID %s\n", i, primService.getUUID());
+ BTUtils.fprintf_td(System.err, " [%02d] %s\n", i, primService.toString());
+ }
+ int j=0;
+ final List<BTGattChar> serviceCharacteristics = primService.getChars();
+ for(final Iterator<BTGattChar> charIter = serviceCharacteristics.iterator(); charIter.hasNext(); j++) {
+ final BTGattChar serviceChar = charIter.next();
+ if( GATT_VERBOSE ) {
+ BTUtils.fprintf_td(System.err, " [%02d.%02d] Characteristic: UUID %s\n", i, j, serviceChar.getUUID());
+ BTUtils.fprintf_td(System.err, " [%02d.%02d] %s\n", i, j, serviceChar.toString());
+ }
+ final GattCharPropertySet properties = serviceChar.getProperties();
+ if( properties.isSet(GattCharPropertySet.Type.Read) ) {
+ final byte[] value = serviceChar.readValue();
+ final String svalue = BTUtils.decodeUTF8String(value, 0, value.length);
+ if( GATT_VERBOSE ) {
+ BTUtils.fprintf_td(System.err, " [%02d.%02d] value: %s ('%s')\n", i, j, BTUtils.bytesHexString(value, 0, -1, true), svalue);
+ }
+ }
+ int k=0;
+ final List<BTGattDesc> charDescList = serviceChar.getDescriptors();
+ for(final Iterator<BTGattDesc> descIter = charDescList.iterator(); descIter.hasNext(); k++) {
+ final BTGattDesc charDesc = descIter.next();
+ if( GATT_VERBOSE ) {
+ BTUtils.fprintf_td(System.err, " [%02d.%02d.%02d] Descriptor: UUID %s\n", i, j, k, charDesc.getUUID());
+ BTUtils.fprintf_td(System.err, " [%02d.%02d.%02d] %s\n", i, j, k, charDesc.toString());
+ }
+ }
+ final boolean cccdEnableResult[] = { false, false };
+ if( serviceChar.enableNotificationOrIndication( cccdEnableResult ) ) {
+ // ClientCharConfigDescriptor (CCD) is available
+ final boolean clAdded = null != serviceChar.addCharListener( new MyGATTEventListener(i, j) );
+ if( GATT_VERBOSE ) {
+ BTUtils.fprintf_td(System.err, " [%02d.%02d] Characteristic-Listener: Notification(%b), Indication(%b): Added %b\n",
+ i, j, cccdEnableResult[0], cccdEnableResult[1], clAdded);
+ BTUtils.fprintf_td(System.err, "\n");
+ }
+ }
+ }
+ if( GATT_VERBOSE ) {
+ BTUtils.fprintf_td(System.err, "\n");
+ }
+ }
+ } catch( final Exception ex) {
+ BTUtils.println(System.err, "****** Client Processing Ready Device: Exception.2 caught for " + device.toString() + ": "+ex.getMessage());
+ ex.printStackTrace();
+ }
+
+ {
+ final long t0 = BTUtils.currentTimeMillis();
+ boolean timeout = false;
+ do {
+ success = completedGATTCommands.get() >= 1 && ( notificationsReceived.get() >= 2 || indicationsReceived.get() >= 2 );
+ if( !success ) {
+ timeout = 3000 < ( BTUtils.currentTimeMillis() - t0 ); // 3s timeout
+ if( !timeout ) {
+ try { Thread.sleep(17); } catch (final InterruptedException e) { }
+ }
+ }
+ } while( !success && !timeout );
+ }
+
+ {
+ // Tell server we have successfully completed the test.
+ final BTGattCmd cmd = new BTGattCmd(device, "FinalHandshake", null /* service_uuid */, DBTConstants.CommandUUID, DBTConstants.ResponseUUID);
+ cmd.setVerbose(true);
+ final boolean cmd_resolved = cmd.isResolved();
+ BTUtils.println(System.err, "Client FinalCommand test: "+cmd.toString()+", resolved "+cmd_resolved);
+ final byte[] cmd_data = success ? DBTConstants.SuccessHandshakeCommandData : DBTConstants.FailHandshakeCommandData;
+ final HCIStatusCode cmd_res = cmd.send(true /* prefNoAck */, cmd_data, 3000 /* timeoutMS */);
+ if( HCIStatusCode.SUCCESS == cmd_res ) {
+ final byte[] resp = cmd.getResponse();
+ if( Arrays.equals(cmd_data, resp) ) {
+ BTUtils.fprintf_td(System.err, "Client Success: %s -> %s (echo response)\n", cmd.toString(), BTUtils.bytesHexString(resp, 0, resp.length, true /* lsb */));
+ } else {
+ BTUtils.fprintf_td(System.err, "Client Failure: %s -> %s (different response)\n", cmd.toString(), BTUtils.bytesHexString(resp, 0, resp.length, true /* lsb */));
+ success = false;
+ }
+ } else {
+ BTUtils.fprintf_td(System.err, "Client Failure: %s -> %s\n", cmd.toString(), cmd_res.toString());
+ success = false;
+ }
+ cmd.close();
+ }
+ } catch (final Throwable t ) {
+ BTUtils.println(System.err, "****** Client Processing Ready Device: Exception.2 caught for " + device.toString() + ": "+t.getMessage());
+ t.printStackTrace();
+ }
+
+ BTUtils.println(System.err, "****** Client Processing Ready Device: End-1: Success " + success +
+ " on " + device.toString() + "; devInProc "+BTDeviceRegistry.getProcessingDeviceCount());
+
+ if( DiscoveryPolicy.PAUSE_CONNECTED_UNTIL_DISCONNECTED == discoveryPolicy ) {
+ device.getAdapter().removeDevicePausingDiscovery(device);
+ }
+
+ BTUtils.println(System.err, "****** Client Processing Ready Device: End-2: Success " + success +
+ " on " + device.toString() + "; devInProc "+BTDeviceRegistry.getProcessingDeviceCount());
+ device.removeAllCharListener();
+
+ if( !KEEP_CONNECTED ) {
+ if( REMOVE_DEVICE ) {
+ device.remove();
+ } else {
+ device.disconnect();
+ }
+ }
+
+ completedMeasurementsTotal.addAndGet(1);
+ if( success ) {
+ completedMeasurementsSuccess.addAndGet(1);
+ }
+ if( 0 < measurementsLeft.get() ) {
+ measurementsLeft.decrementAndGet();
+ }
+ BTUtils.println(System.err, "****** Client Processing Ready Device: Success "+success+
+ "; Measurements completed "+completedMeasurementsSuccess.get()+
+ ", left "+measurementsLeft.get()+
+ "; Received notitifications "+notificationsReceived.get()+", indications "+indicationsReceived.get()+
+ "; Completed GATT commands "+completedGATTCommands.get()+
+ ": "+device.getAddressAndType());
+ }
+
+ private void removeDevice(final BTDevice device) {
+ BTUtils.println(System.err, "****** Client Remove Device: removing: "+device.getAddressAndType());
+
+ if( REMOVE_DEVICE ) {
+ device.remove();
+ }
+ }
+
+ static final boolean le_scan_active = true; // default value
+ static final short le_scan_interval = (short)24; // 15ms, default value
+ static final short le_scan_window = (short)24; // 15ms, default value
+ static final byte filter_policy = (byte)0; // default value
+ static final boolean filter_dup = true; // default value
+
+ @Override
+ public HCIStatusCode startDiscovery(final String msg) {
+ resetLastProcessingStats();
+
+ final HCIStatusCode status = clientAdapter.startDiscovery( discoveryPolicy, le_scan_active, le_scan_interval, le_scan_window, filter_policy, filter_dup );
+ BTUtils.println(System.err, "****** Client Start discovery ("+msg+") result: "+status);
+ return status;
+ }
+
+ @Override
+ public HCIStatusCode stopDiscovery(final String msg) {
+ final HCIStatusCode status = clientAdapter.stopDiscovery();
+ BTUtils.println(System.err, "****** Client Stop discovery ("+msg+") result: "+status);
+ return status;
+ }
+
+ @Override
+ public void close(final String msg) {
+ BTUtils.println(System.err, "****** Client Close: "+msg);
+ clientAdapter.stopDiscovery();
+ clientAdapter.removeStatusListener( myAdapterStatusListener );
+ }
+
+ @Override
+ public boolean initAdapter(final BTAdapter adapter) {
+ if( !useAdapter.equals(EUI48.ALL_DEVICE) && !useAdapter.equals(adapter.getAddressAndType().address) ) {
+ BTUtils.fprintf_td(System.err, "initClientAdapter: Adapter not selected: %s\n", adapter.toString());
+ return false;
+ }
+ adapterName = adapterName + "-" + adapter.getAddressAndType().address.toString().replace(":", "");
+
+ // Initialize with defaults and power-on
+ if( !adapter.isInitialized() ) {
+ final HCIStatusCode status = adapter.initialize( btMode );
+ if( HCIStatusCode.SUCCESS != status ) {
+ BTUtils.fprintf_td(System.err, "initClientAdapter: Adapter initialization failed: %s: %s\n",
+ status.toString(), adapter.toString());
+ return false;
+ }
+ } else if( !adapter.setPowered( true ) ) {
+ BTUtils.fprintf_td(System.err, "initClientAdapter: Already initialized adapter power-on failed:: %s\n", adapter.toString());
+ return false;
+ }
+ // adapter is powered-on
+ BTUtils.fprintf_td(System.err, "initClientAdapter.1: %s\n", adapter.toString());
+
+ if( adapter.setPowered(false) ) {
+ final HCIStatusCode status = adapter.setName(adapterName, adapterShortName);
+ if( HCIStatusCode.SUCCESS == status ) {
+ BTUtils.fprintf_td(System.err, "initClientAdapter: setLocalName OK: %s\n", adapter.toString());
+ } else {
+ BTUtils.fprintf_td(System.err, "initClientAdapter: setLocalName failed: %s\n", adapter.toString());
+ return false;
+ }
+ if( !adapter.setPowered( true ) ) {
+ BTUtils.fprintf_td(System.err, "initClientAdapter: setPower.2 on failed: %s\n", adapter.toString());
+ return false;
+ }
+ } else {
+ BTUtils.fprintf_td(System.err, "initClientAdapter: setPowered.2 off failed: %s\n", adapter.toString());
+ }
+ // adapter is powered-on
+ BTUtils.println(System.err, "initClientAdapter.2: "+adapter.toString());
+
+ {
+ final LE_Features le_feats = adapter.getLEFeatures();
+ BTUtils.fprintf_td(System.err, "initClientAdapter: LE_Features %s\n", le_feats.toString());
+ }
+ if( adapter.getBTMajorVersion() > 4 ) {
+ // BT5 specific
+ final LE_PHYs Tx = new LE_PHYs(LE_PHYs.PHY.LE_2M);
+ final LE_PHYs Rx = new LE_PHYs(LE_PHYs.PHY.LE_2M);
+
+ final HCIStatusCode res = adapter.setDefaultLE_PHY(Tx, Rx);
+ BTUtils.fprintf_td(System.err, "initClientAdapter: Set Default LE PHY: status %s: Tx %s, Rx %s\n",
+ res.toString(), Tx.toString(), Rx.toString());
+ }
+ adapter.addStatusListener( myAdapterStatusListener );
+
+ return true;
+ }
+}
diff --git a/trial/java/trial/org/direct_bt/DBTClientServer1x.java b/trial/java/trial/org/direct_bt/DBTClientServer1x.java
index 42507267..460e6ece 100644
--- a/trial/java/trial/org/direct_bt/DBTClientServer1x.java
+++ b/trial/java/trial/org/direct_bt/DBTClientServer1x.java
@@ -66,8 +66,21 @@ public abstract class DBTClientServer1x extends BaseDBTClientServer {
final void test8x_fullCycle(final long timeout_value,
final String suffix, final int protocolSessionCount, final boolean server_client_order,
- final boolean serverSC, final BTSecurityLevel secLevelServer, final boolean serverShallHaveKeys,
- final BTSecurityLevel secLevelClient, final boolean clientShallHaveKeys)
+ final boolean serverSC, final BTSecurityLevel secLevelServer, final ExpectedPairing serverExpPairing,
+ final BTSecurityLevel secLevelClient, final ExpectedPairing clientExpPairing)
+ {
+ final DBTServer00 server = new DBTServer00("S-"+suffix, EUI48.ALL_DEVICE, BTMode.DUAL, serverSC, secLevelServer);
+ final DBTClient00 client = new DBTClient00("C-"+suffix, EUI48.ALL_DEVICE, BTMode.DUAL);
+ test8x_fullCycle(timeout_value,
+ suffix, protocolSessionCount, server_client_order,
+ server, secLevelServer, serverExpPairing,
+ client, secLevelClient, clientExpPairing);
+ }
+
+ final void test8x_fullCycle(final long timeout_value,
+ final String suffix, final int protocolSessionCount, final boolean server_client_order,
+ final DBTServerTest server, final BTSecurityLevel secLevelServer, final ExpectedPairing serverExpPairing,
+ final DBTClientTest client, final BTSecurityLevel secLevelClient, final ExpectedPairing clientExpPairing)
{
final long t0 = BTUtils.currentTimeMillis();
@@ -89,10 +102,12 @@ public abstract class DBTClientServer1x extends BaseDBTClientServer {
Assert.assertTrue("Adapter count not >= 2 but "+adapters.size(), adapters.size() >= 2);
}
- final DBTServer00 server = new DBTServer00("S-"+suffix, EUI48.ALL_DEVICE, BTMode.DUAL, serverSC, secLevelServer);
- server.servingProtocolSessionsLeft.set(protocolSessionCount);
+ server.setProtocolSessionsLeft( protocolSessionCount );
- final DBTClient00 client = new DBTClient00("C-"+suffix, EUI48.ALL_DEVICE, BTMode.DUAL);
+ client.setProtocolSessionsLeft( protocolSessionCount );
+ client.setKeepConnected( false ); // default, auto-disconnect after work is done
+ client.setRemoveDevice( false ); // default, test side-effects
+ client.setDiscoveryPolicy( DiscoveryPolicy.PAUSE_CONNECTED_UNTIL_DISCONNECTED );
final DBTEndpoint.ChangedAdapterSetListener myChangedAdapterSetListener =
DBTEndpoint.initChangedAdapterSetListener(manager, server_client_order ? Arrays.asList(server, client) : Arrays.asList(client, server));
@@ -103,10 +118,6 @@ public abstract class DBTClientServer1x extends BaseDBTClientServer {
final BTSecurityRegistry.Entry sec = BTSecurityRegistry.getOrCreate(serverName);
sec.sec_level = secLevelClient;
}
- client.KEEP_CONNECTED = false; // default, auto-disconnect after work is done
- client.REMOVE_DEVICE = false; // default, test side-effects
- client.measurementsLeft.set(protocolSessionCount);
- client.discoveryPolicy = DiscoveryPolicy.PAUSE_CONNECTED_UNTIL_DISCONNECTED;
synchronized( mtx_sync ) {
lastCompletedDevice = null;
@@ -146,12 +157,12 @@ public abstract class DBTClientServer1x extends BaseDBTClientServer {
boolean max_connections_hit = false;
do {
synchronized( mtx_sync ) {
- done = ! ( protocolSessionCount > server.servedProtocolSessionsTotal.get() ||
- protocolSessionCount > client.completedMeasurements.get() ||
+ done = ! ( protocolSessionCount > server.getProtocolSessionsDoneSuccess() ||
+ protocolSessionCount > client.getProtocolSessionsDoneSuccess() ||
null == lastCompletedDevice ||
lastCompletedDevice.getConnected() );
}
- max_connections_hit = ( protocolSessionCount * DBTConstants.max_connections_per_session ) <= server.disconnectCount.get();
+ max_connections_hit = ( protocolSessionCount * DBTConstants.max_connections_per_session ) <= server.getDisconnectCount();
test_duration = BTUtils.currentTimeMillis() - t0;
timeout = 0 < timeout_value && timeout_value <= test_duration + 500; // let's timeout here before our timeout timer
if( !done && !max_connections_hit && !timeout ) {
@@ -164,23 +175,25 @@ public abstract class DBTClientServer1x extends BaseDBTClientServer {
BTUtils.fprintf_td(System.err, "****** Test Stats: duration %d ms, timeout[hit %b, value %d ms], max_connections hit %b\n",
test_duration, timeout, timeout_value, max_connections_hit);
BTUtils.fprintf_td(System.err, " Server ProtocolSessions[success %d/%d total, requested %d], disconnects %d of %d max\n",
- server.servedProtocolSessionsSuccess.get(), server.servedProtocolSessionsTotal.get(), protocolSessionCount,
- server.disconnectCount.get(), ( protocolSessionCount * DBTConstants.max_connections_per_session ));
- BTUtils.fprintf_td(System.err, " Client ProtocolSessions success %d \n",
- client.completedMeasurements.get());
+ server.getProtocolSessionsDoneSuccess(), server.getProtocolSessionsDoneTotal(), protocolSessionCount,
+ server.getDisconnectCount(), ( protocolSessionCount * DBTConstants.max_connections_per_session ));
+ BTUtils.fprintf_td(System.err, " Client ProtocolSessions[success %d/%d total, requested %d], disconnects %d of %d max\n",
+ client.getProtocolSessionsDoneSuccess(), client.getProtocolSessionsDoneTotal(), protocolSessionCount,
+ client.getDisconnectCount(), ( protocolSessionCount * DBTConstants.max_connections_per_session ));
BTUtils.fprintf_td(System.err, "\n\n");
Assert.assertFalse( max_connections_hit );
Assert.assertFalse( timeout );
synchronized( mtx_sync ) {
- Assert.assertEquals(protocolSessionCount, server.servedProtocolSessionsTotal.get());
- Assert.assertEquals(protocolSessionCount, server.servedProtocolSessionsSuccess.get());
- Assert.assertEquals(protocolSessionCount, client.completedMeasurements.get());
+ Assert.assertTrue(protocolSessionCount <= server.getProtocolSessionsDoneTotal());
+ Assert.assertEquals(protocolSessionCount, server.getProtocolSessionsDoneSuccess());
+ Assert.assertTrue(protocolSessionCount <= client.getProtocolSessionsDoneTotal());
+ Assert.assertEquals(protocolSessionCount, client.getProtocolSessionsDoneSuccess());
Assert.assertNotNull(lastCompletedDevice);
Assert.assertNotNull(lastCompletedDeviceEIR);
Assert.assertFalse(lastCompletedDevice.getConnected());
- Assert.assertTrue( ( 1 * DBTConstants.max_connections_per_session ) > server.disconnectCount.get() );
+ Assert.assertTrue( ( 1 * DBTConstants.max_connections_per_session ) > server.getDisconnectCount() );
}
//
@@ -203,15 +216,19 @@ public abstract class DBTClientServer1x extends BaseDBTClientServer {
final BTSecurityLevel clientKeysSecLevel = clientKeys.getSecLevel();
Assert.assertEquals(secLevelClient, clientKeysSecLevel);
{
- if( clientShallHaveKeys ) {
+ if( ExpectedPairing.PREPAIRED == clientExpPairing && BTSecurityLevel.NONE.value < secLevelClient.value ) {
// Using encryption: pre-paired
Assert.assertEquals(PairingMode.PRE_PAIRED, lastCompletedDevicePairingMode);
Assert.assertEquals(BTSecurityLevel.ENC_ONLY, lastCompletedDeviceSecurityLevel); // pre-paired fixed level, no auth
- } else if( BTSecurityLevel.NONE.value < secLevelClient.value ) {
+ } else if( ExpectedPairing.NEW_PAIRING == clientExpPairing && BTSecurityLevel.NONE.value < secLevelClient.value ) {
// Using encryption: Newly paired
Assert.assertNotEquals(PairingMode.PRE_PAIRED, lastCompletedDevicePairingMode);
Assert.assertTrue("PairingMode client "+lastCompletedDevicePairingMode+" not > NONE", PairingMode.NONE.value < lastCompletedDevicePairingMode.value);
Assert.assertTrue("SecurityLevel client "+lastCompletedDeviceSecurityLevel+" not >= "+secLevelClient, secLevelClient.value <= lastCompletedDeviceSecurityLevel.value);
+ } else if( ExpectedPairing.DONT_CARE == clientExpPairing && BTSecurityLevel.NONE.value < secLevelClient.value ) {
+ // Any encryption, any pairing
+ Assert.assertTrue("PairingMode client "+lastCompletedDevicePairingMode+" not > NONE", PairingMode.NONE.value < lastCompletedDevicePairingMode.value);
+ Assert.assertTrue("SecurityLevel client "+lastCompletedDeviceSecurityLevel+" not >= "+secLevelClient, secLevelClient.value <= lastCompletedDeviceSecurityLevel.value);
} else {
// No encryption: No pairing
Assert.assertEquals(PairingMode.NONE, lastCompletedDevicePairingMode);
diff --git a/trial/java/trial/org/direct_bt/DBTClientTest.java b/trial/java/trial/org/direct_bt/DBTClientTest.java
index e862d0cb..8b5a33a0 100644
--- a/trial/java/trial/org/direct_bt/DBTClientTest.java
+++ b/trial/java/trial/org/direct_bt/DBTClientTest.java
@@ -25,11 +25,36 @@ package trial.org.direct_bt;
import org.direct_bt.BTAdapter;
import org.direct_bt.BTRole;
+import org.direct_bt.DiscoveryPolicy;
import org.direct_bt.HCIStatusCode;
import org.junit.Assert;
public interface DBTClientTest extends DBTEndpoint {
+ /**
+ * Set DiscoveryPolicy
+ *
+ * Default is {@link DiscoveryPolicy#PAUSE_CONNECTED_UNTIL_READY}
+ */
+ void setDiscoveryPolicy(final DiscoveryPolicy v);
+
+ /**
+ * Set disconnect after processing.
+ *
+ * Default is `false`.
+ */
+ void setKeepConnected(final boolean v);
+
+ /**
+ * Set remove device when disconnecting.
+ *
+ * This removes the device from all instances within adapter
+ * and hence all potential side-effects of the current instance.
+ *
+ * Default is `false`, since it is good to test whether such side-effects exists.
+ */
+ void setRemoveDevice(final boolean v);
+
HCIStatusCode startDiscovery(String msg);
HCIStatusCode stopDiscovery(String msg);
diff --git a/trial/java/trial/org/direct_bt/DBTEndpoint.java b/trial/java/trial/org/direct_bt/DBTEndpoint.java
index 81ef9db9..6ea07e18 100644
--- a/trial/java/trial/org/direct_bt/DBTEndpoint.java
+++ b/trial/java/trial/org/direct_bt/DBTEndpoint.java
@@ -25,6 +25,7 @@ package trial.org.direct_bt;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
import org.direct_bt.BTAdapter;
import org.direct_bt.BTManager;
@@ -58,6 +59,12 @@ public interface DBTEndpoint {
void close(final String msg);
+ void setProtocolSessionsLeft(final int v);
+ int getProtocolSessionsLeft();
+ int getProtocolSessionsDoneTotal();
+ int getProtocolSessionsDoneSuccess();
+ int getDisconnectCount();
+
/**
* Initialize the given adapter for this endpoint.
*
diff --git a/trial/java/trial/org/direct_bt/DBTServer00.java b/trial/java/trial/org/direct_bt/DBTServer00.java
index 8bf7dc04..62483ee4 100644
--- a/trial/java/trial/org/direct_bt/DBTServer00.java
+++ b/trial/java/trial/org/direct_bt/DBTServer00.java
@@ -65,24 +65,25 @@ import org.jau.net.EUI48;
*/
public class DBTServer00 implements DBTServerTest {
final boolean GATT_VERBOSE = false;
- boolean SHOW_UPDATE_EVENTS = false;
-
- final String adapterShortName = "TDev1Srv";
- String adapterName = "TestDev1_Srv";
- EUI48 useAdapter = EUI48.ALL_DEVICE;
- BTMode btMode = BTMode.DUAL;
- boolean use_SC = true;
- BTSecurityLevel adapterSecurityLevel = BTSecurityLevel.UNSET;
+ private final String adapterShortName = "TDev1Srv";
+
+ private final boolean SHOW_UPDATE_EVENTS = false;
+
+ private String adapterName = "TestDev1_Srv";
+ private EUI48 useAdapter = EUI48.ALL_DEVICE;
+ private BTMode btMode = BTMode.DUAL;
+ private boolean use_SC = true;
+ private BTSecurityLevel adapterSecurityLevel = BTSecurityLevel.UNSET;
private final MyAdapterStatusListener myAdapterStatusListener = new MyAdapterStatusListener();
private final MyGATTServerListener gattServerListener = new MyGATTServerListener();
- BTAdapter serverAdapter = null;
+ private BTAdapter serverAdapter = null;
private final Object sync_lock = new Object();
private volatile BTDevice connectedDevice;
- public AtomicInteger disconnectCount = new AtomicInteger(0);
- public AtomicInteger servedProtocolSessionsTotal = new AtomicInteger(0);
- public AtomicInteger servedProtocolSessionsSuccess = new AtomicInteger(0);
- public AtomicInteger servingProtocolSessionsLeft = new AtomicInteger(1);
+ private final AtomicInteger disconnectCount = new AtomicInteger(0);
+ private final AtomicInteger servedProtocolSessionsTotal = new AtomicInteger(0);
+ private final AtomicInteger servedProtocolSessionsSuccess = new AtomicInteger(0);
+ private final AtomicInteger servingProtocolSessionsLeft = new AtomicInteger(1);
public DBTServer00(final String adapterName, final EUI48 useAdapter, final BTMode btMode, final boolean use_SC, final BTSecurityLevel adapterSecurityLevel) {
this.adapterName = adapterName;
@@ -113,6 +114,27 @@ public class DBTServer00 implements DBTServerTest {
@Override
public BTAdapter getAdapter() { return serverAdapter; }
+ @Override
+ public void setProtocolSessionsLeft(final int v) {
+ servingProtocolSessionsLeft.set(v);
+ }
+ @Override
+ public int getProtocolSessionsLeft() {
+ return servingProtocolSessionsLeft.get();
+ }
+ @Override
+ public int getProtocolSessionsDoneTotal() {
+ return servedProtocolSessionsTotal.get();
+ }
+ @Override
+ public int getProtocolSessionsDoneSuccess() {
+ return servedProtocolSessionsSuccess.get();
+ }
+ @Override
+ public int getDisconnectCount() {
+ return this.disconnectCount.get();
+ }
+
private final void setDevice(final BTDevice cd) {
synchronized( sync_lock ) {
connectedDevice = cd;
@@ -422,7 +444,7 @@ public class DBTServer00 implements DBTServerTest {
}
}
- void sendResponse(final byte[] data) {
+ private void sendResponse(final byte[] data) {
final BTDevice connectedDevice_ = getDevice();
if( null != connectedDevice_ && connectedDevice_.getConnected() ) {
if( 0 != handleResponseDataNotify || 0 != handleResponseDataIndicate ) {
diff --git a/trial/java/trial/org/direct_bt/DBTServer01.java b/trial/java/trial/org/direct_bt/DBTServer01.java
new file mode 100644
index 00000000..54d316be
--- /dev/null
+++ b/trial/java/trial/org/direct_bt/DBTServer01.java
@@ -0,0 +1,842 @@
+/**
+ * Author: Sven Gothel <[email protected]>
+ * Copyright (c) 2022 Gothel Software e.K.
+ *
+ * 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 trial.org.direct_bt;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.direct_bt.AdapterSettings;
+import org.direct_bt.AdapterStatusListener;
+import org.direct_bt.BDAddressAndType;
+import org.direct_bt.BTMode;
+import org.direct_bt.BTSecurityLevel;
+import org.direct_bt.BTAdapter;
+import org.direct_bt.BTDevice;
+import org.direct_bt.BTDeviceRegistry;
+import org.direct_bt.BTSecurityRegistry;
+import org.direct_bt.BTUtils;
+import org.direct_bt.DBGattChar;
+import org.direct_bt.DBGattDesc;
+import org.direct_bt.DBGattServer;
+import org.direct_bt.DBGattService;
+import org.direct_bt.DBGattValue;
+import org.direct_bt.DiscoveryPolicy;
+import org.direct_bt.EIRDataTypeSet;
+import org.direct_bt.EInfoReport;
+import org.direct_bt.GAPFlags;
+import org.direct_bt.GattCharPropertySet;
+import org.direct_bt.HCIStatusCode;
+import org.direct_bt.LE_Features;
+import org.direct_bt.LE_PHYs;
+import org.direct_bt.PairingMode;
+import org.direct_bt.SMPIOCapability;
+import org.direct_bt.SMPPairingState;
+import org.direct_bt.ScanType;
+import org.jau.net.EUI48;
+
+import trial.org.direct_bt.DBTServer00.MyAdapterStatusListener;
+import trial.org.direct_bt.DBTServer00.MyGATTServerListener;
+
+/**
+ * This peripheral BTRole::Slave test participant works with DBTClient00.
+ */
+public class DBTServer01 implements DBTServerTest {
+ final boolean GATT_VERBOSE = false;
+ private final String adapterShortName = "TDev1Srv";
+
+ private final boolean SHOW_UPDATE_EVENTS = false;
+
+ private String adapterName = "TestDev1_Srv";
+ private EUI48 useAdapter = EUI48.ALL_DEVICE;
+ private BTMode btMode = BTMode.DUAL;
+ private boolean use_SC = true;
+ private BTSecurityLevel adapterSecurityLevel = BTSecurityLevel.UNSET;
+ private final MyAdapterStatusListener myAdapterStatusListener = new MyAdapterStatusListener();
+ private final MyGATTServerListener gattServerListener = new MyGATTServerListener();
+ private BTAdapter serverAdapter = null;
+ private final Object sync_lock = new Object();
+ private volatile BTDevice connectedDevice;
+
+ private final AtomicInteger disconnectCount = new AtomicInteger(0);
+ private final AtomicInteger servedProtocolSessionsTotal = new AtomicInteger(0);
+ private final AtomicInteger servedProtocolSessionsSuccess = new AtomicInteger(0);
+ private final AtomicInteger servingProtocolSessionsLeft = new AtomicInteger(1);
+
+ public DBTServer01(final String adapterName, final EUI48 useAdapter, final BTMode btMode, final boolean use_SC, final BTSecurityLevel adapterSecurityLevel) {
+ this.adapterName = adapterName;
+ this.useAdapter = useAdapter;
+ this.btMode = btMode;
+ this.use_SC = use_SC;
+ this.adapterSecurityLevel = adapterSecurityLevel;
+
+ dbGattServer.addListener( gattServerListener );
+ }
+ public DBTServer01(final String adapterName, final EUI48 useAdapter, final BTSecurityLevel adapterSecurityLevel) {
+ this(adapterName, useAdapter, BTMode.DUAL, true /* SC */, adapterSecurityLevel);
+ }
+ public DBTServer01(final String adapterName, final BTSecurityLevel adapterSecurityLevel) {
+ this(adapterName, EUI48.ALL_DEVICE, BTMode.DUAL, true /* SC */, adapterSecurityLevel);
+ }
+
+ @Override
+ public String getName() { return adapterName; }
+
+ @Override
+ public BTSecurityLevel getSecurityLevel() { return adapterSecurityLevel; }
+
+ @Override
+ public void setAdapter(final BTAdapter serverAdapter) {
+ this.serverAdapter = serverAdapter;
+ }
+ @Override
+ public BTAdapter getAdapter() { return serverAdapter; }
+
+ @Override
+ public void setProtocolSessionsLeft(final int v) {
+ servingProtocolSessionsLeft.set(v);
+ }
+ @Override
+ public int getProtocolSessionsLeft() {
+ return servingProtocolSessionsLeft.get();
+ }
+ @Override
+ public int getProtocolSessionsDoneTotal() {
+ return servedProtocolSessionsTotal.get();
+ }
+ @Override
+ public int getProtocolSessionsDoneSuccess() {
+ return servedProtocolSessionsSuccess.get();
+ }
+
+ @Override
+ public int getDisconnectCount() {
+ return this.disconnectCount.get();
+ }
+
+ private final void setDevice(final BTDevice cd) {
+ synchronized( sync_lock ) {
+ connectedDevice = cd;
+ }
+ }
+
+ private final BTDevice getDevice() {
+ synchronized( sync_lock ) {
+ return connectedDevice;
+ }
+ }
+
+ private boolean matches(final BTDevice device) {
+ final BTDevice d = getDevice();
+ return null != d ? d.equals(device) : false;
+ }
+
+ static Thread executeOffThread(final Runnable runobj, final String threadName, final boolean detach) {
+ final Thread t = new Thread( runobj, threadName );
+ t.setDaemon( detach );
+ t.start();
+ return t;
+ }
+ static Thread executeOffThread(final Runnable runobj, final boolean detach) {
+ final Thread t = new Thread( runobj );
+ t.setDaemon( detach );
+ t.start();
+ return t;
+ }
+
+ static DBGattValue make_gvalue(final String name) {
+ final byte[] p = name.getBytes(StandardCharsets.UTF_8);
+ return new DBGattValue(p, p.length);
+ }
+ static DBGattValue make_gvalue(final String name, final int capacity) {
+ final byte[] p = name.getBytes(StandardCharsets.UTF_8);
+ return new DBGattValue(p, Math.max(capacity, p.length), capacity > p.length/* variable_length */);
+ }
+ static DBGattValue make_gvalue(final short v) {
+ final byte[] p = { (byte)0, (byte)0 };
+ p[0] = (byte)(v);
+ p[1] = (byte)(v >> 8);
+ return new DBGattValue(p, p.length);
+ }
+ static DBGattValue make_gvalue(final int capacity, final int size) {
+ final byte[] p = new byte[size];
+ return new DBGattValue(p, capacity, true /* variable_length */);
+ }
+
+ // DBGattServerRef dbGattServer = std::make_shared<DBGattServer>(
+ private final DBGattServer dbGattServer = new DBGattServer(
+ /* services: */
+ Arrays.asList( // DBGattService
+ new DBGattService ( true /* primary */,
+ DBGattService.UUID16.GENERIC_ACCESS /* type_ */,
+ Arrays.asList( // DBGattChar
+ new DBGattChar( DBGattChar.UUID16.DEVICE_NAME /* value_type_ */,
+ new GattCharPropertySet(GattCharPropertySet.Type.Read),
+ new ArrayList<DBGattDesc>(/* intentionally w/o Desc */ ),
+ make_gvalue(adapterName, 128) /* value */ ),
+ new DBGattChar( DBGattChar.UUID16.APPEARANCE /* value_type_ */,
+ new GattCharPropertySet(GattCharPropertySet.Type.Read),
+ new ArrayList<DBGattDesc>(/* intentionally w/o Desc */ ),
+ make_gvalue((short)0) /* value */ )
+ ) ),
+ new DBGattService ( true /* primary */,
+ DBGattService.UUID16.DEVICE_INFORMATION /* type_ */,
+ Arrays.asList( // DBGattChar
+ new DBGattChar( DBGattChar.UUID16.MANUFACTURER_NAME_STRING /* value_type_ */,
+ new GattCharPropertySet(GattCharPropertySet.Type.Read),
+ new ArrayList<DBGattDesc>(/* intentionally w/o Desc */ ),
+ make_gvalue("Gothel Software") /* value */ ),
+ new DBGattChar( DBGattChar.UUID16.MODEL_NUMBER_STRING /* value_type_ */,
+ new GattCharPropertySet(GattCharPropertySet.Type.Read),
+ new ArrayList<DBGattDesc>(/* intentionally w/o Desc */ ),
+ make_gvalue("2.4.0-pre") /* value */ ),
+ new DBGattChar( DBGattChar.UUID16.SERIAL_NUMBER_STRING /* value_type_ */,
+ new GattCharPropertySet(GattCharPropertySet.Type.Read),
+ new ArrayList<DBGattDesc>(/* intentionally w/o Desc */ ),
+ make_gvalue("sn:0123456789") /* value */ ),
+ new DBGattChar( DBGattChar.UUID16.HARDWARE_REVISION_STRING /* value_type_ */,
+ new GattCharPropertySet(GattCharPropertySet.Type.Read),
+ new ArrayList<DBGattDesc>(/* intentionally w/o Desc */ ),
+ make_gvalue("hw:0123456789") /* value */ ),
+ new DBGattChar( DBGattChar.UUID16.FIRMWARE_REVISION_STRING /* value_type_ */,
+ new GattCharPropertySet(GattCharPropertySet.Type.Read),
+ new ArrayList<DBGattDesc>(/* intentionally w/o Desc */ ),
+ make_gvalue("fw:0123456789") /* value */ ),
+ new DBGattChar( DBGattChar.UUID16.SOFTWARE_REVISION_STRING /* value_type_ */,
+ new GattCharPropertySet(GattCharPropertySet.Type.Read),
+ new ArrayList<DBGattDesc>(/* intentionally w/o Desc */ ),
+ make_gvalue("sw:0123456789") /* value */ )
+ ) ),
+ new DBGattService ( true /* primary */,
+ DBTConstants.DataServiceUUID /* type_ */,
+ Arrays.asList( // DBGattChar
+ new DBGattChar( DBTConstants.StaticDataUUID /* value_type_ */,
+ new GattCharPropertySet(GattCharPropertySet.Type.Read),
+ Arrays.asList( // DBGattDesc
+ new DBGattDesc( DBGattDesc.UUID16.USER_DESC, make_gvalue("DATA_STATIC") )
+ ),
+ make_gvalue("Proprietary Static Data 0x00010203") /* value */ ),
+ new DBGattChar( DBTConstants.CommandUUID /* value_type_ */,
+ new GattCharPropertySet(GattCharPropertySet.Type.WriteNoAck).set(GattCharPropertySet.Type.WriteWithAck),
+ Arrays.asList( // DBGattDesc
+ new DBGattDesc( DBGattDesc.UUID16.USER_DESC, make_gvalue("COMMAND") )
+ ),
+ make_gvalue(128, 64) /* value */ ),
+ new DBGattChar( DBTConstants.ResponseUUID /* value_type_ */,
+ new GattCharPropertySet(GattCharPropertySet.Type.Notify).set(GattCharPropertySet.Type.Indicate),
+ Arrays.asList( // DBGattDesc
+ new DBGattDesc( DBGattDesc.UUID16.USER_DESC, make_gvalue("RESPONSE") ),
+ DBGattDesc.createClientCharConfig()
+ ),
+ make_gvalue((short)0) /* value */ ),
+ new DBGattChar( DBTConstants.PulseDataUUID /* value_type_ */,
+ new GattCharPropertySet(GattCharPropertySet.Type.Notify).set(GattCharPropertySet.Type.Indicate),
+ Arrays.asList( // DBGattDesc
+ new DBGattDesc( DBGattDesc.UUID16.USER_DESC, make_gvalue("DATA_PULSE") ),
+ DBGattDesc.createClientCharConfig()
+ ),
+ make_gvalue("Synthethic Sensor 01") /* value */ )
+ ) )
+ ) );
+
+
+ class MyAdapterStatusListener extends AdapterStatusListener {
+ @Override
+ public void adapterSettingsChanged(final BTAdapter adapter, final AdapterSettings oldmask,
+ final AdapterSettings newmask, final AdapterSettings changedmask, final long timestamp) {
+ final boolean initialSetting = oldmask.isEmpty();
+ if( initialSetting ) {
+ BTUtils.println(System.err, "****** Server SETTINGS: "+oldmask+" -> "+newmask+", initial "+changedmask);
+ } else {
+ BTUtils.println(System.err, "****** Server SETTINGS: "+oldmask+" -> "+newmask+", changed "+changedmask);
+ }
+ BTUtils.println(System.err, "Server Status Adapter:");
+ BTUtils.println(System.err, adapter.toString());
+ }
+
+ @Override
+ public void discoveringChanged(final BTAdapter adapter, final ScanType currentMeta, final ScanType changedType, final boolean changedEnabled, final DiscoveryPolicy policy, final long timestamp) {
+ BTUtils.println(System.err, "****** Server DISCOVERING: meta "+currentMeta+", changed["+changedType+", enabled "+changedEnabled+", policy "+policy+"] on "+adapter);
+ }
+
+ @Override
+ public boolean deviceFound(final BTDevice device, final long timestamp) {
+ BTUtils.println(System.err, "****** Server FOUND__-1: NOP "+device.toString());
+ return false;
+ }
+
+ @Override
+ public void deviceUpdated(final BTDevice device, final EIRDataTypeSet updateMask, final long timestamp) {
+ if( SHOW_UPDATE_EVENTS ) {
+ BTUtils.println(System.err, "****** Server UPDATED: "+updateMask+" of "+device);
+ }
+ }
+
+ @Override
+ public void deviceConnected(final BTDevice device, final short handle, final long timestamp) {
+ BTUtils.println(System.err, "****** Server CONNECTED (served "+disconnectCount.get()+", left "+servingProtocolSessionsLeft.get()+"): handle 0x"+Integer.toHexString(handle)+": "+device+" on "+device.getAdapter());
+ final boolean available = null == getDevice();
+ if( available ) {
+ setDevice(device);
+ BTDeviceRegistry.addToProcessingDevices(device.getAddressAndType(), device.getName());
+ }
+ }
+
+ @Override
+ public void devicePairingState(final BTDevice device, final SMPPairingState state, final PairingMode mode, final long timestamp) {
+ BTUtils.println(System.err, "****** Server PAIRING_STATE: state "+state+", mode "+mode+": "+device);
+ switch( state ) {
+ case NONE:
+ // next: deviceReady(..)
+ break;
+ case FAILED: {
+ // next: deviceReady() or deviceDisconnected(..)
+ } break;
+ case REQUESTED_BY_RESPONDER:
+ // next: FEATURE_EXCHANGE_STARTED
+ break;
+ case FEATURE_EXCHANGE_STARTED:
+ // next: FEATURE_EXCHANGE_COMPLETED
+ break;
+ case FEATURE_EXCHANGE_COMPLETED:
+ // next: PASSKEY_EXPECTED... or KEY_DISTRIBUTION
+ break;
+ case PASSKEY_EXPECTED: {
+ final BTSecurityRegistry.Entry sec = BTSecurityRegistry.getStartOf(device.getAddressAndType().address, "");
+ if( null != sec && sec.getPairingPasskey() != BTSecurityRegistry.NO_PASSKEY ) {
+ executeOffThread( () -> { device.setPairingPasskey( sec.getPairingPasskey() ); }, "DBT-SetPasskey-"+device.getAddressAndType(), true /* detach */);
+ } else {
+ executeOffThread( () -> { device.setPairingPasskey( 0 ); }, "DBT-SetPasskey-"+device.getAddressAndType(), true /* detach */);
+ // 3s disconnect: executeOffThread( () -> { device.setPairingPasskeyNegative(); }, "DBT-SetPasskeyNegative-"+device.getAddressAndType(), true /* detach */);
+ }
+ // next: KEY_DISTRIBUTION or FAILED
+ } break;
+ case NUMERIC_COMPARE_EXPECTED: {
+ final BTSecurityRegistry.Entry sec = BTSecurityRegistry.getStartOf(device.getAddressAndType().address, "");
+ if( null != sec ) {
+ executeOffThread( () -> { device.setPairingNumericComparison( sec.getPairingNumericComparison() ); }, "DBT-SetNumericComp-"+device.getAddressAndType(), true /* detach */);
+ } else {
+ executeOffThread( () -> { device.setPairingNumericComparison( false ); }, "DBT-SetNumericCompFalse-"+device.getAddressAndType(), true /* detach */);
+ }
+ // next: KEY_DISTRIBUTION or FAILED
+ } break;
+ case OOB_EXPECTED:
+ // FIXME: ABORT
+ break;
+ case KEY_DISTRIBUTION:
+ // next: COMPLETED or FAILED
+ break;
+ case COMPLETED:
+ // next: deviceReady(..)
+ break;
+ default: // nop
+ break;
+ }
+ }
+
+ @Override
+ public void deviceReady(final BTDevice device, final long timestamp) {
+ BTUtils.println(System.err, "****** Server READY-1: NOP " + device.toString());
+ }
+
+ @Override
+ public void deviceDisconnected(final BTDevice device, final HCIStatusCode reason, final short handle, final long timestamp) {
+ BTUtils.println(System.err, "****** Server DISCONNECTED (served "+(1+disconnectCount.get())+", left "+servingProtocolSessionsLeft.get()+"): Reason "+reason+", old handle 0x"+Integer.toHexString(handle)+": "+device+" on "+device.getAdapter());
+ final boolean match = matches(device);
+ if( match ) {
+ setDevice(null);
+ }
+ executeOffThread( () -> { processDisconnectedDevice(device); },
+ "Server DBT-Disconnected-"+device.getAdapter().getAddressAndType(), true /* detach */);
+ }
+
+ @Override
+ public String toString() {
+ return "Server AdapterStatusListener[user, per-adapter]";
+ }
+ };
+
+ class MyGATTServerListener extends DBGattServer.Listener implements AutoCloseable {
+ private final Thread pulseSenderThread;
+ private volatile boolean stopPulseSenderFlag = false;
+
+ private volatile short handlePulseDataNotify = 0;
+ private volatile short handlePulseDataIndicate = 0;
+ private volatile short handleResponseDataNotify = 0;
+ private volatile short handleResponseDataIndicate = 0;
+
+ private int usedMTU = 23; // BTGattHandler::number(BTGattHandler::Defaults::MIN_ATT_MTU);
+
+ private void clear() {
+ synchronized( sync_lock ) {
+ handlePulseDataNotify = 0;
+ handlePulseDataIndicate = 0;
+ handleResponseDataNotify = 0;
+ handleResponseDataIndicate = 0;
+
+ dbGattServer.resetGattClientCharConfig(DBTConstants.DataServiceUUID, DBTConstants.PulseDataUUID);
+ dbGattServer.resetGattClientCharConfig(DBTConstants.DataServiceUUID, DBTConstants.ResponseUUID);
+ }
+ }
+
+ private boolean shallStopPulseSender() {
+ synchronized( sync_lock ) {
+ return stopPulseSenderFlag;
+ }
+ }
+ private void pulseSender() {
+ {
+ final BTDevice connectedDevice_ = getDevice();
+ final String connectedDeviceStr = null != connectedDevice_ ? connectedDevice_.toString() : "n/a";
+ BTUtils.fprintf_td(System.err, "****** Server GATT::PULSE Start %s\n", connectedDeviceStr);
+ }
+ while( !shallStopPulseSender() ) {
+ final BTDevice connectedDevice_ = getDevice();
+ if( null != connectedDevice_ && connectedDevice_.getConnected() ) {
+ if( 0 != handlePulseDataNotify || 0 != handlePulseDataIndicate ) {
+ final String data = String.format("Dynamic Data Example. Elapsed Milliseconds: %,9d", BTUtils.elapsedTimeMillis());
+ final byte[] v = data.getBytes(StandardCharsets.UTF_8);
+ if( 0 != handlePulseDataNotify ) {
+ if( GATT_VERBOSE ) {
+ BTUtils.fprintf_td(System.err, "****** Server GATT::sendNotification: PULSE to %s\n", connectedDevice_.toString());
+ }
+ connectedDevice_.sendNotification(handlePulseDataNotify, v);
+ }
+ if( 0 != handlePulseDataIndicate ) {
+ if( GATT_VERBOSE ) {
+ BTUtils.fprintf_td(System.err, "****** Server GATT::sendIndication: PULSE to %s\n", connectedDevice_.toString());
+ }
+ connectedDevice_.sendIndication(handlePulseDataIndicate, v);
+ }
+ }
+ }
+ if( !shallStopPulseSender() ) {
+ try {
+ Thread.sleep(100); // 100ms
+ } catch (final InterruptedException e) { }
+ }
+ }
+ {
+ final BTDevice connectedDevice_ = getDevice();
+ final String connectedDeviceStr = null != connectedDevice_ ? connectedDevice_.toString() : "n/a";
+ BTUtils.fprintf_td(System.err, "****** Server GATT::PULSE End %s\n", connectedDeviceStr);
+ }
+ }
+
+ private void sendResponse(final byte[] data) {
+ final BTDevice connectedDevice_ = getDevice();
+ if( null != connectedDevice_ && connectedDevice_.getConnected() ) {
+ if( 0 != handleResponseDataNotify || 0 != handleResponseDataIndicate ) {
+ if( 0 != handleResponseDataNotify ) {
+ if( GATT_VERBOSE ) {
+ BTUtils.fprintf_td(System.err, "****** Server GATT::sendNotification: %s to %s\n",
+ BTUtils.bytesHexString(data, 0, data.length, true /* lsb */), connectedDevice_.toString());
+ }
+ connectedDevice_.sendNotification(handleResponseDataNotify, data);
+ }
+ if( 0 != handleResponseDataIndicate ) {
+ if( GATT_VERBOSE ) {
+ BTUtils.fprintf_td(System.err, "****** Server GATT::sendIndication: %s to %s\n",
+ BTUtils.bytesHexString(data, 0, data.length, true /* lsb */), connectedDevice_.toString());
+ }
+ connectedDevice_.sendIndication(handleResponseDataIndicate, data);
+ }
+ }
+ }
+ }
+
+ boolean onceDisconnect = true;
+
+ private void disconnectDevice() {
+ try {
+ Thread.sleep(300);
+ } catch (final InterruptedException e) { }
+
+ final BTDevice connectedDevice_ = getDevice();
+ BTUtils.fprintf_td(System.err, "****** Server GATT::disconnectDevice(sessions [%d ok / %d total], left %d): client %s\n",
+ servedProtocolSessionsSuccess.get(), servedProtocolSessionsTotal.get(), servingProtocolSessionsLeft.get(),
+ connectedDevice_.toString());
+ connectedDevice_.disconnect();
+ }
+
+ public MyGATTServerListener() {
+ pulseSenderThread = executeOffThread( () -> { pulseSender(); }, "GattServer-PulseSender", false /* detach */);
+ }
+
+ @Override
+ public void close() {
+ synchronized( sync_lock ) {
+ clear();
+ stopPulseSenderFlag = true;
+ }
+ try {
+ pulseSenderThread.join(1000);
+ } catch (final InterruptedException e) { }
+ super.close();
+ }
+
+ @Override
+ public void connected(final BTDevice device, final int initialMTU) {
+ final boolean match = matches(device);
+ BTUtils.fprintf_td(System.err, "****** Server GATT::connected(match %b): initMTU %d, %s\n",
+ match, initialMTU, device.toString());
+ if( match ) {
+ synchronized( sync_lock ) {
+ usedMTU = initialMTU;
+ }
+ }
+ }
+
+ @Override
+ public void disconnected(final BTDevice device) {
+ final boolean match = matches(device);
+ BTUtils.fprintf_td(System.err, "****** Server GATT::disconnected(match %b): %s\n", match, device.toString());
+ if( match ) {
+ clear();
+ }
+ }
+
+ @Override
+ public void mtuChanged(final BTDevice device, final int mtu) {
+ final boolean match = matches(device);
+ final int usedMTU_old = usedMTU;
+ if( match ) {
+ synchronized( sync_lock ) {
+ usedMTU = mtu;
+ }
+ }
+ BTUtils.fprintf_td(System.err, "****** Server GATT::mtuChanged(match %b, served %d, left %d): %d -> %d, %s\n",
+ match, servedProtocolSessionsTotal.get(), servingProtocolSessionsLeft.get(),
+ match ? usedMTU_old : 0, mtu, device.toString());
+ if( onceDisconnect ) {
+ onceDisconnect = false;
+ executeOffThread( () -> { disconnectDevice(); }, "GattServer-DisconnectDevice", true /* detach */);
+ }
+ }
+
+ @Override
+ public boolean readCharValue(final BTDevice device, final DBGattService s, final DBGattChar c) {
+ final boolean match = matches(device);
+ if( GATT_VERBOSE ) {
+ BTUtils.fprintf_td(System.err, "****** Server GATT::readCharValue(match %b): to %s, from\n %s\n %s\n",
+ match, device.toString(), s.toString(), c.toString());
+ }
+ return match;
+ }
+
+ @Override
+ public boolean readDescValue(final BTDevice device, final DBGattService s, final DBGattChar c, final DBGattDesc d) {
+ final boolean match = matches(device);
+ if( GATT_VERBOSE ) {
+ BTUtils.fprintf_td(System.err, "****** Server GATT::readDescValue(match %b): to %s, from\n %s\n %s\n %s\n",
+ match, device.toString(), s.toString(), c.toString(), d.toString());
+ }
+ return match;
+ }
+
+ @Override
+ public boolean writeCharValue(final BTDevice device, final DBGattService s, final DBGattChar c, final byte[] value, final int value_offset) {
+ final boolean match = matches(device);
+ if( GATT_VERBOSE ) {
+ final String value_s = BTUtils.bytesHexString(value, 0, value.length, true /* lsbFirst */)+
+ " '"+BTUtils.decodeUTF8String(value, 0, value.length)+"'";
+ BTUtils.fprintf_td(System.err, "****** Server GATT::writeCharValue(match %b): %s @ %d from %s, to\n %s\n %s\n",
+ match, value_s, value_offset,
+ device.toString(), s.toString(), c.toString());
+ }
+ return match;
+ }
+
+ @Override
+ public void writeCharValueDone(final BTDevice device, final DBGattService s, final DBGattChar c) {
+ final boolean match = matches(device);
+ final DBGattValue value = c.getValue();
+ final byte[] data = value.data();
+ boolean isFinalHandshake = false;
+ boolean isFinalHandshakeSuccess = false;
+
+ if( match &&
+ c.getValueType().equals( DBTConstants.CommandUUID ) &&
+ ( 0 != handleResponseDataNotify || 0 != handleResponseDataIndicate ) )
+ {
+ isFinalHandshakeSuccess = Arrays.equals(DBTConstants.SuccessHandshakeCommandData, data);
+ isFinalHandshake = isFinalHandshakeSuccess ||
+ Arrays.equals(DBTConstants.FailHandshakeCommandData, data);
+
+ if( isFinalHandshake ) {
+ if( isFinalHandshakeSuccess ) {
+ servedProtocolSessionsSuccess.addAndGet(1);
+ }
+ servedProtocolSessionsTotal.addAndGet(1); // we assume this to be server, i.e. connected, SMP done and GATT action ..
+ if( servingProtocolSessionsLeft.get() > 0 ) {
+ servingProtocolSessionsLeft.decrementAndGet();
+ }
+ }
+ executeOffThread( () -> { sendResponse( data ); }, true /* detach */);
+ }
+ if( GATT_VERBOSE || isFinalHandshake ) {
+ BTUtils.fprintf_td(System.err, "****** Server GATT::writeCharValueDone(match %b, finalCmd %b, sessions [%d ok / %d total], left %d): From %s, to\n %s\n %s\n Char-Value: %s\n",
+ match, isFinalHandshake, servedProtocolSessionsSuccess.get(), servedProtocolSessionsTotal.get(), servingProtocolSessionsLeft.get(),
+ device.toString(), s.toString(), c.toString(), value.toString());
+ }
+ }
+
+ @Override
+ public boolean writeDescValue(final BTDevice device, final DBGattService s, final DBGattChar c, final DBGattDesc d,
+ final byte[] value, final int value_offset)
+ {
+ final boolean match = matches(device);
+ if( GATT_VERBOSE ) {
+ final String value_s = BTUtils.bytesHexString(value, 0, value.length, true /* lsbFirst */)+
+ " '"+BTUtils.decodeUTF8String(value, 0, value.length)+"'";
+ BTUtils.fprintf_td(System.err, "****** Server GATT::writeDescValue(match %b): %s @ %d from %s\n %s\n %s\n %s\n",
+ match, value_s, value_offset,
+ device.toString(), s.toString(), c.toString(), d.toString());
+ }
+ return match;
+ }
+
+ @Override
+ public void writeDescValueDone(final BTDevice device, final DBGattService s, final DBGattChar c, final DBGattDesc d) {
+ if( GATT_VERBOSE ) {
+ final boolean match = matches(device);
+ final DBGattValue value = d.getValue();
+ BTUtils.fprintf_td(System.err, "****** Server GATT::writeDescValueDone(match %b): From %s\n %s\n %s\n %s\n Desc-Value: %s\n",
+ match, device.toString(), s.toString(), c.toString(), d.toString(), value.toString());
+ }
+ }
+
+ @Override
+ public void clientCharConfigChanged(final BTDevice device, final DBGattService s, final DBGattChar c, final DBGattDesc d,
+ final boolean notificationEnabled, final boolean indicationEnabled)
+ {
+ final boolean match = matches(device);
+ if( GATT_VERBOSE ) {
+ final DBGattValue value = d.getValue();
+ BTUtils.fprintf_td(System.err, "****** Server GATT::clientCharConfigChanged(match %b): notify %b, indicate %b from %s\n %s\n %s\n %s\n Desc-Value: %s\n",
+ match, notificationEnabled, indicationEnabled,
+ device.toString(), s.toString(), c.toString(), d.toString(), value.toString());
+ }
+ if( match ) {
+ final String value_type = c.getValueType();
+ final short value_handle = c.getValueHandle();
+ if( value_type.equals( DBTConstants.PulseDataUUID ) ) {
+ synchronized( sync_lock ) {
+ handlePulseDataNotify = notificationEnabled ? value_handle : 0;
+ handlePulseDataIndicate = indicationEnabled ? value_handle : 0;
+ }
+ } else if( value_type.equals( DBTConstants.ResponseUUID ) ) {
+ synchronized( sync_lock ) {
+ handleResponseDataNotify = notificationEnabled ? value_handle : 0;
+ handleResponseDataIndicate = indicationEnabled ? value_handle : 0;
+ }
+ }
+ }
+ }
+ }
+ static final short adv_interval_min=(short)160; // x0.625 = 100ms
+ static final short adv_interval_max=(short)480; // x0.625 = 300ms
+ static final byte adv_type=(byte)0; // AD_PDU_Type::ADV_IND;
+ static final byte adv_chan_map=(byte)0x07;
+ static final byte filter_policy=(byte)0x00;
+
+ @Override
+ public HCIStatusCode stop(final String msg) {
+ BTUtils.println(System.err, "****** Server Stop.0: "+msg);
+ final HCIStatusCode res = stopAdvertising(msg);
+ final BTDevice connectedDevice_ = getDevice();
+ if( null != connectedDevice_ ) {
+ setDevice(null);
+ connectedDevice_.disconnect();
+ }
+ gattServerListener.clear();
+ BTUtils.println(System.err, "****** Server Stop.X: "+msg);
+ return res;
+ }
+
+ @Override
+ public void close(final String msg) {
+ BTUtils.println(System.err, "****** Server Close.0: "+msg);
+ stop(msg);
+ gattServerListener.close();
+ // dbGattServer.close(); // keep alive
+ serverAdapter.removeStatusListener( myAdapterStatusListener );
+ BTUtils.println(System.err, "****** Server Close.X: "+msg);
+ }
+
+ private HCIStatusCode stopAdvertising(final String msg) {
+ final HCIStatusCode status = serverAdapter.stopAdvertising();
+ BTUtils.println(System.err, "****** Server Stop advertising ("+msg+") result: "+status+": "+serverAdapter.toString());
+ return status;
+ }
+
+ @Override
+ public HCIStatusCode startAdvertising(final String msg) {
+ final EInfoReport eir = new EInfoReport();
+ final EIRDataTypeSet adv_mask = new EIRDataTypeSet();
+ final EIRDataTypeSet scanrsp_mask = new EIRDataTypeSet();
+
+ adv_mask.set(EIRDataTypeSet.DataType.FLAGS);
+ adv_mask.set(EIRDataTypeSet.DataType.SERVICE_UUID);
+
+ scanrsp_mask.set(EIRDataTypeSet.DataType.NAME);
+ scanrsp_mask.set(EIRDataTypeSet.DataType.CONN_IVAL);
+
+ eir.addFlag(GAPFlags.Bit.LE_Gen_Disc);
+ eir.addFlag(GAPFlags.Bit.BREDR_UNSUP);
+
+ eir.addService(DBTConstants.DataServiceUUID);
+ eir.setServicesComplete(false);
+
+ eir.setName(serverAdapter.getName());
+ eir.setConnInterval((short)8, (short)12); // 10ms - 15ms
+
+ final DBGattChar gattDevNameChar = dbGattServer.findGattChar(DBGattService.UUID16.GENERIC_ACCESS, DBGattChar.UUID16.DEVICE_NAME);
+ if( null != gattDevNameChar ) {
+ final byte[] aname_bytes = serverAdapter.getName().getBytes(StandardCharsets.UTF_8);
+ gattDevNameChar.setValue(aname_bytes, 0, aname_bytes.length, 0);
+ }
+
+ BTUtils.println(System.err, "****** Server Start advertising ("+msg+"): EIR "+eir.toString());
+ BTUtils.println(System.err, "****** Server Start advertising ("+msg+"): adv "+adv_mask.toString()+", scanrsp "+scanrsp_mask.toString());
+
+ final HCIStatusCode status = serverAdapter.startAdvertising(dbGattServer, eir, adv_mask, scanrsp_mask,
+ adv_interval_min, adv_interval_max,
+ adv_type, adv_chan_map, filter_policy);
+ BTUtils.println(System.err, "****** Server Start advertising ("+msg+") result: "+status+": "+serverAdapter.toString());
+ if( GATT_VERBOSE ) {
+ BTUtils.println(System.err, dbGattServer.toFullString());
+ }
+ return status;
+ }
+
+ private void processDisconnectedDevice(final BTDevice device) {
+ BTUtils.println(System.err, "****** Server Disconnected Device (count "+(1+disconnectCount.get())+
+ ", served "+servedProtocolSessionsTotal.get()+", left "+servingProtocolSessionsLeft.get()+"): Start "+device.toString());
+
+ // already unpaired
+ stopAdvertising("device-disconnected");
+ device.remove();
+ BTDeviceRegistry.removeFromProcessingDevices(device.getAddressAndType());
+
+ disconnectCount.addAndGet(1);
+
+ try {
+ Thread.sleep(100); // wait a little (FIXME: Fast restart of advertising error)
+ } catch (final InterruptedException e) { }
+
+ if( servingProtocolSessionsLeft.get() > 0 ) {
+ startAdvertising("device-disconnected");
+ }
+
+ BTUtils.println(System.err, "****** Server Disonnected Device: End "+device.toString());
+ }
+
+ @Override
+ public boolean initAdapter(final BTAdapter adapter) {
+ if( !useAdapter.equals(EUI48.ALL_DEVICE) && !useAdapter.equals(adapter.getAddressAndType().address) ) {
+ BTUtils.fprintf_td(System.err, "initServerAdapter: Adapter not selected: %s\n", adapter.toString());
+ return false;
+ }
+ adapterName = adapterName + "-" + adapter.getAddressAndType().address.toString().replace(":", "");
+
+ if( !adapter.isInitialized() ) {
+ // Initialize with defaults and power-on
+ final HCIStatusCode status = adapter.initialize( btMode );
+ if( HCIStatusCode.SUCCESS != status ) {
+ BTUtils.fprintf_td(System.err, "initServerAdapter: initialization failed: %s: %s\n",
+ status.toString(), adapter.toString());
+ return false;
+ }
+ } else if( !adapter.setPowered( true ) ) {
+ BTUtils.fprintf_td(System.err, "initServerAdapter: setPower.1 on failed: %s\n", adapter.toString());
+ return false;
+ }
+ // adapter is powered-on
+ BTUtils.println(System.err, "initServerAdapter.1: "+adapter.toString());
+
+ if( adapter.setPowered(false) ) {
+ HCIStatusCode status = adapter.setName(adapterName, adapterShortName);
+ if( HCIStatusCode.SUCCESS == status ) {
+ BTUtils.fprintf_td(System.err, "initServerAdapter: setLocalName OK: %s\n", adapter.toString());
+ } else {
+ BTUtils.fprintf_td(System.err, "initServerAdapter: setLocalName failed: %s\n", adapter.toString());
+ return false;
+ }
+
+ status = adapter.setSecureConnections( use_SC );
+ if( HCIStatusCode.SUCCESS == status ) {
+ BTUtils.fprintf_td(System.err, "initServerAdapter: setSecureConnections OK: %s\n", adapter.toString());
+ } else {
+ BTUtils.fprintf_td(System.err, "initServerAdapter: setSecureConnections failed: %s\n", adapter.toString());
+ return false;
+ }
+
+ final short conn_min_interval = 8; // 10ms
+ final short conn_max_interval = 40; // 50ms
+ final short conn_latency = 0;
+ final short supervision_timeout = 50; // 500ms
+ status = adapter.setDefaultConnParam(conn_min_interval, conn_max_interval, conn_latency, supervision_timeout);
+ if( HCIStatusCode.SUCCESS == status ) {
+ BTUtils.fprintf_td(System.err, "initServerAdapter: setDefaultConnParam OK: %s\n", adapter.toString());
+ } else {
+ BTUtils.fprintf_td(System.err, "initServerAdapter: setDefaultConnParam failed: %s\n", adapter.toString());
+ return false;
+ }
+
+ if( !adapter.setPowered( true ) ) {
+ BTUtils.fprintf_td(System.err, "initServerAdapter: setPower.2 on failed: %s\n", adapter.toString());
+ return false;
+ }
+ } else {
+ BTUtils.fprintf_td(System.err, "initServerAdapter: setPowered.2 off failed: %s\n", adapter.toString());
+ }
+ // adapter is powered-on
+ BTUtils.println(System.err, "initServerAdapter.2: "+adapter.toString());
+
+ {
+ final LE_Features le_feats = adapter.getLEFeatures();
+ BTUtils.fprintf_td(System.err, "initServerAdapter: LE_Features %s\n", le_feats.toString());
+ }
+ if( adapter.getBTMajorVersion() > 4 ) {
+ // BT5 specific
+ final LE_PHYs Tx = new LE_PHYs( LE_PHYs.PHY.LE_2M );
+ final LE_PHYs Rx = new LE_PHYs( LE_PHYs.PHY.LE_2M );
+ final HCIStatusCode res = adapter.setDefaultLE_PHY(Tx, Rx);
+ BTUtils.fprintf_td(System.err, "initServerAdapter: Set Default LE PHY: status %s: Tx %s, Rx %s\n",
+ res.toString(), Tx.toString(), Rx.toString());
+ }
+ adapter.setSMPKeyPath(DBTConstants.SERVER_KEY_PATH);
+
+ adapter.addStatusListener( myAdapterStatusListener );
+
+ adapter.setServerConnSecurity(adapterSecurityLevel, SMPIOCapability.UNSET);
+
+ return true;
+ }
+}
diff --git a/trial/java/trial/org/direct_bt/ExpectedPairing.java b/trial/java/trial/org/direct_bt/ExpectedPairing.java
new file mode 100644
index 00000000..1a67533a
--- /dev/null
+++ b/trial/java/trial/org/direct_bt/ExpectedPairing.java
@@ -0,0 +1,31 @@
+/**
+ * Author: Sven Gothel <[email protected]>
+ * Copyright (c) 2022 Gothel Software e.K.
+ *
+ * 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 trial.org.direct_bt;
+
+public enum ExpectedPairing {
+ DONT_CARE,
+ NEW_PAIRING,
+ PREPAIRED
+};
+
diff --git a/trial/java/trial/org/direct_bt/TestDBTClientServer00.java b/trial/java/trial/org/direct_bt/TestDBTClientServer00.java
index 37a0024b..77dc2250 100644
--- a/trial/java/trial/org/direct_bt/TestDBTClientServer00.java
+++ b/trial/java/trial/org/direct_bt/TestDBTClientServer00.java
@@ -108,7 +108,7 @@ public class TestDBTClientServer00 extends BaseDBTClientServer {
final String serverName = "TestDBTCS00-S-T10";
final DBTServer00 server = new DBTServer00(serverName, EUI48.ALL_DEVICE, BTMode.DUAL, true /* SC */, BTSecurityLevel.NONE);
- server.servingProtocolSessionsLeft.set(1);
+ server.setProtocolSessionsLeft(1);
final DBTEndpoint.ChangedAdapterSetListener myChangedAdapterSetListener =
DBTEndpoint.initChangedAdapterSetListener(manager, Arrays.asList(server));
diff --git a/trial/java/trial/org/direct_bt/TestDBTClientServer10_NoEnc.java b/trial/java/trial/org/direct_bt/TestDBTClientServer10_NoEnc.java
index b1c53a64..d18c2478 100644
--- a/trial/java/trial/org/direct_bt/TestDBTClientServer10_NoEnc.java
+++ b/trial/java/trial/org/direct_bt/TestDBTClientServer10_NoEnc.java
@@ -46,18 +46,18 @@ public class TestDBTClientServer10_NoEnc extends DBTClientServer1x {
@Test(timeout = 20000)
public final void test00_FullCycle_EncNone() {
- final boolean serverShallHaveKeys = false;
- final boolean clientShallHaveKeys = false;
+ final ExpectedPairing serverExpPairing = ExpectedPairing.DONT_CARE;
+ final ExpectedPairing clientExpPairing = ExpectedPairing.DONT_CARE;
test8x_fullCycle(20000, "10", 1, true /* server_client_order */, serverSC,
- BTSecurityLevel.NONE, serverShallHaveKeys, BTSecurityLevel.NONE, clientShallHaveKeys);
+ BTSecurityLevel.NONE, serverExpPairing, BTSecurityLevel.NONE, clientExpPairing);
}
@Test(timeout = 30000)
public final void test01_FullCycle_EncNone() {
- final boolean serverShallHaveKeys = false;
- final boolean clientShallHaveKeys = false;
+ final ExpectedPairing serverExpPairing = ExpectedPairing.DONT_CARE;
+ final ExpectedPairing clientExpPairing = ExpectedPairing.DONT_CARE;
test8x_fullCycle(30000, "11", 2, true /* server_client_order */, serverSC,
- BTSecurityLevel.NONE, serverShallHaveKeys, BTSecurityLevel.NONE, clientShallHaveKeys);
+ BTSecurityLevel.NONE, serverExpPairing, BTSecurityLevel.NONE, clientExpPairing);
}
public static void main(final String args[]) {
diff --git a/trial/java/trial/org/direct_bt/TestDBTClientServer12_NoEnc.java b/trial/java/trial/org/direct_bt/TestDBTClientServer12_NoEnc.java
index 7d1aac65..477b9281 100644
--- a/trial/java/trial/org/direct_bt/TestDBTClientServer12_NoEnc.java
+++ b/trial/java/trial/org/direct_bt/TestDBTClientServer12_NoEnc.java
@@ -46,18 +46,18 @@ public class TestDBTClientServer12_NoEnc extends DBTClientServer1x {
@Test(timeout = 20000)
public final void test02_FullCycle_EncNone() {
- final boolean serverShallHaveKeys = false;
- final boolean clientShallHaveKeys = false;
+ final ExpectedPairing serverExpPairing = ExpectedPairing.DONT_CARE;
+ final ExpectedPairing clientExpPairing = ExpectedPairing.DONT_CARE;
test8x_fullCycle(20000, "12", 1, false /* server_client_order */, serverSC,
- BTSecurityLevel.NONE, serverShallHaveKeys, BTSecurityLevel.NONE, clientShallHaveKeys);
+ BTSecurityLevel.NONE, serverExpPairing, BTSecurityLevel.NONE, clientExpPairing);
}
@Test(timeout = 30000)
public final void test03_FullCycle_EncNone() {
- final boolean serverShallHaveKeys = false;
- final boolean clientShallHaveKeys = false;
+ final ExpectedPairing serverExpPairing = ExpectedPairing.DONT_CARE;
+ final ExpectedPairing clientExpPairing = ExpectedPairing.DONT_CARE;
test8x_fullCycle(30000, "13", 2, false /* server_client_order */, serverSC,
- BTSecurityLevel.NONE, serverShallHaveKeys, BTSecurityLevel.NONE, clientShallHaveKeys);
+ BTSecurityLevel.NONE, serverExpPairing, BTSecurityLevel.NONE, clientExpPairing);
}
public static void main(final String args[]) {
diff --git a/trial/java/trial/org/direct_bt/TestDBTClientServer20_SC0.java b/trial/java/trial/org/direct_bt/TestDBTClientServer20_SC0.java
index 3659a53e..e4b06b76 100644
--- a/trial/java/trial/org/direct_bt/TestDBTClientServer20_SC0.java
+++ b/trial/java/trial/org/direct_bt/TestDBTClientServer20_SC0.java
@@ -46,18 +46,18 @@ public class TestDBTClientServer20_SC0 extends DBTClientServer1x {
@Test(timeout = 40000)
public final void test10_FullCycle_EncOnlyNo1() {
- final boolean serverShallHaveKeys = false;
- final boolean clientShallHaveKeys = false;
+ final ExpectedPairing serverExpPairing = ExpectedPairing.NEW_PAIRING;
+ final ExpectedPairing clientExpPairing = ExpectedPairing.NEW_PAIRING;
test8x_fullCycle(40000, "20", 1, true /* server_client_order */, serverSC,
- BTSecurityLevel.ENC_ONLY, serverShallHaveKeys, BTSecurityLevel.ENC_ONLY, clientShallHaveKeys);
+ BTSecurityLevel.ENC_ONLY, serverExpPairing, BTSecurityLevel.ENC_ONLY, clientExpPairing);
}
@Test(timeout = 40000)
public final void test20_FullCycle_EncOnlyNo2() {
- final boolean serverShallHaveKeys = true;
- final boolean clientShallHaveKeys = true;
+ final ExpectedPairing serverExpPairing = ExpectedPairing.PREPAIRED;
+ final ExpectedPairing clientExpPairing = ExpectedPairing.PREPAIRED;
test8x_fullCycle(40000, "21", 2, true /* server_client_order */, serverSC,
- BTSecurityLevel.ENC_ONLY, serverShallHaveKeys, BTSecurityLevel.ENC_ONLY, clientShallHaveKeys);
+ BTSecurityLevel.ENC_ONLY, serverExpPairing, BTSecurityLevel.ENC_ONLY, clientExpPairing);
}
public static void main(final String args[]) {
diff --git a/trial/java/trial/org/direct_bt/TestDBTClientServer22_SC0.java b/trial/java/trial/org/direct_bt/TestDBTClientServer22_SC0.java
index 49a361a8..10fa3663 100644
--- a/trial/java/trial/org/direct_bt/TestDBTClientServer22_SC0.java
+++ b/trial/java/trial/org/direct_bt/TestDBTClientServer22_SC0.java
@@ -46,18 +46,18 @@ public class TestDBTClientServer22_SC0 extends DBTClientServer1x {
@Test(timeout = 40000)
public final void test11_FullCycle_EncOnlyNo1() {
- final boolean serverShallHaveKeys = false;
- final boolean clientShallHaveKeys = false;
+ final ExpectedPairing serverExpPairing = ExpectedPairing.NEW_PAIRING;
+ final ExpectedPairing clientExpPairing = ExpectedPairing.NEW_PAIRING;
test8x_fullCycle(40000, "22", 1, false /* server_client_order */, serverSC,
- BTSecurityLevel.ENC_ONLY, serverShallHaveKeys, BTSecurityLevel.ENC_ONLY, clientShallHaveKeys);
+ BTSecurityLevel.ENC_ONLY, serverExpPairing, BTSecurityLevel.ENC_ONLY, clientExpPairing);
}
@Test(timeout = 40000)
public final void test21_FullCycle_EncOnlyNo2() {
- final boolean serverShallHaveKeys = true;
- final boolean clientShallHaveKeys = true;
+ final ExpectedPairing serverExpPairing = ExpectedPairing.PREPAIRED;
+ final ExpectedPairing clientExpPairing = ExpectedPairing.PREPAIRED;
test8x_fullCycle(40000, "23", 2, false /* server_client_order */, serverSC,
- BTSecurityLevel.ENC_ONLY, serverShallHaveKeys, BTSecurityLevel.ENC_ONLY, clientShallHaveKeys);
+ BTSecurityLevel.ENC_ONLY, serverExpPairing, BTSecurityLevel.ENC_ONLY, clientExpPairing);
}
public static void main(final String args[]) {
diff --git a/trial/java/trial/org/direct_bt/TestDBTClientServer30_SC1.java b/trial/java/trial/org/direct_bt/TestDBTClientServer30_SC1.java
index 55e05b04..708c3a43 100644
--- a/trial/java/trial/org/direct_bt/TestDBTClientServer30_SC1.java
+++ b/trial/java/trial/org/direct_bt/TestDBTClientServer30_SC1.java
@@ -46,18 +46,18 @@ public class TestDBTClientServer30_SC1 extends DBTClientServer1x {
@Test(timeout = 40000)
public final void test10_FullCycle_EncOnlyNo1() {
- final boolean serverShallHaveKeys = false;
- final boolean clientShallHaveKeys = false;
+ final ExpectedPairing serverExpPairing = ExpectedPairing.NEW_PAIRING;
+ final ExpectedPairing clientExpPairing = ExpectedPairing.NEW_PAIRING;
test8x_fullCycle(40000, "30", 1, true /* server_client_order */, serverSC,
- BTSecurityLevel.ENC_ONLY, serverShallHaveKeys, BTSecurityLevel.ENC_ONLY, clientShallHaveKeys);
+ BTSecurityLevel.ENC_ONLY, serverExpPairing, BTSecurityLevel.ENC_ONLY, clientExpPairing);
}
@Test(timeout = 40000)
public final void test20_FullCycle_EncOnlyNo2() {
- final boolean serverShallHaveKeys = true;
- final boolean clientShallHaveKeys = true;
+ final ExpectedPairing serverExpPairing = ExpectedPairing.PREPAIRED;
+ final ExpectedPairing clientExpPairing = ExpectedPairing.PREPAIRED;
test8x_fullCycle(40000, "31", 2, true /* server_client_order */, serverSC,
- BTSecurityLevel.ENC_ONLY, serverShallHaveKeys, BTSecurityLevel.ENC_ONLY, clientShallHaveKeys);
+ BTSecurityLevel.ENC_ONLY, serverExpPairing, BTSecurityLevel.ENC_ONLY, clientExpPairing);
}
public static void main(final String args[]) {
diff --git a/trial/java/trial/org/direct_bt/TestDBTClientServer32_SC1.java b/trial/java/trial/org/direct_bt/TestDBTClientServer32_SC1.java
index 522afd22..b6afa327 100644
--- a/trial/java/trial/org/direct_bt/TestDBTClientServer32_SC1.java
+++ b/trial/java/trial/org/direct_bt/TestDBTClientServer32_SC1.java
@@ -46,18 +46,18 @@ public class TestDBTClientServer32_SC1 extends DBTClientServer1x {
@Test(timeout = 40000)
public final void test11_FullCycle_EncOnlyNo1() {
- final boolean serverShallHaveKeys = false;
- final boolean clientShallHaveKeys = false;
+ final ExpectedPairing serverExpPairing = ExpectedPairing.NEW_PAIRING;
+ final ExpectedPairing clientExpPairing = ExpectedPairing.NEW_PAIRING;
test8x_fullCycle(40000, "32", 1, false /* server_client_order */, serverSC,
- BTSecurityLevel.ENC_ONLY, serverShallHaveKeys, BTSecurityLevel.ENC_ONLY, clientShallHaveKeys);
+ BTSecurityLevel.ENC_ONLY, serverExpPairing, BTSecurityLevel.ENC_ONLY, clientExpPairing);
}
@Test(timeout = 40000)
public final void test21_FullCycle_EncOnlyNo2() {
- final boolean serverShallHaveKeys = true;
- final boolean clientShallHaveKeys = true;
+ final ExpectedPairing serverExpPairing = ExpectedPairing.PREPAIRED;
+ final ExpectedPairing clientExpPairing = ExpectedPairing.PREPAIRED;
test8x_fullCycle(40000, "33", 2, false /* server_client_order */, serverSC,
- BTSecurityLevel.ENC_ONLY, serverShallHaveKeys, BTSecurityLevel.ENC_ONLY, clientShallHaveKeys);
+ BTSecurityLevel.ENC_ONLY, serverExpPairing, BTSecurityLevel.ENC_ONLY, clientExpPairing);
}
public static void main(final String args[]) {
diff --git a/trial/java/trial/org/direct_bt/TestDBTProvokeClientServer_i470.java b/trial/java/trial/org/direct_bt/TestDBTProvokeClientServer_i470.java
new file mode 100644
index 00000000..cb96610c
--- /dev/null
+++ b/trial/java/trial/org/direct_bt/TestDBTProvokeClientServer_i470.java
@@ -0,0 +1,69 @@
+/**
+ * Author: Sven Gothel <[email protected]>
+ * Copyright (c) 2022 Gothel Software e.K.
+ *
+ * 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 trial.org.direct_bt;
+
+import org.direct_bt.BTMode;
+import org.direct_bt.BTSecurityLevel;
+import org.jau.net.EUI48;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+/**
+ * Testing w/o client filtering processing device and hence not blocking deviceFound.
+ *
+ * In other words, relying on BTAdapter to filter out:
+ * - already discovered devices
+ * - already connected devices
+ *
+ * Further, the server will issue a disconnect once only 300 ms after 1st MTU exchange,
+ * disrupting the client's getGATTServices().
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class TestDBTProvokeClientServer_i470 extends DBTClientServer1x {
+
+ @Test(timeout = 20000)
+ public final void test_i470()
+ {
+ final boolean serverSC = true;
+ final String suffix = "i470";
+ final int protocolSessionCount = 2;
+ final boolean server_client_order = true;
+ final ExpectedPairing serverExpPairing = ExpectedPairing.DONT_CARE;
+ final ExpectedPairing clientExpPairing = ExpectedPairing.DONT_CARE;
+
+ // final DBTServerTest server = new DBTServer01("S-"+suffix, EUI48.ALL_DEVICE, BTMode.DUAL, serverSC, BTSecurityLevel.ENC_ONLY);
+ final DBTServerTest server = new DBTServer00("S-"+suffix, EUI48.ALL_DEVICE, BTMode.DUAL, serverSC, BTSecurityLevel.ENC_ONLY);
+ final DBTClientTest client = new DBTClient01("C-"+suffix, EUI48.ALL_DEVICE, BTMode.DUAL);
+
+ test8x_fullCycle(20000, suffix, protocolSessionCount, server_client_order,
+ server, BTSecurityLevel.ENC_ONLY, serverExpPairing,
+ client, BTSecurityLevel.ENC_ONLY, clientExpPairing);
+ }
+
+ public static void main(final String args[]) {
+ org.junit.runner.JUnitCore.main(TestDBTProvokeClientServer_i470.class.getName());
+ }
+}