Matter SDK Coverage Report
Current view: top level - ble - BtpEngine.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 73.2 % 224 164
Test Date: 2025-01-17 19:00:11 Functions: 73.3 % 15 11

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2020-2021 Project CHIP Authors
       4              :  *    Copyright (c) 2014-2017 Nest Labs, Inc.
       5              :  *
       6              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       7              :  *    you may not use this file except in compliance with the License.
       8              :  *    You may obtain a copy of the License at
       9              :  *
      10              :  *        http://www.apache.org/licenses/LICENSE-2.0
      11              :  *
      12              :  *    Unless required by applicable law or agreed to in writing, software
      13              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      14              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15              :  *    See the License for the specific language governing permissions and
      16              :  *    limitations under the License.
      17              :  */
      18              : 
      19              : /**
      20              :  *    @file
      21              :  *      This module implements encode, decode, fragmentation and reassembly of
      22              :  *      Bluetooth Transport Layer (BTP) packet types for transport of a
      23              :  *      CHIP-over-Bluetooth Low Energy (CHIPoBLE) byte-stream over point-to-point
      24              :  *      Bluetooth Low Energy (BLE) links.
      25              :  *
      26              :  */
      27              : 
      28              : #define _CHIP_BLE_BLE_H
      29              : #include "BtpEngine.h"
      30              : 
      31              : #include <utility>
      32              : 
      33              : #include <lib/core/CHIPConfig.h>
      34              : #include <lib/support/BitFlags.h>
      35              : #include <lib/support/BufferReader.h>
      36              : #include <lib/support/CodeUtils.h>
      37              : #include <lib/support/SafeInt.h>
      38              : #include <lib/support/Span.h>
      39              : #include <lib/support/logging/CHIPLogging.h>
      40              : #include <system/SystemPacketBuffer.h>
      41              : 
      42              : #include "BleError.h"
      43              : 
      44              : // Define below to enable extremely verbose BLE-specific debug logging.
      45              : #undef CHIP_BTP_PROTOCOL_ENGINE_DEBUG_LOGGING_ENABLED
      46              : 
      47              : #ifdef CHIP_BTP_PROTOCOL_ENGINE_DEBUG_LOGGING_ENABLED
      48              : #define ChipLogDebugBtpEngine(MOD, MSG, ...) ChipLogError(MOD, MSG, ##__VA_ARGS__)
      49              : #define ChipLogDebugBufferBtpEngine(MOD, BUF) ChipLogByteSpan(MOD, ByteSpan((BUF)->Start(), (BUF)->DataLength()))
      50              : #else
      51              : #define ChipLogDebugBtpEngine(MOD, MSG, ...)
      52              : #define ChipLogDebugBufferBtpEngine(MOD, BUF)
      53              : #endif
      54              : 
      55              : namespace chip {
      56              : namespace Ble {
      57              : 
      58           15 : static inline void IncSeqNum(SequenceNumber_t & a_seq_num)
      59              : {
      60           15 :     a_seq_num = static_cast<SequenceNumber_t>(0xff & ((a_seq_num) + 1));
      61           15 : }
      62              : 
      63            8 : static inline bool DidReceiveData(BitFlags<BtpEngine::HeaderFlags> rx_flags)
      64              : {
      65           16 :     return rx_flags.HasAny(BtpEngine::HeaderFlags::kStartMessage, BtpEngine::HeaderFlags::kContinueMessage,
      66            8 :                            BtpEngine::HeaderFlags::kEndMessage);
      67              : }
      68              : 
      69              : const uint16_t BtpEngine::sDefaultFragmentSize = 20;  // 23-byte minimum ATT_MTU - 3 bytes for ATT operation header
      70              : const uint16_t BtpEngine::sMaxFragmentSize     = 244; // Maximum size of BTP segment
      71              : 
      72           18 : CHIP_ERROR BtpEngine::Init(void * an_app_state, bool expect_first_ack)
      73              : {
      74           18 :     mAppState              = an_app_state;
      75           18 :     mRxState               = kState_Idle;
      76           18 :     mRxBuf                 = nullptr;
      77           18 :     mRxNewestUnackedSeqNum = 0;
      78           18 :     mRxOldestUnackedSeqNum = 0;
      79           18 :     mRxFragmentSize        = sDefaultFragmentSize;
      80           18 :     mTxState               = kState_Idle;
      81           18 :     mTxBuf                 = nullptr;
      82           18 :     mTxFragmentSize        = sDefaultFragmentSize;
      83           18 :     mRxCharCount           = 0;
      84           18 :     mRxPacketCount         = 0;
      85           18 :     mTxCharCount           = 0;
      86           18 :     mTxPacketCount         = 0;
      87           18 :     mTxNewestUnackedSeqNum = 0;
      88           18 :     mTxOldestUnackedSeqNum = 0;
      89              : 
      90           18 :     if (expect_first_ack)
      91              :     {
      92           12 :         mTxNextSeqNum = 1;
      93           12 :         mExpectingAck = true;
      94           12 :         mRxNextSeqNum = 0;
      95              :     }
      96              :     else
      97              :     {
      98            6 :         mTxNextSeqNum = 0;
      99            6 :         mExpectingAck = false;
     100            6 :         mRxNextSeqNum = 1;
     101              :     }
     102              : 
     103           18 :     return CHIP_NO_ERROR;
     104              : }
     105              : 
     106            7 : SequenceNumber_t BtpEngine::GetAndIncrementNextTxSeqNum()
     107              : {
     108            7 :     SequenceNumber_t ret = mTxNextSeqNum;
     109              : 
     110              :     // If not already expecting ack...
     111            7 :     if (!mExpectingAck)
     112              :     {
     113            3 :         mExpectingAck          = true;
     114            3 :         mTxOldestUnackedSeqNum = mTxNextSeqNum;
     115              :     }
     116              : 
     117              :     // Update newest unacknowledged sequence number.
     118            7 :     mTxNewestUnackedSeqNum = mTxNextSeqNum;
     119              : 
     120              :     // Increment mTxNextSeqNum.
     121            7 :     IncSeqNum(mTxNextSeqNum);
     122              : 
     123            7 :     return ret;
     124              : }
     125              : 
     126            0 : SequenceNumber_t BtpEngine::GetAndRecordRxAckSeqNum()
     127              : {
     128            0 :     SequenceNumber_t ret = mRxNewestUnackedSeqNum;
     129              : 
     130            0 :     mRxNewestUnackedSeqNum = mRxNextSeqNum;
     131            0 :     mRxOldestUnackedSeqNum = mRxNextSeqNum;
     132              : 
     133            0 :     return ret;
     134              : }
     135              : 
     136            2 : bool BtpEngine::HasUnackedData() const
     137              : {
     138            2 :     return (mRxOldestUnackedSeqNum != mRxNextSeqNum);
     139              : }
     140              : 
     141            0 : bool BtpEngine::IsValidAck(SequenceNumber_t ack_num) const
     142              : {
     143              :     ChipLogDebugBtpEngine(Ble, "entered IsValidAck, ack = %u, oldest = %u, newest = %u", ack_num, mTxOldestUnackedSeqNum,
     144              :                           mTxNewestUnackedSeqNum);
     145              : 
     146              :     // Return false if not awaiting any ack.
     147            0 :     if (!mExpectingAck)
     148              :     {
     149              :         ChipLogDebugBtpEngine(Ble, "unexpected ack is invalid");
     150            0 :         return false;
     151              :     }
     152              : 
     153              :     // Assumption: maximum valid sequence number equals maximum value of SequenceNumber_t.
     154              : 
     155            0 :     if (mTxNewestUnackedSeqNum >= mTxOldestUnackedSeqNum) // If current unacked interval does NOT wrap...
     156              :     {
     157            0 :         return (ack_num <= mTxNewestUnackedSeqNum && ack_num >= mTxOldestUnackedSeqNum);
     158              :     }
     159              :     // Else, if current unacked interval DOES wrap...
     160            0 :     return (ack_num <= mTxNewestUnackedSeqNum || ack_num >= mTxOldestUnackedSeqNum);
     161              : }
     162              : 
     163            0 : CHIP_ERROR BtpEngine::HandleAckReceived(SequenceNumber_t ack_num)
     164              : {
     165              :     ChipLogDebugBtpEngine(Ble, "entered HandleAckReceived, ack_num = %u", ack_num);
     166              : 
     167              :     // Ensure ack_num falls within range of ack values we're expecting.
     168            0 :     VerifyOrReturnError(IsValidAck(ack_num), BLE_ERROR_INVALID_ACK);
     169              : 
     170            0 :     if (mTxNewestUnackedSeqNum == ack_num) // If ack is for newest outstanding unacknowledged fragment...
     171              :     {
     172            0 :         mTxOldestUnackedSeqNum = ack_num;
     173              : 
     174              :         // All outstanding fragments have been acknowledged.
     175            0 :         mExpectingAck = false;
     176              :     }
     177              :     else // If ack is valid, but not for newest outstanding unacknowledged fragment...
     178              :     {
     179              :         // Update newest unacknowledged fragment to one past that which was just acknowledged.
     180            0 :         mTxOldestUnackedSeqNum = ack_num;
     181            0 :         IncSeqNum(mTxOldestUnackedSeqNum);
     182              :     }
     183              : 
     184            0 :     return CHIP_NO_ERROR;
     185              : }
     186              : 
     187              : // Calling convention:
     188              : //   EncodeStandAloneAck may only be called if data arg is committed for immediate, synchronous subsequent transmission.
     189            0 : CHIP_ERROR BtpEngine::EncodeStandAloneAck(const PacketBufferHandle & data)
     190              : {
     191              :     // Ensure enough headroom exists for the lower BLE layers.
     192            0 :     VerifyOrReturnError(data->EnsureReservedSize(CHIP_CONFIG_BLE_PKT_RESERVED_SIZE), CHIP_ERROR_NO_MEMORY);
     193              : 
     194              :     // Ensure enough space for standalone ack payload.
     195            0 :     VerifyOrReturnError(data->MaxDataLength() >= kTransferProtocolStandaloneAckHeaderSize, CHIP_ERROR_NO_MEMORY);
     196            0 :     uint8_t * characteristic = data->Start();
     197              : 
     198              :     // Since there's no preexisting message payload, we can write BTP header without adjusting data start pointer.
     199            0 :     characteristic[0] = static_cast<uint8_t>(HeaderFlags::kFragmentAck);
     200              : 
     201              :     // Acknowledge most recently received sequence number.
     202            0 :     characteristic[1] = GetAndRecordRxAckSeqNum();
     203              :     ChipLogDebugBtpEngine(Ble, "===> encoded stand-alone ack = %u", characteristic[1]);
     204              : 
     205              :     // Include sequence number for stand-alone ack itself.
     206            0 :     characteristic[2] = GetAndIncrementNextTxSeqNum();
     207              : 
     208              :     // Set ack payload data length.
     209            0 :     data->SetDataLength(kTransferProtocolStandaloneAckHeaderSize);
     210              : 
     211            0 :     return CHIP_NO_ERROR;
     212              : }
     213              : 
     214              : // Calling convention:
     215              : //   BtpEngine does not retain ownership of reassembled messages, layer above needs to free when done.
     216              : //
     217              : //   BtpEngine does not reset itself on error. Upper layer should free outbound message and inbound reassembly buffers
     218              : //   if there is a problem.
     219              : 
     220              : // HandleCharacteristicReceived():
     221              : //
     222              : //   Non-NULL characteristic data arg is always either designated as or appended to the message reassembly buffer,
     223              : //   or freed if it holds a stand-alone ack. In all cases, caller must clear its reference to data arg when this
     224              : //   function returns.
     225              : //
     226              : //   Upper layer must immediately clean up and reinitialize protocol engine if returned err != CHIP_NO_ERROR.
     227            8 : CHIP_ERROR BtpEngine::HandleCharacteristicReceived(System::PacketBufferHandle && data, SequenceNumber_t & receivedAck,
     228              :                                                    bool & didReceiveAck)
     229              : {
     230            8 :     CHIP_ERROR err = CHIP_NO_ERROR;
     231            8 :     BitFlags<HeaderFlags> rx_flags;
     232              : 
     233            8 :     VerifyOrExit(!data.IsNull(), err = CHIP_ERROR_INVALID_ARGUMENT);
     234              : 
     235              :     { // Scope for reader, so we can do the VerifyOrExit above.
     236              :         // BLE data uses little-endian byte order.
     237            8 :         Encoding::LittleEndian::Reader reader(data->Start(), data->DataLength());
     238              : 
     239            8 :         mRxCharCount++;
     240              : 
     241              :         // Get header flags, always in first byte.
     242            8 :         err = reader.Read8(rx_flags.RawStorage()).StatusCode();
     243            8 :         SuccessOrExit(err);
     244              : 
     245            8 :         didReceiveAck = rx_flags.Has(HeaderFlags::kFragmentAck);
     246              : 
     247              :         // Get ack number, if any.
     248            8 :         if (didReceiveAck)
     249              :         {
     250            0 :             err = reader.Read8(&receivedAck).StatusCode();
     251            0 :             SuccessOrExit(err);
     252              : 
     253            0 :             err = HandleAckReceived(receivedAck);
     254            0 :             SuccessOrExit(err);
     255              :         }
     256              : 
     257              :         // Get sequence number.
     258            8 :         err = reader.Read8(&mRxNewestUnackedSeqNum).StatusCode();
     259            8 :         SuccessOrExit(err);
     260              : 
     261              :         // Verify that received sequence number is the next one we'd expect.
     262            8 :         VerifyOrExit(mRxNewestUnackedSeqNum == mRxNextSeqNum, err = BLE_ERROR_INVALID_BTP_SEQUENCE_NUMBER);
     263              : 
     264              :         // Increment next expected rx sequence number.
     265            8 :         IncSeqNum(mRxNextSeqNum);
     266              : 
     267              :         // If fragment was stand-alone ack, we're done here; no payload for message reassembler.
     268            8 :         if (!DidReceiveData(rx_flags))
     269              :         {
     270            0 :             ExitNow();
     271              :         }
     272              : 
     273              :         // Truncate the incoming fragment length by the mRxFragmentSize as the negotiated
     274              :         // mRxFragmentSize may be smaller than the characteristic size.  Make sure
     275              :         // we're not truncating to a data length smaller than what we have already consumed.
     276            8 :         VerifyOrExit(reader.OctetsRead() <= mRxFragmentSize, err = BLE_ERROR_REASSEMBLER_INCORRECT_STATE);
     277            8 :         data->SetDataLength(std::min(data->DataLength(), static_cast<size_t>(mRxFragmentSize)));
     278              : 
     279              :         // Now mark the bytes we consumed as consumed.
     280            8 :         data->ConsumeHead(static_cast<uint16_t>(reader.OctetsRead()));
     281              : 
     282              :         ChipLogDebugBtpEngine(Ble, ">>> BTP reassembler received data:");
     283              :         ChipLogDebugBufferBtpEngine(Ble, data);
     284              :     }
     285              : 
     286            8 :     if (mRxState == kState_Idle)
     287              :     {
     288              :         // We need a new reader, because the state of our outer reader no longer
     289              :         // matches the state of the packetbuffer, both in terms of start
     290              :         // position and available length.
     291            5 :         Encoding::LittleEndian::Reader startReader(data->Start(), data->DataLength());
     292              : 
     293              :         // Verify StartMessage header flag set.
     294            5 :         VerifyOrExit(rx_flags.Has(HeaderFlags::kStartMessage), err = BLE_ERROR_INVALID_BTP_HEADER_FLAGS);
     295              : 
     296            5 :         err = startReader.Read16(&mRxLength).StatusCode();
     297            5 :         SuccessOrExit(err);
     298              : 
     299            5 :         mRxState = kState_InProgress;
     300              : 
     301            5 :         data->ConsumeHead(static_cast<uint16_t>(startReader.OctetsRead()));
     302              : 
     303              :         // Create a new buffer for use as the Rx re-assembly area.
     304            5 :         mRxBuf = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize);
     305              : 
     306            5 :         VerifyOrExit(!mRxBuf.IsNull(), err = CHIP_ERROR_NO_MEMORY);
     307              : 
     308            5 :         mRxBuf->AddToEnd(std::move(data));
     309            5 :         mRxBuf->CompactHead(); // will free 'data' and adjust rx buf's end/length
     310              : 
     311              :         // For now, limit BtpEngine message size to max length of 1 pbuf, as we do for chip messages sent via IP.
     312              :         // TODO add support for BtpEngine messages longer than 1 pbuf
     313            5 :         VerifyOrExit(!mRxBuf->HasChainedBuffer(), err = CHIP_ERROR_INBOUND_MESSAGE_TOO_BIG);
     314              :     }
     315            3 :     else if (mRxState == kState_InProgress)
     316              :     {
     317              :         // Verify StartMessage header flag NOT set, since we're in the middle of receiving a message.
     318            3 :         VerifyOrExit(!rx_flags.Has(HeaderFlags::kStartMessage), err = BLE_ERROR_INVALID_BTP_HEADER_FLAGS);
     319              : 
     320              :         // Verify ContinueMessage or EndMessage header flag set.
     321            3 :         VerifyOrExit(rx_flags.HasAny(HeaderFlags::kContinueMessage, HeaderFlags::kEndMessage),
     322              :                      err = BLE_ERROR_INVALID_BTP_HEADER_FLAGS);
     323              : 
     324              :         // Add received fragment to reassembled message buffer.
     325            3 :         mRxBuf->AddToEnd(std::move(data));
     326            3 :         mRxBuf->CompactHead(); // will free 'data' and adjust rx buf's end/length
     327              : 
     328              :         // For now, limit BtpEngine message size to max length of 1 pbuf, as we do for chip messages sent via IP.
     329              :         // TODO add support for BtpEngine messages longer than 1 pbuf
     330            3 :         VerifyOrExit(!mRxBuf->HasChainedBuffer(), err = CHIP_ERROR_INBOUND_MESSAGE_TOO_BIG);
     331              :     }
     332              :     else
     333              :     {
     334            0 :         err = BLE_ERROR_REASSEMBLER_INCORRECT_STATE;
     335            0 :         ExitNow();
     336              :     }
     337              : 
     338            8 :     if (rx_flags.Has(HeaderFlags::kEndMessage))
     339              :     {
     340              :         // Trim remainder, if any, of the received packet buffer based on sender-specified length of reassembled message.
     341            5 :         VerifyOrExit(CanCastTo<uint16_t>(mRxBuf->DataLength()), err = CHIP_ERROR_MESSAGE_TOO_LONG);
     342            5 :         int padding = static_cast<uint16_t>(mRxBuf->DataLength()) - mRxLength;
     343              : 
     344            5 :         if (padding > 0)
     345              :         {
     346            0 :             mRxBuf->SetDataLength(static_cast<size_t>(mRxLength));
     347              :         }
     348              : 
     349              :         // Ensure all received fragments add up to sender-specified total message size.
     350            5 :         VerifyOrExit(mRxBuf->DataLength() == mRxLength, err = BLE_ERROR_REASSEMBLER_MISSING_DATA);
     351              : 
     352              :         // We've reassembled the entire message.
     353            5 :         mRxState = kState_Complete;
     354            5 :         mRxPacketCount++;
     355              :     }
     356              : 
     357            3 : exit:
     358            8 :     if (err != CHIP_NO_ERROR)
     359              :     {
     360            0 :         mRxState = kState_Error;
     361              : 
     362              :         // Dump protocol engine state, plus header flags and received data length.
     363            0 :         ChipLogError(Ble, "HandleCharacteristicReceived failed, err = %" CHIP_ERROR_FORMAT ", rx_flags = %u", err.Format(),
     364              :                      rx_flags.Raw());
     365            0 :         if (didReceiveAck)
     366              :         {
     367            0 :             ChipLogError(Ble, "With rx'd ack = %u", receivedAck);
     368              :         }
     369            0 :         if (!mRxBuf.IsNull())
     370              :         {
     371            0 :             ChipLogError(Ble, "With rx buf data length = %u", static_cast<unsigned>(mRxBuf->DataLength()));
     372              :         }
     373            0 :         LogState();
     374              : 
     375            0 :         if (!data.IsNull()) // NOLINT(bugprone-use-after-move)
     376              :         {
     377              :             // Tack received data onto rx buffer, to be freed when end point resets protocol engine on close.
     378            0 :             if (!mRxBuf.IsNull())
     379              :             {
     380            0 :                 mRxBuf->AddToEnd(std::move(data));
     381              :             }
     382              :             else
     383              :             {
     384            0 :                 mRxBuf = std::move(data);
     385              :             }
     386              :         }
     387              :     }
     388              : 
     389            8 :     return err;
     390              : }
     391              : 
     392           14 : PacketBufferHandle BtpEngine::TakeRxPacket()
     393              : {
     394           14 :     if (mRxState == kState_Complete)
     395              :     {
     396            2 :         mRxState = kState_Idle;
     397              :     }
     398           14 :     return std::move(mRxBuf);
     399              : }
     400              : 
     401              : // Calling convention:
     402              : //   May only be called if data arg is committed for immediate, synchronous subsequent transmission.
     403              : //   Returns false on error. Caller must free data arg on error.
     404            7 : bool BtpEngine::HandleCharacteristicSend(System::PacketBufferHandle data, bool send_ack)
     405              : {
     406              :     uint8_t * characteristic;
     407            7 :     mTxCharCount++;
     408              : 
     409            7 :     if (send_ack && !HasUnackedData())
     410              :     {
     411            0 :         ChipLogError(Ble, "HandleCharacteristicSend: send_ack true, but nothing to acknowledge.");
     412            0 :         return false;
     413              :     }
     414              : 
     415            7 :     if (mTxState == kState_Idle)
     416              :     {
     417            4 :         if (data.IsNull())
     418              :         {
     419            0 :             return false;
     420              :         }
     421              : 
     422            4 :         mTxBuf   = std::move(data);
     423            4 :         mTxState = kState_InProgress;
     424            4 :         VerifyOrReturnError(CanCastTo<uint16_t>(mTxBuf->DataLength()), false);
     425            4 :         mTxLength = static_cast<uint16_t>(mTxBuf->DataLength());
     426              : 
     427              :         ChipLogDebugBtpEngine(Ble, ">>> CHIPoBle preparing to send whole message:");
     428              :         ChipLogDebugBufferBtpEngine(Ble, mTxBuf);
     429              : 
     430              :         // Determine fragment header size.
     431            4 :         uint8_t header_size =
     432              :             send_ack ? kTransferProtocolMaxHeaderSize : (kTransferProtocolMaxHeaderSize - kTransferProtocolAckSize);
     433              : 
     434              :         // Ensure enough headroom exists for the BTP header, and any headroom needed by the lower BLE layers.
     435            4 :         if (!mTxBuf->EnsureReservedSize(header_size + CHIP_CONFIG_BLE_PKT_RESERVED_SIZE))
     436              :         {
     437              :             // handle error
     438            0 :             ChipLogError(Ble, "HandleCharacteristicSend: not enough headroom");
     439            0 :             mTxState = kState_Error;
     440            0 :             mTxBuf   = nullptr; // Avoid double-free after assignment above, as caller frees data on error.
     441              : 
     442            0 :             return false;
     443              :         }
     444              : 
     445              :         // prepend header.
     446            4 :         characteristic = mTxBuf->Start();
     447            4 :         characteristic -= header_size;
     448            4 :         mTxBuf->SetStart(characteristic);
     449            4 :         uint8_t cursor = 1; // first position past header flags byte
     450            4 :         BitFlags<HeaderFlags> headerFlags(HeaderFlags::kStartMessage);
     451              : 
     452            4 :         if (send_ack)
     453              :         {
     454            0 :             headerFlags.Set(HeaderFlags::kFragmentAck);
     455            0 :             characteristic[cursor++] = GetAndRecordRxAckSeqNum();
     456              :             ChipLogDebugBtpEngine(Ble, "===> encoded piggybacked ack, ack_num = %u", characteristic[cursor - 1]);
     457              :         }
     458              : 
     459            4 :         characteristic[cursor++] = GetAndIncrementNextTxSeqNum();
     460            4 :         characteristic[cursor++] = static_cast<uint8_t>(mTxLength & 0xff);
     461            4 :         characteristic[cursor++] = static_cast<uint8_t>(mTxLength >> 8);
     462              : 
     463            4 :         if ((mTxLength + cursor) <= mTxFragmentSize)
     464              :         {
     465            2 :             mTxBuf->SetDataLength(static_cast<uint16_t>(mTxLength + cursor));
     466            2 :             mTxLength = 0;
     467            2 :             headerFlags.Set(HeaderFlags::kEndMessage);
     468            2 :             mTxState = kState_Complete;
     469            2 :             mTxPacketCount++;
     470              :         }
     471              :         else
     472              :         {
     473            2 :             mTxBuf->SetDataLength(mTxFragmentSize);
     474            2 :             mTxLength = static_cast<uint16_t>((mTxLength + cursor) - mTxFragmentSize);
     475              :         }
     476              : 
     477            4 :         characteristic[0] = headerFlags.Raw();
     478              :         ChipLogDebugBtpEngine(Ble, ">>> CHIPoBle preparing to send first fragment:");
     479              :         ChipLogDebugBufferBtpEngine(Ble, mTxBuf);
     480              :     }
     481            3 :     else if (mTxState == kState_InProgress)
     482              :     {
     483            3 :         if (!data.IsNull())
     484              :         {
     485            0 :             return false;
     486              :         }
     487              : 
     488              :         // advance past the previous fragment
     489            3 :         characteristic = mTxBuf->Start();
     490            3 :         characteristic += mTxFragmentSize;
     491              : 
     492              :         // prepend header
     493            3 :         characteristic -= send_ack ? kTransferProtocolMidFragmentMaxHeaderSize
     494              :                                    : (kTransferProtocolMidFragmentMaxHeaderSize - kTransferProtocolAckSize);
     495            3 :         mTxBuf->SetStart(characteristic);
     496            3 :         uint8_t cursor = 1; // first position past header flags byte
     497              : 
     498            3 :         BitFlags<HeaderFlags> headerFlags(HeaderFlags::kContinueMessage);
     499              : 
     500            3 :         if (send_ack)
     501              :         {
     502            0 :             headerFlags.Set(HeaderFlags::kFragmentAck);
     503            0 :             characteristic[cursor++] = GetAndRecordRxAckSeqNum();
     504              :             ChipLogDebugBtpEngine(Ble, "===> encoded piggybacked ack, ack_num = %u", characteristic[cursor - 1]);
     505              :         }
     506              : 
     507            3 :         characteristic[cursor++] = GetAndIncrementNextTxSeqNum();
     508              : 
     509            3 :         if ((mTxLength + cursor) <= mTxFragmentSize)
     510              :         {
     511            2 :             mTxBuf->SetDataLength(static_cast<uint16_t>(mTxLength + cursor));
     512            2 :             mTxLength = 0;
     513            2 :             headerFlags.Set(HeaderFlags::kEndMessage);
     514            2 :             mTxState = kState_Complete;
     515            2 :             mTxPacketCount++;
     516              :         }
     517              :         else
     518              :         {
     519            1 :             mTxBuf->SetDataLength(mTxFragmentSize);
     520            1 :             mTxLength = static_cast<uint16_t>((mTxLength + cursor) - mTxFragmentSize);
     521              :         }
     522              : 
     523            3 :         characteristic[0] = headerFlags.Raw();
     524              :         ChipLogDebugBtpEngine(Ble, ">>> CHIPoBle preparing to send additional fragment:");
     525              :         ChipLogDebugBufferBtpEngine(Ble, mTxBuf);
     526              :     }
     527              :     else
     528              :     {
     529              :         // Invalid tx state.
     530            0 :         return false;
     531              :     }
     532              : 
     533            7 :     return true;
     534              : }
     535              : 
     536           12 : PacketBufferHandle BtpEngine::TakeTxPacket()
     537              : {
     538           12 :     if (mTxState == kState_Complete)
     539              :     {
     540            1 :         mTxState = kState_Idle;
     541              :     }
     542           12 :     return std::move(mTxBuf);
     543              : }
     544              : 
     545           12 : void BtpEngine::LogState() const
     546              : {
     547           12 :     ChipLogError(Ble, "mAppState: %p", mAppState);
     548              : 
     549           12 :     ChipLogError(Ble, "mRxFragmentSize: %d", mRxFragmentSize);
     550           12 :     ChipLogError(Ble, "mRxState: %d", mRxState);
     551           12 :     ChipLogError(Ble, "mRxBuf: %d", !mRxBuf.IsNull());
     552           12 :     ChipLogError(Ble, "mRxNextSeqNum: %d", mRxNextSeqNum);
     553           12 :     ChipLogError(Ble, "mRxNewestUnackedSeqNum: %d", mRxNewestUnackedSeqNum);
     554           12 :     ChipLogError(Ble, "mRxOldestUnackedSeqNum: %d", mRxOldestUnackedSeqNum);
     555           12 :     ChipLogError(Ble, "mRxCharCount: %d", mRxCharCount);
     556           12 :     ChipLogError(Ble, "mRxPacketCount: %d", mRxPacketCount);
     557              : 
     558           12 :     ChipLogError(Ble, "mTxFragmentSize: %d", mTxFragmentSize);
     559           12 :     ChipLogError(Ble, "mTxState: %d", mTxState);
     560           12 :     ChipLogError(Ble, "mTxBuf: %d", !mTxBuf.IsNull());
     561           12 :     ChipLogError(Ble, "mTxNextSeqNum: %d", mTxNextSeqNum);
     562           12 :     ChipLogError(Ble, "mTxNewestUnackedSeqNum: %d", mTxNewestUnackedSeqNum);
     563           12 :     ChipLogError(Ble, "mTxOldestUnackedSeqNum: %d", mTxOldestUnackedSeqNum);
     564           12 :     ChipLogError(Ble, "mTxCharCount: %d", mTxCharCount);
     565           12 :     ChipLogError(Ble, "mTxPacketCount: %d", mTxPacketCount);
     566           12 : }
     567              : 
     568            4 : void BtpEngine::LogStateDebug() const
     569              : {
     570              : #ifdef CHIP_BTP_PROTOCOL_ENGINE_DEBUG_LOGGING_ENABLED
     571              :     LogState();
     572              : #endif
     573            4 : }
     574              : 
     575              : } /* namespace Ble */
     576              : } /* namespace chip */
        

Generated by: LCOV version 2.0-1