mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #5313 from pan-/ble-cordio-pal-gap
Cordio: Pal Gap implementationpull/5744/merge
commit
dc87f0b1e6
|
@ -282,7 +282,6 @@ private:
|
|||
pal::Gap &_pal_gap;
|
||||
pal::GenericAccessService &_gap_service;
|
||||
BLEProtocol::AddressType_t _address_type;
|
||||
pal::address_t _address;
|
||||
pal::initiator_policy_t _initiator_policy_mode;
|
||||
pal::scanning_filter_policy_t _scanning_filter_policy;
|
||||
pal::advertising_filter_policy_t _advertising_filter_policy;
|
||||
|
|
|
@ -376,7 +376,6 @@ GenericGap::GenericGap(
|
|||
_pal_gap(pal_gap),
|
||||
_gap_service(generic_access_service),
|
||||
_address_type(BLEProtocol::AddressType::PUBLIC),
|
||||
_address(),
|
||||
_initiator_policy_mode(pal::initiator_policy_t::NO_FILTER),
|
||||
_scanning_filter_policy(pal::scanning_filter_policy_t::NO_FILTER),
|
||||
_advertising_filter_policy(pal::advertising_filter_policy_t::NO_FILTER),
|
||||
|
@ -416,7 +415,6 @@ ble_error_t GenericGap::setAddress(
|
|||
}
|
||||
|
||||
_address_type = type;
|
||||
_address = pal::address_t(address, true);
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
|
@ -439,7 +437,14 @@ ble_error_t GenericGap::getAddress(
|
|||
BLEProtocol::AddressBytes_t address
|
||||
) {
|
||||
*type = _address_type;
|
||||
memcpy(address, _address.data(), _address.size());
|
||||
pal::address_t address_value;
|
||||
if (_address_type == BLEProtocol::AddressType::PUBLIC) {
|
||||
address_value = _pal_gap.get_device_address();
|
||||
} else {
|
||||
address_value = _pal_gap.get_random_address();
|
||||
}
|
||||
|
||||
memcpy(address, address_value.data(), address_value.size());
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
|
@ -990,6 +995,12 @@ void GenericGap::on_connection_complete(const pal::GapConnectionCompleteEvent& e
|
|||
e.connection_latency,
|
||||
e.supervision_timeout
|
||||
};
|
||||
pal::address_t address;
|
||||
if (_address_type == BLEProtocol::AddressType::PUBLIC) {
|
||||
address = _pal_gap.get_device_address();
|
||||
} else {
|
||||
address = _pal_gap.get_random_address();
|
||||
}
|
||||
|
||||
processConnectionEvent(
|
||||
e.connection_handle,
|
||||
|
@ -997,7 +1008,7 @@ void GenericGap::on_connection_complete(const pal::GapConnectionCompleteEvent& e
|
|||
(BLEProtocol::AddressType_t) e.peer_address_type.value(),
|
||||
e.peer_address.data(),
|
||||
_address_type,
|
||||
_address.data(),
|
||||
address.data(),
|
||||
&connection_params
|
||||
);
|
||||
} else {
|
||||
|
|
|
@ -22,12 +22,15 @@
|
|||
#include "ble/BLEInstanceBase.h"
|
||||
|
||||
#include "CordioHCIDriver.h"
|
||||
#include "CordioGap.h"
|
||||
#include "CordioGattServer.h"
|
||||
#include "CordioSecurityManager.h"
|
||||
#include "CordioPalAttClient.h"
|
||||
#include "ble/pal/AttClientToGattClientAdapter.h"
|
||||
#include "ble/generic/GenericGattClient.h"
|
||||
#include "CordioPalGap.h"
|
||||
#include "CordioPalGenericAccessService.h"
|
||||
#include "ble/generic/GenericGap.h"
|
||||
#include "ble/pal/SimpleEventQueue.h"
|
||||
|
||||
namespace ble {
|
||||
namespace vendor {
|
||||
|
@ -81,12 +84,12 @@ public:
|
|||
/**
|
||||
* @see BLEInstanceBase::getGap
|
||||
*/
|
||||
virtual Gap& getGap();
|
||||
virtual ::Gap& getGap();
|
||||
|
||||
/**
|
||||
* @see BLEInstanceBase::getGap
|
||||
*/
|
||||
virtual const Gap& getGap() const;
|
||||
virtual const ::Gap& getGap() const;
|
||||
|
||||
/**
|
||||
* @see BLEInstanceBase::getGattServer
|
||||
|
@ -143,6 +146,7 @@ private:
|
|||
} initialization_status;
|
||||
|
||||
::BLE::InstanceID_t instanceID;
|
||||
mutable pal::SimpleEventQueue _event_queue;
|
||||
};
|
||||
|
||||
} // namespace cordio
|
||||
|
|
|
@ -1,262 +0,0 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2017-2017 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef CORDIO_GAP_H_
|
||||
#define CORDIO_GAP_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "ble/blecommon.h"
|
||||
#include "ble/GapAdvertisingParams.h"
|
||||
#include "ble/GapAdvertisingData.h"
|
||||
#include "ble/Gap.h"
|
||||
#include "ble/GapScanningParams.h"
|
||||
#include "dm_api.h"
|
||||
#include "att_api.h"
|
||||
|
||||
namespace ble {
|
||||
namespace vendor {
|
||||
namespace cordio {
|
||||
|
||||
/**
|
||||
* @see ::Gap
|
||||
*/
|
||||
class Gap : public ::Gap
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Return the Gap singleton implementing ::Gap for the Cordio stac.
|
||||
*/
|
||||
static Gap &getInstance();
|
||||
|
||||
/**
|
||||
* This function shall be called once the stack has been initialized
|
||||
*/
|
||||
void initialize();
|
||||
|
||||
/**
|
||||
* @see ::Gap::setAddress
|
||||
*/
|
||||
virtual ble_error_t setAddress(AddressType_t type, const Address_t address);
|
||||
|
||||
/**
|
||||
* @see ::Gap::getAddress
|
||||
*/
|
||||
virtual ble_error_t getAddress(AddressType_t *typeP, Address_t address);
|
||||
|
||||
/**
|
||||
* @see ::Gap::setAdvertisingData
|
||||
*/
|
||||
virtual ble_error_t setAdvertisingData(
|
||||
const GapAdvertisingData&, const GapAdvertisingData&
|
||||
);
|
||||
|
||||
/**
|
||||
* @see ::Gap::connect
|
||||
*/
|
||||
virtual ble_error_t connect(
|
||||
const BLEProtocol::AddressBytes_t peerAddr,
|
||||
BLEProtocol::AddressType_t peerAddrType,
|
||||
const ConnectionParams_t* connectionParams,
|
||||
const GapScanningParams* scanParams
|
||||
);
|
||||
|
||||
/**
|
||||
* @see ::Gap::getMinAdvertisingInterval
|
||||
*/
|
||||
virtual uint16_t getMinAdvertisingInterval() const;
|
||||
|
||||
/**
|
||||
* @see ::Gap::getMinNonConnectableAdvertisingInterval
|
||||
*/
|
||||
virtual uint16_t getMinNonConnectableAdvertisingInterval() const;
|
||||
|
||||
/**
|
||||
* @see ::Gap::getMaxAdvertisingInterval
|
||||
*/
|
||||
virtual uint16_t getMaxAdvertisingInterval() const;
|
||||
|
||||
/**
|
||||
* @see ::Gap::startAdvertising
|
||||
*/
|
||||
virtual ble_error_t startAdvertising(const GapAdvertisingParams &);
|
||||
|
||||
/**
|
||||
* @see ::Gap::stopAdvertising
|
||||
*/
|
||||
virtual ble_error_t stopAdvertising();
|
||||
|
||||
/**
|
||||
* @see ::Gap::disconnect
|
||||
*/
|
||||
virtual ble_error_t disconnect(
|
||||
Handle_t connectionHandle,
|
||||
DisconnectionReason_t reason
|
||||
);
|
||||
|
||||
/**
|
||||
* @see ::Gap::disconnect
|
||||
*/
|
||||
virtual ble_error_t disconnect(DisconnectionReason_t reason);
|
||||
|
||||
/**
|
||||
* @see ::Gap::setDeviceName
|
||||
*/
|
||||
virtual ble_error_t setDeviceName(const uint8_t *deviceName);
|
||||
|
||||
/**
|
||||
* @see ::Gap::getDeviceName
|
||||
*/
|
||||
virtual ble_error_t getDeviceName(uint8_t *deviceName, unsigned *lengthP);
|
||||
|
||||
/**
|
||||
* @see ::Gap::setAppearance
|
||||
*/
|
||||
virtual ble_error_t setAppearance(GapAdvertisingData::Appearance appearance);
|
||||
|
||||
/**
|
||||
* @see ::Gap::getAppearance
|
||||
*/
|
||||
virtual ble_error_t getAppearance(GapAdvertisingData::Appearance *appearanceP);
|
||||
|
||||
/**
|
||||
* @see ::Gap::setTxPower
|
||||
*/
|
||||
virtual ble_error_t setTxPower(int8_t txPower);
|
||||
|
||||
/**
|
||||
* @see ::Gap::getPermittedTxPowerValues
|
||||
*/
|
||||
virtual void getPermittedTxPowerValues(
|
||||
const int8_t **valueArrayPP, size_t *countP
|
||||
);
|
||||
|
||||
/**
|
||||
* Set the internal connection handle
|
||||
*/
|
||||
void setConnectionHandle(uint16_t m_connectionHandle);
|
||||
|
||||
/**
|
||||
* Get the current connection handle
|
||||
*/
|
||||
uint16_t getConnectionHandle();
|
||||
|
||||
/**
|
||||
* @see ::Gap::getPreferredConnectionParams
|
||||
*/
|
||||
virtual ble_error_t getPreferredConnectionParams(ConnectionParams_t *params);
|
||||
|
||||
/**
|
||||
* @see ::Gap::setPreferredConnectionParams
|
||||
*/
|
||||
virtual ble_error_t setPreferredConnectionParams(
|
||||
const ConnectionParams_t *params
|
||||
);
|
||||
|
||||
/**
|
||||
* @see ::Gap::updateConnectionParams
|
||||
*/
|
||||
virtual ble_error_t updateConnectionParams(
|
||||
Handle_t handle, const ConnectionParams_t *params
|
||||
);
|
||||
|
||||
/**
|
||||
* @see ::Gap::startRadioScan
|
||||
*/
|
||||
virtual ble_error_t startRadioScan(const GapScanningParams &scanningParams);
|
||||
|
||||
/**
|
||||
* @see ::Gap::stopScan
|
||||
*/
|
||||
virtual ble_error_t stopScan();
|
||||
|
||||
/**
|
||||
* Called when advertising is stopped.
|
||||
*/
|
||||
void advertisingStopped();
|
||||
|
||||
// Whitelist management
|
||||
|
||||
/**
|
||||
* @see ::Gap::getMaxWhitelistSize
|
||||
*/
|
||||
virtual uint8_t getMaxWhitelistSize(void) const;
|
||||
|
||||
/**
|
||||
* @see ::Gap::getWhitelist
|
||||
*/
|
||||
virtual ble_error_t getWhitelist(Whitelist_t &whitelist) const;
|
||||
|
||||
/**
|
||||
* @see ::Gap::setWhitelist
|
||||
*/
|
||||
virtual ble_error_t setWhitelist(const Whitelist_t &whitelist);
|
||||
|
||||
/**
|
||||
* @see ::Gap::setAdvertisingPolicyMode
|
||||
*/
|
||||
virtual ble_error_t setAdvertisingPolicyMode(AdvertisingPolicyMode_t mode);
|
||||
|
||||
/**
|
||||
* @see ::Gap::getAdvertisingPolicyMode
|
||||
*/
|
||||
virtual AdvertisingPolicyMode_t getAdvertisingPolicyMode(void) const;
|
||||
|
||||
/**
|
||||
* @see ::Gap::setScanningPolicyMode
|
||||
*/
|
||||
virtual ble_error_t setScanningPolicyMode(ScanningPolicyMode_t mode);
|
||||
|
||||
/**
|
||||
* @see ::Gap::getScanningPolicyMode
|
||||
*/
|
||||
virtual ScanningPolicyMode_t getScanningPolicyMode(void) const;
|
||||
|
||||
/**
|
||||
* @see ::Gap::setInitiatorPolicyMode
|
||||
*/
|
||||
virtual ble_error_t setInitiatorPolicyMode(InitiatorPolicyMode_t mode);
|
||||
|
||||
/**
|
||||
* @see ::Gap::getInitiatorPolicyMode
|
||||
*/
|
||||
virtual InitiatorPolicyMode_t getInitiatorPolicyMode(void) const;
|
||||
|
||||
/**
|
||||
* @see ::Gap::reset
|
||||
*/
|
||||
virtual ble_error_t reset(void);
|
||||
|
||||
private:
|
||||
Gap();
|
||||
|
||||
Gap(Gap const &);
|
||||
void operator=(Gap const &);
|
||||
|
||||
uint16_t m_connectionHandle;
|
||||
addr_type_t m_type;
|
||||
Address_t m_addr;
|
||||
|
||||
AdvertisingPolicyMode_t advertising_policy_mode;
|
||||
ScanningPolicyMode_t scanning_policy_mode;
|
||||
InitiatorPolicyMode_t initiator_policy_mode;
|
||||
Whitelist_t whitelist;
|
||||
};
|
||||
|
||||
} // namespace cordio
|
||||
} // namespace vendor
|
||||
} // namespace ble
|
||||
|
||||
#endif /* CORDIO_GAP_H_ */
|
|
@ -0,0 +1,477 @@
|
|||
#ifndef CORDIO_PAL_GAP_
|
||||
#define CORDIO_PAL_GAP_
|
||||
|
||||
#include "ble/pal/PalGap.h"
|
||||
#include "dm_api.h"
|
||||
|
||||
namespace ble {
|
||||
namespace pal {
|
||||
namespace vendor {
|
||||
namespace cordio {
|
||||
|
||||
/**
|
||||
* Implementation of ble::pal::Gap for the Cordio stack.
|
||||
*/
|
||||
class Gap : public ::ble::pal::Gap {
|
||||
|
||||
public:
|
||||
virtual ble_error_t initialize() {
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
virtual ble_error_t terminate() {
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
virtual address_t get_device_address() {
|
||||
return address_t(HciGetBdAddr(), true);
|
||||
}
|
||||
|
||||
virtual address_t get_random_address() {
|
||||
return device_random_address;
|
||||
}
|
||||
|
||||
virtual ble_error_t set_random_address(const address_t& address) {
|
||||
device_random_address = address;
|
||||
DmDevSetRandAddr(const_cast<uint8_t*>(address.data()));
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
virtual ble_error_t set_advertising_parameters(
|
||||
uint16_t advertising_interval_min,
|
||||
uint16_t advertising_interval_max,
|
||||
advertising_type_t advertising_type,
|
||||
own_address_type_t own_address_type,
|
||||
advertising_peer_address_type_t peer_address_type,
|
||||
const address_t& peer_address,
|
||||
advertising_channel_map_t advertising_channel_map,
|
||||
advertising_filter_policy_t advertising_filter_policy
|
||||
) {
|
||||
DmAdvSetInterval(
|
||||
DM_ADV_HANDLE_DEFAULT,
|
||||
advertising_interval_min,
|
||||
advertising_interval_max
|
||||
);
|
||||
|
||||
DmAdvSetAddrType(own_address_type.value());
|
||||
|
||||
DmAdvSetChannelMap(
|
||||
DM_ADV_HANDLE_DEFAULT,
|
||||
advertising_channel_map.value()
|
||||
);
|
||||
|
||||
DmDevSetFilterPolicy(
|
||||
DM_FILT_POLICY_MODE_ADV,
|
||||
advertising_filter_policy.value()
|
||||
);
|
||||
|
||||
DmAdvConfig(
|
||||
DM_ADV_HANDLE_DEFAULT,
|
||||
advertising_type.value(),
|
||||
peer_address_type.value(),
|
||||
const_cast<uint8_t*>(peer_address.data())
|
||||
);
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
virtual ble_error_t set_advertising_data(
|
||||
uint8_t advertising_data_length,
|
||||
const advertising_data_t& advertising_data
|
||||
) {
|
||||
DmAdvSetData(
|
||||
DM_ADV_HANDLE_DEFAULT,
|
||||
HCI_ADV_DATA_OP_COMP_FRAG,
|
||||
DM_DATA_LOC_ADV,
|
||||
advertising_data_length,
|
||||
const_cast<uint8_t*>(advertising_data.data())
|
||||
);
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
virtual ble_error_t set_scan_response_data(
|
||||
uint8_t scan_response_data_length,
|
||||
const advertising_data_t& scan_response_data
|
||||
) {
|
||||
DmAdvSetData(
|
||||
DM_ADV_HANDLE_DEFAULT,
|
||||
HCI_ADV_DATA_OP_COMP_FRAG,
|
||||
DM_DATA_LOC_SCAN,
|
||||
scan_response_data_length,
|
||||
const_cast<uint8_t*>(scan_response_data.data())
|
||||
);
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
virtual ble_error_t advertising_enable(bool enable) {
|
||||
if (enable) {
|
||||
uint8_t adv_handles[] = { DM_ADV_HANDLE_DEFAULT };
|
||||
uint16_t adv_durations[] = { /* infinite */ 0 };
|
||||
uint8_t max_ea_events[] = { 0 };
|
||||
DmAdvStart(1, adv_handles, adv_durations, max_ea_events);
|
||||
} else {
|
||||
uint8_t adv_handles[] = { DM_ADV_HANDLE_DEFAULT };
|
||||
DmAdvStop(1, adv_handles);
|
||||
}
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
virtual ble_error_t set_scan_parameters(
|
||||
bool active_scanning,
|
||||
uint16_t scan_interval,
|
||||
uint16_t scan_window,
|
||||
own_address_type_t own_address_type,
|
||||
scanning_filter_policy_t filter_policy
|
||||
) {
|
||||
use_active_scanning = active_scanning;
|
||||
DmScanSetInterval(HCI_INIT_PHY_LE_1M_BIT, &scan_interval, &scan_window);
|
||||
DmScanSetAddrType(own_address_type.value());
|
||||
DmDevSetFilterPolicy(
|
||||
DM_FILT_POLICY_MODE_SCAN,
|
||||
filter_policy.value()
|
||||
);
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
virtual ble_error_t scan_enable(
|
||||
bool enable,
|
||||
bool filter_duplicates
|
||||
) {
|
||||
if (enable) {
|
||||
uint8_t scanType = use_active_scanning ? DM_SCAN_TYPE_ACTIVE : DM_SCAN_TYPE_PASSIVE;
|
||||
DmScanStart(
|
||||
HCI_SCAN_PHY_LE_1M_BIT,
|
||||
DM_DISC_MODE_NONE,
|
||||
&scanType,
|
||||
filter_duplicates,
|
||||
0,
|
||||
0
|
||||
);
|
||||
} else {
|
||||
DmScanStop();
|
||||
}
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
virtual ble_error_t create_connection(
|
||||
uint16_t scan_interval,
|
||||
uint16_t scan_window,
|
||||
initiator_policy_t initiator_policy,
|
||||
connection_peer_address_type_t peer_address_type,
|
||||
const address_t& peer_address,
|
||||
own_address_type_t own_address_type,
|
||||
uint16_t connection_interval_min,
|
||||
uint16_t connection_interval_max,
|
||||
uint16_t connection_latency,
|
||||
uint16_t supervision_timeout,
|
||||
uint16_t minimum_connection_event_length,
|
||||
uint16_t maximum_connection_event_length
|
||||
) {
|
||||
DmConnSetScanInterval(scan_interval, scan_window);
|
||||
DmDevSetFilterPolicy(DM_FILT_POLICY_MODE_INIT, initiator_policy.value());
|
||||
DmConnSetAddrType(own_address_type.value());
|
||||
|
||||
hciConnSpec_t conn_spec = {
|
||||
connection_interval_min,
|
||||
connection_interval_max,
|
||||
connection_latency,
|
||||
supervision_timeout,
|
||||
minimum_connection_event_length,
|
||||
maximum_connection_event_length
|
||||
};
|
||||
DmConnSetConnSpec(&conn_spec);
|
||||
|
||||
dmConnId_t connection_id = DmConnOpen(
|
||||
DM_CLIENT_ID_APP,
|
||||
HCI_INIT_PHY_LE_1M_BIT,
|
||||
peer_address_type.value(),
|
||||
const_cast<uint8_t*>(peer_address.data())
|
||||
);
|
||||
|
||||
if (connection_id == DM_CONN_ID_NONE) {
|
||||
return BLE_ERROR_INTERNAL_STACK_FAILURE;
|
||||
}
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
virtual ble_error_t cancel_connection_creation() {
|
||||
DmConnClose(
|
||||
DM_CLIENT_ID_APP,
|
||||
/* connection handle - invalid */ DM_CONN_ID_NONE,
|
||||
/* reason - invalid (use success) */ 0x00
|
||||
);
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
virtual uint8_t read_white_list_capacity() {
|
||||
return HciGetWhiteListSize();
|
||||
}
|
||||
|
||||
virtual ble_error_t clear_whitelist() {
|
||||
DmDevWhiteListClear();
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
virtual ble_error_t add_device_to_whitelist(
|
||||
whitelist_address_type_t address_type,
|
||||
address_t address
|
||||
) {
|
||||
DmDevWhiteListAdd(
|
||||
address_type.value(),
|
||||
const_cast<uint8_t*>(address.data())
|
||||
);
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
virtual ble_error_t remove_device_from_whitelist(
|
||||
whitelist_address_type_t address_type,
|
||||
address_t address
|
||||
) {
|
||||
DmDevWhiteListRemove(
|
||||
address_type.value(),
|
||||
const_cast<uint8_t*>(address.data())
|
||||
);
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
virtual ble_error_t connection_parameters_update(
|
||||
connection_handle_t connection,
|
||||
uint16_t connection_interval_min,
|
||||
uint16_t connection_interval_max,
|
||||
uint16_t connection_latency,
|
||||
uint16_t supervision_timeout,
|
||||
uint16_t minimum_connection_event_length,
|
||||
uint16_t maximum_connection_event_length
|
||||
) {
|
||||
if (DmConnCheckIdle(connection) != 0) {
|
||||
return BLE_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
hciConnSpec_t connection_spec = {
|
||||
connection_interval_min,
|
||||
connection_interval_max,
|
||||
connection_latency,
|
||||
supervision_timeout,
|
||||
minimum_connection_event_length,
|
||||
maximum_connection_event_length
|
||||
};
|
||||
DmConnUpdate(
|
||||
connection,
|
||||
&connection_spec
|
||||
);
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
virtual ble_error_t accept_connection_parameter_request(
|
||||
connection_handle_t connection_handle,
|
||||
uint16_t interval_min,
|
||||
uint16_t interval_max,
|
||||
uint16_t latency,
|
||||
uint16_t supervision_timeout,
|
||||
uint16_t minimum_connection_event_length,
|
||||
uint16_t maximum_connection_event_length
|
||||
) {
|
||||
hciConnSpec_t connection_spec = {
|
||||
interval_min,
|
||||
interval_max,
|
||||
latency,
|
||||
supervision_timeout,
|
||||
minimum_connection_event_length,
|
||||
maximum_connection_event_length
|
||||
};
|
||||
DmRemoteConnParamReqReply(connection_handle, &connection_spec);
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
virtual ble_error_t reject_connection_parameter_request(
|
||||
connection_handle_t connection_handle,
|
||||
hci_error_code_t rejection_reason
|
||||
) {
|
||||
DmRemoteConnParamReqNegReply(
|
||||
connection_handle,
|
||||
rejection_reason.value()
|
||||
);
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
virtual ble_error_t disconnect(
|
||||
connection_handle_t connection,
|
||||
disconnection_reason_t disconnection_reason
|
||||
) {
|
||||
DmConnClose(
|
||||
DM_CLIENT_ID_APP,
|
||||
connection,
|
||||
disconnection_reason.value()
|
||||
);
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
// singleton of the ARM Cordio client
|
||||
static Gap& get_gap() {
|
||||
static Gap _gap;
|
||||
return _gap;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef bool (*event_handler_t)(const wsfMsgHdr_t* msg);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Callback which handle wsfMsgHdr_t and forward them to emit_gap_event.
|
||||
*/
|
||||
static void gap_handler(const wsfMsgHdr_t* msg) {
|
||||
if (msg == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// all handlers are stored in a static array
|
||||
static const event_handler_t handlers[] = {
|
||||
&event_handler<ConnectionCompleteMessageConverter>,
|
||||
&event_handler<GapAdvertisingReportMessageConverter>,
|
||||
&event_handler<DisconnectionMessageConverter>,
|
||||
&event_handler<ConnectionUpdateMessageConverter>,
|
||||
&event_handler<RemoteConnectionParameterRequestMessageConverter>
|
||||
};
|
||||
|
||||
// event->hdr.param: connection handle
|
||||
|
||||
// traverse all handlers and execute them with the event in input.
|
||||
// exit if an handler has handled the event.
|
||||
for(size_t i = 0; i < (sizeof(handlers)/sizeof(handlers[0])); ++i) {
|
||||
if (handlers[i](msg)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* T shall define a can_convert and convert function and a type
|
||||
*/
|
||||
template<typename T>
|
||||
static bool event_handler(const wsfMsgHdr_t* msg) {
|
||||
if (T::can_convert(msg)) {
|
||||
get_gap().emit_gap_event(T::convert((const typename T::type*)msg));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Traits defining can_convert for events.
|
||||
*/
|
||||
template<uint8_t EventID>
|
||||
struct MessageConverter {
|
||||
static bool can_convert(const wsfMsgHdr_t* msg) {
|
||||
if (msg->event == EventID) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct ConnectionCompleteMessageConverter : public MessageConverter<DM_CONN_OPEN_IND> {
|
||||
typedef hciLeConnCmplEvt_t type;
|
||||
|
||||
static GapConnectionCompleteEvent convert(const hciLeConnCmplEvt_t* conn_evt) {
|
||||
return GapConnectionCompleteEvent(
|
||||
conn_evt->status,
|
||||
// note the usage of the stack handle, not the HCI handle
|
||||
conn_evt->hdr.param,
|
||||
(connection_role_t::type) conn_evt->role,
|
||||
(advertising_peer_address_type_t::type) conn_evt->addrType,
|
||||
conn_evt->peerAddr,
|
||||
conn_evt->connInterval,
|
||||
conn_evt->connLatency,
|
||||
conn_evt->supTimeout
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct GapAdvertisingReportMessageConverter : public MessageConverter<DM_SCAN_REPORT_IND> {
|
||||
typedef hciLeAdvReportEvt_t type;
|
||||
|
||||
struct CordioGapAdvertisingReportEvent : public GapAdvertisingReportEvent {
|
||||
CordioGapAdvertisingReportEvent(const advertising_t& advertising) :
|
||||
GapAdvertisingReportEvent(), advertising(advertising) {
|
||||
}
|
||||
|
||||
virtual ~CordioGapAdvertisingReportEvent() { }
|
||||
|
||||
virtual uint8_t size() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
virtual advertising_t operator[](uint8_t i) const {
|
||||
return advertising;
|
||||
}
|
||||
|
||||
advertising_t advertising;
|
||||
};
|
||||
|
||||
static CordioGapAdvertisingReportEvent convert(const hciLeAdvReportEvt_t *scan_report) {
|
||||
GapAdvertisingReportEvent::advertising_t advertising = {
|
||||
(received_advertising_type_t::type) scan_report->eventType,
|
||||
(connection_peer_address_type_t::type) scan_report->addrType,
|
||||
scan_report->addr,
|
||||
make_const_ArrayView(scan_report->pData, scan_report->len),
|
||||
scan_report->rssi
|
||||
};
|
||||
return CordioGapAdvertisingReportEvent(advertising);
|
||||
}
|
||||
};
|
||||
|
||||
struct DisconnectionMessageConverter : public MessageConverter<DM_CONN_CLOSE_IND> {
|
||||
typedef hciDisconnectCmplEvt_t type;
|
||||
|
||||
static GapDisconnectionCompleteEvent convert(const hciDisconnectCmplEvt_t* disc_evt) {
|
||||
return GapDisconnectionCompleteEvent(
|
||||
disc_evt->status,
|
||||
// note the usage of the stack handle, not the HCI handle
|
||||
disc_evt->hdr.param,
|
||||
disc_evt->reason
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct ConnectionUpdateMessageConverter : public MessageConverter<DM_CONN_UPDATE_IND> {
|
||||
typedef hciLeConnUpdateCmplEvt_t type;
|
||||
|
||||
static GapConnectionUpdateEvent convert(const hciLeConnUpdateCmplEvt_t* evt) {
|
||||
return GapConnectionUpdateEvent(
|
||||
evt->status,
|
||||
evt->hdr.param,
|
||||
evt->connInterval,
|
||||
evt->connLatency,
|
||||
evt->supTimeout
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct RemoteConnectionParameterRequestMessageConverter : public MessageConverter<DM_REM_CONN_PARAM_REQ_IND> {
|
||||
typedef hciLeRemConnParamReqEvt_t type;
|
||||
|
||||
static GapRemoteConnectionParameterRequestEvent convert(const hciLeRemConnParamReqEvt_t* evt) {
|
||||
return GapRemoteConnectionParameterRequestEvent(
|
||||
evt->hdr.param,
|
||||
evt->intervalMin,
|
||||
evt->intervalMax,
|
||||
evt->latency,
|
||||
evt->timeout
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
address_t device_random_address;
|
||||
bool use_active_scanning;
|
||||
};
|
||||
|
||||
} // cordio
|
||||
} // vendor
|
||||
} // pal
|
||||
} // ble
|
||||
|
||||
#endif /* CORDIO_PAL_GAP_ */
|
|
@ -0,0 +1,88 @@
|
|||
#ifndef CORDIO_PAL_GENERIC_ACCESS_SERVICE_
|
||||
#define CORDIO_PAL_GENERIC_ACCESS_SERVICE_
|
||||
|
||||
#include "ble/pal/GenericAccessService.h"
|
||||
#include "CordioGattServer.h"
|
||||
|
||||
|
||||
namespace ble {
|
||||
namespace pal {
|
||||
namespace vendor {
|
||||
namespace cordio {
|
||||
|
||||
/**
|
||||
* Implementation of ble::pal::GenericAccessService for the Cordio stack.
|
||||
*/
|
||||
class GenericAccessService : public ::ble::pal::GenericAccessService {
|
||||
public:
|
||||
GenericAccessService() { }
|
||||
|
||||
virtual ~GenericAccessService() { }
|
||||
|
||||
virtual ble_error_t get_device_name_length(uint8_t& length) {
|
||||
const uint8_t* name = NULL;
|
||||
uint16_t actual_length = 0;
|
||||
|
||||
gatt_server().getDeviceName(name, actual_length);
|
||||
length = actual_length;
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
virtual ble_error_t get_device_name(ArrayView<uint8_t>& array) {
|
||||
const uint8_t* name = NULL;
|
||||
uint16_t length = 0;
|
||||
|
||||
gatt_server().getDeviceName(name, length);
|
||||
|
||||
if (length > array.size()) {
|
||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
memcpy(array.data(), name, length);
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
virtual ble_error_t set_device_name(const uint8_t* device_name) {
|
||||
return gatt_server().setDeviceName(device_name);
|
||||
}
|
||||
|
||||
virtual ble_error_t get_appearance(
|
||||
GapAdvertisingData::Appearance& appearance
|
||||
) {
|
||||
appearance = gatt_server().getAppearance();
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
virtual ble_error_t set_appearance(
|
||||
GapAdvertisingData::Appearance appearance
|
||||
) {
|
||||
gatt_server().setAppearance(appearance);
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
virtual ble_error_t get_peripheral_prefered_connection_parameters(
|
||||
::Gap::ConnectionParams_t& parameters
|
||||
) {
|
||||
parameters = gatt_server().getPreferredConnectionParams();
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
virtual ble_error_t set_peripheral_prefered_connection_parameters(
|
||||
const ::Gap::ConnectionParams_t& parameters
|
||||
) {
|
||||
gatt_server().setPreferredConnectionParams(parameters);
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
private:
|
||||
ble::vendor::cordio::GattServer& gatt_server() {
|
||||
return ble::vendor::cordio::GattServer::getInstance();
|
||||
}
|
||||
};
|
||||
|
||||
} // cordio
|
||||
} // vendor
|
||||
} // pal
|
||||
} // ble
|
||||
|
||||
#endif /* CORDIO_PAL_GENERIC_ACCESS_SERVICE_ */
|
|
@ -39,9 +39,6 @@
|
|||
/*! WSF handler ID */
|
||||
wsfHandlerId_t stack_handler_id;
|
||||
|
||||
/* Store the Event signaling state */
|
||||
bool isEventsSignaled = false;
|
||||
|
||||
/**
|
||||
* Weak definition of ble_cordio_get_hci_driver.
|
||||
* A runtime error is generated if the user does not define any
|
||||
|
@ -78,10 +75,7 @@ extern "C" void hci_mbed_os_handle_reset_sequence(uint8_t* msg)
|
|||
*/
|
||||
extern "C" void wsf_mbed_ble_signal_event(void)
|
||||
{
|
||||
if(isEventsSignaled == false) {
|
||||
isEventsSignaled = true;
|
||||
ble::vendor::cordio::BLE::deviceInstance().signalEventsToProcess(::BLE::DEFAULT_INSTANCE);
|
||||
}
|
||||
ble::vendor::cordio::BLE::deviceInstance().signalEventsToProcess(::BLE::DEFAULT_INSTANCE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -99,7 +93,8 @@ namespace cordio {
|
|||
|
||||
BLE::BLE(CordioHCIDriver& hci_driver) :
|
||||
initialization_status(NOT_INITIALIZED),
|
||||
instanceID(::BLE::DEFAULT_INSTANCE)
|
||||
instanceID(::BLE::DEFAULT_INSTANCE),
|
||||
_event_queue()
|
||||
{
|
||||
_hci_driver = &hci_driver;
|
||||
stack_setup();
|
||||
|
@ -122,9 +117,9 @@ ble_error_t BLE::init(
|
|||
::BLE::InstanceID_t instanceID,
|
||||
FunctionPointerWithContext< ::BLE::InitializationCompleteCallbackContext *> initCallback)
|
||||
{
|
||||
|
||||
switch (initialization_status) {
|
||||
case NOT_INITIALIZED:
|
||||
_event_queue.initialize(this, instanceID);
|
||||
_init_callback = initCallback;
|
||||
start_stack_reset();
|
||||
return BLE_ERROR_NONE;
|
||||
|
@ -157,6 +152,7 @@ ble_error_t BLE::shutdown()
|
|||
getGattServer().reset();
|
||||
getGattClient().reset();
|
||||
getGap().reset();
|
||||
_event_queue.clear();
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
@ -167,15 +163,25 @@ const char* BLE::getVersion()
|
|||
return version;
|
||||
}
|
||||
|
||||
Gap& BLE::getGap()
|
||||
::Gap& BLE::getGap()
|
||||
{
|
||||
return cordio::Gap::getInstance();
|
||||
typedef ::Gap& return_type;
|
||||
const BLE* self = this;
|
||||
return const_cast<return_type>(self->getGap());
|
||||
}
|
||||
|
||||
const Gap& BLE::getGap() const
|
||||
const ::Gap& BLE::getGap() const
|
||||
{
|
||||
return cordio::Gap::getInstance();
|
||||
}
|
||||
static pal::vendor::cordio::Gap& cordio_pal_gap =
|
||||
pal::vendor::cordio::Gap::get_gap();
|
||||
static pal::vendor::cordio::GenericAccessService cordio_gap_service;
|
||||
static ble::generic::GenericGap gap(
|
||||
_event_queue,
|
||||
cordio_pal_gap,
|
||||
cordio_gap_service
|
||||
);
|
||||
return gap;
|
||||
};
|
||||
|
||||
GattServer& BLE::getGattServer()
|
||||
{
|
||||
|
@ -226,11 +232,8 @@ void BLE::waitForEvent()
|
|||
|
||||
void BLE::processEvents()
|
||||
{
|
||||
if (isEventsSignaled) {
|
||||
isEventsSignaled = false;
|
||||
callDispatcher();
|
||||
}
|
||||
}
|
||||
callDispatcher();
|
||||
}
|
||||
|
||||
void BLE::stack_handler(wsfEventMask_t event, wsfMsgHdr_t* msg)
|
||||
{
|
||||
|
@ -245,66 +248,12 @@ void BLE::processEvents()
|
|||
BLE_ERROR_NONE
|
||||
};
|
||||
deviceInstance().getGattServer().initialize();
|
||||
deviceInstance().getGap().initialize();
|
||||
deviceInstance().initialization_status = INITIALIZED;
|
||||
_init_callback.call(&context);
|
||||
} break;
|
||||
|
||||
case DM_ADV_START_IND:
|
||||
break;
|
||||
|
||||
case DM_ADV_STOP_IND:
|
||||
Gap::getInstance().advertisingStopped();
|
||||
break;
|
||||
|
||||
case DM_SCAN_REPORT_IND: {
|
||||
hciLeAdvReportEvt_t *scan_report = (hciLeAdvReportEvt_t*) msg;
|
||||
Gap::getInstance().processAdvertisementReport(
|
||||
scan_report->addr,
|
||||
scan_report->rssi,
|
||||
(scan_report->eventType == DM_RPT_SCAN_RESPONSE) ? true : false,
|
||||
(GapAdvertisingParams::AdvertisingType_t) scan_report->eventType,
|
||||
scan_report->len,
|
||||
scan_report->pData
|
||||
);
|
||||
} break;
|
||||
|
||||
case DM_CONN_OPEN_IND: {
|
||||
hciLeConnCmplEvt_t* conn_evt = (hciLeConnCmplEvt_t*) msg;
|
||||
dmConnId_t connection_id = conn_evt->hdr.param;
|
||||
Gap::getInstance().setConnectionHandle(connection_id);
|
||||
Gap::AddressType_t own_addr_type;
|
||||
Gap::Address_t own_addr;
|
||||
Gap::getInstance().getAddress(&own_addr_type, own_addr);
|
||||
|
||||
Gap::ConnectionParams_t params = {
|
||||
conn_evt->connInterval,
|
||||
conn_evt->connInterval,
|
||||
conn_evt->connLatency,
|
||||
conn_evt->supTimeout
|
||||
};
|
||||
|
||||
Gap::getInstance().processConnectionEvent(
|
||||
connection_id,
|
||||
(conn_evt->role == DM_ROLE_MASTER) ? Gap::CENTRAL : Gap::PERIPHERAL,
|
||||
(Gap::AddressType_t) conn_evt->addrType,
|
||||
conn_evt->peerAddr,
|
||||
own_addr_type,
|
||||
own_addr,
|
||||
¶ms
|
||||
);
|
||||
} break;
|
||||
|
||||
case DM_CONN_CLOSE_IND: {
|
||||
dmEvt_t *disconnect_evt = (dmEvt_t*) msg;
|
||||
Gap::getInstance().setConnectionHandle(DM_CONN_ID_NONE);
|
||||
Gap::getInstance().processDisconnectionEvent(
|
||||
disconnect_evt->hdr.param,
|
||||
(Gap::DisconnectionReason_t) disconnect_evt->connClose.reason
|
||||
);
|
||||
} break;
|
||||
|
||||
default:
|
||||
ble::pal::vendor::cordio::Gap::gap_handler(msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -419,6 +368,10 @@ void BLE::start_stack_reset()
|
|||
|
||||
void BLE::callDispatcher()
|
||||
{
|
||||
// process the external event queue
|
||||
_event_queue.process();
|
||||
|
||||
// follow by stack events
|
||||
static uint32_t lastTimeUs = us_ticker_read();
|
||||
uint32_t currTimeUs, deltaTimeMs;
|
||||
|
||||
|
|
|
@ -1,543 +0,0 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2017-2017 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "CordioGap.h"
|
||||
#include "mbed.h"
|
||||
#include "dm_api.h"
|
||||
#include "CordioGattServer.h"
|
||||
#include "hci_core.h"
|
||||
|
||||
/**< Minimum Advertising interval in 625 us units, i.e. 20 ms. */
|
||||
#define BLE_GAP_ADV_INTERVAL_MIN 0x0020
|
||||
|
||||
/**< Minimum Advertising interval in 625 us units for non connectable mode, i.e. 100 ms. */
|
||||
#define BLE_GAP_ADV_NONCON_INTERVAL_MIN 0x00A0
|
||||
|
||||
/**< Maximum Advertising interval in 625 us units, i.e. 10.24 s. */
|
||||
#define BLE_GAP_ADV_INTERVAL_MAX 0x4000
|
||||
|
||||
namespace ble {
|
||||
namespace vendor {
|
||||
namespace cordio {
|
||||
|
||||
Gap &Gap::getInstance()
|
||||
{
|
||||
static Gap m_instance;
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
void Gap::initialize()
|
||||
{
|
||||
uint8_t whitelist_size = HciGetWhiteListSize();
|
||||
|
||||
if (whitelist_size == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
whitelist.addresses = new(std::nothrow) BLEProtocol::Address_t[whitelist_size];
|
||||
if (whitelist.addresses == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
whitelist.size = 0;
|
||||
whitelist.capacity = hciCoreCb.whiteListSize;
|
||||
}
|
||||
|
||||
ble_error_t Gap::setAddress(AddressType_t type, const Address_t address)
|
||||
{
|
||||
switch (type) {
|
||||
case BLEProtocol::AddressType::PUBLIC:
|
||||
// TODO: use vendor specific commands from the driver
|
||||
return BLE_ERROR_OPERATION_NOT_PERMITTED;
|
||||
|
||||
// See bluetooth 5, Vol 6 part, part B, 1.3.2
|
||||
case BLEProtocol::AddressType::RANDOM_STATIC:
|
||||
if ((address[5] >> 6) != 3) {
|
||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
m_type = type;
|
||||
BdaCpy(m_addr, address);
|
||||
DmDevSetRandAddr(m_addr);
|
||||
break;
|
||||
|
||||
// should not be here, generation is supposed to be handled by the controller.
|
||||
case BLEProtocol::AddressType::RANDOM_PRIVATE_RESOLVABLE:
|
||||
case BLEProtocol::AddressType::RANDOM_PRIVATE_NON_RESOLVABLE:
|
||||
m_type = type;
|
||||
return BLE_ERROR_NONE;
|
||||
|
||||
default:
|
||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
DmAdvSetAddrType(m_type);
|
||||
DmConnSetAddrType(m_type);
|
||||
DmScanSetAddrType(m_type);
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t Gap::getAddress(AddressType_t *typeP, Address_t address)
|
||||
{
|
||||
*typeP = m_type;
|
||||
|
||||
if(m_type == BLEProtocol::AddressType::RANDOM_PRIVATE_RESOLVABLE ||
|
||||
m_type == BLEProtocol::AddressType::RANDOM_PRIVATE_RESOLVABLE) {
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
BdaCpy(address, m_addr);
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t Gap::setAdvertisingData(const GapAdvertisingData &advData, const GapAdvertisingData &scanResponse)
|
||||
{
|
||||
/* Make sure we don't exceed the advertising payload length */
|
||||
if (advData.getPayloadLen() > GAP_ADVERTISING_DATA_MAX_PAYLOAD) {
|
||||
return BLE_ERROR_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
/* Make sure we have a payload! */
|
||||
if (advData.getPayloadLen() == 0) {
|
||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
/* set advertising and scan response data for discoverable mode */
|
||||
DmAdvSetData(DM_ADV_HANDLE_DEFAULT, HCI_ADV_DATA_OP_COMP_FRAG, DM_DATA_LOC_ADV, advData.getPayloadLen(), (uint8_t*)advData.getPayload());
|
||||
DmAdvSetData(DM_ADV_HANDLE_DEFAULT, HCI_ADV_DATA_OP_COMP_FRAG, DM_DATA_LOC_SCAN, scanResponse.getPayloadLen(), (uint8_t*)scanResponse.getPayload());
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t Gap::connect(
|
||||
const BLEProtocol::AddressBytes_t peerAddr,
|
||||
BLEProtocol::AddressType_t peerAddrType,
|
||||
const ConnectionParams_t* connectionParams,
|
||||
const GapScanningParams* scanParams
|
||||
) {
|
||||
// prepare the scan interval
|
||||
if (scanParams != NULL) {
|
||||
DmConnSetScanInterval(scanParams->getInterval(), scanParams->getWindow());
|
||||
}
|
||||
|
||||
if (connectionParams != NULL) {
|
||||
hciConnSpec_t conn_spec = {
|
||||
/* connIntervalMin */ connectionParams->minConnectionInterval,
|
||||
/* connIntervalMax */ connectionParams->maxConnectionInterval,
|
||||
/* connLatency */ connectionParams->slaveLatency,
|
||||
/* supTimeout */ connectionParams->connectionSupervisionTimeout,
|
||||
/* minCeLen */ DM_GAP_CONN_EST_MIN_CE_LEN,
|
||||
/* maxCeLen */ DM_GAP_CONN_EST_MAX_CE_LEN
|
||||
};
|
||||
DmConnSetConnSpec(&conn_spec);
|
||||
}
|
||||
|
||||
DmScanStop();
|
||||
dmConnId_t connection_id = DmConnOpen(
|
||||
DM_CLIENT_ID_APP,
|
||||
HCI_INIT_PHY_LE_1M_BIT,
|
||||
peerAddrType,
|
||||
(uint8_t*) peerAddr
|
||||
);
|
||||
|
||||
if (connection_id == DM_CONN_ID_NONE) {
|
||||
return BLE_ERROR_INTERNAL_STACK_FAILURE;
|
||||
}
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
uint16_t Gap::getMinAdvertisingInterval() const
|
||||
{
|
||||
return BLE_GAP_ADV_INTERVAL_MIN;
|
||||
}
|
||||
|
||||
uint16_t Gap::getMinNonConnectableAdvertisingInterval() const
|
||||
{
|
||||
return BLE_GAP_ADV_NONCON_INTERVAL_MIN;
|
||||
}
|
||||
|
||||
uint16_t Gap::getMaxAdvertisingInterval() const
|
||||
{
|
||||
return BLE_GAP_ADV_INTERVAL_MAX;
|
||||
}
|
||||
|
||||
ble_error_t Gap::startAdvertising(const GapAdvertisingParams ¶ms)
|
||||
{
|
||||
/* Make sure we support the advertising type */
|
||||
if (params.getAdvertisingType() == GapAdvertisingParams::ADV_CONNECTABLE_DIRECTED) {
|
||||
/* ToDo: This requires a proper security implementation, etc. */
|
||||
return BLE_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* Check interval range */
|
||||
if (params.getAdvertisingType() == GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED) {
|
||||
/* Min delay is slightly longer for unconnectable devices */
|
||||
if ((params.getIntervalInADVUnits() < GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MIN_NONCON) ||
|
||||
(params.getIntervalInADVUnits() > GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MAX)) {
|
||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
if ((params.getIntervalInADVUnits() < GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MIN) ||
|
||||
(params.getIntervalInADVUnits() > GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MAX)) {
|
||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check timeout is zero for Connectable Directed */
|
||||
if ((params.getAdvertisingType() == GapAdvertisingParams::ADV_CONNECTABLE_DIRECTED) && (params.getTimeout() != 0)) {
|
||||
/* Timeout must be 0 with this type, although we'll never get here */
|
||||
/* since this isn't implemented yet anyway */
|
||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
/* Check timeout for other advertising types */
|
||||
if ((params.getAdvertisingType() != GapAdvertisingParams::ADV_CONNECTABLE_DIRECTED) &&
|
||||
(params.getTimeout() > GapAdvertisingParams::GAP_ADV_PARAMS_TIMEOUT_MAX)) {
|
||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
uint16_t adv_interval_min = params.getIntervalInADVUnits();
|
||||
if (adv_interval_min == GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MAX) {
|
||||
--adv_interval_min;
|
||||
}
|
||||
uint16_t adv_interval_max = adv_interval_min + 1;
|
||||
|
||||
DmAdvSetInterval(DM_ADV_HANDLE_DEFAULT, adv_interval_min, adv_interval_max);
|
||||
|
||||
/* Peer Addr Type 0 = Public */
|
||||
uint8_t peerAddrType = 0;
|
||||
uint8_t peerAddr[6] = { 0 };
|
||||
DmAdvConfig(DM_ADV_HANDLE_DEFAULT, params.getAdvertisingType(), peerAddrType, peerAddr);
|
||||
|
||||
uint8_t adv_handles[] = { DM_ADV_HANDLE_DEFAULT };
|
||||
uint16_t adv_durations[] = { (uint16_t) (params.getTimeout() * 1000) };
|
||||
uint8_t max_ea_events[] = { 0 };
|
||||
DmAdvStart(1, adv_handles, adv_durations, max_ea_events);
|
||||
|
||||
state.advertising = 1;
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t Gap::stopAdvertising(void)
|
||||
{
|
||||
uint8_t adv_handles[] = { DM_ADV_HANDLE_DEFAULT };
|
||||
DmAdvStop(1, adv_handles);
|
||||
|
||||
state.advertising = 0;
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t Gap::disconnect(Handle_t connectionHandle, DisconnectionReason_t reason)
|
||||
{
|
||||
DmConnClose(DM_CLIENT_ID_APP, connectionHandle, reason);
|
||||
|
||||
state.advertising = 0;
|
||||
state.connected = 0;
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t Gap::disconnect(DisconnectionReason_t reason)
|
||||
{
|
||||
DmConnClose(DM_CLIENT_ID_APP, m_connectionHandle, reason);
|
||||
|
||||
state.advertising = 0;
|
||||
state.connected = 0;
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t Gap::setDeviceName(const uint8_t *deviceName)
|
||||
{
|
||||
return GattServer::getInstance().setDeviceName(deviceName);
|
||||
}
|
||||
|
||||
ble_error_t Gap::getDeviceName(uint8_t *deviceName, unsigned *lengthP)
|
||||
{
|
||||
const uint8_t* name = NULL;
|
||||
uint16_t length = 0;
|
||||
|
||||
GattServer::getInstance().getDeviceName(name, length);
|
||||
|
||||
if (deviceName != NULL) {
|
||||
memcpy(deviceName, name, std::min((uint16_t) *lengthP, length));
|
||||
}
|
||||
|
||||
*lengthP = length;
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t Gap::setAppearance(GapAdvertisingData::Appearance appearance)
|
||||
{
|
||||
GattServer::getInstance().setAppearance(appearance);
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t Gap::getAppearance(GapAdvertisingData::Appearance *appearanceP)
|
||||
{
|
||||
*appearanceP = GattServer::getInstance().getAppearance();
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t Gap::setTxPower(int8_t txPower)
|
||||
{
|
||||
#if 0
|
||||
HciVsSetTxPower(txPower);
|
||||
return BLE_ERROR_NONE;
|
||||
#else
|
||||
return BLE_ERROR_NOT_IMPLEMENTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Gap::getPermittedTxPowerValues(const int8_t **valueArrayPP, size_t *countP)
|
||||
{
|
||||
*valueArrayPP = NULL;
|
||||
*countP = 0;
|
||||
}
|
||||
|
||||
void Gap::setConnectionHandle(uint16_t connectionHandle)
|
||||
{
|
||||
m_connectionHandle = connectionHandle;
|
||||
}
|
||||
|
||||
uint16_t Gap::getConnectionHandle(void)
|
||||
{
|
||||
return m_connectionHandle;
|
||||
}
|
||||
|
||||
ble_error_t Gap::getPreferredConnectionParams(ConnectionParams_t *params)
|
||||
{
|
||||
*params = GattServer::getInstance().getPreferredConnectionParams();
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t Gap::setPreferredConnectionParams(const ConnectionParams_t *params)
|
||||
{
|
||||
// ensure that parameters are correct
|
||||
// see BLUETOOTH SPECIFICATION Version 4.2 [Vol 3, Part C]
|
||||
// section 12.3 PERIPHERAL PREFERRED CONNECTION PARAMETERS CHARACTERISTIC
|
||||
if (((0x0006 > params->minConnectionInterval) || (params->minConnectionInterval > 0x0C80)) &&
|
||||
params->minConnectionInterval != 0xFFFF) {
|
||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
if (((params->minConnectionInterval > params->maxConnectionInterval) || (params->maxConnectionInterval > 0x0C80)) &&
|
||||
params->maxConnectionInterval != 0xFFFF) {
|
||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
if (params->slaveLatency > 0x01F3) {
|
||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
if (((0x000A > params->connectionSupervisionTimeout) || (params->connectionSupervisionTimeout > 0x0C80)) &&
|
||||
params->connectionSupervisionTimeout != 0xFFFF) {
|
||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
GattServer::getInstance().setPreferredConnectionParams(*params);
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t Gap::updateConnectionParams(Handle_t handle, const ConnectionParams_t *newParams)
|
||||
{
|
||||
if (DmConnCheckIdle(handle) != 0) {
|
||||
return BLE_STACK_BUSY;
|
||||
}
|
||||
|
||||
hciConnSpec_t connSpec;
|
||||
connSpec.connIntervalMin = newParams->minConnectionInterval;
|
||||
connSpec.connIntervalMax = newParams->maxConnectionInterval;
|
||||
connSpec.connLatency = newParams->slaveLatency;
|
||||
connSpec.supTimeout = newParams->connectionSupervisionTimeout;
|
||||
DmConnUpdate(handle, &connSpec);
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t Gap::startRadioScan(const GapScanningParams &scanningParams)
|
||||
{
|
||||
// not needed to start scanning if the whitelist is empty and the scanning
|
||||
// policy filter all the advertising packets
|
||||
if ((whitelist.size == 0) && (scanning_policy_mode == Gap::SCAN_POLICY_FILTER_ALL_ADV)) {
|
||||
return BLE_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
uint16_t scan_intervals[] = { scanningParams.getInterval() };
|
||||
uint16_t scan_windows[] = { scanningParams.getWindow() };
|
||||
|
||||
DmScanSetInterval(HCI_SCAN_PHY_LE_1M_BIT, scan_intervals, scan_windows);
|
||||
|
||||
uint8_t scanType = scanningParams.getActiveScanning() ? DM_SCAN_TYPE_ACTIVE : DM_SCAN_TYPE_PASSIVE;
|
||||
uint32_t duration = (uint32_t)scanningParams.getTimeout() * 1000;
|
||||
if (duration > 0xFFFF) {
|
||||
// saturate to 16-bits
|
||||
duration = 0xFFFF;
|
||||
}
|
||||
|
||||
DmScanStart(HCI_SCAN_PHY_LE_1M_BIT, DM_DISC_MODE_NONE, &scanType, TRUE, duration, 0);
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t Gap::stopScan(void)
|
||||
{
|
||||
DmScanStop();
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
void Gap::advertisingStopped(void)
|
||||
{
|
||||
/* If advertising stopped due to a call to stopAdvertising(), state.advertising will
|
||||
* be '0.' Otherwise, advertising must have stopped due to a timeout
|
||||
*/
|
||||
if (state.advertising) {
|
||||
processTimeoutEvent(Gap::TIMEOUT_SRC_ADVERTISING);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t Gap::getMaxWhitelistSize(void) const
|
||||
{
|
||||
return whitelist.capacity;
|
||||
}
|
||||
|
||||
ble_error_t Gap::getWhitelist(Whitelist_t &other) const
|
||||
{
|
||||
// i is a shorthand for other.size
|
||||
uint8_t& i = other.size;
|
||||
|
||||
for (i = 0; (i < whitelist.capacity) && (i < other.capacity); ++i) {
|
||||
other.addresses[i] = whitelist.addresses[i];
|
||||
}
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t Gap::setWhitelist(const Whitelist_t& other)
|
||||
{
|
||||
if (other.capacity > whitelist.capacity) {
|
||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
// note : can be improved by sending the diff instead of the full list
|
||||
|
||||
DmDevWhiteListClear();
|
||||
|
||||
// alias i to whitelist.size
|
||||
uint8_t& i = whitelist.size;
|
||||
|
||||
for (i = 0; (i < other.capacity) && (i < whitelist.capacity); ++i) {
|
||||
whitelist.addresses[i] = other.addresses[i];
|
||||
DmDevWhiteListAdd(
|
||||
(whitelist.addresses[i].type > 1) ? 0xFF : whitelist.addresses[i].type,
|
||||
whitelist.addresses[i].address
|
||||
);
|
||||
}
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t Gap::setAdvertisingPolicyMode(AdvertisingPolicyMode_t mode)
|
||||
{
|
||||
bool_t result = DmDevSetFilterPolicy(
|
||||
DM_FILT_POLICY_MODE_ADV,
|
||||
mode
|
||||
);
|
||||
|
||||
if (result == false) {
|
||||
return BLE_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
advertising_policy_mode = mode;
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
Gap::AdvertisingPolicyMode_t Gap::getAdvertisingPolicyMode(void) const
|
||||
{
|
||||
return advertising_policy_mode;
|
||||
}
|
||||
|
||||
ble_error_t Gap::setScanningPolicyMode(ScanningPolicyMode_t mode)
|
||||
{
|
||||
bool_t result = DmDevSetFilterPolicy(
|
||||
DM_FILT_POLICY_MODE_SCAN,
|
||||
mode
|
||||
);
|
||||
|
||||
if (result == false) {
|
||||
return BLE_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
scanning_policy_mode = mode;
|
||||
return BLE_ERROR_NONE;
|
||||
|
||||
}
|
||||
|
||||
Gap::ScanningPolicyMode_t Gap::getScanningPolicyMode(void) const
|
||||
{
|
||||
return scanning_policy_mode;
|
||||
}
|
||||
|
||||
ble_error_t Gap::setInitiatorPolicyMode(InitiatorPolicyMode_t mode)
|
||||
{
|
||||
bool_t result = DmDevSetFilterPolicy(
|
||||
DM_FILT_POLICY_MODE_INIT,
|
||||
mode
|
||||
);
|
||||
|
||||
if (result == false) {
|
||||
return BLE_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
initiator_policy_mode = mode;
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
Gap::InitiatorPolicyMode_t Gap::getInitiatorPolicyMode(void) const
|
||||
{
|
||||
return initiator_policy_mode;
|
||||
}
|
||||
|
||||
ble_error_t Gap::reset(void)
|
||||
{
|
||||
this->::Gap::reset();
|
||||
delete[] whitelist.addresses;
|
||||
whitelist.addresses = NULL;
|
||||
whitelist.size = 0;
|
||||
whitelist.capacity = 0;
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
Gap::Gap() :
|
||||
::Gap(),
|
||||
m_connectionHandle(DM_CONN_ID_NONE),
|
||||
m_type(BLEProtocol::AddressType::RANDOM_STATIC),
|
||||
m_addr(),
|
||||
advertising_policy_mode(ADV_POLICY_IGNORE_WHITELIST),
|
||||
scanning_policy_mode(SCAN_POLICY_IGNORE_WHITELIST),
|
||||
initiator_policy_mode(INIT_POLICY_IGNORE_WHITELIST),
|
||||
whitelist()
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace cordio
|
||||
} // namespace vendor
|
||||
} // namespace ble
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include "CordioGattServer.h"
|
||||
#include "CordioGap.h"
|
||||
#include "mbed.h"
|
||||
#include "wsf_types.h"
|
||||
#include "att_api.h"
|
||||
|
@ -286,33 +285,63 @@ ble_error_t GattServer::read(Gap::Handle_t connectionHandle, GattAttribute::Hand
|
|||
|
||||
ble_error_t GattServer::write(GattAttribute::Handle_t attributeHandle, const uint8_t buffer[], uint16_t len, bool localOnly)
|
||||
{
|
||||
uint16_t connectionHandle = Gap::getInstance().getConnectionHandle();
|
||||
// Check to see if this is a CCCD, if it is the case update the value for all
|
||||
// connections
|
||||
uint8_t idx;
|
||||
for (idx = 0; idx < cccCnt; idx++) {
|
||||
if (attributeHandle == cccSet[idx].handle) {
|
||||
for (uint16_t conn_id = 0, conn_found = 0; (conn_found < DM_CONN_MAX) && (conn_id < 0x100); ++conn_id) {
|
||||
if (DmConnInUse(conn_id) == true) {
|
||||
++conn_found;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
AttsCccSet(conn_id, idx, *((uint16_t*)buffer));
|
||||
}
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
// write the value to the attribute handle
|
||||
if (AttsSetAttr(attributeHandle, len, (uint8_t*)buffer) != ATT_SUCCESS) {
|
||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
if (!localOnly) {
|
||||
if (connectionHandle != DM_CONN_ID_NONE) {
|
||||
// return if the update does not have to be propagated to peers
|
||||
if (localOnly) {
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
// Check to see if this characteristic has a CCCD attribute
|
||||
uint8_t idx;
|
||||
for (idx = 0; idx < cccCnt; idx++) {
|
||||
if (attributeHandle == cccHandles[idx]) {
|
||||
break;
|
||||
}
|
||||
// Check to see if this characteristic has a CCCD attribute
|
||||
for (idx = 0; idx < cccCnt; idx++) {
|
||||
if (attributeHandle == cccHandles[idx]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// exit if the characteristic has no CCCD attribute
|
||||
if (idx >= cccCnt) {
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
// This characteristic has a CCCD attribute. Handle notifications and indications.
|
||||
// for all connections
|
||||
|
||||
for (uint16_t conn_id = 0, conn_found = 0; (conn_found < DM_CONN_MAX) && (conn_id < 0x100); ++conn_id) {
|
||||
if (DmConnInUse(conn_id) == true) {
|
||||
++conn_found;
|
||||
} else {
|
||||
uint16_t cccEnabled = AttsCccEnabled(conn_id, idx);
|
||||
if (cccEnabled & ATT_CLIENT_CFG_NOTIFY) {
|
||||
AttsHandleValueNtf(conn_id, attributeHandle, len, (uint8_t*)buffer);
|
||||
}
|
||||
if (idx < cccCnt) {
|
||||
// This characteristic has a CCCD attribute. Handle notifications and indications.
|
||||
uint16_t cccEnabled = AttsCccEnabled(connectionHandle, idx);
|
||||
if (cccEnabled & ATT_CLIENT_CFG_NOTIFY) {
|
||||
AttsHandleValueNtf(connectionHandle, attributeHandle, len, (uint8_t*)buffer);
|
||||
}
|
||||
if (cccEnabled & ATT_CLIENT_CFG_INDICATE) {
|
||||
AttsHandleValueInd(connectionHandle, attributeHandle, len, (uint8_t*)buffer);
|
||||
}
|
||||
if (cccEnabled & ATT_CLIENT_CFG_INDICATE) {
|
||||
AttsHandleValueInd(conn_id, attributeHandle, len, (uint8_t*)buffer);
|
||||
}
|
||||
}
|
||||
|
||||
AttsCccSet(conn_id, idx, *((uint16_t*)buffer));
|
||||
}
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
|
@ -332,26 +361,59 @@ ble_error_t GattServer::write(Gap::Handle_t connectionHandle, GattAttribute::Han
|
|||
}
|
||||
}
|
||||
|
||||
// This is not a CCCD. Use the non-connection specific update method.
|
||||
return write(attributeHandle, buffer, len, localOnly);
|
||||
// write the value to the attribute handle
|
||||
if (AttsSetAttr(attributeHandle, len, (uint8_t*)buffer) != ATT_SUCCESS) {
|
||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
// return if the update does not have to be propagated to peers
|
||||
if (localOnly) {
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
// Check to see if this characteristic has a CCCD attribute
|
||||
for (idx = 0; idx < cccCnt; idx++) {
|
||||
if (attributeHandle == cccHandles[idx]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// exit if the characteristic has no CCCD attribute
|
||||
if (idx >= cccCnt) {
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
// This characteristic has a CCCD attribute. Handle notifications and indications.
|
||||
uint16_t cccEnabled = AttsCccEnabled(connectionHandle, idx);
|
||||
if (cccEnabled & ATT_CLIENT_CFG_NOTIFY) {
|
||||
AttsHandleValueNtf(connectionHandle, attributeHandle, len, (uint8_t*)buffer);
|
||||
}
|
||||
if (cccEnabled & ATT_CLIENT_CFG_INDICATE) {
|
||||
AttsHandleValueInd(connectionHandle, attributeHandle, len, (uint8_t*)buffer);
|
||||
}
|
||||
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
ble_error_t GattServer::areUpdatesEnabled(const GattCharacteristic &characteristic, bool *enabledP)
|
||||
{
|
||||
uint16_t connectionHandle = Gap::getInstance().getConnectionHandle();
|
||||
|
||||
if (connectionHandle != DM_CONN_ID_NONE) {
|
||||
uint8_t idx;
|
||||
for (idx = 0; idx < cccCnt; idx++) {
|
||||
if (characteristic.getValueHandle() == cccHandles[idx]) {
|
||||
uint16_t cccValue = AttsCccGet(connectionHandle, idx);
|
||||
if (cccValue & ATT_CLIENT_CFG_NOTIFY) {
|
||||
*enabledP = true;
|
||||
for (size_t idx = 0; idx < cccCnt; idx++) {
|
||||
if (characteristic.getValueHandle() == cccHandles[idx]) {
|
||||
for (uint16_t conn_id = 0, conn_found = 0; (conn_found < DM_CONN_MAX) && (conn_id < 0x100); ++conn_id) {
|
||||
if (DmConnInUse(conn_id) == true) {
|
||||
++conn_found;
|
||||
} else {
|
||||
*enabledP = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
uint16_t cccValue = AttsCccGet(conn_id, idx);
|
||||
if ((cccValue & ATT_CLIENT_CFG_NOTIFY) || (cccValue & ATT_CLIENT_CFG_INDICATE)) {
|
||||
*enabledP = true;
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
*enabledP = false;
|
||||
return BLE_ERROR_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -365,7 +427,7 @@ ble_error_t GattServer::areUpdatesEnabled(Gap::Handle_t connectionHandle, const
|
|||
for (idx = 0; idx < cccCnt; idx++) {
|
||||
if (characteristic.getValueHandle() == cccHandles[idx]) {
|
||||
uint16_t cccValue = AttsCccGet(connectionHandle, idx);
|
||||
if (cccValue & ATT_CLIENT_CFG_NOTIFY) {
|
||||
if (cccValue & ATT_CLIENT_CFG_NOTIFY || (cccValue & ATT_CLIENT_CFG_INDICATE)) {
|
||||
*enabledP = true;
|
||||
} else {
|
||||
*enabledP = false;
|
||||
|
|
Loading…
Reference in New Issue