blob: ee0c8fb614efc42de31ab62b7894311987983d6a [file] [log] [blame]
/*
*
* Copyright (c) 2020 Project CHIP Authors
* 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 implements the CHIP Connection object that maintains a BLE connection.
*
*/
#include <transport/BLE.h>
#include <support/CodeUtils.h>
#include <support/logging/CHIPLogging.h>
#include <transport/raw/MessageHeader.h>
#include <inttypes.h>
using namespace chip::Ble;
using namespace chip::System;
namespace chip {
namespace Transport {
BLE::~BLE()
{
if (mBleEndPoint)
{
// Ble endpoint is only non null if ble endpoint is initialized and connected
mBleEndPoint->Close();
mBleEndPoint = nullptr;
}
}
CHIP_ERROR BLE::Init(RendezvousSessionDelegate * delegate, const RendezvousParameters & params)
{
CHIP_ERROR err = CHIP_NO_ERROR;
BleLayer * bleLayer = params.GetBleLayer();
VerifyOrExit(mState == State::kNotReady, err = CHIP_ERROR_INCORRECT_STATE);
VerifyOrExit(bleLayer, err = CHIP_ERROR_INCORRECT_STATE);
mDelegate = delegate;
mBleLayer = bleLayer;
mBleLayer->mAppState = reinterpret_cast<void *>(this);
mBleLayer->OnChipBleConnectReceived = OnNewConnection;
if (params.HasDiscriminator())
{
err = DelegateConnection(params.GetDiscriminator());
}
else if (params.HasConnectionObject())
{
err = InitInternal(params.GetConnectionObject());
}
SuccessOrExit(err);
exit:
return err;
}
CHIP_ERROR BLE::InitInternal(BLE_CONNECTION_OBJECT connObj)
{
CHIP_ERROR err = CHIP_NO_ERROR;
err = mBleLayer->NewBleEndPoint(&mBleEndPoint, connObj, kBleRole_Central, true);
SuccessOrExit(err);
// Initiate CHIP over BLE protocol connection.
SetupEvents(mBleEndPoint);
err = mBleEndPoint->StartConnect();
SuccessOrExit(err);
exit:
if (err != CHIP_NO_ERROR)
{
if (mBleEndPoint)
{
mBleEndPoint->Close();
mBleEndPoint = nullptr;
}
}
return err;
}
CHIP_ERROR BLE::SetEndPoint(Ble::BLEEndPoint * endPoint)
{
CHIP_ERROR err = CHIP_NO_ERROR;
VerifyOrExit(endPoint->mState == BLEEndPoint::kState_Connected, err = CHIP_ERROR_INVALID_ARGUMENT);
mBleEndPoint = endPoint;
SetupEvents(mBleEndPoint);
// Manually trigger the OnConnectComplete callback.
OnBleEndPointConnectionComplete(endPoint, err);
exit:
return err;
}
void BLE::SetupEvents(Ble::BLEEndPoint * endPoint)
{
endPoint->mAppState = reinterpret_cast<void *>(this);
endPoint->OnMessageReceived = OnBleEndPointReceive;
endPoint->OnConnectComplete = OnBleEndPointConnectionComplete;
endPoint->OnConnectionClosed = OnBleEndPointConnectionClosed;
}
CHIP_ERROR BLE::DelegateConnection(const uint16_t connDiscriminator)
{
CHIP_ERROR err = CHIP_NO_ERROR;
err = mBleLayer->NewBleConnection(reinterpret_cast<void *>(this), connDiscriminator, OnBleConnectionComplete,
OnBleConnectionError);
SuccessOrExit(err);
exit:
return err;
}
CHIP_ERROR BLE::SendMessage(const PacketHeader & header, const Transport::PeerAddress & address, System::PacketBuffer * msgIn)
{
CHIP_ERROR err = CHIP_NO_ERROR;
const uint16_t headerSize = header.EncodeSizeBytes();
uint16_t actualEncodedHeaderSize;
PacketBufferHandle msgBuf;
msgBuf.Adopt(msgIn);
VerifyOrExit(address.GetTransportType() == Type::kBle, err = CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrExit(mState == State::kInitialized, err = CHIP_ERROR_INCORRECT_STATE);
VerifyOrExit(mBleEndPoint != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
VerifyOrExit(msgBuf->EnsureReservedSize(headerSize), err = CHIP_ERROR_NO_MEMORY);
msgBuf->SetStart(msgBuf->Start() - headerSize);
err = header.Encode(msgBuf->Start(), msgBuf->DataLength(), &actualEncodedHeaderSize);
SuccessOrExit(err);
VerifyOrExit(headerSize == actualEncodedHeaderSize, err = CHIP_ERROR_INTERNAL);
err = mBleEndPoint->Send(std::move(msgBuf));
SuccessOrExit(err);
exit:
return err;
}
void BLE::OnBleConnectionComplete(void * appState, BLE_CONNECTION_OBJECT connObj)
{
CHIP_ERROR err = CHIP_NO_ERROR;
BLE * ble = reinterpret_cast<BLE *>(appState);
err = ble->InitInternal(connObj);
SuccessOrExit(err);
exit:
if (err != CHIP_NO_ERROR)
{
ble->OnBleConnectionError(appState, err);
}
}
void BLE::OnBleConnectionError(void * appState, BLE_ERROR err)
{
BLE * ble = reinterpret_cast<BLE *>(appState);
if (ble->mDelegate)
{
ble->mDelegate->OnRendezvousError(err);
}
}
void BLE::OnBleEndPointReceive(BLEEndPoint * endPoint, PacketBufferHandle buffer)
{
BLE * ble = reinterpret_cast<BLE *>(endPoint->mAppState);
CHIP_ERROR err = CHIP_NO_ERROR;
if (ble->mDelegate)
{
uint16_t headerSize = 0;
PacketHeader header;
err = header.Decode(buffer->Start(), buffer->DataLength(), &headerSize);
SuccessOrExit(err);
buffer->ConsumeHead(headerSize);
ble->mDelegate->OnRendezvousMessageReceived(header, Transport::PeerAddress(Transport::Type::kBle), std::move(buffer));
}
exit:
if (err != CHIP_NO_ERROR)
{
ChipLogError(Inet, "Failed to receive BLE message: %s", ErrorStr(err));
}
}
void BLE::OnBleEndPointConnectionComplete(BLEEndPoint * endPoint, BLE_ERROR err)
{
BLE * ble = reinterpret_cast<BLE *>(endPoint->mAppState);
ble->mState = State::kInitialized;
if (ble->mDelegate)
{
if (err != BLE_NO_ERROR)
{
ble->mDelegate->OnRendezvousError(err);
}
else
{
ble->mDelegate->OnRendezvousConnectionOpened();
}
}
}
void BLE::OnBleEndPointConnectionClosed(BLEEndPoint * endPoint, BLE_ERROR err)
{
BLE * ble = reinterpret_cast<BLE *>(endPoint->mAppState);
ble->mState = State::kNotReady;
if (ble->mDelegate)
{
if (err != BLE_NO_ERROR)
{
ble->mDelegate->OnRendezvousError(err);
}
ble->mDelegate->OnRendezvousConnectionClosed();
}
}
void BLE::OnNewConnection(BLEEndPoint * endPoint)
{
BLE * ble = reinterpret_cast<BLE *>(endPoint->mAppState);
CHIP_ERROR err = ble->SetEndPoint(endPoint);
if (err != CHIP_NO_ERROR)
{
ChipLogError(Ble, "Transport::BLE Init failure: %s", ErrorStr(err));
}
}
} // namespace Transport
} // namespace chip