diff options
-rw-r--r-- | trial/direct_bt/dbt_client00.hpp | 705 | ||||
-rw-r--r-- | trial/direct_bt/dbt_client01.hpp | 49 | ||||
-rw-r--r-- | trial/direct_bt/dbt_client_server1x.hpp | 9 | ||||
-rw-r--r-- | trial/direct_bt/dbt_server00.hpp | 774 | ||||
-rw-r--r-- | trial/direct_bt/dbt_server01.hpp | 11 | ||||
-rw-r--r-- | trial/direct_bt/test_client_server00.cpp | 5 | ||||
-rw-r--r-- | trial/direct_bt/test_provoke_client_server_i470.cpp | 5 | ||||
-rw-r--r-- | trial/java/trial/org/direct_bt/DBTClient00.java | 717 | ||||
-rw-r--r-- | trial/java/trial/org/direct_bt/DBTClient01.java | 28 | ||||
-rw-r--r-- | trial/java/trial/org/direct_bt/DBTClientServer1x.java | 4 | ||||
-rw-r--r-- | trial/java/trial/org/direct_bt/DBTServer00.java | 814 | ||||
-rw-r--r-- | trial/java/trial/org/direct_bt/TestDBTClientServer00.java | 2 |
12 files changed, 77 insertions, 3046 deletions
diff --git a/trial/direct_bt/dbt_client00.hpp b/trial/direct_bt/dbt_client00.hpp deleted file mode 100644 index 903ed477..00000000 --- a/trial/direct_bt/dbt_client00.hpp +++ /dev/null @@ -1,705 +0,0 @@ -/** - * 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. - */ - -#ifndef DBT_CLIENT00_HPP_ -#define DBT_CLIENT00_HPP_ - -#include "dbt_constants.hpp" - -#include "dbt_client_test.hpp" - -class DBTClient00; -typedef std::shared_ptr<DBTClient00> DBTClient00Ref; - -using namespace jau; -using namespace jau::fractions_i64_literals; - -/** - * This central BTRole::Master participant works with DBTServer00. - */ -class DBTClient00 : public DBTClientTest { - private: - bool KEEP_CONNECTED = false; - - bool REMOVE_DEVICE = false; - - DiscoveryPolicy discoveryPolicy = DiscoveryPolicy::PAUSE_CONNECTED_UNTIL_READY; // default value - - static const bool GATT_VERBOSE = false; - static const bool SHOW_UPDATE_EVENTS = false; - - 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 completedMeasurementsTotal = 0; - jau::sc_atomic_int completedMeasurementsSuccess = 0; - jau::sc_atomic_int measurementsLeft = 0; - - const uint64_t timestamp_t0 = getCurrentMilliseconds(); - // const fraction_i64 timestamp_t0 = jau::getMonotonicMicroseconds(); - - const uint8_t cmd_arg = 0x44; - - class MyAdapterStatusListener : public AdapterStatusListener { - public: - DBTClient00& parent; - - MyAdapterStatusListener(DBTClient00& p) : parent(p) {} - - void adapterSettingsChanged(BTAdapter &a, const AdapterSetting oldmask, const AdapterSetting newmask, - const AdapterSetting changedmask, const uint64_t timestamp) override { - const bool initialSetting = AdapterSetting::NONE == oldmask; - if( initialSetting ) { - fprintf_td(stderr, "****** Client SETTINGS_INITIAL: %s -> %s, changed %s\n", to_string(oldmask).c_str(), - to_string(newmask).c_str(), to_string(changedmask).c_str()); - } else { - fprintf_td(stderr, "****** Client SETTINGS_CHANGED: %s -> %s, changed %s\n", to_string(oldmask).c_str(), - to_string(newmask).c_str(), to_string(changedmask).c_str()); - } - fprintf_td(stderr, "Client Status BTAdapter:\n"); - fprintf_td(stderr, "%s\n", a.toString().c_str()); - (void)timestamp; - } - - void discoveringChanged(BTAdapter &a, const ScanType currentMeta, const ScanType changedType, const bool changedEnabled, const DiscoveryPolicy policy, const uint64_t timestamp) override { - fprintf_td(stderr, "****** Client DISCOVERING: meta %s, changed[%s, enabled %d, policy %s]: %s\n", - to_string(currentMeta).c_str(), to_string(changedType).c_str(), changedEnabled, to_string(policy).c_str(), a.toString().c_str()); - (void)timestamp; - } - - bool deviceFound(BTDeviceRef device, const uint64_t timestamp) override { - (void)timestamp; - if( !BTDeviceRegistry::isDeviceProcessing( device->getAddressAndType() ) && - ( !BTDeviceRegistry::isWaitingForAnyDevice() || - ( BTDeviceRegistry::isWaitingForDevice(device->getAddressAndType().address, device->getName()) && - ( 0 < parent.measurementsLeft || !BTDeviceRegistry::isDeviceProcessed(device->getAddressAndType()) ) - ) - ) - ) - { - fprintf_td(stderr, "****** Client FOUND__-0: Connecting %s\n", device->toString(true).c_str()); - { - const uint64_t td = jau::getCurrentMilliseconds() - parent.timestamp_t0; // adapter-init -> now - fprintf_td(stderr, "PERF: adapter-init -> FOUND__-0 %" PRIu64 " ms\n", td); - } - std::thread dc(&DBTClient00::connectDiscoveredDevice, &parent, device); // @suppress("Invalid arguments") - dc.detach(); - return true; - } else { - fprintf_td(stderr, "****** Client FOUND__-1: NOP %s\n", device->toString(true).c_str()); - return false; - } - } - - void deviceUpdated(BTDeviceRef device, const EIRDataType updateMask, const uint64_t timestamp) override { - (void)device; - (void)updateMask; - (void)timestamp; - } - - void deviceConnected(BTDeviceRef device, const bool discovered, const uint64_t timestamp) override { - fprintf_td(stderr, "****** Client CONNECTED (discovered %d): %s\n", discovered, device->toString(true).c_str()); - (void)discovered; - (void)timestamp; - } - - void devicePairingState(BTDeviceRef device, const SMPPairingState state, const PairingMode mode, const uint64_t timestamp) override { - fprintf_td(stderr, "****** Client PAIRING STATE: state %s, mode %s, %s\n", - to_string(state).c_str(), to_string(mode).c_str(), device->toString().c_str()); - (void)timestamp; - switch( state ) { - case SMPPairingState::NONE: - // next: deviceReady(..) - break; - case SMPPairingState::FAILED: { - const bool res = SMPKeyBin::remove(DBTConstants::CLIENT_KEY_PATH, *device); - fprintf_td(stderr, "****** PAIRING_STATE: state %s; Remove key file %s, res %d\n", - to_string(state).c_str(), SMPKeyBin::getFilename(DBTConstants::CLIENT_KEY_PATH, *device).c_str(), res); - // next: deviceReady() or deviceDisconnected(..) - } break; - case SMPPairingState::REQUESTED_BY_RESPONDER: - // next: FEATURE_EXCHANGE_STARTED - break; - case SMPPairingState::FEATURE_EXCHANGE_STARTED: - // next: FEATURE_EXCHANGE_COMPLETED - break; - case SMPPairingState::FEATURE_EXCHANGE_COMPLETED: - // next: PASSKEY_EXPECTED... or KEY_DISTRIBUTION - break; - case SMPPairingState::PASSKEY_EXPECTED: { - const BTSecurityRegistry::Entry* sec = BTSecurityRegistry::getStartOf(device->getAddressAndType().address, device->getName()); - if( nullptr != sec && sec->getPairingPasskey() != BTSecurityRegistry::Entry::NO_PASSKEY ) { - std::thread dc(&BTDevice::setPairingPasskey, device, static_cast<uint32_t>( sec->getPairingPasskey() )); - dc.detach(); - } else { - std::thread dc(&BTDevice::setPairingPasskey, device, 0); - // 3s disconnect: std::thread dc(&BTDevice::setPairingPasskeyNegative, device); - dc.detach(); - } - // next: KEY_DISTRIBUTION or FAILED - } break; - case SMPPairingState::NUMERIC_COMPARE_EXPECTED: { - const BTSecurityRegistry::Entry* sec = BTSecurityRegistry::getStartOf(device->getAddressAndType().address, device->getName()); - if( nullptr != sec ) { - std::thread dc(&BTDevice::setPairingNumericComparison, device, sec->getPairingNumericComparison()); - dc.detach(); - } else { - std::thread dc(&BTDevice::setPairingNumericComparison, device, false); - dc.detach(); - } - // next: KEY_DISTRIBUTION or FAILED - } break; - case SMPPairingState::OOB_EXPECTED: - // FIXME: ABORT - break; - case SMPPairingState::KEY_DISTRIBUTION: - // next: COMPLETED or FAILED - break; - case SMPPairingState::COMPLETED: - // next: deviceReady(..) - break; - default: // nop - break; - } - } - - void deviceReady(BTDeviceRef device, const uint64_t timestamp) override { - (void)timestamp; - if( !BTDeviceRegistry::isDeviceProcessing( device->getAddressAndType() ) && - ( !BTDeviceRegistry::isWaitingForAnyDevice() || - ( BTDeviceRegistry::isWaitingForDevice(device->getAddressAndType().address, device->getName()) && - ( 0 < parent.measurementsLeft || !BTDeviceRegistry::isDeviceProcessed(device->getAddressAndType()) ) - ) - ) - ) - { - parent.deviceReadyCount++; - fprintf_td(stderr, "****** Client READY-0: Processing[%d] %s\n", parent.deviceReadyCount.load(), device->toString(true).c_str()); - BTDeviceRegistry::addToProcessingDevices(device->getAddressAndType(), device->getName()); - - // Be nice to Test* case, allowing to reach its own listener.deviceReady() added later - std::thread dc(&DBTClient00::processReadyDevice, &parent, device); - dc.detach(); - // processReadyDevice(device); // AdapterStatusListener::deviceReady() explicitly allows prolonged and complex code execution! - } else { - fprintf_td(stderr, "****** Client READY-1: NOP %s\n", device->toString(true).c_str()); - } - } - - void deviceDisconnected(BTDeviceRef device, const HCIStatusCode reason, const uint16_t handle, const uint64_t timestamp) override { - fprintf_td(stderr, "****** Client DISCONNECTED: Reason 0x%X (%s), old handle %s: %s\n", - static_cast<uint8_t>(reason), to_string(reason).c_str(), - 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(); - } - - std::string toString() const noexcept override { - return "Client MyAdapterStatusListener[this "+to_hexstring(this)+"]"; - } - - }; - - class MyGATTEventListener : public BTGattCharListener { - private: - DBTClient00& parent; - - public: - MyGATTEventListener(DBTClient00& p) : parent(p) {} - - void notificationReceived(BTGattCharRef charDecl, const TROOctets& char_value, const uint64_t timestamp) override { - if( GATT_VERBOSE ) { - const uint64_t tR = jau::getCurrentMilliseconds(); - fprintf_td(stderr, "** Characteristic-Notify: UUID %s, td %" PRIu64 " ******\n", - charDecl->value_type->toUUID128String().c_str(), (tR-timestamp)); - fprintf_td(stderr, "** Characteristic: %s ******\n", charDecl->toString().c_str()); - fprintf_td(stderr, "** Value R: %s ******\n", char_value.toString().c_str()); - fprintf_td(stderr, "** Value S: %s ******\n", jau::dfa_utf8_decode(char_value.get_ptr(), char_value.size()).c_str()); - } - parent.notificationsReceived++; - } - - void indicationReceived(BTGattCharRef charDecl, - const TROOctets& char_value, const uint64_t timestamp, - const bool confirmationSent) override - { - if( GATT_VERBOSE ) { - const uint64_t tR = jau::getCurrentMilliseconds(); - fprintf_td(stderr, "** Characteristic-Indication: UUID %s, td %" PRIu64 ", confirmed %d ******\n", - charDecl->value_type->toUUID128String().c_str(), (tR-timestamp), confirmationSent); - fprintf_td(stderr, "** Characteristic: %s ******\n", charDecl->toString().c_str()); - fprintf_td(stderr, "** Value R: %s ******\n", char_value.toString().c_str()); - fprintf_td(stderr, "** Value S: %s ******\n", jau::dfa_utf8_decode(char_value.get_ptr(), char_value.size()).c_str()); - } - parent.indicationsReceived++; - } - }; - - const std::string adapterShortName = "TDev2Clt"; - std::string adapterName = "TestDev2_Clt"; - EUI48 useAdapter = EUI48::ALL_DEVICE; - BTMode btMode = BTMode::DUAL; - BTAdapterRef clientAdapter = nullptr; - std::shared_ptr<AdapterStatusListener> myAdapterStatusListener = std::make_shared<MyAdapterStatusListener>(*this); - - public: - DBTClient00(const std::string& adapterName_, const EUI48 useAdapter_, const BTMode btMode_) { - this->adapterName = adapterName_; - this->useAdapter = useAdapter_; - this->btMode = btMode_; - } - - std::string getName() override { return adapterName; } - - void setAdapter(BTAdapterRef clientAdapter_) override { - this->clientAdapter = clientAdapter_; - } - - 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; - notificationsReceived = 0; - indicationsReceived = 0; - } - - void connectDiscoveredDevice(BTDeviceRef device) { - fprintf_td(stderr, "****** Client Connecting Device: Start %s\n", device->toString().c_str()); - - resetLastProcessingStats(); - - const BTSecurityRegistry::Entry* sec = BTSecurityRegistry::getStartOf(device->getAddressAndType().address, device->getName()); - if( nullptr != sec ) { - fprintf_td(stderr, "****** Client Connecting Device: Found SecurityDetail %s for %s\n", sec->toString().c_str(), device->toString().c_str()); - } else { - fprintf_td(stderr, "****** Client Connecting Device: No SecurityDetail for %s\n", device->toString().c_str()); - } - const BTSecurityLevel req_sec_level = nullptr != sec ? sec->getSecLevel() : BTSecurityLevel::UNSET; - HCIStatusCode res = device->uploadKeys(DBTConstants::CLIENT_KEY_PATH, req_sec_level, true /* verbose_ */); - fprintf_td(stderr, "****** Client Connecting Device: BTDevice::uploadKeys(...) result %s\n", to_string(res).c_str()); - if( HCIStatusCode::SUCCESS != res ) { - if( nullptr != sec ) { - if( sec->isSecurityAutoEnabled() ) { - bool r = device->setConnSecurityAuto( sec->getSecurityAutoIOCap() ); - fprintf_td(stderr, "****** Client Connecting Device: Using SecurityDetail.SEC AUTO %s, set OK %d\n", sec->toString().c_str(), r); - } else if( sec->isSecLevelOrIOCapSet() ) { - bool r = device->setConnSecurity( sec->getSecLevel(), sec->getIOCap() ); - fprintf_td(stderr, "****** Client Connecting Device: Using SecurityDetail.Level+IOCap %s, set OK %d\n", sec->toString().c_str(), r); - } else { - bool r = device->setConnSecurityAuto( SMPIOCapability::KEYBOARD_ONLY ); - fprintf_td(stderr, "****** Client Connecting Device: Setting SEC AUTO security detail w/ KEYBOARD_ONLY (%s) -> set OK %d\n", sec->toString().c_str(), r); - } - } else { - bool r = device->setConnSecurityAuto( SMPIOCapability::KEYBOARD_ONLY ); - fprintf_td(stderr, "****** Client Connecting Device: Setting SEC AUTO security detail w/ KEYBOARD_ONLY -> set OK %d\n", r); - } - } - std::shared_ptr<const EInfoReport> eir = device->getEIR(); - fprintf_td(stderr, "Client EIR-1 %s\n", device->getEIRInd()->toString().c_str()); - fprintf_td(stderr, "Client EIR-2 %s\n", device->getEIRScanRsp()->toString().c_str()); - fprintf_td(stderr, "Client EIR-+ %s\n", eir->toString().c_str()); - - uint16_t conn_interval_min = (uint16_t)8; // 10ms - uint16_t conn_interval_max = (uint16_t)12; // 15ms - const uint16_t conn_latency = (uint16_t)0; - if( eir->isSet(EIRDataType::CONN_IVAL) ) { - eir->getConnInterval(conn_interval_min, conn_interval_max); - } - const uint16_t supervision_timeout = (uint16_t) 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); - fprintf_td(stderr, "****** Client Connecting Device: End result %s of %s\n", to_string(res).c_str(), device->toString().c_str()); - } - - void processReadyDevice(BTDeviceRef device) { - fprintf_td(stderr, "****** Client Processing Ready Device: Start %s\n", device->toString().c_str()); - - const uint64_t t1 = jau::getCurrentMilliseconds(); - - SMPKeyBin::createAndWrite(*device, DBTConstants::CLIENT_KEY_PATH, true /* verbose */); - - const uint64_t t2 = jau::getCurrentMilliseconds(); - - bool success = false; - - { - LE_PHYs resTx, resRx; - HCIStatusCode res = device->getConnectedLE_PHY(resTx, resRx); - fprintf_td(stderr, "****** Client Got Connected LE PHY: status %s: Tx %s, Rx %s\n", - to_string(res).c_str(), to_string(resTx).c_str(), to_string(resRx).c_str()); - } - - const uint64_t t3 = jau::getCurrentMilliseconds(); - - // - // GATT Service Processing - // - try { - jau::darray<BTGattServiceRef> primServices = device->getGattServices(); - if( 0 == primServices.size() ) { - fprintf_td(stderr, "****** Clinet Processing Ready Device: getServices() failed %s\n", device->toString().c_str()); - goto exit; - } - - const uint64_t t5 = jau::getCurrentMilliseconds(); - { - const uint64_t td00 = device->getLastDiscoveryTimestamp() - timestamp_t0; // adapter-init to discovered - const uint64_t td01 = t1 - timestamp_t0; // adapter-init to processing-start - const uint64_t td05 = t5 - timestamp_t0; // adapter-init -> gatt-complete - const uint64_t tdc1 = t1 - device->getLastDiscoveryTimestamp(); // discovered to processing-start - const uint64_t tdc5 = t5 - device->getLastDiscoveryTimestamp(); // discovered to gatt-complete - const uint64_t td12 = t2 - t1; // SMPKeyBin - const uint64_t td23 = t3 - t2; // LE_PHY - const uint64_t td13 = t3 - t1; // SMPKeyBin + LE_PHY - const uint64_t td35 = t5 - t3; // get-gatt-services - fprintf_td(stderr, "\n\n\n"); - fprintf_td(stderr, "PERF: GATT primary-services completed\n" - "PERF: adapter-init to discovered %" PRIu64 " ms,\n" - "PERF: adapter-init to processing-start %" PRIu64 " ms,\n" - "PERF: adapter-init to gatt-complete %" PRIu64 " ms\n" - "PERF: discovered to processing-start %" PRIu64 " ms,\n" - "PERF: discovered to gatt-complete %" PRIu64 " ms,\n" - "PERF: SMPKeyBin + LE_PHY %" PRIu64 " ms (SMPKeyBin %" PRIu64 " ms, LE_PHY %" PRIu64 " ms),\n" - "PERF: get-gatt-services %" PRIu64 " ms,\n\n", - td00, td01, td05, - tdc1, tdc5, - td13, td12, td23, td35); - } - - { - BTGattCmd cmd = BTGattCmd(*device, "TestCmd", DBTConstants::CommandUUID, DBTConstants::ResponseUUID, 256); - cmd.setVerbose(true); - const bool cmd_resolved = cmd.isResolved(); - fprintf_td(stderr, "Command test: %s, resolved %d\n", cmd.toString().c_str(), cmd_resolved); - POctets cmd_data(1, endian::little); - cmd_data.put_uint8_nc(0, cmd_arg); - const HCIStatusCode cmd_res = cmd.send(true /* prefNoAck */, cmd_data, 3_s); - if( HCIStatusCode::SUCCESS == cmd_res ) { - const jau::TROOctets& resp = cmd.getResponse(); - if( 1 == resp.size() && resp.get_uint8_nc(0) == cmd_arg ) { - fprintf_td(stderr, "Client Success: %s -> %s (echo response)\n", cmd.toString().c_str(), resp.toString().c_str()); - completedGATTCommands++; - } else { - fprintf_td(stderr, "Client Failure: %s -> %s (different response)\n", cmd.toString().c_str(), resp.toString().c_str()); - } - } else { - fprintf_td(stderr, "Client Failure: %s -> %s\n", cmd.toString().c_str(), to_string(cmd_res).c_str()); - } - // cmd.close(); // done via dtor - } - - bool gattListenerError = false; - std::vector<BTGattCharListenerRef> gattListener; - int loop = 0; - do { - for(size_t i=0; i<primServices.size(); i++) { - BTGattService & primService = *primServices.at(i); - if( GATT_VERBOSE ) { - fprintf_td(stderr, " [%2.2d] Service UUID %s (%s)\n", i, - primService.type->toUUID128String().c_str(), - primService.type->getTypeSizeString().c_str()); - fprintf_td(stderr, " [%2.2d] %s\n", i, primService.toString().c_str()); - } - jau::darray<BTGattCharRef> & serviceCharacteristics = primService.characteristicList; - for(size_t j=0; j<serviceCharacteristics.size(); j++) { - BTGattCharRef & serviceChar = serviceCharacteristics.at(j); - if( GATT_VERBOSE ) { - fprintf_td(stderr, " [%2.2d.%2.2d] Characteristic: UUID %s (%s)\n", i, j, - serviceChar->value_type->toUUID128String().c_str(), - serviceChar->value_type->getTypeSizeString().c_str()); - fprintf_td(stderr, " [%2.2d.%2.2d] %s\n", i, j, serviceChar->toString().c_str()); - } - if( serviceChar->hasProperties(BTGattChar::PropertyBitVal::Read) ) { - POctets value(BTGattHandler::number(BTGattHandler::Defaults::MAX_ATT_MTU), 0, jau::endian::little); - if( serviceChar->readValue(value) ) { - std::string sval = dfa_utf8_decode(value.get_ptr(), value.size()); - if( GATT_VERBOSE ) { - fprintf_td(stderr, " [%2.2d.%2.2d] value: %s ('%s')\n", (int)i, (int)j, value.toString().c_str(), sval.c_str()); - } - } - } - jau::darray<BTGattDescRef> & charDescList = serviceChar->descriptorList; - for(size_t k=0; k<charDescList.size(); k++) { - BTGattDesc & charDesc = *charDescList.at(k); - if( GATT_VERBOSE ) { - fprintf_td(stderr, " [%2.2d.%2.2d.%2.2d] Descriptor: UUID %s (%s)\n", i, j, k, - charDesc.type->toUUID128String().c_str(), - charDesc.type->getTypeSizeString().c_str()); - fprintf_td(stderr, " [%2.2d.%2.2d.%2.2d] %s\n", i, j, k, charDesc.toString().c_str()); - } - } - if( 0 == loop ) { - bool cccdEnableResult[2]; - if( serviceChar->enableNotificationOrIndication( cccdEnableResult ) ) { - // ClientCharConfigDescriptor (CCD) is available - std::shared_ptr<BTGattCharListener> gattEventListener = std::make_shared<MyGATTEventListener>(*this); - bool clAdded = serviceChar->addCharListener( gattEventListener ); - if( clAdded ) { - gattListener.push_back(gattEventListener); - } else { - gattListenerError = true; - fprintf_td(stderr, "Client Error: Failed to add GattListener: %s @ %s, gattListener %zu\n", - gattEventListener->toString().c_str(), serviceChar->toString().c_str(), gattListener.size()); - } - if( GATT_VERBOSE ) { - fprintf_td(stderr, " [%2.2d.%2.2d] Characteristic-Listener: Notification(%d), Indication(%d): Added %d\n", - (int)i, (int)j, cccdEnableResult[0], cccdEnableResult[1], clAdded); - fprintf_td(stderr, "\n"); - } - } - } - } - if( GATT_VERBOSE ) { - fprintf_td(stderr, "\n"); - } - } - success = notificationsReceived >= 2 || indicationsReceived >= 2; - ++loop; - } while( !success && device->getConnected() && !gattListenerError ); - - if( gattListenerError ) { - success = false; - } - { - int i = 0; - for(BTGattCharListenerRef gcl : gattListener) { - if( !device->removeCharListener(gcl) ) { - fprintf_td(stderr, "Client: Failed to remove GattListener[%d/%zu]: %s @ %s\n", - i, gattListener.size(), gcl->toString().c_str(), device->toString().c_str()); - success = false; - } - ++i; - } - } - - if( device->getConnected() ) { - // Tell server we have successfully completed the test. - BTGattCmd cmd = BTGattCmd(*device, "FinalHandshake", DBTConstants::CommandUUID, DBTConstants::ResponseUUID, 256); - cmd.setVerbose(true); - const bool cmd_resolved = cmd.isResolved(); - fprintf_td(stderr, "FinalCommand test: %s, resolved %d\n", cmd.toString().c_str(), cmd_resolved); - const int data_sz = DBTConstants::FailHandshakeCommandData.size(); - POctets cmd_data(data_sz, endian::little); - if( success ) { - cmd_data.put_bytes_nc(0, DBTConstants::SuccessHandshakeCommandData.data(), data_sz); - } else { - cmd_data.put_bytes_nc(0, DBTConstants::FailHandshakeCommandData.data(), data_sz); - } - const HCIStatusCode cmd_res = cmd.send(true /* prefNoAck */, cmd_data, 3_s); - if( HCIStatusCode::SUCCESS == cmd_res ) { - const jau::TROOctets& resp = cmd.getResponse(); - - if( cmd_data.size() == resp.size() && - 0 == ::memcmp(cmd_data.get_ptr(), resp.get_ptr(), resp.size()) ) - { - fprintf_td(stderr, "Client Success: %s -> %s (echo response)\n", cmd.toString().c_str(), resp.toString().c_str()); - } else { - fprintf_td(stderr, "Client Failure: %s -> %s (different response)\n", cmd.toString().c_str(), resp.toString().c_str()); - } - } else { - fprintf_td(stderr, "Client Failure: %s -> %s\n", cmd.toString().c_str(), to_string(cmd_res).c_str()); - } - // cmd.close(); // done via dtor - } - } catch ( std::exception & e ) { - fprintf_td(stderr, "****** Client Processing Ready Device: Exception.2 caught for %s: %s\n", device->toString().c_str(), e.what()); - } - - exit: - fprintf_td(stderr, "****** Client Processing Ready Device: End-1: Success %d on %s; devInProc %zu\n", - success, device->toString().c_str(), BTDeviceRegistry::getProcessingDeviceCount()); - - BTDeviceRegistry::removeFromProcessingDevices(device->getAddressAndType()); - - if( DiscoveryPolicy::PAUSE_CONNECTED_UNTIL_DISCONNECTED == discoveryPolicy ) { - device->getAdapter().removeDevicePausingDiscovery(*device); - } - - fprintf_td(stderr, "****** Client Processing Ready Device: End-2: Success %d on %s; devInProc %zu\n", - success, device->toString().c_str(), BTDeviceRegistry::getProcessingDeviceCount()); - - if( success ) { - BTDeviceRegistry::addToProcessedDevices(device->getAddressAndType(), device->getName()); - } - device->removeAllCharListener(); - - if( !KEEP_CONNECTED ) { - if( REMOVE_DEVICE ) { - device->remove(); - } else { - device->disconnect(); - } - } - - completedMeasurementsTotal++; - if( success ) { - completedMeasurementsSuccess++; - } - if( 0 < measurementsLeft ) { - measurementsLeft--; - } - 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, completedMeasurementsSuccess.load(), - measurementsLeft.load(), notificationsReceived.load(), indicationsReceived.load(), - completedGATTCommands.load(), device->getAddressAndType().toString().c_str()); - } - - void removeDevice(BTDeviceRef device) { - fprintf_td(stderr, "****** Client Remove Device: removing: %s\n", device->getAddressAndType().toString().c_str()); - - BTDeviceRegistry::removeFromProcessingDevices(device->getAddressAndType()); - - if( REMOVE_DEVICE ) { - device->remove(); - } - } - - static const bool le_scan_active = true; // default value - static const uint16_t le_scan_interval = 24; // default value - static const uint16_t le_scan_window = 24; // default value - static const uint8_t filter_policy = 0; // default value - static const bool filter_dup = true; // default value - - public: - - HCIStatusCode startDiscovery(const std::string& msg) override { - HCIStatusCode status = clientAdapter->startDiscovery( discoveryPolicy, le_scan_active, le_scan_interval, le_scan_window, filter_policy, filter_dup ); - fprintf_td(stderr, "****** Client Start discovery (%s) result: %s: %s\n", msg.c_str(), to_string(status).c_str(), clientAdapter->toString().c_str()); - return status; - } - - HCIStatusCode stopDiscovery(const std::string& msg) override { - HCIStatusCode status = clientAdapter->stopDiscovery(); - fprintf_td(stderr, "****** Client Stop discovery (%s) result: %s\n", msg.c_str(), to_string(status).c_str()); - return status; - } - - void close(const std::string& msg) override { - fprintf_td(stderr, "****** Client Close: %s\n", msg.c_str()); - clientAdapter->stopDiscovery(); - clientAdapter->removeStatusListener( myAdapterStatusListener ); - } - - bool initAdapter(BTAdapterRef adapter) override { - if( useAdapter != EUI48::ALL_DEVICE && useAdapter != adapter->getAddressAndType().address ) { - fprintf_td(stderr, "initClientAdapter: Adapter not selected: %s\n", adapter->toString().c_str()); - return false; - } - adapterName = adapterName + "-" + adapter->getAddressAndType().address.toString(); - { - auto it = std::remove( adapterName.begin(), adapterName.end(), ':'); - adapterName.erase(it, adapterName.end()); - } - - // Initialize with defaults and power-on - if( !adapter->isInitialized() ) { - HCIStatusCode status = adapter->initialize( btMode ); - if( HCIStatusCode::SUCCESS != status ) { - fprintf_td(stderr, "initClientAdapter: Adapter initialization failed: %s: %s\n", - to_string(status).c_str(), adapter->toString().c_str()); - return false; - } - } else if( !adapter->setPowered( true ) ) { - fprintf_td(stderr, "initClientAdapter: Already initialized adapter power-on failed:: %s\n", adapter->toString().c_str()); - return false; - } - // adapter is powered-on - fprintf_td(stderr, "initClientAdapter.1: %s\n", adapter->toString().c_str()); - { - const LE_Features le_feats = adapter->getLEFeatures(); - fprintf_td(stderr, "initClientAdapter: LE_Features %s\n", to_string(le_feats).c_str()); - } - - if( adapter->setPowered(false) ) { - HCIStatusCode status = adapter->setName(adapterName, adapterShortName); - if( HCIStatusCode::SUCCESS == status ) { - fprintf_td(stderr, "initClientAdapter: setLocalName OK: %s\n", adapter->toString().c_str()); - } else { - fprintf_td(stderr, "initClientAdapter: setLocalName failed: %s\n", adapter->toString().c_str()); - return false; - } - - if( !adapter->setPowered( true ) ) { - fprintf_td(stderr, "initClientAdapter: setPower.2 on failed: %s\n", adapter->toString().c_str()); - return false; - } - } else { - fprintf_td(stderr, "initClientAdapter: setPowered.2 off failed: %s\n", adapter->toString().c_str()); - return false; - } - // adapter is powered-on - fprintf_td(stderr, "initClientAdapter.2: %s\n", adapter->toString().c_str()); - - { - const LE_Features le_feats = adapter->getLEFeatures(); - fprintf_td(stderr, "initClientAdapter: LE_Features %s\n", to_string(le_feats).c_str()); - } - if( adapter->getBTMajorVersion() > 4 ) { - LE_PHYs Tx { LE_PHYs::LE_2M }, Rx { LE_PHYs::LE_2M }; - HCIStatusCode res = adapter->setDefaultLE_PHY(Tx, Rx); - fprintf_td(stderr, "initClientAdapter: Set Default LE PHY: status %s: Tx %s, Rx %s\n", - to_string(res).c_str(), to_string(Tx).c_str(), to_string(Rx).c_str()); - } - adapter->addStatusListener( myAdapterStatusListener ); - - return true; - } -}; - -#endif /* DBT_CLIENT00_HPP_ */ diff --git a/trial/direct_bt/dbt_client01.hpp b/trial/direct_bt/dbt_client01.hpp index faf128e1..9d6dcdce 100644 --- a/trial/direct_bt/dbt_client01.hpp +++ b/trial/direct_bt/dbt_client01.hpp @@ -39,22 +39,9 @@ using namespace jau::fractions_i64_literals; * This central BTRole::Master participant works with DBTServer00. */ class DBTClient01 : 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 @@ -67,16 +54,18 @@ class DBTClient01 : public DBTClientTest { 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 completedMeasurementsTotal = 0; jau::sc_atomic_int completedMeasurementsSuccess = 0; jau::sc_atomic_int measurementsLeft = 0; bool do_disconnect = false; - private: const uint64_t timestamp_t0 = getCurrentMilliseconds(); // const fraction_i64 timestamp_t0 = jau::getMonotonicMicroseconds(); + const uint8_t cmd_arg = 0x44; + class MyAdapterStatusListener : public AdapterStatusListener { public: DBTClient01& parent; @@ -335,6 +324,7 @@ class DBTClient01 : public DBTClientTest { private: void resetLastProcessingStats() { + completedGATTCommands = 0; notificationsReceived = 0; indicationsReceived = 0; } @@ -441,6 +431,28 @@ class DBTClient01 : public DBTClientTest { td13, td12, td23, td35); } + { + BTGattCmd cmd = BTGattCmd(*device, "TestCmd", DBTConstants::CommandUUID, DBTConstants::ResponseUUID, 256); + cmd.setVerbose(true); + const bool cmd_resolved = cmd.isResolved(); + fprintf_td(stderr, "Command test: %s, resolved %d\n", cmd.toString().c_str(), cmd_resolved); + POctets cmd_data(1, endian::little); + cmd_data.put_uint8_nc(0, cmd_arg); + const HCIStatusCode cmd_res = cmd.send(true /* prefNoAck */, cmd_data, 3_s); + if( HCIStatusCode::SUCCESS == cmd_res ) { + const jau::TROOctets& resp = cmd.getResponse(); + if( 1 == resp.size() && resp.get_uint8_nc(0) == cmd_arg ) { + fprintf_td(stderr, "Client Success: %s -> %s (echo response)\n", cmd.toString().c_str(), resp.toString().c_str()); + completedGATTCommands++; + } else { + fprintf_td(stderr, "Client Failure: %s -> %s (different response)\n", cmd.toString().c_str(), resp.toString().c_str()); + } + } else { + fprintf_td(stderr, "Client Failure: %s -> %s\n", cmd.toString().c_str(), to_string(cmd_res).c_str()); + } + // cmd.close(); // done via dtor + } + bool gattListenerError = false; std::vector<BTGattCharListenerRef> gattListener; int loop = 0; @@ -510,6 +522,8 @@ class DBTClient01 : public DBTClientTest { ++loop; } while( !success && device->getConnected() && !gattListenerError ); + success = success && completedGATTCommands >= 1; + if( gattListenerError ) { success = false; } @@ -587,10 +601,11 @@ class DBTClient01 : public DBTClientTest { } } fprintf_td(stderr, "****** Client Processing Ready Device: Success %d; Measurements completed %d" - ", left %d; Received notitifications %d, indications %d: %s\n", + ", left %d; Received notitifications %d, indications %d" + "; Completed GATT commands %d: %s\n", success, completedMeasurementsSuccess.load(), measurementsLeft.load(), notificationsReceived.load(), indicationsReceived.load(), - device->getAddressAndType().toString().c_str()); + completedGATTCommands.load(), device->getAddressAndType().toString().c_str()); } void removeDevice(BTDeviceRef device) { diff --git a/trial/direct_bt/dbt_client_server1x.hpp b/trial/direct_bt/dbt_client_server1x.hpp index dbaa620e..faee48a8 100644 --- a/trial/direct_bt/dbt_client_server1x.hpp +++ b/trial/direct_bt/dbt_client_server1x.hpp @@ -29,8 +29,8 @@ #include "dbt_base_client_server.hpp" -#include "dbt_server00.hpp" -#include "dbt_client00.hpp" +#include "dbt_server01.hpp" +#include "dbt_client01.hpp" using namespace direct_bt; @@ -63,8 +63,9 @@ class DBTClientServer1x { const bool serverSC, const BTSecurityLevel secLevelServer, const ExpectedPairing serverExpPairing, const BTSecurityLevel secLevelClient, const ExpectedPairing clientExpPairing) { - 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); + std::shared_ptr<DBTServer01> server = std::make_shared<DBTServer01>("S-"+suffix, EUI48::ALL_DEVICE, BTMode::DUAL, + serverSC, secLevelServer, false /* do_disconnect_ */); + std::shared_ptr<DBTClient01> client = std::make_shared<DBTClient01>("C-"+suffix, EUI48::ALL_DEVICE, BTMode::DUAL, false /* do_disconnect_ */); test8x_fullCycle(suffix, protocolSessionCount, DBTConstants::max_connections_per_session, true /* expSuccess */, server_client_order, diff --git a/trial/direct_bt/dbt_server00.hpp b/trial/direct_bt/dbt_server00.hpp deleted file mode 100644 index 27231d8c..00000000 --- a/trial/direct_bt/dbt_server00.hpp +++ /dev/null @@ -1,774 +0,0 @@ -/** - * 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. - */ - -#ifndef DBT_SERVER00_HPP_ -#define DBT_SERVER00_HPP_ - -#include "dbt_constants.hpp" - -#include "dbt_server_test.hpp" - -class DBTServer00; -typedef std::shared_ptr<DBTServer00> DBTServer00Ref; - -using namespace jau; - -/** - * This peripheral BTRole::Slave test participant works with DBTClient00. - */ -class DBTServer00 : public DBTServerTest { - private: - static jau::POctets make_poctets(const char* name) { - return jau::POctets( (const uint8_t*)name, (nsize_t)strlen(name), endian::little ); - } - static jau::POctets make_poctets(const char* name, const jau::nsize_t capacity) { - const nsize_t name_len = (nsize_t)strlen(name); - jau::POctets p( std::max<nsize_t>(capacity, name_len), name_len, endian::little ); - p.bzero(); - p.put_bytes_nc(0, reinterpret_cast<const uint8_t*>(name), name_len); - return p; - } - static jau::POctets make_poctets(const uint16_t v) { - jau::POctets p(2, endian::little); - p.put_uint16_nc(0, v); - return p; - } - static jau::POctets make_poctets(const jau::nsize_t capacity, const jau::nsize_t size) { - jau::POctets p(capacity, size, endian::little); - p.bzero(); - return p; - } - - static const bool GATT_VERBOSE = false; - static const bool SHOW_UPDATE_EVENTS = false; - - const std::string adapterShortName = "TDev1Srv"; - std::string adapterName = "TestDev1_Srv"; - jau::EUI48 useAdapter = jau::EUI48::ALL_DEVICE; - BTMode btMode = BTMode::DUAL; - bool use_SC = true; - BTSecurityLevel adapterSecurityLevel = BTSecurityLevel::UNSET; - - 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 - std::make_shared<DBGattService> ( true /* primary */, - std::make_unique<const jau::uuid16_t>(GattServiceType::GENERIC_ACCESS) /* type_ */, - jau::make_darray ( // DBGattChar - std::make_shared<DBGattChar>( std::make_unique<const jau::uuid16_t>(GattCharacteristicType::DEVICE_NAME) /* value_type_ */, - BTGattChar::PropertyBitVal::Read, - jau::darray<DBGattDescRef>() /* intentionally empty */, - make_poctets(adapterName.c_str(), 128) /* value */, true /* variable_length */ ), - std::make_shared<DBGattChar>( std::make_unique<const jau::uuid16_t>(GattCharacteristicType::APPEARANCE) /* value_type_ */, - BTGattChar::PropertyBitVal::Read, - jau::darray<DBGattDescRef>() /* intentionally empty */, - make_poctets((uint16_t)0) /* value */ ) - ) ), - std::make_shared<DBGattService> ( true /* primary */, - std::make_unique<const jau::uuid16_t>(GattServiceType::DEVICE_INFORMATION) /* type_ */, - jau::make_darray ( // DBGattChar - std::make_shared<DBGattChar>( std::make_unique<const jau::uuid16_t>(GattCharacteristicType::MANUFACTURER_NAME_STRING) /* value_type_ */, - BTGattChar::PropertyBitVal::Read, - jau::darray<DBGattDescRef>() /* intentionally empty */, - make_poctets("Gothel Software") /* value */ ), - std::make_shared<DBGattChar>( std::make_unique<const jau::uuid16_t>(GattCharacteristicType::MODEL_NUMBER_STRING) /* value_type_ */, - BTGattChar::PropertyBitVal::Read, - jau::darray<DBGattDescRef>() /* intentionally empty */, - make_poctets("2.4.0-pre") /* value */ ), - std::make_shared<DBGattChar>( std::make_unique<const jau::uuid16_t>(GattCharacteristicType::SERIAL_NUMBER_STRING) /* value_type_ */, - BTGattChar::PropertyBitVal::Read, - jau::darray<DBGattDescRef>() /* intentionally empty */, - make_poctets("sn:0123456789") /* value */ ), - std::make_shared<DBGattChar>( std::make_unique<const jau::uuid16_t>(GattCharacteristicType::HARDWARE_REVISION_STRING) /* value_type_ */, - BTGattChar::PropertyBitVal::Read, - jau::darray<DBGattDescRef>() /* intentionally empty */, - make_poctets("hw:0123456789") /* value */ ), - std::make_shared<DBGattChar>( std::make_unique<const jau::uuid16_t>(GattCharacteristicType::FIRMWARE_REVISION_STRING) /* value_type_ */, - BTGattChar::PropertyBitVal::Read, - jau::darray<DBGattDescRef>() /* intentionally empty */, - make_poctets("fw:0123456789") /* value */ ), - std::make_shared<DBGattChar>( std::make_unique<const jau::uuid16_t>(GattCharacteristicType::SOFTWARE_REVISION_STRING) /* value_type_ */, - BTGattChar::PropertyBitVal::Read, - jau::darray<DBGattDescRef>() /* intentionally empty */, - make_poctets("sw:0123456789") /* value */ ) - ) ), - std::make_shared<DBGattService> ( true /* primary */, - std::make_unique<const jau::uuid128_t>(DBTConstants::DataServiceUUID) /* type_ */, - jau::make_darray ( // DBGattChar - std::make_shared<DBGattChar>( std::make_unique<const jau::uuid128_t>(DBTConstants::StaticDataUUID) /* value_type_ */, - BTGattChar::PropertyBitVal::Read, - jau::make_darray ( // DBGattDesc - std::make_shared<DBGattDesc>( BTGattDesc::TYPE_USER_DESC, make_poctets("DATA_STATIC") ) - ), - make_poctets("Proprietary Static Data 0x00010203") /* value */ ), - std::make_shared<DBGattChar>( std::make_unique<const jau::uuid128_t>(DBTConstants::CommandUUID) /* value_type_ */, - BTGattChar::PropertyBitVal::WriteNoAck | BTGattChar::PropertyBitVal::WriteWithAck, - jau::make_darray ( // DBGattDesc - std::make_shared<DBGattDesc>( BTGattDesc::TYPE_USER_DESC, make_poctets("COMMAND") ) - ), - make_poctets(128, 64) /* value */, true /* variable_length */ ), - std::make_shared<DBGattChar>( std::make_unique<const jau::uuid128_t>(DBTConstants::ResponseUUID) /* value_type_ */, - BTGattChar::PropertyBitVal::Notify | BTGattChar::PropertyBitVal::Indicate, - jau::make_darray ( // DBGattDesc - std::make_shared<DBGattDesc>( BTGattDesc::TYPE_USER_DESC, make_poctets("RESPONSE") ), - DBGattDesc::createClientCharConfig() - ), - make_poctets((uint16_t)0) /* value */ ), - std::make_shared<DBGattChar>( std::make_unique<const jau::uuid128_t>(DBTConstants::PulseDataUUID) /* value_type_ */, - BTGattChar::PropertyBitVal::Notify | BTGattChar::PropertyBitVal::Indicate, - jau::make_darray ( // DBGattDesc - std::make_shared<DBGattDesc>( BTGattDesc::TYPE_USER_DESC, make_poctets("DATA_PULSE") ), - DBGattDesc::createClientCharConfig() - ), - make_poctets("Synthethic Sensor 01") /* value */ ) - ) ) - ) ); - - - std::mutex mtx_sync; - BTDeviceRef connectedDevice; - - void setDevice(BTDeviceRef cd) { - const std::lock_guard<std::mutex> lock(mtx_sync); // RAII-style acquire and relinquish via destructor - connectedDevice = cd; - } - - BTDeviceRef getDevice() { - const std::lock_guard<std::mutex> lock(mtx_sync); // RAII-style acquire and relinquish via destructor - return connectedDevice; - } - - bool matches(const BTDeviceRef& device) { - const BTDeviceRef d = getDevice(); - return nullptr != d ? (*d) == *device : false; - } - - class MyAdapterStatusListener : public AdapterStatusListener { - public: - DBTServer00& parent; - - MyAdapterStatusListener(DBTServer00& p) : parent(p) {} - - void adapterSettingsChanged(BTAdapter &a, const AdapterSetting oldmask, const AdapterSetting newmask, - const AdapterSetting changedmask, const uint64_t timestamp) override { - const bool initialSetting = AdapterSetting::NONE == oldmask; - if( initialSetting ) { - fprintf_td(stderr, "****** Server SETTINGS_INITIAL: %s -> %s, changed %s\n", to_string(oldmask).c_str(), - to_string(newmask).c_str(), to_string(changedmask).c_str()); - } else { - fprintf_td(stderr, "****** Server SETTINGS_CHANGED: %s -> %s, changed %s\n", to_string(oldmask).c_str(), - to_string(newmask).c_str(), to_string(changedmask).c_str()); - } - fprintf_td(stderr, "Server Status BTAdapter:\n"); - fprintf_td(stderr, "%s\n", a.toString().c_str()); - (void)timestamp; - } - - void discoveringChanged(BTAdapter &a, const ScanType currentMeta, const ScanType changedType, const bool changedEnabled, const DiscoveryPolicy policy, const uint64_t timestamp) override { - fprintf_td(stderr, "****** Server DISCOVERING: meta %s, changed[%s, enabled %d, policy %s]: %s\n", - to_string(currentMeta).c_str(), to_string(changedType).c_str(), changedEnabled, to_string(policy).c_str(), a.toString().c_str()); - (void)timestamp; - } - - bool deviceFound(BTDeviceRef device, const uint64_t timestamp) override { - (void)timestamp; - - fprintf_td(stderr, "****** Server FOUND__-1: NOP %s\n", device->toString(true).c_str()); - return false; - } - - void deviceUpdated(BTDeviceRef device, const EIRDataType updateMask, const uint64_t timestamp) override { - if( SHOW_UPDATE_EVENTS ) { - fprintf_td(stderr, "****** Server UPDATED: %s of %s\n", to_string(updateMask).c_str(), device->toString(true).c_str()); - } - (void)timestamp; - } - - void deviceConnected(BTDeviceRef device, const bool discovered, const uint64_t timestamp) override { - fprintf_td(stderr, "****** Server CONNECTED (discovered %d): %s\n", discovered, device->toString(true).c_str()); - const bool available = nullptr == parent.getDevice(); - if( available ) { - parent.setDevice(device); - BTDeviceRegistry::addToProcessingDevices(device->getAddressAndType(), device->getName()); - } - (void)discovered; - (void)timestamp; - } - - void devicePairingState(BTDeviceRef device, const SMPPairingState state, const PairingMode mode, const uint64_t timestamp) override { - fprintf_td(stderr, "****** Server PAIRING STATE: state %s, mode %s, %s\n", - to_string(state).c_str(), to_string(mode).c_str(), device->toString().c_str()); - (void)timestamp; - switch( state ) { - case SMPPairingState::NONE: - // next: deviceReady(..) - break; - case SMPPairingState::FAILED: { - // next: deviceReady() or deviceDisconnected(..) - } break; - case SMPPairingState::REQUESTED_BY_RESPONDER: - // next: FEATURE_EXCHANGE_STARTED - break; - case SMPPairingState::FEATURE_EXCHANGE_STARTED: - // next: FEATURE_EXCHANGE_COMPLETED - break; - case SMPPairingState::FEATURE_EXCHANGE_COMPLETED: - // next: PASSKEY_EXPECTED... or KEY_DISTRIBUTION - break; - case SMPPairingState::PASSKEY_EXPECTED: { - const BTSecurityRegistry::Entry* sec = BTSecurityRegistry::getStartOf(device->getAddressAndType().address, ""); - if( nullptr != sec && sec->getPairingPasskey() != BTSecurityRegistry::Entry::NO_PASSKEY ) { - std::thread dc(&BTDevice::setPairingPasskey, device, static_cast<uint32_t>( sec->getPairingPasskey() )); - dc.detach(); - } else { - std::thread dc(&BTDevice::setPairingPasskey, device, 0); - // 3s disconnect: std::thread dc(&BTDevice::setPairingPasskeyNegative, device); - dc.detach(); - } - // next: KEY_DISTRIBUTION or FAILED - } break; - case SMPPairingState::NUMERIC_COMPARE_EXPECTED: { - const BTSecurityRegistry::Entry* sec = BTSecurityRegistry::getStartOf(device->getAddressAndType().address, ""); - if( nullptr != sec ) { - std::thread dc(&BTDevice::setPairingNumericComparison, device, sec->getPairingNumericComparison()); - dc.detach(); - } else { - std::thread dc(&BTDevice::setPairingNumericComparison, device, false); - dc.detach(); - } - // next: KEY_DISTRIBUTION or FAILED - } break; - case SMPPairingState::OOB_EXPECTED: - // FIXME: ABORT - break; - case SMPPairingState::KEY_DISTRIBUTION: - // next: COMPLETED or FAILED - break; - case SMPPairingState::COMPLETED: - // next: deviceReady(..) - break; - default: // nop - break; - } - } - - void deviceReady(BTDeviceRef device, const uint64_t timestamp) override { - (void)timestamp; - fprintf_td(stderr, "****** Server READY-1: NOP %s\n", device->toString(true).c_str()); - } - - void deviceDisconnected(BTDeviceRef device, const HCIStatusCode reason, const uint16_t handle, const uint64_t timestamp) override { - fprintf_td(stderr, "****** Server DISCONNECTED (count %zu): Reason 0x%X (%s), old handle %s: %s\n", - 1+parent.disconnectCount.load(), static_cast<uint8_t>(reason), to_string(reason).c_str(), - to_hexstring(handle).c_str(), device->toString(true).c_str()); - - const bool match = parent.matches(device); - if( match ) { - parent.setDevice(nullptr); - } - std::thread sd(&DBTServer00::processDisconnectedDevice, &parent, device); // @suppress("Invalid arguments") - sd.detach(); - (void)timestamp; - } - - std::string toString() const noexcept override { - return "Server MyAdapterStatusListener[this "+to_hexstring(this)+"]"; - } - - }; - - class MyGATTServerListener : public DBGattServer::Listener { - private: - DBTServer00& parent; - jau::service_runner pulse_service; - - jau::sc_atomic_uint16 handlePulseDataNotify = 0; - jau::sc_atomic_uint16 handlePulseDataIndicate = 0; - jau::sc_atomic_uint16 handleResponseDataNotify = 0; - jau::sc_atomic_uint16 handleResponseDataIndicate = 0; - - uint16_t usedMTU = BTGattHandler::number(BTGattHandler::Defaults::MIN_ATT_MTU); - - void pulse_worker_init(jau::service_runner& sr) noexcept { - (void)sr; - const BTDeviceRef connectedDevice_ = parent.getDevice(); - const std::string connectedDeviceStr = nullptr != connectedDevice_ ? connectedDevice_->toString() : "n/a"; - fprintf_td(stderr, "****** Server GATT::PULSE Start %s\n", connectedDeviceStr.c_str()); - } - void pulse_worker(jau::service_runner& sr) noexcept { - BTDeviceRef connectedDevice_ = parent.getDevice(); - if( nullptr != connectedDevice_ && connectedDevice_->getConnected() ) { - if( 0 != handlePulseDataNotify || 0 != handlePulseDataIndicate ) { - std::string data( "Dynamic Data Example. Elapsed Milliseconds: "+jau::to_decstring(environment::getElapsedMillisecond(), ',', 9) ); - jau::POctets v(data.size()+1, jau::endian::little); - v.put_string_nc(0, data, v.size(), true /* includeEOS */); - if( 0 != handlePulseDataNotify ) { - if( GATT_VERBOSE ) { - fprintf_td(stderr, "****** Server GATT::sendNotification: PULSE to %s\n", connectedDevice_->toString().c_str()); - } - connectedDevice_->sendNotification(handlePulseDataNotify, v); - } - if( 0 != handlePulseDataIndicate ) { - if( GATT_VERBOSE ) { - fprintf_td(stderr, "****** Server GATT::sendIndication: PULSE to %s\n", connectedDevice_->toString().c_str()); - } - connectedDevice_->sendIndication(handlePulseDataIndicate, v); - } - } - } - if( !sr.shall_stop() ) { - jau::sleep_for( 100_ms ); - } - } - void pulse_worker_end(jau::service_runner& sr) noexcept { - (void)sr; - const BTDeviceRef connectedDevice_ = parent.getDevice(); - const std::string connectedDeviceStr = nullptr != connectedDevice_ ? connectedDevice_->toString() : "n/a"; - fprintf_td(stderr, "****** Server GATT::PULSE End %s\n", connectedDeviceStr.c_str()); - } - - void sendResponse(jau::POctets data) { - BTDeviceRef connectedDevice_ = parent.getDevice(); - if( nullptr != connectedDevice_ && connectedDevice_->getConnected() ) { - if( 0 != handleResponseDataNotify || 0 != handleResponseDataIndicate ) { - if( 0 != handleResponseDataNotify ) { - if( GATT_VERBOSE ) { - fprintf_td(stderr, "****** GATT::sendNotification: %s to %s\n", - data.toString().c_str(), connectedDevice_->toString().c_str()); - } - connectedDevice_->sendNotification(handleResponseDataNotify, data); - } - if( 0 != handleResponseDataIndicate ) { - if( GATT_VERBOSE ) { - fprintf_td(stderr, "****** GATT::sendIndication: %s to %s\n", - data.toString().c_str(), connectedDevice_->toString().c_str()); - } - connectedDevice_->sendIndication(handleResponseDataIndicate, data); - } - } - } - } - - public: - - MyGATTServerListener(DBTServer00& p) - : parent(p), - pulse_service("MyGATTServerListener::pulse", THREAD_SHUTDOWN_TIMEOUT_MS, - jau::bindMemberFunc(this, &MyGATTServerListener::pulse_worker), - jau::bindMemberFunc(this, &MyGATTServerListener::pulse_worker_init), - jau::bindMemberFunc(this, &MyGATTServerListener::pulse_worker_end)) - { - pulse_service.start(); - } - - ~MyGATTServerListener() noexcept { - pulse_service.stop(); - } - - void clear() { - const std::lock_guard<std::mutex> lock(parent.mtx_sync); // RAII-style acquire and relinquish via destructor - - handlePulseDataNotify = 0; - handlePulseDataIndicate = 0; - handleResponseDataNotify = 0; - handleResponseDataIndicate = 0; - - parent.dbGattServer->resetGattClientCharConfig(DBTConstants::DataServiceUUID, DBTConstants::PulseDataUUID); - parent.dbGattServer->resetGattClientCharConfig(DBTConstants::DataServiceUUID, DBTConstants::ResponseUUID); - } - - void close() noexcept { - pulse_service.stop(); - clear(); - } - - 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", - match, (int)initialMTU, device->toString().c_str()); - if( match ) { - const std::lock_guard<std::mutex> lock(parent.mtx_sync); // RAII-style acquire and relinquish via destructor - usedMTU = initialMTU; - } - } - - void disconnected(BTDeviceRef device) override { - const bool match = parent.matches(device); - fprintf_td(stderr, "****** Server GATT::disconnected(match %d): %s\n", match, device->toString().c_str()); - if( match ) { - clear(); - } - } - - void mtuChanged(BTDeviceRef device, const uint16_t mtu) override { - const bool match = parent.matches(device); - const uint16_t usedMTU_old = usedMTU; - if( match ) { - const std::lock_guard<std::mutex> lock(parent.mtx_sync); // RAII-style acquire and relinquish via destructor - usedMTU = mtu; - } - fprintf_td(stderr, "****** Server GATT::mtuChanged(match %d, served %zu, left %zu): %d -> %d, %s\n", - match, parent.servedProtocolSessionsTotal.load(), parent.servingProtocolSessionsLeft.load(), - match ? (int)usedMTU_old : 0, (int)mtu, device->toString().c_str()); - } - - bool readCharValue(BTDeviceRef device, DBGattServiceRef s, DBGattCharRef c) override { - const bool match = parent.matches(device); - if( GATT_VERBOSE ) { - fprintf_td(stderr, "****** Server GATT::readCharValue(match %d): to %s, from\n %s\n %s\n", - match, device->toString().c_str(), s->toString().c_str(), c->toString().c_str()); - } - return match; - } - - bool readDescValue(BTDeviceRef device, DBGattServiceRef s, DBGattCharRef c, DBGattDescRef d) override { - const bool match = parent.matches(device); - if( GATT_VERBOSE ) { - fprintf_td(stderr, "****** Server GATT::readDescValue(match %d): to %s, from\n %s\n %s\n %s\n", - match, device->toString().c_str(), s->toString().c_str(), c->toString().c_str(), d->toString().c_str()); - } - return match; - } - - bool writeCharValue(BTDeviceRef device, DBGattServiceRef s, DBGattCharRef c, const jau::TROOctets & value, const uint16_t value_offset) override { - const bool match = parent.matches(device); - if( GATT_VERBOSE ) { - fprintf_td(stderr, "****** Server GATT::writeCharValue(match %d): %s '%s' @ %u from %s, to\n %s\n %s\n", - match, value.toString().c_str(), jau::dfa_utf8_decode( value.get_ptr(), value.size() ).c_str(), - value_offset, - device->toString().c_str(), s->toString().c_str(), c->toString().c_str()); - } - return match; - } - void writeCharValueDone(BTDeviceRef device, DBGattServiceRef s, DBGattCharRef c) override { - const bool match = parent.matches(device); - const jau::TROOctets& value = c->getValue(); - bool isFinalHandshake = false; - bool isFinalHandshakeSuccess = false; - - if( match && - c->getValueType()->equivalent( DBTConstants::CommandUUID ) && - ( 0 != handleResponseDataNotify || 0 != handleResponseDataIndicate ) ) - { - isFinalHandshakeSuccess = DBTConstants::SuccessHandshakeCommandData.size() == value.size() && - 0 == ::memcmp(DBTConstants::SuccessHandshakeCommandData.data(), value.get_ptr(), value.size()); - isFinalHandshake = isFinalHandshakeSuccess || - ( DBTConstants::FailHandshakeCommandData.size() == value.size() && - 0 == ::memcmp(DBTConstants::FailHandshakeCommandData.data(), value.get_ptr(), value.size()) ); - - if( isFinalHandshake ) { - if( isFinalHandshakeSuccess ) { - parent.servedProtocolSessionsSuccess++; - } - parent.servedProtocolSessionsTotal++; - if( parent.servingProtocolSessionsLeft > 0 ) { - parent.servingProtocolSessionsLeft--; - } - } - jau::POctets value2(value); - std::thread senderThread(&MyGATTServerListener::sendResponse, this, value2); // @suppress("Invalid arguments") - senderThread.detach(); - } - if( GATT_VERBOSE || isFinalHandshake ) { - fprintf_td(stderr, "****** Server GATT::writeCharValueDone(match %d, finalCmd %d, sessions [%d ok / %d total], left %d): From %s, to\n %s\n %s\n Char-Value: %s\n", - match, isFinalHandshake, parent.servedProtocolSessionsSuccess.load(), parent.servedProtocolSessionsTotal.load(), parent.servingProtocolSessionsLeft.load(), - device->toString().c_str(), s->toString().c_str(), c->toString().c_str(), value.toString().c_str()); - } - } - - bool writeDescValue(BTDeviceRef device, DBGattServiceRef s, DBGattCharRef c, DBGattDescRef d, const jau::TROOctets & value, const uint16_t value_offset) override { - const bool match = parent.matches(device); - if( GATT_VERBOSE ) { - fprintf_td(stderr, "****** Server GATT::writeDescValue(match %d): %s '%s' @ %u from %s\n %s\n %s\n %s\n", - match, value.toString().c_str(), jau::dfa_utf8_decode( value.get_ptr(), value.size() ).c_str(), - value_offset, - device->toString().c_str(), s->toString().c_str(), c->toString().c_str(), d->toString().c_str()); - } - return match; - } - void writeDescValueDone(BTDeviceRef device, DBGattServiceRef s, DBGattCharRef c, DBGattDescRef d) override { - if( GATT_VERBOSE ) { - const bool match = parent.matches(device); - const jau::TROOctets& value = d->getValue(); - fprintf_td(stderr, "****** Server GATT::writeDescValueDone(match %d): From %s\n %s\n %s\n %s\n Desc-Value: %s\n", - match, device->toString().c_str(), s->toString().c_str(), c->toString().c_str(), d->toString().c_str(), value.toString().c_str()); - } - } - - void clientCharConfigChanged(BTDeviceRef device, DBGattServiceRef s, DBGattCharRef c, DBGattDescRef d, const bool notificationEnabled, const bool indicationEnabled) override { - const bool match = parent.matches(device); - if( GATT_VERBOSE ) { - const jau::TROOctets& value = d->getValue(); - fprintf_td(stderr, "****** GATT::clientCharConfigChanged(match %d): notify %d, indicate %d from %s\n %s\n %s\n %s\n Desc-Value: %s\n", - match, notificationEnabled, indicationEnabled, - device->toString().c_str(), s->toString().c_str(), c->toString().c_str(), d->toString().c_str(), value.toString().c_str()); - } - if( match ) { - if( c->getValueType()->equivalent( DBTConstants::PulseDataUUID ) ) { - const std::lock_guard<std::mutex> lock(parent.mtx_sync); // RAII-style acquire and relinquish via destructor - handlePulseDataNotify = notificationEnabled ? c->getValueHandle() : 0; - handlePulseDataIndicate = indicationEnabled ? c->getValueHandle() : 0; - } else if( c->getValueType()->equivalent( DBTConstants::ResponseUUID ) ) { - const std::lock_guard<std::mutex> lock(parent.mtx_sync); // RAII-style acquire and relinquish via destructor - handleResponseDataNotify = notificationEnabled ? c->getValueHandle() : 0; - handleResponseDataIndicate = indicationEnabled ? c->getValueHandle() : 0; - } - } - } - }; - - std::shared_ptr<MyGATTServerListener> gattServerListener = std::make_shared<MyGATTServerListener>(*this); - std::shared_ptr<AdapterStatusListener> myAdapterStatusListener = std::make_shared<MyAdapterStatusListener>(*this); - - BTAdapterRef serverAdapter = nullptr; - - public: - - DBTServer00(const std::string& adapterName_, const jau::EUI48& useAdapter_, const BTMode btMode_, const bool use_SC_, const BTSecurityLevel adapterSecurityLevel_) { - this->adapterName = adapterName_; - this->useAdapter = useAdapter_; - this->btMode = btMode_; - this->use_SC = use_SC_; - this->adapterSecurityLevel = adapterSecurityLevel_; - - dbGattServer->addListener( gattServerListener ); - } - DBTServer00(const std::string& adapterName_, const jau::EUI48& useAdapter_, const BTSecurityLevel adapterSecurityLevel_) - : DBTServer00(adapterName_, useAdapter_, BTMode::DUAL, true /* SC */, adapterSecurityLevel_) - { } - - DBTServer00(const std::string& adapterName_, const BTSecurityLevel adapterSecurityLevel_) - : DBTServer00(adapterName_, EUI48::ALL_DEVICE, BTMode::DUAL, true /* SC */, adapterSecurityLevel_) - { } - - std::string getName() override { return adapterName; } - - BTSecurityLevel getSecurityLevel() override { return adapterSecurityLevel; } - - void setAdapter(BTAdapterRef serverAdapter_) override { - this->serverAdapter = serverAdapter_; - } - - BTAdapterRef getAdapter() override { return serverAdapter; } - - private: - static const uint16_t adv_interval_min=160; // x0.625 = 100ms - static const uint16_t adv_interval_max=480; // x0.625 = 300ms - static const AD_PDU_Type adv_type=AD_PDU_Type::ADV_IND; - static const uint8_t adv_chan_map=0x07; - static const uint8_t filter_policy=0x00; - - public: - - void close(const std::string& msg) override { - fprintf_td(stderr, "****** Server Close.0: %s\n", msg.c_str()); - serverAdapter->removeStatusListener( myAdapterStatusListener ); - { - stopAdvertising(msg); - BTDeviceRef connectedDevice_ = getDevice(); - if( nullptr != connectedDevice_ ) { - setDevice(nullptr); - connectedDevice_->disconnect(); - } - } - gattServerListener->close(); - // dbGattServer = nullptr; // keep alive - stopAdvertising(msg); // try once more in case of already started AdapterStatusListener - 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(); - fprintf_td(stderr, "****** Server Stop advertising (%s) result: %s: %s\n", msg.c_str(), to_string(status).c_str(), serverAdapter->toString().c_str()); - return status; - } - - public: - - HCIStatusCode startAdvertising(const std::string& msg) override { - EInfoReport eir; - EIRDataType adv_mask = EIRDataType::FLAGS | EIRDataType::SERVICE_UUID; - EIRDataType scanrsp_mask = EIRDataType::NAME | EIRDataType::CONN_IVAL; - - eir.addFlags(GAPFlags::LE_Gen_Disc); - eir.addFlags(GAPFlags::BREDR_UNSUP); - - eir.addService(DBTConstants::DataServiceUUID); - eir.setServicesComplete(false); - - eir.setName(serverAdapter->getName()); - eir.setConnInterval(8, 12); // 10ms - 15ms - - DBGattCharRef gattDevNameChar = dbGattServer->findGattChar( jau::uuid16_t(GattServiceType::GENERIC_ACCESS), - jau::uuid16_t(GattCharacteristicType::DEVICE_NAME) ); - if( nullptr != gattDevNameChar ) { - std::string aname = serverAdapter->getName(); - gattDevNameChar->setValue(reinterpret_cast<uint8_t*>(aname.data()), aname.size(), 0); - } - - fprintf_td(stderr, "****** Start advertising (%s): EIR %s\n", msg.c_str(), eir.toString().c_str()); - fprintf_td(stderr, "****** Start advertising (%s): adv %s, scanrsp %s\n", msg.c_str(), to_string(adv_mask).c_str(), to_string(scanrsp_mask).c_str()); - - HCIStatusCode status = serverAdapter->startAdvertising(dbGattServer, eir, adv_mask, scanrsp_mask, - adv_interval_min, adv_interval_max, - adv_type, adv_chan_map, filter_policy); - fprintf_td(stderr, "****** Server Start advertising (%s) result: %s: %s\n", msg.c_str(), to_string(status).c_str(), serverAdapter->toString().c_str()); - if( GATT_VERBOSE ) { - fprintf_td(stderr, "%s", dbGattServer->toFullString().c_str()); - } - return status; - } - - private: - void processDisconnectedDevice(BTDeviceRef device) { - fprintf_td(stderr, "****** Server Disconnected Device (count %zu, seved %zu, left %zu): Start %s\n", - 1+disconnectCount.load(), servedProtocolSessionsTotal.load(), servingProtocolSessionsLeft.load(), device->toString().c_str()); - - // already unpaired - stopAdvertising("device-disconnected"); - device->remove(); - BTDeviceRegistry::removeFromProcessingDevices(device->getAddressAndType()); - - disconnectCount++; - - jau::sleep_for( 100_ms ); // wait a little (FIXME: Fast restart of advertising error) - - if( servingProtocolSessionsLeft > 0 ) { - startAdvertising("device-disconnected"); - } - - fprintf_td(stderr, "****** Server Disonnected Device: End %s\n", device->toString().c_str()); - } - - public: - - bool initAdapter(BTAdapterRef adapter) override { - if( useAdapter != EUI48::ALL_DEVICE && useAdapter != adapter->getAddressAndType().address ) { - fprintf_td(stderr, "initServerAdapter: Adapter not selected: %s\n", adapter->toString().c_str()); - return false; - } - adapterName = adapterName + "-" + adapter->getAddressAndType().address.toString(); - { - auto it = std::remove( adapterName.begin(), adapterName.end(), ':'); - adapterName.erase(it, adapterName.end()); - } - - if( !adapter->isInitialized() ) { - // Initialize with defaults and power-on - const HCIStatusCode status = adapter->initialize( btMode ); - if( HCIStatusCode::SUCCESS != status ) { - fprintf_td(stderr, "initServerAdapter: initialize failed: %s: %s\n", - to_string(status).c_str(), adapter->toString().c_str()); - return false; - } - } else if( !adapter->setPowered( true ) ) { - fprintf_td(stderr, "initServerAdapter: setPower.1 on failed: %s\n", adapter->toString().c_str()); - return false; - } - // adapter is powered-on - fprintf_td(stderr, "initServerAdapter.1: %s\n", adapter->toString().c_str()); - - if( adapter->setPowered(false) ) { - HCIStatusCode status = adapter->setName(adapterName, adapterShortName); - if( HCIStatusCode::SUCCESS == status ) { - fprintf_td(stderr, "initServerAdapter: setLocalName OK: %s\n", adapter->toString().c_str()); - } else { - fprintf_td(stderr, "initServerAdapter: setLocalName failed: %s\n", adapter->toString().c_str()); - return false; - } - - status = adapter->setSecureConnections( use_SC ); - if( HCIStatusCode::SUCCESS == status ) { - fprintf_td(stderr, "initServerAdapter: setSecureConnections OK: %s\n", adapter->toString().c_str()); - } else { - fprintf_td(stderr, "initServerAdapter: setSecureConnections failed: %s\n", adapter->toString().c_str()); - return false; - } - - const uint16_t conn_min_interval = 8; // 10ms - const uint16_t conn_max_interval = 40; // 50ms - const uint16_t conn_latency = 0; - const uint16_t supervision_timeout = 50; // 500ms - status = adapter->setDefaultConnParam(conn_min_interval, conn_max_interval, conn_latency, supervision_timeout); - if( HCIStatusCode::SUCCESS == status ) { - fprintf_td(stderr, "initServerAdapter: setDefaultConnParam OK: %s\n", adapter->toString().c_str()); - } else { - fprintf_td(stderr, "initServerAdapter: setDefaultConnParam failed: %s\n", adapter->toString().c_str()); - return false; - } - - if( !adapter->setPowered( true ) ) { - fprintf_td(stderr, "initServerAdapter: setPower.2 on failed: %s\n", adapter->toString().c_str()); - return false; - } - } else { - fprintf_td(stderr, "initServerAdapter: setPowered.2 off failed: %s\n", adapter->toString().c_str()); - return false; - } - // adapter is powered-on - fprintf_td(stderr, "initServerAdapter.2: %s\n", adapter->toString().c_str()); - - { - const LE_Features le_feats = adapter->getLEFeatures(); - fprintf_td(stderr, "initServerAdapter: LE_Features %s\n", to_string(le_feats).c_str()); - } - if( adapter->getBTMajorVersion() > 4 ) { - LE_PHYs Tx { LE_PHYs::LE_2M }, Rx { LE_PHYs::LE_2M }; - HCIStatusCode res = adapter->setDefaultLE_PHY(Tx, Rx); - fprintf_td(stderr, "initServerAdapter: Set Default LE PHY: status %s: Tx %s, Rx %s\n", - to_string(res).c_str(), to_string(Tx).c_str(), to_string(Rx).c_str()); - } - adapter->setSMPKeyPath(DBTConstants::SERVER_KEY_PATH); - - adapter->addStatusListener( myAdapterStatusListener ); - - adapter->setServerConnSecurity(adapterSecurityLevel, SMPIOCapability::UNSET); - - return true; - } -}; - -#endif // DBT_SERVER00_HPP_ diff --git a/trial/direct_bt/dbt_server01.hpp b/trial/direct_bt/dbt_server01.hpp index e435b83d..4db62506 100644 --- a/trial/direct_bt/dbt_server01.hpp +++ b/trial/direct_bt/dbt_server01.hpp @@ -430,7 +430,6 @@ class DBTServer01 : public DBTServerTest { clear(); } - 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", @@ -519,11 +518,9 @@ class DBTServer01 : public DBTServerTest { parent.servingProtocolSessionsLeft--; } } - { - jau::POctets value2(value); - std::thread senderThread(&MyGATTServerListener::sendResponse, this, value2); - senderThread.detach(); - } + jau::POctets value2(value); + std::thread senderThread(&MyGATTServerListener::sendResponse, this, value2); + senderThread.detach(); } if( GATT_VERBOSE || isFinalHandshake ) { fprintf_td(stderr, "****** Server GATT::writeCharValueDone(match %d, finalCmd %d, sessions [%d ok / %d total], left %d): From %s, to\n %s\n %s\n Char-Value: %s\n", @@ -690,7 +687,7 @@ class DBTServer01 : public DBTServerTest { private: void processDisconnectedDevice(BTDeviceRef device) { - fprintf_td(stderr, "****** Server Disconnected Device (count %zu, seved %zu, left %zu): Start %s\n", + fprintf_td(stderr, "****** Server Disconnected Device (count %zu, served %zu, left %zu): Start %s\n", 1+disconnectCount.load(), servedProtocolSessionsTotal.load(), servingProtocolSessionsLeft.load(), device->toString().c_str()); // already unpaired diff --git a/trial/direct_bt/test_client_server00.cpp b/trial/direct_bt/test_client_server00.cpp index 43e8eb1c..f545191d 100644 --- a/trial/direct_bt/test_client_server00.cpp +++ b/trial/direct_bt/test_client_server00.cpp @@ -34,7 +34,7 @@ #include "dbt_base_client_server.hpp" -#include "dbt_server00.hpp" +#include "dbt_server01.hpp" using namespace direct_bt; @@ -96,7 +96,8 @@ TEST_CASE( "Server StartStop and SwitchRole Trial 00.2", "[trial][startstop][swi REQUIRE( manager->getAdapterCount() >= 1 ); 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); + std::shared_ptr<DBTServer01> server = std::make_shared<DBTServer01>(serverName, EUI48::ALL_DEVICE, BTMode::DUAL, + true /* SC */, BTSecurityLevel::NONE, false /* do_disconnect_ */); server->setProtocolSessionsLeft(1); ChangedAdapterSetCallback myChangedAdapterSetFunc = DBTEndpoint::initChangedAdapterSetListener(manager, { server }); diff --git a/trial/direct_bt/test_provoke_client_server_i470.cpp b/trial/direct_bt/test_provoke_client_server_i470.cpp index 0e7ce19a..d2da1908 100644 --- a/trial/direct_bt/test_provoke_client_server_i470.cpp +++ b/trial/direct_bt/test_provoke_client_server_i470.cpp @@ -27,11 +27,10 @@ #include <catch2/catch_amalgamated.hpp> #include <jau/test/catch2_ext.hpp> -// #include "dbt_base_client_server.hpp" #include "dbt_client_server1x.hpp" -#include "dbt_server01.hpp" -#include "dbt_client01.hpp" +// #include "dbt_server01.hpp" +// #include "dbt_client01.hpp" using namespace direct_bt; diff --git a/trial/java/trial/org/direct_bt/DBTClient00.java b/trial/java/trial/org/direct_bt/DBTClient00.java deleted file mode 100644 index 7366eb72..00000000 --- a/trial/java/trial/org/direct_bt/DBTClient00.java +++ /dev/null @@ -1,717 +0,0 @@ -/** - * 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.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.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.BTGattCharListener; -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; -import org.junit.Assert; - -/** - * This central BTRole::Master participant works with DBTServer00. - */ -public class DBTClient00 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 DBTClient00(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.isDeviceProcessing( device.getAddressAndType() ) && - ( !BTDeviceRegistry.isWaitingForAnyDevice() || - ( BTDeviceRegistry.isWaitingForDevice(device.getAddressAndType().address, device.getName()) && - ( 0 < measurementsLeft.get() || !BTDeviceRegistry.isDeviceProcessed(device.getAddressAndType()) ) - ) - ) - ) - { - 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 boolean discovered, final long timestamp) { - BTUtils.println(System.err, "****** Client CONNECTED (discovered "+discovered+"): "+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) { - if( !BTDeviceRegistry.isDeviceProcessing( device.getAddressAndType() ) && - ( !BTDeviceRegistry.isWaitingForAnyDevice() || - ( BTDeviceRegistry.isWaitingForDevice(device.getAddressAndType().address, device.getName()) && - ( 0 < measurementsLeft.get() || !BTDeviceRegistry.isDeviceProcessed(device.getAddressAndType()) ) - ) - ) - ) - { - 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"); - } - BTDeviceRegistry.addToProcessingDevices(device.getAddressAndType(), device.getName()); - - // 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! - } else { - BTUtils.println(System.err, "****** Client 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, "****** 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 extends BTGattCharListener { - @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, "** Characteristic-Notify: UUID %s, td %d ******\n", - charDecl.getUUID(), (tR-timestamp)); - BTUtils.fprintf_td(System.err, "** Characteristic: %s ******\n", charDecl.toString()); - BTUtils.fprintf_td(System.err, "** Value R: size %d, ro: %s ******\n", value.length, BTUtils.bytesHexString(value, 0, -1, true)); - BTUtils.fprintf_td(System.err, "** Value S: %s ******\n", 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, "** Characteristic-Indication: UUID %s, td %d, confirmed %b ******\n", - charDecl.getUUID(), (tR-timestamp), confirmationSent); - BTUtils.fprintf_td(System.err, "** Characteristic: %s ******\n", charDecl.toString()); - BTUtils.fprintf_td(System.err, "** Value R: size %d, ro: %s ******\n", value.length, BTUtils.bytesHexString(value, 0, -1, true)); - BTUtils.fprintf_td(System.err, "** Value S: %s ******\n", 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(); - } - - boolean gattListenerError = false; - final List<BTGattCharListener> gattListener = new ArrayList<BTGattCharListener>(); - int loop = 0; - do { - 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()); - } - } - if( 0 == loop ) { - final boolean cccdEnableResult[] = { false, false }; - if( serviceChar.enableNotificationOrIndication( cccdEnableResult ) ) { - // ClientCharConfigDescriptor (CCD) is available - final MyGATTEventListener gattEventListener = new MyGATTEventListener(); - final boolean clAdded = serviceChar.addCharListener( gattEventListener ); - if( clAdded ) { - gattListener.add(gattEventListener); - } else { - gattListenerError = true; - BTUtils.fprintf_td(System.err, "Client Error: Failed to add GattListener: %s @ %s, gattListener %d\n", - gattEventListener.toString(), serviceChar.toString(), gattListener.size()); - } - 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"); - } - } - success = notificationsReceived.get() >= 2 || indicationsReceived.get() >= 2; - ++loop; - } catch( final Exception ex) { - BTUtils.println(System.err, "****** Client Processing Ready Device: Exception.2 caught for " + device.toString() + ": "+ex.getMessage()); - ex.printStackTrace(); - } - } while( !success && device.getConnected() && !gattListenerError ); - - if( gattListenerError ) { - success = false; - } - { - int i = 0; - for(final BTGattCharListener gcl : gattListener) { - if( !device.removeCharListener(gcl) ) { - BTUtils.fprintf_td(System.err, "Client Error: Failed to remove GattListener[%d/%d]: %s @ %s\n", - i, gattListener.size(), gcl.toString(), device.toString()); - success = false; - } - ++i; - } - } - - if( device.getConnected() ) { - // 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()); - - BTDeviceRegistry.removeFromProcessingDevices( device.getAddressAndType() ); - - 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()); - if( success ) { - BTDeviceRegistry.addToProcessedDevices(device.getAddressAndType(), device.getName()); - } - 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()); - - BTDeviceRegistry.removeFromProcessingDevices(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/DBTClient01.java b/trial/java/trial/org/direct_bt/DBTClient01.java index 22d905e3..4f239afd 100644 --- a/trial/java/trial/org/direct_bt/DBTClient01.java +++ b/trial/java/trial/org/direct_bt/DBTClient01.java @@ -70,6 +70,8 @@ public class DBTClient01 implements DBTClientTest { 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; @@ -86,6 +88,7 @@ public class DBTClient01 implements DBTClientTest { 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); @@ -342,6 +345,7 @@ public class DBTClient01 implements DBTClientTest { } private void resetLastProcessingStats() { + completedGATTCommands.set(0); notificationsReceived.set(0); indicationsReceived.set(0); } @@ -447,6 +451,27 @@ public class DBTClient01 implements DBTClientTest { "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(); + } + boolean gattListenerError = false; final List<BTGattCharListener> gattListener = new ArrayList<BTGattCharListener>(); int loop = 0; @@ -517,6 +542,8 @@ public class DBTClient01 implements DBTClientTest { } } while( !success && device.getConnected() && !gattListenerError ); + success = success && completedGATTCommands.get() >= 1; + if( gattListenerError ) { success = false; } @@ -589,6 +616,7 @@ public class DBTClient01 implements DBTClientTest { "; Measurements completed "+completedMeasurementsSuccess.get()+ ", left "+measurementsLeft.get()+ "; Received notitifications "+notificationsReceived.get()+", indications "+indicationsReceived.get()+ + "; Completed GATT commands "+completedGATTCommands.get()+ ": "+device.getAddressAndType()); } diff --git a/trial/java/trial/org/direct_bt/DBTClientServer1x.java b/trial/java/trial/org/direct_bt/DBTClientServer1x.java index 823aed8d..0a15b68f 100644 --- a/trial/java/trial/org/direct_bt/DBTClientServer1x.java +++ b/trial/java/trial/org/direct_bt/DBTClientServer1x.java @@ -72,8 +72,8 @@ public abstract class DBTClientServer1x extends BaseDBTClientServer { 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); + final DBTServer01 server = new DBTServer01("S-"+suffix, EUI48.ALL_DEVICE, BTMode.DUAL, serverSC, secLevelServer, false /* do_disconnect */); + final DBTClient01 client = new DBTClient01("C-"+suffix, EUI48.ALL_DEVICE, BTMode.DUAL, false /* do_disconnect */); test8x_fullCycle(timeout_value, suffix, protocolSessionCount, DBTConstants.max_connections_per_session, true /* expSuccess */, server_client_order, diff --git a/trial/java/trial/org/direct_bt/DBTServer00.java b/trial/java/trial/org/direct_bt/DBTServer00.java deleted file mode 100644 index 5d5ec583..00000000 --- a/trial/java/trial/org/direct_bt/DBTServer00.java +++ /dev/null @@ -1,814 +0,0 @@ -/** - * 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; - -/** - * This peripheral BTRole::Slave test participant works with DBTClient00. - */ -public class DBTServer00 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 DBTServer00(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 DBTServer00(final String adapterName, final EUI48 useAdapter, final BTSecurityLevel adapterSecurityLevel) { - this(adapterName, useAdapter, BTMode.DUAL, true /* SC */, adapterSecurityLevel); - } - public DBTServer00(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 boolean discovered, final long timestamp) { - BTUtils.println(System.err, "****** Server CONNECTED (served "+disconnectCount.get()+", left "+servingProtocolSessionsLeft.get()+"): discovered "+discovered+": "+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); - } - } - } - } - - 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()); - } - - @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 void close(final String msg) { - BTUtils.println(System.err, "****** Server Close.0: "+msg); - serverAdapter.removeStatusListener( myAdapterStatusListener ); - { - stopAdvertising(msg); - final BTDevice connectedDevice_ = getDevice(); - if( null != connectedDevice_ ) { - setDevice(null); - connectedDevice_.disconnect(); - } - } - gattServerListener.close(); - // dbGattServer.close(); // keep alive - stopAdvertising(msg); // try once more in case of already started AdapterStatusListener - 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/TestDBTClientServer00.java b/trial/java/trial/org/direct_bt/TestDBTClientServer00.java index 22c116ed..4d369082 100644 --- a/trial/java/trial/org/direct_bt/TestDBTClientServer00.java +++ b/trial/java/trial/org/direct_bt/TestDBTClientServer00.java @@ -107,7 +107,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); + final DBTServer01 server = new DBTServer01(serverName, EUI48.ALL_DEVICE, BTMode.DUAL, true /* SC */, BTSecurityLevel.NONE, false /* do_disconnect */); server.setProtocolSessionsLeft(1); final DBTEndpoint.ChangedAdapterSetListener myChangedAdapterSetListener = |