blob: 0705b9d307b3b4014d385bc91bb5c51b1fe533f4 [file] [log] [blame]
/*
*
* Copyright (c) 2014-2017 Nest Labs, Inc.
* All rights reserved.
*
* 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.
*/
/**
* @file
* This file defines objects that provide an abstraction layer between a
* platform's Bluetooth Low Energy (BLE) implementation and the Weave
* stack.
*
* The BleLayer obect accepts BLE data and control input from the
* application via a functional interface. It performs the fragmentation
* and reassembly required to transmit Weave message via a BLE GATT
* characteristic interface, and drives incoming messages up the Weave
* stack.
*
* During initialization, the BleLayer object requires a pointer to the
* platform's implementation of the BleAdapter object. This object is
* defined but not implemented by the Weave stack, and provides the
* BleLayer with a functional interface to drive outgoing GATT
* characteristic writes and indications. It also provides a mechanism
* for Weave to inform the application when it has finished using a given
* BLE connection, i.e., when the WeaveConnection object wrapping this
* connection has closed.
*
* To enable Weave over BLE for a new platform, the application developer
* must implement the BleAdapter class for their platform, pass it to the
* BleLayer on startup, pass a pointer to this BleLayer to their instance
* of WeaveMessageLayer, and ensure that the application calls the
* necessary BleLayer functions to drive BLE data and control input up the
* stack.
*/
#ifndef BLELAYER_H_
#define BLELAYER_H_
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif
#include <stdint.h>
#include <BleLayer/BleConfig.h>
#include <SystemLayer/SystemLayer.h>
#include <SystemLayer/SystemPacketBuffer.h>
#include <BleLayer/BlePlatformDelegate.h>
#include <BleLayer/BleApplicationDelegate.h>
#include <BleLayer/BleUUID.h>
#include <BleLayer/BleError.h>
#if BLE_CONFIG_PROVIDE_OBSOLESCENT_INTERFACES
#include <InetLayer/InetLayer.h>
#endif // BLE_CONFIG_PROVIDE_OBSOLESCENT_INTERFACES
namespace nl {
namespace Ble {
using ::nl::Weave::System::PacketBuffer;
#define NUM_SUPPORTED_PROTOCOL_VERSIONS 8 /**< Number of unsigned 4-bit representations of supported transport protocol
* versions encapsulated in a BleTransportCapabilitiesRequest. Defined by
* Weave over BLE protocol specification. */
/// Version(s) of the Nest BLE Transport Protocol that this stack supports.
#define NL_BLE_TRANSPORT_PROTOCOL_MIN_SUPPORTED_VERSION kBleTransportProtocolVersion_V2
#define NL_BLE_TRANSPORT_PROTOCOL_MAX_SUPPORTED_VERSION kBleTransportProtocolVersion_V3
/// Forward declarations.
class BleLayer;
class BLEEndPoint;
/// Role of end points' associated BLE connections. Determines means used by end points to send and receive data.
typedef enum
{
kBleRole_Central = 0,
kBleRole_Peripheral = 1
} BleRole;
/// Enum defining versions of Weave over BLE transport protocol.
typedef enum
{
kBleTransportProtocolVersion_None = 0,
kBleTransportProtocolVersion_V1 = 1, // Prototype WoBLe version without ACKs or flow-control.
kBleTransportProtocolVersion_V2 = 2, // First WoBLE version with ACKs and flow-control.
kBleTransportProtocolVersion_V3 = 3 // First WoBLE version with asymetric fragement sizes.
} BleTransportProtocolVersion;
class BleLayerObject
{
friend class BleLayer;
public:
// Public data members:
BleLayer *mBle; ///< [READ-ONLY] Pointer to the BleLayer object that owns this object.
void *mAppState; ///< Generic pointer to app-specific data associated with the object.
protected:
uint32_t mRefCount;
void AddRef(void) { mRefCount++; }
void Release(void);
};
class BleTransportCapabilitiesRequestMessage
{
public:
/**
* An array of size NUM_SUPPORTED_PROTOCOL_VERSIONS listing versions of the BLE transport protocol that this
* node supports. Each protocol version is specified as a 4-bit unsigned integer. A zero-value
* represents unused array elements. Counting up from the zero-index, the first zero-value specifies the end of
* the list of supported protocol versions.
*/
uint8_t mSupportedProtocolVersions[(NUM_SUPPORTED_PROTOCOL_VERSIONS / 2) + (NUM_SUPPORTED_PROTOCOL_VERSIONS % 2)];
uint16_t mMtu; /**< The MTU that has been negotiated for this BLE connection. Specified in
* the BleTransportCapabilitiesRequestMessage because the remote node may be unable
* to glean this info from its own BLE hardware/software stack, such as on
* older Android platforms.
*
* A value of 0 means that the central could not determine the negotiated
* BLE connection MTU. */
uint8_t mWindowSize; /**< The initial and maximum receive window size offered by the central,
* defined in terms of GATT indication payloads. */
/** Set supported version value at given index in SupportedProtcolVersions. uint8_t version argument is truncated
* to 4 least-significant bits. Index shall be 0 through number of SupportedProtocolVersions elements - 1. */
void SetSupportedProtocolVersion(uint8_t index, uint8_t version);
/// Must be able to reserve 20 byte data length in msgBuf.
BLE_ERROR Encode(PacketBuffer *msgBuf) const;
static BLE_ERROR Decode(const PacketBuffer &msgBuf, BleTransportCapabilitiesRequestMessage& msg);
};
class BleTransportCapabilitiesResponseMessage
{
public:
uint8_t mSelectedProtocolVersion; /**< The lower 4 bits specify the BLE transport protocol version that the BLE
* peripheral has selected for this connection. */
/**< A value of kBleTransportProtocolVersion_None means that no supported protocol
* version was found in the central's capabilities request. The central should
* unsubscribe after such a response has been sent to free up the peripheral for
* connections from devices with supported protocol versions. */
uint16_t mFragmentSize; /**< BLE transport fragment size selected by peripheral in response to MTU value in
* BleTransportCapabilitiesRequestMessage and its local observation of the BLE
* connection MTU. */
uint8_t mWindowSize; /**< The initial and maximum receive window size offered by the peripheral,
* defined in terms of GATT write payloads. */
/// Must be able to reserve 20 byte data length in msgBuf.
BLE_ERROR Encode(PacketBuffer *msgBuf) const;
static BLE_ERROR Decode(const PacketBuffer &msgBuf, BleTransportCapabilitiesResponseMessage& msg);
};
/**
* @class BleLayer
*
* @brief
* This class provides an interface for a single thread to drive data
* either up the stack via the BleLayer platform interface functions,
* or down the stack via a WeaveConnection object associated with a
* BLEEndPoint.
*
* There are two ways to associate a WeaveConnection (defined by the
* WeaveMessageLayer) with a BLE connection:
*
* First, the application can passively receive an incoming BLE connection
* and hand the platform-specific BLE_CONNECTION_OBJECT that this receipt
* generates to BleLayer via the corresponding platform interface function.
* This causes BleLayer to wrap the BLE_CONNECTION_OBJECT in a BLEEndPoint,
* and notify WeaveMessageLayer that a new BLE conneciotn has been received.
* The message layer then wraps the new BLEEndPoint object in a
* WeaveConnection, and hands this object to the application via the message
* layer's OnConnectionReceived callback.
*
* Second, the application can actively form an outgoing BLE connection, e.g.,
* by connecting to a BLE peripheral. It then creates a new WeaveConnection
* via the WeaveMessageLayer, assigns an authentication type to this
* connection, and binds it to the BLE_CONNECTION_OBJECT for the new BLE
* connection via WeaveConnection::ConnectBle. This function then
* establishes the secure session type specified by the WeaveConnection's
* authentication type member variable.
*
*/
class NL_DLL_EXPORT BleLayer
{
friend class BLEEndPoint;
#if WEAVE_ENABLE_WOBLE_TEST
friend class WoBleTest;
#endif
public:
// Public data members:
enum
{
kState_NotInitialized = 0,
kState_Initialized = 1
} mState; ///< [READ-ONLY] Current state
void *mAppState;
typedef void (*BleConnectionReceivedFunct)(BLEEndPoint *newEndPoint);
BleConnectionReceivedFunct OnWeaveBleConnectReceived;
public:
// Public functions:
BleLayer(void);
BLE_ERROR Init(BlePlatformDelegate *platformDelegate, BleApplicationDelegate *appDelegate, Weave::System::Layer *systemLayer);
#if BLE_CONFIG_PROVIDE_OBSOLESCENT_INTERFACES
BLE_ERROR Init(BlePlatformDelegate *platformDelegate, BleApplicationDelegate *appDelegate, Inet::InetLayer *inetLayer);
#endif // BLE_CONFIG_PROVIDE_OBSOLESCENT_INTERFACES
BLE_ERROR Shutdown(void);
BLE_ERROR NewBleEndPoint(BLEEndPoint **retEndPoint, BLE_CONNECTION_OBJECT connObj, BleRole role, bool autoClose);
/**< Platform interface functions:
* Calling conventions:
* Weave takes ownership of PacketBuffers received through these functions,
* and will free them or pass ownership up the stack.
*
* Beyond each call, no guarantees are provided as to the lifetime of UUID arguments.
*
* A 'true' return value means the Weave stack successfully handled the
* corresponding message or state indication. 'false' means the Weave stack either
* failed or chose not to handle this. In case of 'false,' the Weave stack will not
* have freed or taken ownership of any PacketBuffer arguments. This contract allows the
* platform to pass BLE events to Weave without needing to know which characteristics
* Weave cares about.
* Platform must call this function when a GATT subscription has been established to any Weave service
* charateristic.
*
* If this function returns true, Weave has accepted the BLE connection and wrapped it
* in a WeaveConnection object. If Weave accepts a BLE connection, the platform MUST
* notify Weave if the subscription is canceled or the underlying BLE connection is
* closed, or the associated WeaveConnection will never be closed or freed. */
bool HandleSubscribeReceived(BLE_CONNECTION_OBJECT connObj, const WeaveBleUUID *svcId, const WeaveBleUUID *charId);
/// Call when a GATT subscribe request succeeds.
bool HandleSubscribeComplete(BLE_CONNECTION_OBJECT connObj, const WeaveBleUUID *svcId, const WeaveBleUUID *charId);
/**< Platform must call this function when a GATT unsubscribe is requested on any Weave
* service charateristic, that is, when an existing GATT subscription on a Weave service
* characteristic is canceled. */
bool HandleUnsubscribeReceived(BLE_CONNECTION_OBJECT connObj, const WeaveBleUUID *svcId, const WeaveBleUUID *charId);
/// Call when a GATT unsubscribe request succeeds.
bool HandleUnsubscribeComplete(BLE_CONNECTION_OBJECT connObj, const WeaveBleUUID *svcId, const WeaveBleUUID *charId);
/// Call when a GATT write request is received.
bool HandleWriteReceived(BLE_CONNECTION_OBJECT connObj, const WeaveBleUUID *svcId, const WeaveBleUUID *charId, PacketBuffer *pBuf);
/// Call when a GATT indication is received.
bool HandleIndicationReceived(BLE_CONNECTION_OBJECT connObj, const WeaveBleUUID *svcId, const WeaveBleUUID *charId, PacketBuffer *pBuf);
/// Call when an outstanding GATT write request receives a positive receipt confirmation.
bool HandleWriteConfirmation(BLE_CONNECTION_OBJECT connObj, const WeaveBleUUID *svcId, const WeaveBleUUID *charId);
/// Call when an oustanding GATT indication receives a positive receipt confirmation.
bool HandleIndicationConfirmation(BLE_CONNECTION_OBJECT connObj, const WeaveBleUUID *svcId, const WeaveBleUUID *charId);
/// Call when a GATT read request is received.
bool HandleReadReceived(BLE_CONNECTION_OBJECT connObj, BLE_READ_REQUEST_CONTEXT requestContext, const WeaveBleUUID *svcId, const WeaveBleUUID *charId);
/**< Platform must call this function when any previous operation undertaken by the BleLayer via BleAdapter
* fails, such as a characteristic write request or subscribe attempt, or when a BLE connection is closed.
*
* In most cases, this will prompt Weave to close the associated WeaveConnection and notify that platform that
* it has abandoned the underlying BLE connection.
*
* NOTE: if the application explicitly closes a BLE connection with an associated WeaveConnection such that
* the BLE connection close will not generate an upcall to Weave, HandleConnectionError must be called with
* err = BLE_ERROR_APP_CLOSED_CONNECTION to prevent the leak of this WeaveConnection and its end point object. */
void HandleConnectionError(BLE_CONNECTION_OBJECT connObj, BLE_ERROR err);
#if WEAVE_ENABLE_WOBLE_TEST
BLEEndPoint *mTestBleEndPoint;
#endif
private:
// Private data members:
// UUID of Weave service characteristic used for central writes.
static const WeaveBleUUID WEAVE_BLE_CHAR_1_ID;
// UUID of Weave service characteristic used for peripheral indications.
static const WeaveBleUUID WEAVE_BLE_CHAR_2_ID;
BlePlatformDelegate *mPlatformDelegate;
BleApplicationDelegate *mApplicationDelegate;
Weave::System::Layer *mSystemLayer;
private:
// Private functions:
void HandleDataReceived(BLE_CONNECTION_OBJECT connObj, PacketBuffer *pBuf);
void HandleAckReceived(BLE_CONNECTION_OBJECT connObj);
void DriveSending(void);
BLE_ERROR HandleBleTransportConnectionInitiated(BLE_CONNECTION_OBJECT connObj, PacketBuffer *pBuf);
static BleTransportProtocolVersion GetHighestSupportedProtocolVersion(const BleTransportCapabilitiesRequestMessage &reqMsg);
};
#if BLE_CONFIG_PROVIDE_OBSOLESCENT_INTERFACES
inline BLE_ERROR BleLayer::Init(BlePlatformDelegate* aPlatformDelegate, BleApplicationDelegate* aAppDelegate,
Inet::InetLayer* aInetLayer)
{
return Init(aPlatformDelegate, aAppDelegate, aInetLayer->SystemLayer());
}
#endif // BLE_CONFIG_PROVIDE_OBSOLESCENT_INTERFACES
} /* namespace Ble */
} /* namespace nl */
#include "BLEEndPoint.h"
#endif /* BLELAYER_H_ */