LCOV - code coverage report
Current view: top level - ble - BtpEngine.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 0 228 0.0 %
Date: 2024-02-15 08:20:41 Functions: 0 16 0.0 %

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

Generated by: LCOV version 1.14