Skip to content

Commit

Permalink
Integrate BDX and ExchangeDelegate (#8514)
Browse files Browse the repository at this point in the history
* BdxEndpoint class for ExchangeContext integration

* restyling and small comment change

* Add CONFIG_DEVICE_LAYER compile guards around SystemLayer::StartTimer

* initialize with System::Layer pointer instead of using DeviceLayer

* remove unnecessary chip::bdx:: prefix

Co-authored-by: Boris Zbarsky <[email protected]>

* Rename Endpoint to TransferFacilitator

* call WillSendMessage() for every received BDX message

* restyle BUILD.gn

* fix comment spelling

Co-authored-by: Boris Zbarsky <[email protected]>

Co-authored-by: Boris Zbarsky <[email protected]>
  • Loading branch information
holbrookt and bzbarsky-apple authored Aug 4, 2021
1 parent 5f3f225 commit 77c1c53
Show file tree
Hide file tree
Showing 3 changed files with 257 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/protocols/bdx/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ static_library("bdx") {
"BdxMessages.h",
"BdxTransferSession.cpp",
"BdxTransferSession.h",
"TransferFacilitator.cpp",
"TransferFacilitator.h",
]

cflags = [ "-Wconversion" ]
Expand Down
117 changes: 117 additions & 0 deletions src/protocols/bdx/TransferFacilitator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/*
*
* 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));
}

// Almost every BDX message will follow up with a response on the exchange. Even messages that might signify the end of a
// transfer could necessitate a response if they are received at the wrong time.
// For this reason, it is left up to the application logic to call ExchangeContext::Close() when it has determined that the
// transfer is finished.
mExchangeCtx->WillSendMessage();

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
138 changes: 138 additions & 0 deletions src/protocols/bdx/TransferFacilitator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/*
*
* 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.
*
* NOTE: It is the responsiblity of the implementer to Close the underlying ExchangeContext when it has determined that the
* transfer is finished. This class assumes that a response message will be sent for all received messages.
*
* @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

0 comments on commit 77c1c53

Please sign in to comment.