Matter SDK Coverage Report
Current view: top level - ble - BtpEngine.cpp (source / functions) Coverage Total Hit
Test: SHA:704d97f9c619242ad76fcf75aeabc67802fa72d4 Lines: 100.0 % 224 224
Test Date: 2026-05-18 07:37:39 Functions: 100.0 % 15 15

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

Generated by: LCOV version 2.0-1