Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integrate BDX and ExchangeDelegate #8514

Merged
merged 9 commits into from
Aug 4, 2021
2 changes: 2 additions & 0 deletions src/protocols/bdx/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ static_library("bdx") {
output_name = "libBdx"

sources = [
"TransferFacilitator.cpp",
"TransferFacilitator.h",
"BdxMessages.cpp",
"BdxMessages.h",
"BdxTransferSession.cpp",
Expand Down
110 changes: 110 additions & 0 deletions src/protocols/bdx/TransferFacilitator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
*
* Copyright (c) 2021 Project CHIP Authors
*
* 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 "TransferFacilitator.h"

#include <core/CHIPError.h>
#include <messaging/ExchangeContext.h>
#include <messaging/ExchangeDelegate.h>
#include <platform/CHIPDeviceLayer.h>
#include <protocols/bdx/BdxTransferSession.h>
#include <support/BitFlags.h>
#include <system/SystemClock.h>
#include <system/SystemLayer.h>

namespace chip {
namespace bdx {

CHIP_ERROR TransferFacilitator::OnMessageReceived(chip::Messaging::ExchangeContext * ec, const chip::PacketHeader & packetHeader,
const chip::PayloadHeader & payloadHeader,
chip::System::PacketBufferHandle && payload)
{
if (mExchangeCtx == nullptr)
{
mExchangeCtx = ec;
}

ChipLogDetail(BDX, "%s: message 0x%x protocol %u", __FUNCTION__, static_cast<uint8_t>(payloadHeader.GetMessageType()),
payloadHeader.GetProtocolID().GetProtocolId());
CHIP_ERROR err =
mTransfer.HandleMessageReceived(payloadHeader, std::move(payload), System::Platform::Clock::GetMonotonicMilliseconds());
if (err != CHIP_NO_ERROR)
{
ChipLogError(BDX, "failed to handle message: %s", ErrorStr(err));
}
return err;
}

void TransferFacilitator::OnResponseTimeout(Messaging::ExchangeContext * ec)
{
ChipLogError(BDX, "%s, ec: %d", __FUNCTION__, ec->GetExchangeId());
mExchangeCtx = nullptr;
mTransfer.Reset();
}

void TransferFacilitator::PollTimerHandler(chip::System::Layer * systemLayer, void * appState, CHIP_ERROR error)
{
VerifyOrReturn(appState != nullptr);
static_cast<TransferFacilitator *>(appState)->PollForOutput();
}

void TransferFacilitator::PollForOutput()
{
TransferSession::OutputEvent outEvent;
mTransfer.PollOutput(outEvent, System::Platform::Clock::GetMonotonicMilliseconds());
HandleTransferSessionOutput(outEvent);

VerifyOrReturn(mSystemLayer != nullptr, ChipLogError(BDX, "%s mSystemLayer is null", __FUNCTION__));
mSystemLayer->StartTimer(mPollFreqMs, PollTimerHandler, this);
}

void TransferFacilitator::ScheduleImmediatePoll()
{
VerifyOrReturn(mSystemLayer != nullptr, ChipLogError(BDX, "%s mSystemLayer is null", __FUNCTION__));
mSystemLayer->StartTimer(kImmediatePollDelayMs, PollTimerHandler, this);
}

CHIP_ERROR Responder::PrepareForTransfer(System::Layer * layer, TransferRole role, BitFlags<TransferControlFlags> xferControlOpts,
uint16_t maxBlockSize, uint32_t timeoutMs, uint32_t pollFreqMs)
{
VerifyOrReturnError(layer != nullptr, CHIP_ERROR_INVALID_ARGUMENT);

mPollFreqMs = pollFreqMs;
mSystemLayer = layer;

ReturnErrorOnFailure(mTransfer.WaitForTransfer(role, xferControlOpts, maxBlockSize, timeoutMs));

mSystemLayer->StartTimer(mPollFreqMs, PollTimerHandler, this);
return CHIP_NO_ERROR;
}

CHIP_ERROR Initiator::InitiateTransfer(System::Layer * layer, TransferRole role, const TransferSession::TransferInitData & initData,
uint32_t timeoutMs, uint32_t pollFreqMs)
{
VerifyOrReturnError(layer != nullptr, CHIP_ERROR_INVALID_ARGUMENT);

mPollFreqMs = pollFreqMs;
mSystemLayer = layer;

ReturnErrorOnFailure(mTransfer.StartTransfer(role, initData, timeoutMs));

mSystemLayer->StartTimer(mPollFreqMs, PollTimerHandler, this);
return CHIP_NO_ERROR;
}

} // namespace bdx
} // namespace chip
135 changes: 135 additions & 0 deletions src/protocols/bdx/TransferFacilitator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
/*
*
* Copyright (c) 2021 Project CHIP Authors
*
* 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 BdxEndpoint.h
*
* This file defines interfaces for connecting the BDX state machine (TransferSession) to the messaging layer.
*/

#include <core/CHIPError.h>
#include <messaging/ExchangeContext.h>
#include <messaging/ExchangeDelegate.h>
#include <protocols/bdx/BdxTransferSession.h>
#include <support/BitFlags.h>
#include <system/SystemLayer.h>

#pragma once

namespace chip {
namespace bdx {

/**
* An abstract class with methods for handling BDX messages from an ExchangeContext and polling a TransferSession state machine.
*
* This class does not define any methods for beginning a transfer or initializing the underlying TransferSession object (see
* Initiator and Responder below).
* This class contains a repeating timer which regurlaly polls the TransferSession state machine.
* A CHIP node may have many TransferFacilitator instances but only one TransferFacilitator should be used for each BDX transfer.
*/
class TransferFacilitator : public Messaging::ExchangeDelegate
{
public:
TransferFacilitator() : mExchangeCtx(nullptr), mSystemLayer(nullptr), mPollFreqMs(kDefaultPollFreqMs) {}
~TransferFacilitator() = default;

private:
// Inherited from ExchangeContext
CHIP_ERROR OnMessageReceived(chip::Messaging::ExchangeContext * ec, const chip::PacketHeader & packetHeader,
const chip::PayloadHeader & payloadHeader, chip::System::PacketBufferHandle && payload) override;
void OnResponseTimeout(Messaging::ExchangeContext * ec) override;

/**
* This method should be implemented to contain business-logic handling of BDX messages and other TransferSession events.
*
* @param[in] event An OutputEvent that contains output from the TransferSession object.
*/
virtual void HandleTransferSessionOutput(TransferSession::OutputEvent & event) = 0;

protected:
/**
* The callback for when the poll timer expires. The poll timer regulates how often the TransferSession is polled.
*/
static void PollTimerHandler(chip::System::Layer * systemLayer, void * appState, CHIP_ERROR error);

/**
* Polls the TransferSession object and calls HandleTransferSessionOutput.
*/
void PollForOutput();

/**
* Starts the poll timer with a very short timeout.
*/
void ScheduleImmediatePoll();

TransferSession mTransfer;
Messaging::ExchangeContext * mExchangeCtx;
System::Layer * mSystemLayer;
uint32_t mPollFreqMs;
static constexpr uint32_t kDefaultPollFreqMs = 500;
static constexpr uint32_t kImmediatePollDelayMs = 1;
};

/**
* A TransferFacilitator that is initialized to respond to an incoming BDX transfer request.
*
* Provides a method for initializing the TransferSession member but still needs to be extended to implement
* HandleTransferSessionOutput. It is intended that this class will be used as a delegate for handling an unsolicited BDX message.
*/
class Responder : public TransferFacilitator
{
public:
/**
* Initialize the TransferSession state machine to be ready for an incoming transfer request, and start the polling timer.
*
* @param[in] layer A System::Layer pointer to use to start the polling timer
* @param[in] role The role of the Responder: Sender or Receiver of BDX data
* @param[in] xferControlOpts Supported transfer modes (see TransferControlFlags)
* @param[in] maxBlockSize The supported maximum size of BDX Block data
* @param[in] timeoutMs The chosen timeout delay for the BDX transfer in milliseconds
* @param[in] pollFreqMs The period for the TransferSession poll timer in milliseconds
*/
CHIP_ERROR PrepareForTransfer(System::Layer * layer, TransferRole role, BitFlags<TransferControlFlags> xferControlOpts,
uint16_t maxBlockSize, uint32_t timeoutMs,
uint32_t pollFreqMs = TransferFacilitator::kDefaultPollFreqMs);
};

/**
* A TransferFacilitator that initiates a BDX transfer.
*
* Provides a method for initializing the TransferSession member (thus beginning the transfer) but still needs to be extended to
* implement HandleTransferSessionOutput.
*/
class Initiator : public TransferFacilitator
{
public:
/**
* Initialize the TransferSession state machine to prepare a transfer request message (does not send the message) and start the
* poll timer.
*
* @param[in] layer A System::Layer pointer to use to start the polling timer
* @param[in] role The role of the Initiator: Sender or Receiver of BDX data
* @param[in] initData Data needed for preparing a transfer request BDX message
* @param[in] timeoutMs The chosen timeout delay for the BDX transfer in milliseconds
* @param[in] pollFreqMs The period for the TransferSession poll timer in milliseconds
*/
CHIP_ERROR InitiateTransfer(System::Layer * layer, TransferRole role, const TransferSession::TransferInitData & initData,
uint32_t timeoutMs, uint32_t pollFreqMs = TransferFacilitator::kDefaultPollFreqMs);
};

} // namespace bdx
} // namespace chip