3 * Copyright (c) 2020-2021 Project CHIP Authors
4 * Copyright (c) 2014-2017 Nest Labs, Inc.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * This file implements a Bluetooth Low Energy (BLE) connection
22 * endpoint abstraction for the byte-streaming,
23 * connection-oriented CHIP over Bluetooth Low Energy (CHIPoBLE)
24 * Bluetooth Transport Protocol (BTP).
28 #ifndef __STDC_LIMIT_MACROS
29 #define __STDC_LIMIT_MACROS
34 #include <ble/BleConfig.h>
36 #if CONFIG_NETWORK_LAYER_BLE
37 #include <core/CHIPConfig.h>
39 #include <support/BitFlags.h>
40 #include <support/CHIPFaultInjection.h>
41 #include <support/CodeUtils.h>
42 #include <support/logging/CHIPLogging.h>
44 #include <ble/BLEEndPoint.h>
45 #include <ble/BleLayer.h>
46 #include <ble/BtpEngine.h>
47 #if CHIP_ENABLE_CHIPOBLE_TEST
48 #include "BtpEngineTest.h"
53 // Define below to enable extremely verbose, BLE end point-specific debug logging.
54 #undef CHIP_BLE_END_POINT_DEBUG_LOGGING_ENABLED
56 #ifdef CHIP_BLE_END_POINT_DEBUG_LOGGING_ENABLED
57 #define ChipLogDebugBleEndPoint(MOD, MSG, ...) ChipLogError(MOD, MSG, ## __VA_ARGS__)
59 #define ChipLogDebugBleEndPoint(MOD, MSG, ...)
63 * @def BLE_CONFIG_IMMEDIATE_ACK_WINDOW_THRESHOLD
66 * If an end point's receive window drops equal to or below this value, it will send an immediate acknowledgement
67 * packet to re-open its window instead of waiting for the send-ack timer to expire.
70 #define BLE_CONFIG_IMMEDIATE_ACK_WINDOW_THRESHOLD 1
73 * @def BLE_CONNECT_TIMEOUT_MS
76 * This is the amount of time, in milliseconds, after a BLE end point initiates a transport protocol connection
77 * or receives the initial portion of a connect request before the end point will automatically release its BLE
78 * connection and free itself if the transport connection has not been established.
81 #define BLE_CONNECT_TIMEOUT_MS 15000 // 15 seconds
84 * @def BLE_UNSUBSCRIBE_TIMEOUT_MS
87 * This is amount of time, in milliseconds, which a BLE end point will wait for an unsubscribe operation to complete
88 * before it automatically releases its BLE connection and frees itself. The default value of 5 seconds is arbitary.
91 #define BLE_UNSUBSCRIBE_TIMEOUT_MS 5000 // 5 seconds
93 #define BTP_ACK_RECEIVED_TIMEOUT_MS 15000 // 15 seconds
94 #define BTP_ACK_SEND_TIMEOUT_MS 2500 // 2.5 seconds
96 #define BTP_WINDOW_NO_ACK_SEND_THRESHOLD 1 // Data fragments may only be sent without piggybacked
97 // acks if receiver's window size is above this threshold.
104 BLE_ERROR BLEEndPoint::StartConnect()
106 BLE_ERROR err = BLE_NO_ERROR;
107 BleTransportCapabilitiesRequestMessage req;
108 PacketBufferHandle buf;
109 constexpr uint8_t numVersions =
110 CHIP_BLE_TRANSPORT_PROTOCOL_MAX_SUPPORTED_VERSION - CHIP_BLE_TRANSPORT_PROTOCOL_MIN_SUPPORTED_VERSION + 1;
111 static_assert(numVersions <= NUM_SUPPORTED_PROTOCOL_VERSIONS, "Incompatibly protocol versions");
113 // Ensure we're in the correct state.
114 VerifyOrExit(mState == kState_Ready, err = BLE_ERROR_INCORRECT_STATE);
115 mState = kState_Connecting;
117 // Build BLE transport protocol capabilities request.
118 buf = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize);
119 VerifyOrExit(!buf.IsNull(), err = BLE_ERROR_NO_MEMORY);
121 // Zero-initialize BLE transport capabilities request.
122 memset(&req, 0, sizeof(req));
124 req.mMtu = mBle->mPlatformDelegate->GetMTU(mConnObj);
126 req.mWindowSize = BLE_MAX_RECEIVE_WINDOW_SIZE;
128 // Populate request with highest supported protocol versions
129 for (uint8_t i = 0; i < numVersions; i++)
131 req.SetSupportedProtocolVersion(i, static_cast<uint8_t>(CHIP_BLE_TRANSPORT_PROTOCOL_MAX_SUPPORTED_VERSION - i));
134 err = req.Encode(buf);
137 // Start connect timer. Canceled when end point freed or connection established.
138 err = StartConnectTimer();
141 // Send BLE transport capabilities request to peripheral via GATT write.
142 // Add reference to message fragment for duration of platform's GATT write attempt. CHIP retains partial
143 // ownership of message fragment's packet buffer, since this is the same buffer as that of the whole message, just
144 // with a fragmenter-modified payload offset and data length, by a Retain() on the handle when calling this function.
145 if (!SendWrite(buf.Retain()))
147 err = BLE_ERROR_GATT_WRITE_FAILED;
151 // Free request buffer on write confirmation. Stash a reference to it in mSendQueue, which we don't use anyway
152 // until the connection has been set up.
153 QueueTx(std::move(buf), kType_Data);
156 // If we failed to initiate the connection, close the end point.
157 if (err != BLE_NO_ERROR)
160 DoClose(kBleCloseFlag_AbortTransmission, err);
166 BLE_ERROR BLEEndPoint::HandleConnectComplete()
168 BLE_ERROR err = BLE_NO_ERROR;
170 mState = kState_Connected;
172 // Cancel the connect timer.
175 // We've successfully completed the BLE transport protocol handshake, so let the application know we're open for business.
176 if (OnConnectComplete != nullptr)
178 // Indicate connect complete to next-higher layer.
179 OnConnectComplete(this, BLE_NO_ERROR);
183 // If no connect complete callback has been set up, close the end point.
184 err = BLE_ERROR_NO_CONNECT_COMPLETE_CALLBACK;
190 BLE_ERROR BLEEndPoint::HandleReceiveConnectionComplete()
192 BLE_ERROR err = BLE_NO_ERROR;
194 ChipLogDebugBleEndPoint(Ble, "entered HandleReceiveConnectionComplete");
195 mState = kState_Connected;
197 // Cancel receive connection timer.
198 StopReceiveConnectionTimer();
200 // We've successfully completed the BLE transport protocol handshake, so let the application know we're open for business.
201 if (mBle->OnChipBleConnectReceived != nullptr)
203 // Indicate BLE transport protocol connection received to next-higher layer.
204 mBle->OnChipBleConnectReceived(this);
208 err = BLE_ERROR_NO_CONNECTION_RECEIVED_CALLBACK;
214 void BLEEndPoint::HandleSubscribeReceived()
216 BLE_ERROR err = BLE_NO_ERROR;
218 VerifyOrExit(mState == kState_Connecting || mState == kState_Aborting, err = BLE_ERROR_INCORRECT_STATE);
219 VerifyOrExit(!mSendQueue.IsNull(), err = BLE_ERROR_INCORRECT_STATE);
221 // Send BTP capabilities response to peripheral via GATT indication.
222 #if CHIP_ENABLE_CHIPOBLE_TEST
223 VerifyOrExit(mBtpEngine.PopPacketTag(mSendQueue) == kType_Data, err = BLE_ERROR_INVALID_BTP_HEADER_FLAGS);
225 // Add reference to message fragment for duration of platform's GATT indication attempt. CHIP retains partial
226 // ownership of message fragment's packet buffer, since this is the same buffer as that of the whole message, just
227 // with a fragmenter-modified payload offset and data length.
228 if (!SendIndication(mSendQueue.Retain()))
230 // Ensure transmit queue is empty and set to NULL.
232 mSendQueue = nullptr;
235 ChipLogError(Ble, "cap resp ind failed");
236 err = BLE_ERROR_GATT_INDICATE_FAILED;
240 // Shrink remote receive window counter by 1, since we've sent an indication which requires acknowledgement.
241 mRemoteReceiveWindowSize = static_cast<SequenceNumber_t>(mRemoteReceiveWindowSize - 1);
242 ChipLogDebugBleEndPoint(Ble, "decremented remote rx window, new size = %u", mRemoteReceiveWindowSize);
244 // Start ack recvd timer for handshake indication.
245 err = StartAckReceivedTimer();
248 ChipLogDebugBleEndPoint(Ble, "got subscribe, sent indication w/ capabilities response");
250 // If SendIndication returns true, mSendQueue is freed on indication confirmation, or on close in case of
253 if (mState != kState_Aborting)
255 // If peripheral accepted the BTP connection, its end point must enter the connected state here, i.e. before it
256 // receives a GATT confirmation for the capabilities response indication. This behavior is required to handle the
257 // case where a peripheral's BLE controller passes up the central's first message fragment write before the
258 // capabilities response indication confirmation. If the end point waited for this indication confirmation before
259 // it entered the connected state, it'd be in the wrong state to receive the central's first data write, and drop
260 // the corresponding message fragment.
261 err = HandleReceiveConnectionComplete();
263 } // Else State == kState_Aborting, so we'll close end point when indication confirmation received.
266 if (err != BLE_NO_ERROR)
268 DoClose(kBleCloseFlag_SuppressCallback | kBleCloseFlag_AbortTransmission, err);
272 void BLEEndPoint::HandleSubscribeComplete()
274 ChipLogProgress(Ble, "subscribe complete, ep = %p", this);
275 mConnStateFlags.Clear(ConnectionStateFlag::kGattOperationInFlight);
277 BLE_ERROR err = DriveSending();
279 if (err != BLE_NO_ERROR)
281 DoClose(kBleCloseFlag_AbortTransmission, BLE_NO_ERROR);
285 void BLEEndPoint::HandleUnsubscribeComplete()
287 // Don't bother to clear GattOperationInFlight, we're about to free the end point anyway.
291 bool BLEEndPoint::IsConnected(uint8_t state) const
293 return (state == kState_Connected || state == kState_Closing);
296 bool BLEEndPoint::IsUnsubscribePending() const
298 return mTimerStateFlags.Has(TimerStateFlag::kUnsubscribeTimerRunning);
301 void BLEEndPoint::Abort()
303 // No more callbacks after this point, since application explicitly called Abort().
304 OnConnectComplete = nullptr;
305 OnConnectionClosed = nullptr;
306 OnMessageReceived = nullptr;
307 #if CHIP_ENABLE_CHIPOBLE_TEST
308 OnCommandReceived = NULL;
311 DoClose(kBleCloseFlag_SuppressCallback | kBleCloseFlag_AbortTransmission, BLE_NO_ERROR);
314 void BLEEndPoint::Close()
316 // No more callbacks after this point, since application explicitly called Close().
317 OnConnectComplete = nullptr;
318 OnConnectionClosed = nullptr;
319 OnMessageReceived = nullptr;
320 #if CHIP_ENABLE_CHIPOBLE_TEST
321 OnCommandReceived = NULL;
324 DoClose(kBleCloseFlag_SuppressCallback, BLE_NO_ERROR);
327 void BLEEndPoint::DoClose(uint8_t flags, BLE_ERROR err)
329 uint8_t oldState = mState;
331 // If end point is not closed or closing, OR end point was closing gracefully, but tx abort has been specified...
332 if ((mState != kState_Closed && mState != kState_Closing) ||
333 (mState == kState_Closing && (flags & kBleCloseFlag_AbortTransmission)))
335 // Cancel Connect and ReceiveConnect timers if they are running.
336 // Check role first to avoid needless iteration over timer pool.
337 if (mRole == kBleRole_Central)
341 else // (mRole == kBleRole_Peripheral), verified on Init
343 StopReceiveConnectionTimer();
346 // If transmit buffer is empty or a transmission abort was specified...
347 if (mBtpEngine.TxState() == BtpEngine::kState_Idle || (flags & kBleCloseFlag_AbortTransmission))
349 FinalizeClose(oldState, flags, err);
353 // Wait for send queue and fragmenter's tx buffer to become empty, to ensure all pending messages have been
354 // sent. Only free end point and tell platform it can throw away the underlying BLE connection once all
355 // pending messages have been sent and acknowledged by the remote CHIPoBLE stack, or once the remote stack
356 // closes the CHIPoBLE connection.
358 // In so doing, BLEEndPoint attempts to emulate the level of reliability afforded by TCPEndPoint and TCP
359 // sockets in general with a typical default SO_LINGER option. That said, there is no hard guarantee that
360 // pending messages will be sent once (Do)Close() is called, so developers should use application-level
361 // messages to confirm the receipt of all data sent prior to a Close() call.
362 mState = kState_Closing;
364 if ((flags & kBleCloseFlag_SuppressCallback) == 0)
366 DoCloseCallback(oldState, flags, err);
372 void BLEEndPoint::FinalizeClose(uint8_t oldState, uint8_t flags, BLE_ERROR err)
374 mState = kState_Closed;
376 // Ensure transmit queue is empty and set to NULL.
378 mSendQueue = nullptr;
381 // Fire application's close callback if we haven't already, and it's not suppressed.
382 if (oldState != kState_Closing && (flags & kBleCloseFlag_SuppressCallback) == 0)
384 DoCloseCallback(oldState, flags, err);
387 // If underlying BLE connection has closed, connection object is invalid, so just free the end point and return.
388 if (err == BLE_ERROR_REMOTE_DEVICE_DISCONNECTED || err == BLE_ERROR_APP_CLOSED_CONNECTION)
390 mConnObj = BLE_CONNECTION_UNINITIALIZED; // Clear handle to BLE connection, so we don't double-close it.
393 else // Otherwise, try to signal close to remote device before end point releases BLE connection and frees itself.
395 if (mRole == kBleRole_Central && mConnStateFlags.Has(ConnectionStateFlag::kDidBeginSubscribe))
397 // Cancel send and receive-ack timers, if running.
398 StopAckReceivedTimer();
401 // Indicate close of chipConnection to peripheral via GATT unsubscribe. Keep end point allocated until
402 // unsubscribe completes or times out, so platform doesn't close underlying BLE connection before
403 // we're really sure the unsubscribe request has been sent.
404 if (!mBle->mPlatformDelegate->UnsubscribeCharacteristic(mConnObj, &CHIP_BLE_SVC_ID, &mBle->CHIP_BLE_CHAR_2_ID))
406 ChipLogError(Ble, "BtpEngine unsub failed");
408 // If unsubscribe fails, release BLE connection and free end point immediately.
411 else if (mConnObj != BLE_CONNECTION_UNINITIALIZED)
413 // Unsubscribe request was sent successfully, and a confirmation wasn't spontaneously generated or
414 // received in the downcall to UnsubscribeCharacteristic, so set timer for the unsubscribe to complete.
415 err = StartUnsubscribeTimer();
417 if (err != BLE_NO_ERROR)
422 // Mark unsubscribe GATT operation in progress.
423 mConnStateFlags.Set(ConnectionStateFlag::kGattOperationInFlight);
426 else // mRole == kBleRole_Peripheral, OR mTimerStateFlags.Has(ConnectionStateFlag::kDidBeginSubscribe) == false...
433 void BLEEndPoint::DoCloseCallback(uint8_t state, uint8_t flags, BLE_ERROR err)
435 if (state == kState_Connecting)
437 if (OnConnectComplete != nullptr)
439 OnConnectComplete(this, err);
444 if (OnConnectionClosed != nullptr)
446 OnConnectionClosed(this, err);
450 // Callback fires once per end point lifetime.
451 OnConnectComplete = nullptr;
452 OnConnectionClosed = nullptr;
455 void BLEEndPoint::ReleaseBleConnection()
457 if (mConnObj != BLE_CONNECTION_UNINITIALIZED)
459 if (mConnStateFlags.Has(ConnectionStateFlag::kAutoClose))
461 ChipLogProgress(Ble, "Auto-closing end point's BLE connection.");
462 mBle->mPlatformDelegate->CloseConnection(mConnObj);
466 ChipLogProgress(Ble, "Releasing end point's BLE connection back to application.");
467 mBle->mApplicationDelegate->NotifyChipConnectionClosed(mConnObj);
470 // Never release the same BLE connection twice.
471 mConnObj = BLE_CONNECTION_UNINITIALIZED;
475 void BLEEndPoint::Free()
477 // Release BLE connection. Will close connection if AutoClose enabled for this end point. Otherwise, informs
478 // application that CHIP is done with this BLE connection, and application makes decision about whether to close
479 // and clean up or retain connection.
480 ReleaseBleConnection();
482 // Clear fragmentation and reassembly engine's Tx and Rx buffers. Counters will be reset by next engine init.
485 // Clear pending ack buffer, if any.
486 mAckToSend = nullptr;
488 // Cancel all timers.
490 StopReceiveConnectionTimer();
491 StopAckReceivedTimer();
493 StopUnsubscribeTimer();
494 #if CHIP_ENABLE_CHIPOBLE_TEST
495 mBtpEngineTest.StopTestTimer();
497 OnCommandReceived = NULL;
501 OnConnectComplete = nullptr;
502 OnMessageReceived = nullptr;
503 OnConnectionClosed = nullptr;
505 // Clear handle to underlying BLE connection.
506 mConnObj = BLE_CONNECTION_UNINITIALIZED;
508 // Release the AddRef() that happened when the end point was allocated.
512 void BLEEndPoint::FreeBtpEngine()
514 // Free transmit disassembly buffer
515 mBtpEngine.ClearTxPacket();
517 // Free receive reassembly buffer
518 mBtpEngine.ClearRxPacket();
521 BLE_ERROR BLEEndPoint::Init(BleLayer * bleLayer, BLE_CONNECTION_OBJECT connObj, BleRole role, bool autoClose)
523 BLE_ERROR err = BLE_NO_ERROR;
524 bool expectInitialAck;
526 // Fail if already initialized.
527 VerifyOrExit(mBle == nullptr, err = BLE_ERROR_INCORRECT_STATE);
530 VerifyOrExit(bleLayer != nullptr, err = BLE_ERROR_BAD_ARGS);
531 VerifyOrExit(connObj != BLE_CONNECTION_UNINITIALIZED, err = BLE_ERROR_BAD_ARGS);
532 VerifyOrExit((role == kBleRole_Central || role == kBleRole_Peripheral), err = BLE_ERROR_BAD_ARGS);
534 // If end point plays peripheral role, expect ack for indication sent as last step of BTP handshake.
535 // If central, periperal's handshake indication 'ack's write sent by central to kick off the BTP handshake.
536 expectInitialAck = (role == kBleRole_Peripheral);
538 err = mBtpEngine.Init(this, expectInitialAck);
539 if (err != BLE_NO_ERROR)
541 ChipLogError(Ble, "BtpEngine init failed");
545 #if CHIP_ENABLE_CHIPOBLE_TEST
546 err = (BLE_ERROR) mTxQueueMutex.Init(mTxQueueMutex);
547 if (err != BLE_NO_ERROR)
549 ChipLogError(Ble, "%s: Mutex init failed", __FUNCTION__);
552 err = mBtpEngineTest.Init(this);
553 if (err != BLE_NO_ERROR)
555 ChipLogError(Ble, "BTP test init failed");
560 // BleLayerObject initialization:
564 // BLEEndPoint data members:
567 mTimerStateFlags.ClearAll();
568 mConnStateFlags.ClearAll().Set(ConnectionStateFlag::kAutoClose, autoClose);
569 mLocalReceiveWindowSize = 0;
570 mRemoteReceiveWindowSize = 0;
571 mReceiveWindowMaxSize = 0;
572 mSendQueue = nullptr;
573 mAckToSend = nullptr;
575 ChipLogDebugBleEndPoint(Ble, "initialized local rx window, size = %u", mLocalReceiveWindowSize);
577 // End point is ready to connect or receive a connection.
578 mState = kState_Ready;
584 BLE_ERROR BLEEndPoint::SendCharacteristic(PacketBufferHandle && buf)
586 BLE_ERROR err = BLE_NO_ERROR;
588 if (mRole == kBleRole_Central)
590 if (!SendWrite(std::move(buf)))
592 err = BLE_ERROR_GATT_WRITE_FAILED;
596 // Write succeeded, so shrink remote receive window counter by 1.
597 mRemoteReceiveWindowSize = static_cast<SequenceNumber_t>(mRemoteReceiveWindowSize - 1);
598 ChipLogDebugBleEndPoint(Ble, "decremented remote rx window, new size = %u", mRemoteReceiveWindowSize);
601 else // (mRole == kBleRole_Peripheral), verified on Init
603 if (!SendIndication(std::move(buf)))
605 err = BLE_ERROR_GATT_INDICATE_FAILED;
609 // Indication succeeded, so shrink remote receive window counter by 1.
610 mRemoteReceiveWindowSize = static_cast<SequenceNumber_t>(mRemoteReceiveWindowSize - 1);
611 ChipLogDebugBleEndPoint(Ble, "decremented remote rx window, new size = %u", mRemoteReceiveWindowSize);
619 * Routine to queue the Tx packet with a packet type
620 * kType_Data(0) - data packet
621 * kType_Control(1) - control packet
623 void BLEEndPoint::QueueTx(PacketBufferHandle && data, PacketType_t type)
625 #if CHIP_ENABLE_CHIPOBLE_TEST
626 ChipLogDebugBleEndPoint(Ble, "%s: data->%p, type %d, len %d", __FUNCTION__, data, type, data->DataLength());
627 mBtpEngine.PushPacketTag(data, type);
632 if (mSendQueue.IsNull())
634 mSendQueue = std::move(data);
635 ChipLogDebugBleEndPoint(Ble, "%s: Set data as new mSendQueue %p, type %d", __FUNCTION__, mSendQueue->Start(), type);
639 mSendQueue->AddToEnd(std::move(data));
640 ChipLogDebugBleEndPoint(Ble, "%s: Append data to mSendQueue %p, type %d", __FUNCTION__, mSendQueue->Start(), type);
646 BLE_ERROR BLEEndPoint::Send(PacketBufferHandle data)
648 ChipLogDebugBleEndPoint(Ble, "entered Send");
650 BLE_ERROR err = BLE_NO_ERROR;
652 VerifyOrExit(!data.IsNull(), err = BLE_ERROR_BAD_ARGS);
653 VerifyOrExit(IsConnected(mState), err = BLE_ERROR_INCORRECT_STATE);
655 // Ensure outgoing message fits in a single contiguous packet buffer, as currently required by the
656 // message fragmentation and reassembly engine.
657 if (data->HasChainedBuffer())
661 if (data->HasChainedBuffer())
663 err = BLE_ERROR_OUTBOUND_MESSAGE_TOO_BIG;
668 // Add new message to send queue.
669 QueueTx(std::move(data), kType_Data);
671 // Send first fragment of new message, if we can.
672 err = DriveSending();
676 ChipLogDebugBleEndPoint(Ble, "exiting Send");
677 if (err != BLE_NO_ERROR)
679 DoClose(kBleCloseFlag_AbortTransmission, err);
685 bool BLEEndPoint::PrepareNextFragment(PacketBufferHandle && data, bool & sentAck)
687 // If we have a pending fragment acknowledgement to send, piggyback it on the fragment we're about to transmit.
688 if (mTimerStateFlags.Has(TimerStateFlag::kSendAckTimerRunning))
690 // Reset local receive window counter.
691 mLocalReceiveWindowSize = mReceiveWindowMaxSize;
692 ChipLogDebugBleEndPoint(Ble, "reset local rx window on piggyback ack tx, size = %u", mLocalReceiveWindowSize);
694 // Tell caller AND fragmenter we have an ack to piggyback.
699 // No ack to piggyback.
703 return mBtpEngine.HandleCharacteristicSend(std::move(data), sentAck);
706 BLE_ERROR BLEEndPoint::SendNextMessage()
708 BLE_ERROR err = BLE_NO_ERROR;
711 // Get the first queued packet to send
713 #if CHIP_ENABLE_CHIPOBLE_TEST
714 // Return if tx queue is empty
715 // Note: PopHead() does not check an empty queue
716 if (mSendQueue.IsNull())
723 PacketBufferHandle data = mSendQueue.PopHead();
726 #if CHIP_ENABLE_CHIPOBLE_TEST
727 // Get and consume the packet tag in message buffer
728 PacketType_t type = mBtpEngine.PopPacketTag(data);
729 mBtpEngine.SetTxPacketType(type);
730 mBtpEngineTest.DoTxTiming(data, BTP_TX_START);
733 // Hand whole message payload to the fragmenter.
734 VerifyOrExit(PrepareNextFragment(std::move(data), sentAck), err = BLE_ERROR_CHIPOBLE_PROTOCOL_ABORT);
737 // Todo: reenabled it after integrating fault injection
738 // Send first message fragment over the air.
739 CHIP_FAULT_INJECT(chip::FaultInjection::kFault_CHIPOBLESend, {
740 if (mRole == kBleRole_Central)
742 err = BLE_ERROR_GATT_WRITE_FAILED;
746 err = BLE_ERROR_GATT_INDICATE_FAILED;
751 err = SendCharacteristic(mBtpEngine.BorrowTxPacket());
756 // If sent piggybacked ack, stop send-ack timer.
760 // Start ack received timer, if it's not already running.
761 err = StartAckReceivedTimer();
768 BLE_ERROR BLEEndPoint::ContinueMessageSend()
773 if (!PrepareNextFragment(nullptr, sentAck))
776 ChipLogError(Ble, "btp fragmenter error on send!");
777 mBtpEngine.LogState();
779 err = BLE_ERROR_CHIPOBLE_PROTOCOL_ABORT;
783 err = SendCharacteristic(mBtpEngine.BorrowTxPacket());
788 // If sent piggybacked ack, stop send-ack timer.
792 // Start ack received timer, if it's not already running.
793 err = StartAckReceivedTimer();
800 BLE_ERROR BLEEndPoint::HandleHandshakeConfirmationReceived()
802 ChipLogDebugBleEndPoint(Ble, "entered HandleHandshakeConfirmationReceived");
804 BLE_ERROR err = BLE_NO_ERROR;
805 uint8_t closeFlags = kBleCloseFlag_AbortTransmission;
807 // Free capabilities request/response payload.
809 mSendQueue.FreeHead();
812 if (mRole == kBleRole_Central)
814 // Subscribe to characteristic which peripheral will use to send indications. Prompts peripheral to send
815 // BLE transport capabilities indication.
816 VerifyOrExit(mBle->mPlatformDelegate->SubscribeCharacteristic(mConnObj, &CHIP_BLE_SVC_ID, &mBle->CHIP_BLE_CHAR_2_ID),
817 err = BLE_ERROR_GATT_SUBSCRIBE_FAILED);
819 // We just sent a GATT subscribe request, so make sure to attempt unsubscribe on close.
820 mConnStateFlags.Set(ConnectionStateFlag::kDidBeginSubscribe);
822 // Mark GATT operation in progress for subscribe request.
823 mConnStateFlags.Set(ConnectionStateFlag::kGattOperationInFlight);
825 else // (mRole == kBleRole_Peripheral), verified on Init
827 ChipLogDebugBleEndPoint(Ble, "got peripheral handshake indication confirmation");
829 if (mState == kState_Connected) // If we accepted BTP connection...
831 // If local receive window size has shrunk to or below immediate ack threshold, AND a message fragment is not
832 // pending on which to piggyback an ack, send immediate stand-alone ack.
833 if (mLocalReceiveWindowSize <= BLE_CONFIG_IMMEDIATE_ACK_WINDOW_THRESHOLD && mSendQueue.IsNull())
835 err = DriveStandAloneAck(); // Encode stand-alone ack and drive sending.
840 // Drive sending in case application callend Send() after we sent the handshake indication, but
841 // before the GATT confirmation for this indication was received.
842 err = DriveSending();
846 else if (mState == kState_Aborting) // Else, if we rejected BTP connection...
848 closeFlags |= kBleCloseFlag_SuppressCallback;
849 err = BLE_ERROR_INCOMPATIBLE_PROTOCOL_VERSIONS;
855 ChipLogDebugBleEndPoint(Ble, "exiting HandleHandshakeConfirmationReceived");
857 if (err != BLE_NO_ERROR)
859 DoClose(closeFlags, err);
865 BLE_ERROR BLEEndPoint::HandleFragmentConfirmationReceived()
867 BLE_ERROR err = BLE_NO_ERROR;
869 ChipLogDebugBleEndPoint(Ble, "entered HandleFragmentConfirmationReceived");
871 // Suppress error logging if GATT confirmation overlaps with unsubscribe on final close.
872 if (IsUnsubscribePending())
874 ChipLogDebugBleEndPoint(Ble, "send conf rx'd while unsubscribe in flight");
878 // Ensure we're in correct state to receive confirmation of non-handshake GATT send.
879 VerifyOrExit(IsConnected(mState), err = BLE_ERROR_INCORRECT_STATE);
881 // TODO Packet buffer high water mark optimization: if ack pending, but fragmenter state == complete, free fragmenter's
882 // tx buf before sending ack.
884 if (mConnStateFlags.Has(ConnectionStateFlag::kStandAloneAckInFlight))
886 // If confirmation was received for stand-alone ack, free its tx buffer.
887 mAckToSend = nullptr;
889 mConnStateFlags.Clear(ConnectionStateFlag::kStandAloneAckInFlight);
892 // If local receive window size has shrunk to or below immediate ack threshold, AND a message fragment is not
893 // pending on which to piggyback an ack, send immediate stand-alone ack.
895 // This check covers the case where the local receive window has shrunk between transmission and confirmation of
896 // the stand-alone ack, and also the case where a window size < the immediate ack threshold was detected in
897 // Receive(), but the stand-alone ack was deferred due to a pending outbound message fragment.
898 if (mLocalReceiveWindowSize <= BLE_CONFIG_IMMEDIATE_ACK_WINDOW_THRESHOLD && mSendQueue.IsNull() &&
899 mBtpEngine.TxState() != BtpEngine::kState_InProgress)
901 err = DriveStandAloneAck(); // Encode stand-alone ack and drive sending.
906 err = DriveSending();
911 if (err != BLE_NO_ERROR)
913 DoClose(kBleCloseFlag_AbortTransmission, err);
919 BLE_ERROR BLEEndPoint::HandleGattSendConfirmationReceived()
921 ChipLogDebugBleEndPoint(Ble, "entered HandleGattSendConfirmationReceived");
923 // Mark outstanding GATT operation as finished.
924 mConnStateFlags.Clear(ConnectionStateFlag::kGattOperationInFlight);
926 // If confirmation was for outbound portion of BTP connect handshake...
927 if (!mConnStateFlags.Has(ConnectionStateFlag::kCapabilitiesConfReceived))
929 mConnStateFlags.Set(ConnectionStateFlag::kCapabilitiesConfReceived);
931 return HandleHandshakeConfirmationReceived();
934 return HandleFragmentConfirmationReceived();
937 BLE_ERROR BLEEndPoint::DriveStandAloneAck()
939 BLE_ERROR err = BLE_NO_ERROR;
941 // Stop send-ack timer if running.
944 // If stand-alone ack not already pending, allocate new payload buffer here.
945 if (mAckToSend.IsNull())
947 mAckToSend = System::PacketBufferHandle::New(kTransferProtocolStandaloneAckHeaderSize);
948 VerifyOrExit(!mAckToSend.IsNull(), err = BLE_ERROR_NO_MEMORY);
951 // Attempt to send stand-alone ack.
952 err = DriveSending();
959 BLE_ERROR BLEEndPoint::DoSendStandAloneAck()
961 ChipLogDebugBleEndPoint(Ble, "entered DoSendStandAloneAck; sending stand-alone ack");
963 // Encode and transmit stand-alone ack.
964 mBtpEngine.EncodeStandAloneAck(mAckToSend);
965 BLE_ERROR err = SendCharacteristic(mAckToSend.Retain());
968 // Reset local receive window counter.
969 mLocalReceiveWindowSize = mReceiveWindowMaxSize;
970 ChipLogDebugBleEndPoint(Ble, "reset local rx window on stand-alone ack tx, size = %u", mLocalReceiveWindowSize);
972 mConnStateFlags.Set(ConnectionStateFlag::kStandAloneAckInFlight);
974 // Start ack received timer, if it's not already running.
975 err = StartAckReceivedTimer();
982 BLE_ERROR BLEEndPoint::DriveSending()
984 BLE_ERROR err = BLE_NO_ERROR;
986 ChipLogDebugBleEndPoint(Ble, "entered DriveSending");
988 // If receiver's window is almost closed and we don't have an ack to send, OR we do have an ack to send but
989 // receiver's window is completely empty, OR another GATT operation is in flight, awaiting confirmation...
990 if ((mRemoteReceiveWindowSize <= BTP_WINDOW_NO_ACK_SEND_THRESHOLD &&
991 !mTimerStateFlags.Has(TimerStateFlag::kSendAckTimerRunning) && mAckToSend.IsNull()) ||
992 (mRemoteReceiveWindowSize == 0) || (mConnStateFlags.Has(ConnectionStateFlag::kGattOperationInFlight)))
994 #ifdef CHIP_BLE_END_POINT_DEBUG_LOGGING_ENABLED
995 if (mRemoteReceiveWindowSize <= BTP_WINDOW_NO_ACK_SEND_THRESHOLD &&
996 !mTimerStateFlags.Has(TimerStateFlag::kSendAckTimerRunning) && mAckToSend.IsNull())
998 ChipLogDebugBleEndPoint(Ble, "NO SEND: receive window almost closed, and no ack to send");
1001 if (mRemoteReceiveWindowSize == 0)
1003 ChipLogDebugBleEndPoint(Ble, "NO SEND: remote receive window closed");
1006 if (mConnStateFlags.Has(ConnectionStateFlag::kGattOperationInFlight))
1008 ChipLogDebugBleEndPoint(Ble, "NO SEND: Gatt op in flight");
1012 // Can't send anything.
1016 // Otherwise, let's see what we can send.
1018 if (!mAckToSend.IsNull()) // If immediate, stand-alone ack is pending, send it.
1020 err = DoSendStandAloneAck();
1023 else if (mBtpEngine.TxState() == BtpEngine::kState_Idle) // Else send next message fragment, if any.
1025 // Fragmenter's idle, let's see what's in the send queue...
1026 if (!mSendQueue.IsNull())
1028 // Transmit first fragment of next whole message in send queue.
1029 err = SendNextMessage();
1037 else if (mBtpEngine.TxState() == BtpEngine::kState_InProgress)
1039 // Send next fragment of message currently held by fragmenter.
1040 err = ContinueMessageSend();
1043 else if (mBtpEngine.TxState() == BtpEngine::kState_Complete)
1045 // Clear fragmenter's pointer to sent message buffer and reset its Tx state.
1046 // Buffer will be freed at scope exit.
1047 PacketBufferHandle sentBuf = mBtpEngine.TakeTxPacket();
1048 #if CHIP_ENABLE_CHIPOBLE_TEST
1049 mBtpEngineTest.DoTxTiming(sentBuf, BTP_TX_DONE);
1050 #endif // CHIP_ENABLE_CHIPOBLE_TEST
1052 if (!mSendQueue.IsNull())
1054 // Transmit first fragment of next whole message in send queue.
1055 err = SendNextMessage();
1058 else if (mState == kState_Closing && !mBtpEngine.ExpectingAck()) // and mSendQueue is NULL, per above...
1060 // If end point closing, got last ack, and got out-of-order confirmation for last send, finalize close.
1061 FinalizeClose(mState, kBleCloseFlag_SuppressCallback, BLE_NO_ERROR);
1073 BLE_ERROR BLEEndPoint::HandleCapabilitiesRequestReceived(PacketBufferHandle data)
1075 BLE_ERROR err = BLE_NO_ERROR;
1076 BleTransportCapabilitiesRequestMessage req;
1077 BleTransportCapabilitiesResponseMessage resp;
1078 PacketBufferHandle responseBuf;
1081 VerifyOrExit(!data.IsNull(), err = BLE_ERROR_BAD_ARGS);
1083 mState = kState_Connecting;
1085 // Decode BTP capabilities request.
1086 err = BleTransportCapabilitiesRequestMessage::Decode(data, req);
1089 responseBuf = System::PacketBufferHandle::New(kCapabilitiesResponseLength);
1090 VerifyOrExit(!responseBuf.IsNull(), err = BLE_ERROR_NO_MEMORY);
1092 // Determine BLE connection's negotiated ATT MTU, if possible.
1093 if (req.mMtu > 0) // If MTU was observed and provided by central...
1095 mtu = req.mMtu; // Accept central's observation of the MTU.
1097 else // Otherwise, retrieve it via the platform delegate...
1099 mtu = mBle->mPlatformDelegate->GetMTU(mConnObj);
1102 // Select fragment size for connection based on ATT MTU.
1103 if (mtu > 0) // If one or both device knows connection's MTU...
1105 resp.mFragmentSize =
1106 chip::min(static_cast<uint16_t>(mtu - 3), BtpEngine::sMaxFragmentSize); // Reserve 3 bytes of MTU for ATT header.
1108 else // Else, if neither device knows MTU...
1110 ChipLogProgress(Ble, "cannot determine ATT MTU; selecting default fragment size = %u", BtpEngine::sDefaultFragmentSize);
1111 resp.mFragmentSize = BtpEngine::sDefaultFragmentSize;
1114 // Select local and remote max receive window size based on local resources available for both incoming writes AND
1115 // GATT confirmations.
1116 mRemoteReceiveWindowSize = mLocalReceiveWindowSize = mReceiveWindowMaxSize =
1117 chip::min(req.mWindowSize, static_cast<uint8_t>(BLE_MAX_RECEIVE_WINDOW_SIZE));
1118 resp.mWindowSize = mReceiveWindowMaxSize;
1120 ChipLogProgress(Ble, "local and remote recv window sizes = %u", resp.mWindowSize);
1122 // Select BLE transport protocol version from those supported by central, or none if no supported version found.
1123 resp.mSelectedProtocolVersion = BleLayer::GetHighestSupportedProtocolVersion(req);
1124 ChipLogProgress(Ble, "selected BTP version %d", resp.mSelectedProtocolVersion);
1126 if (resp.mSelectedProtocolVersion == kBleTransportProtocolVersion_None)
1128 // If BLE transport protocol versions incompatible, prepare to close connection after subscription has been
1129 // received and capabilities response has been sent.
1130 ChipLogError(Ble, "incompatible BTP versions; peripheral expected between %d and %d",
1131 CHIP_BLE_TRANSPORT_PROTOCOL_MIN_SUPPORTED_VERSION, CHIP_BLE_TRANSPORT_PROTOCOL_MAX_SUPPORTED_VERSION);
1132 mState = kState_Aborting;
1134 else if ((resp.mSelectedProtocolVersion == kBleTransportProtocolVersion_V1) ||
1135 (resp.mSelectedProtocolVersion == kBleTransportProtocolVersion_V2))
1137 // Set Rx and Tx fragment sizes to the same value
1138 mBtpEngine.SetRxFragmentSize(resp.mFragmentSize);
1139 mBtpEngine.SetTxFragmentSize(resp.mFragmentSize);
1141 else // resp.SelectedProtocolVersion >= kBleTransportProtocolVersion_V3
1143 // This is the peripheral, so set Rx fragment size, and leave Tx at default
1144 mBtpEngine.SetRxFragmentSize(resp.mFragmentSize);
1146 ChipLogProgress(Ble, "using BTP fragment sizes rx %d / tx %d.", mBtpEngine.GetRxFragmentSize(), mBtpEngine.GetTxFragmentSize());
1148 err = resp.Encode(responseBuf);
1151 // Stash capabilities response payload and wait for subscription from central.
1152 QueueTx(std::move(responseBuf), kType_Data);
1154 // Start receive timer. Canceled when end point freed or connection established.
1155 err = StartReceiveConnectionTimer();
1162 BLE_ERROR BLEEndPoint::HandleCapabilitiesResponseReceived(PacketBufferHandle data)
1164 BLE_ERROR err = BLE_NO_ERROR;
1165 BleTransportCapabilitiesResponseMessage resp;
1167 VerifyOrExit(!data.IsNull(), err = BLE_ERROR_BAD_ARGS);
1169 // Decode BTP capabilities response.
1170 err = BleTransportCapabilitiesResponseMessage::Decode(data, resp);
1173 VerifyOrExit(resp.mFragmentSize > 0, err = BLE_ERROR_INVALID_FRAGMENT_SIZE);
1175 ChipLogProgress(Ble, "peripheral chose BTP version %d; central expected between %d and %d", resp.mSelectedProtocolVersion,
1176 CHIP_BLE_TRANSPORT_PROTOCOL_MIN_SUPPORTED_VERSION, CHIP_BLE_TRANSPORT_PROTOCOL_MAX_SUPPORTED_VERSION);
1178 if ((resp.mSelectedProtocolVersion < CHIP_BLE_TRANSPORT_PROTOCOL_MIN_SUPPORTED_VERSION) ||
1179 (resp.mSelectedProtocolVersion > CHIP_BLE_TRANSPORT_PROTOCOL_MAX_SUPPORTED_VERSION))
1181 err = BLE_ERROR_INCOMPATIBLE_PROTOCOL_VERSIONS;
1185 // Set fragment size as minimum of (reported ATT MTU, BTP characteristic size)
1186 resp.mFragmentSize = chip::min(resp.mFragmentSize, BtpEngine::sMaxFragmentSize);
1188 if ((resp.mSelectedProtocolVersion == kBleTransportProtocolVersion_V1) ||
1189 (resp.mSelectedProtocolVersion == kBleTransportProtocolVersion_V2))
1191 mBtpEngine.SetRxFragmentSize(resp.mFragmentSize);
1192 mBtpEngine.SetTxFragmentSize(resp.mFragmentSize);
1194 else // resp.SelectedProtocolVersion >= kBleTransportProtocolVersion_V3
1196 // This is the central, so set Tx fragement size, and leave Rx at default.
1197 mBtpEngine.SetTxFragmentSize(resp.mFragmentSize);
1199 ChipLogProgress(Ble, "using BTP fragment sizes rx %d / tx %d.", mBtpEngine.GetRxFragmentSize(), mBtpEngine.GetTxFragmentSize());
1201 // Select local and remote max receive window size based on local resources available for both incoming indications
1202 // AND GATT confirmations.
1203 mRemoteReceiveWindowSize = mLocalReceiveWindowSize = mReceiveWindowMaxSize = resp.mWindowSize;
1205 ChipLogProgress(Ble, "local and remote recv window size = %u", resp.mWindowSize);
1207 // Shrink local receive window counter by 1, since connect handshake indication requires acknowledgement.
1208 mLocalReceiveWindowSize = static_cast<SequenceNumber_t>(mLocalReceiveWindowSize - 1);
1209 ChipLogDebugBleEndPoint(Ble, "decremented local rx window, new size = %u", mLocalReceiveWindowSize);
1211 // Send ack for connection handshake indication when timer expires. Sequence numbers always start at 0,
1212 // and the reassembler's "last received seq num" is initialized to 0 and updated when new fragments are
1213 // received from the peripheral, so we don't need to explicitly mark the ack num to send here.
1214 err = StartSendAckTimer();
1217 // We've sent a capabilities request write and received a compatible response, so the connect
1218 // operation has completed successfully.
1219 err = HandleConnectComplete();
1226 // Returns number of open slots in remote receive window given the input values.
1227 SequenceNumber_t BLEEndPoint::AdjustRemoteReceiveWindow(SequenceNumber_t lastReceivedAck, SequenceNumber_t maxRemoteWindowSize,
1228 SequenceNumber_t newestUnackedSentSeqNum)
1230 // Assumption: SequenceNumber_t is uint8_t.
1231 // Assumption: Maximum possible sequence number value is UINT8_MAX.
1232 // Assumption: Sequence numbers incremented past maximum value wrap to 0.
1233 // Assumption: newest unacked sent sequence number never exceeds current (and by extension, new and un-wrapped)
1234 // window boundary, so it never wraps relative to last received ack, if new window boundary would not
1237 // Define new window boundary (inclusive) as uint16_t, so its value can temporarily exceed UINT8_MAX.
1238 uint16_t newRemoteWindowBoundary = static_cast<uint16_t>(lastReceivedAck + maxRemoteWindowSize);
1240 if (newRemoteWindowBoundary > UINT8_MAX && newestUnackedSentSeqNum < lastReceivedAck)
1242 // New window boundary WOULD wrap, and latest unacked seq num already HAS wrapped, so add offset to difference.
1243 return static_cast<uint8_t>(newRemoteWindowBoundary - (newestUnackedSentSeqNum + UINT8_MAX));
1246 // Neither values would or have wrapped, OR new boundary WOULD wrap but latest unacked seq num does not, so no
1248 return static_cast<uint8_t>(newRemoteWindowBoundary - newestUnackedSentSeqNum);
1251 BLE_ERROR BLEEndPoint::Receive(PacketBufferHandle data)
1253 ChipLogDebugBleEndPoint(Ble, "+++++++++++++++++++++ entered receive");
1254 BLE_ERROR err = BLE_NO_ERROR;
1255 SequenceNumber_t receivedAck = 0;
1256 uint8_t closeFlags = kBleCloseFlag_AbortTransmission;
1257 bool didReceiveAck = false;
1259 #if CHIP_ENABLE_CHIPOBLE_TEST
1260 if (mBtpEngine.IsCommandPacket(data))
1262 ChipLogDebugBleEndPoint(Ble, "%s: Received Control frame: Flags %x", __FUNCTION__, *(data->Start()));
1266 { // This is a special handling on the first CHIPoBLE data packet, the CapabilitiesRequest.
1267 // Suppress error logging if peer's send overlaps with our unsubscribe on final close.
1268 if (IsUnsubscribePending())
1270 ChipLogDebugBleEndPoint(Ble, "characteristic rx'd while unsubscribe in flight");
1274 // If we're receiving the first inbound packet of a BLE transport connection handshake...
1275 if (!mConnStateFlags.Has(ConnectionStateFlag::kCapabilitiesMsgReceived))
1277 if (mRole == kBleRole_Central) // If we're a central receiving a capabilities response indication...
1279 // Ensure end point's in the right state before continuing.
1280 VerifyOrExit(mState == kState_Connecting, err = BLE_ERROR_INCORRECT_STATE);
1281 mConnStateFlags.Set(ConnectionStateFlag::kCapabilitiesMsgReceived);
1283 err = HandleCapabilitiesResponseReceived(std::move(data));
1286 else // Or, a peripheral receiving a capabilities request write...
1288 // Ensure end point's in the right state before continuing.
1289 VerifyOrExit(mState == kState_Ready, err = BLE_ERROR_INCORRECT_STATE);
1290 mConnStateFlags.Set(ConnectionStateFlag::kCapabilitiesMsgReceived);
1292 err = HandleCapabilitiesRequestReceived(std::move(data));
1294 if (err != BLE_NO_ERROR)
1296 // If an error occurred decoding and handling the capabilities request, release the BLE connection.
1297 // Central's connect attempt will time out if peripheral's application decides to keep the BLE
1298 // connection open, or fail immediately if the application closes the connection.
1299 closeFlags = closeFlags | kBleCloseFlag_SuppressCallback;
1304 // If received data was handshake packet, don't feed it to message reassembler.
1307 } // End handling the CapabilitiesRequest
1309 ChipLogDebugBleEndPoint(Ble, "prepared to rx post-handshake btp packet");
1311 // We've received a post-handshake BTP packet.
1312 // Ensure end point's in the right state before continuing.
1313 if (!IsConnected(mState))
1315 ChipLogError(Ble, "ep rx'd packet in bad state");
1316 err = BLE_ERROR_INCORRECT_STATE;
1321 ChipLogDebugBleEndPoint(Ble, "BTP about to rx characteristic, state before:");
1322 mBtpEngine.LogStateDebug();
1324 // Pass received packet into BTP protocol engine.
1325 err = mBtpEngine.HandleCharacteristicReceived(std::move(data), receivedAck, didReceiveAck);
1327 ChipLogDebugBleEndPoint(Ble, "BTP rx'd characteristic, state after:");
1328 mBtpEngine.LogStateDebug();
1332 // Protocol engine accepted the fragment, so shrink local receive window counter by 1.
1333 mLocalReceiveWindowSize = static_cast<SequenceNumber_t>(mLocalReceiveWindowSize - 1);
1334 ChipLogDebugBleEndPoint(Ble, "decremented local rx window, new size = %u", mLocalReceiveWindowSize);
1336 // Respond to received ack, if any.
1339 ChipLogDebugBleEndPoint(Ble, "got btp ack = %u", receivedAck);
1341 // If ack was rx'd for neweset unacked sent fragment, stop ack received timer.
1342 if (!mBtpEngine.ExpectingAck())
1344 ChipLogDebugBleEndPoint(Ble, "got ack for last outstanding fragment");
1345 StopAckReceivedTimer();
1347 if (mState == kState_Closing && mSendQueue.IsNull() && mBtpEngine.TxState() == BtpEngine::kState_Idle)
1349 // If end point closing, got confirmation for last send, and waiting for last ack, finalize close.
1350 FinalizeClose(mState, kBleCloseFlag_SuppressCallback, BLE_NO_ERROR);
1354 else // Else there are still sent fragments for which acks are expected, so restart ack received timer.
1356 ChipLogDebugBleEndPoint(Ble, "still expecting ack(s), restarting timer...");
1357 err = RestartAckReceivedTimer();
1361 ChipLogDebugBleEndPoint(Ble, "about to adjust remote rx window; got ack num = %u, newest unacked sent seq num = %u, \
1362 old window size = %u, max window size = %u",
1363 receivedAck, mBtpEngine.GetNewestUnackedSentSequenceNumber(), mRemoteReceiveWindowSize,
1364 mReceiveWindowMaxSize);
1366 // Open remote device's receive window according to sequence number it just acknowledged.
1367 mRemoteReceiveWindowSize =
1368 AdjustRemoteReceiveWindow(receivedAck, mReceiveWindowMaxSize, mBtpEngine.GetNewestUnackedSentSequenceNumber());
1370 ChipLogDebugBleEndPoint(Ble, "adjusted remote rx window, new size = %u", mRemoteReceiveWindowSize);
1372 // Restart message transmission if it was previously paused due to window exhaustion.
1373 err = DriveSending();
1377 // The previous DriveSending() might have generated a piggyback acknowledgement if there was
1378 // previously un-acked data. Otherwise, prepare to send acknowledgement for newly received fragment.
1380 // If local receive window is below immediate ack threshold, AND there is no previous stand-alone ack in
1381 // flight, AND there is no pending outbound message fragment on which the ack can and will be piggybacked,
1382 // send immediate stand-alone ack to reopen window for sender.
1384 // The "GATT operation in flight" check below covers "pending outbound message fragment" by extension, as when
1385 // a message has been passed to the end point via Send(), its next outbound fragment must either be in flight
1386 // itself, or awaiting the completion of another in-flight GATT operation.
1388 // If any GATT operation is in flight that is NOT a stand-alone ack, the window size will be checked against
1389 // this threshold again when the GATT operation is confirmed.
1390 if (mBtpEngine.HasUnackedData())
1392 if (mLocalReceiveWindowSize <= BLE_CONFIG_IMMEDIATE_ACK_WINDOW_THRESHOLD &&
1393 !mConnStateFlags.Has(ConnectionStateFlag::kGattOperationInFlight))
1395 ChipLogDebugBleEndPoint(Ble, "sending immediate ack");
1396 err = DriveStandAloneAck();
1401 ChipLogDebugBleEndPoint(Ble, "starting send-ack timer");
1403 // Send ack when timer expires.
1404 err = StartSendAckTimer();
1409 // If we've reassembled a whole message...
1410 if (mBtpEngine.RxState() == BtpEngine::kState_Complete)
1412 // Take ownership of message buffer
1413 System::PacketBufferHandle full_packet = mBtpEngine.TakeRxPacket();
1415 ChipLogDebugBleEndPoint(Ble, "reassembled whole msg, len = %d", full_packet->DataLength());
1417 #if CHIP_ENABLE_CHIPOBLE_TEST
1418 // If we have a control message received callback, and end point is not closing...
1419 if (mBtpEngine.RxPacketType() == kType_Control && OnCommandReceived && mState != kState_Closing)
1421 ChipLogDebugBleEndPoint(Ble, "%s: calling OnCommandReceived, seq# %u, len = %u, type %u", __FUNCTION__, receivedAck,
1422 full_packet->DataLength(), mBtpEngine.RxPacketType());
1423 // Pass received control message up the stack.
1424 mBtpEngine.SetRxPacketSeq(receivedAck);
1425 OnCommandReceived(this, std::move(full_packet));
1429 // If we have a message received callback, and end point is not closing...
1430 if (OnMessageReceived && mState != kState_Closing)
1432 // Pass received message up the stack.
1433 OnMessageReceived(this, std::move(full_packet));
1438 if (err != BLE_NO_ERROR)
1440 DoClose(closeFlags, err);
1446 bool BLEEndPoint::SendWrite(PacketBufferHandle && buf)
1448 mConnStateFlags.Set(ConnectionStateFlag::kGattOperationInFlight);
1450 return mBle->mPlatformDelegate->SendWriteRequest(mConnObj, &CHIP_BLE_SVC_ID, &mBle->CHIP_BLE_CHAR_1_ID, std::move(buf));
1453 bool BLEEndPoint::SendIndication(PacketBufferHandle && buf)
1455 mConnStateFlags.Set(ConnectionStateFlag::kGattOperationInFlight);
1457 return mBle->mPlatformDelegate->SendIndication(mConnObj, &CHIP_BLE_SVC_ID, &mBle->CHIP_BLE_CHAR_2_ID, std::move(buf));
1460 BLE_ERROR BLEEndPoint::StartConnectTimer()
1462 BLE_ERROR err = BLE_NO_ERROR;
1463 chip::System::Error timerErr;
1465 timerErr = mBle->mSystemLayer->StartTimer(BLE_CONNECT_TIMEOUT_MS, HandleConnectTimeout, this);
1466 VerifyOrExit(timerErr == CHIP_SYSTEM_NO_ERROR, err = BLE_ERROR_START_TIMER_FAILED);
1467 mTimerStateFlags.Set(TimerStateFlag::kConnectTimerRunning);
1473 BLE_ERROR BLEEndPoint::StartReceiveConnectionTimer()
1475 BLE_ERROR err = BLE_NO_ERROR;
1476 chip::System::Error timerErr;
1478 timerErr = mBle->mSystemLayer->StartTimer(BLE_CONNECT_TIMEOUT_MS, HandleReceiveConnectionTimeout, this);
1479 VerifyOrExit(timerErr == CHIP_SYSTEM_NO_ERROR, err = BLE_ERROR_START_TIMER_FAILED);
1480 mTimerStateFlags.Set(TimerStateFlag::kReceiveConnectionTimerRunning);
1486 BLE_ERROR BLEEndPoint::StartAckReceivedTimer()
1488 BLE_ERROR err = BLE_NO_ERROR;
1489 chip::System::Error timerErr;
1491 if (!mTimerStateFlags.Has(TimerStateFlag::kAckReceivedTimerRunning))
1493 timerErr = mBle->mSystemLayer->StartTimer(BTP_ACK_RECEIVED_TIMEOUT_MS, HandleAckReceivedTimeout, this);
1494 VerifyOrExit(timerErr == CHIP_SYSTEM_NO_ERROR, err = BLE_ERROR_START_TIMER_FAILED);
1496 mTimerStateFlags.Set(TimerStateFlag::kAckReceivedTimerRunning);
1503 BLE_ERROR BLEEndPoint::RestartAckReceivedTimer()
1505 BLE_ERROR err = BLE_NO_ERROR;
1507 VerifyOrExit(mTimerStateFlags.Has(TimerStateFlag::kAckReceivedTimerRunning), err = BLE_ERROR_INCORRECT_STATE);
1509 StopAckReceivedTimer();
1511 err = StartAckReceivedTimer();
1518 BLE_ERROR BLEEndPoint::StartSendAckTimer()
1520 BLE_ERROR err = BLE_NO_ERROR;
1521 chip::System::Error timerErr;
1523 ChipLogDebugBleEndPoint(Ble, "entered StartSendAckTimer");
1525 if (!mTimerStateFlags.Has(TimerStateFlag::kSendAckTimerRunning))
1527 ChipLogDebugBleEndPoint(Ble, "starting new SendAckTimer");
1528 timerErr = mBle->mSystemLayer->StartTimer(BTP_ACK_SEND_TIMEOUT_MS, HandleSendAckTimeout, this);
1529 VerifyOrExit(timerErr == CHIP_SYSTEM_NO_ERROR, err = BLE_ERROR_START_TIMER_FAILED);
1531 mTimerStateFlags.Set(TimerStateFlag::kSendAckTimerRunning);
1538 BLE_ERROR BLEEndPoint::StartUnsubscribeTimer()
1540 BLE_ERROR err = BLE_NO_ERROR;
1541 chip::System::Error timerErr;
1543 timerErr = mBle->mSystemLayer->StartTimer(BLE_UNSUBSCRIBE_TIMEOUT_MS, HandleUnsubscribeTimeout, this);
1544 VerifyOrExit(timerErr == CHIP_SYSTEM_NO_ERROR, err = BLE_ERROR_START_TIMER_FAILED);
1545 mTimerStateFlags.Set(TimerStateFlag::kUnsubscribeTimerRunning);
1551 void BLEEndPoint::StopConnectTimer()
1553 // Cancel any existing connect timer.
1554 mBle->mSystemLayer->CancelTimer(HandleConnectTimeout, this);
1555 mTimerStateFlags.Clear(TimerStateFlag::kConnectTimerRunning);
1558 void BLEEndPoint::StopReceiveConnectionTimer()
1560 // Cancel any existing receive connection timer.
1561 mBle->mSystemLayer->CancelTimer(HandleReceiveConnectionTimeout, this);
1562 mTimerStateFlags.Clear(TimerStateFlag::kReceiveConnectionTimerRunning);
1565 void BLEEndPoint::StopAckReceivedTimer()
1567 // Cancel any existing ack-received timer.
1568 mBle->mSystemLayer->CancelTimer(HandleAckReceivedTimeout, this);
1569 mTimerStateFlags.Clear(TimerStateFlag::kAckReceivedTimerRunning);
1572 void BLEEndPoint::StopSendAckTimer()
1574 // Cancel any existing send-ack timer.
1575 mBle->mSystemLayer->CancelTimer(HandleSendAckTimeout, this);
1576 mTimerStateFlags.Clear(TimerStateFlag::kSendAckTimerRunning);
1579 void BLEEndPoint::StopUnsubscribeTimer()
1581 // Cancel any existing unsubscribe timer.
1582 mBle->mSystemLayer->CancelTimer(HandleUnsubscribeTimeout, this);
1583 mTimerStateFlags.Clear(TimerStateFlag::kUnsubscribeTimerRunning);
1586 void BLEEndPoint::HandleConnectTimeout(chip::System::Layer * systemLayer, void * appState, chip::System::Error err)
1588 BLEEndPoint * ep = static_cast<BLEEndPoint *>(appState);
1590 // Check for event-based timer race condition.
1591 if (ep->mTimerStateFlags.Has(TimerStateFlag::kConnectTimerRunning))
1593 ChipLogError(Ble, "connect handshake timed out, closing ep %p", ep);
1594 ep->mTimerStateFlags.Clear(TimerStateFlag::kConnectTimerRunning);
1595 ep->DoClose(kBleCloseFlag_AbortTransmission, BLE_ERROR_CONNECT_TIMED_OUT);
1599 void BLEEndPoint::HandleReceiveConnectionTimeout(chip::System::Layer * systemLayer, void * appState, chip::System::Error err)
1601 BLEEndPoint * ep = static_cast<BLEEndPoint *>(appState);
1603 // Check for event-based timer race condition.
1604 if (ep->mTimerStateFlags.Has(TimerStateFlag::kReceiveConnectionTimerRunning))
1606 ChipLogError(Ble, "receive handshake timed out, closing ep %p", ep);
1607 ep->mTimerStateFlags.Clear(TimerStateFlag::kReceiveConnectionTimerRunning);
1608 ep->DoClose(kBleCloseFlag_SuppressCallback | kBleCloseFlag_AbortTransmission, BLE_ERROR_RECEIVE_TIMED_OUT);
1612 void BLEEndPoint::HandleAckReceivedTimeout(chip::System::Layer * systemLayer, void * appState, chip::System::Error err)
1614 BLEEndPoint * ep = static_cast<BLEEndPoint *>(appState);
1616 // Check for event-based timer race condition.
1617 if (ep->mTimerStateFlags.Has(TimerStateFlag::kAckReceivedTimerRunning))
1619 ChipLogError(Ble, "ack recv timeout, closing ep %p", ep);
1620 ep->mBtpEngine.LogStateDebug();
1621 ep->mTimerStateFlags.Clear(TimerStateFlag::kAckReceivedTimerRunning);
1622 ep->DoClose(kBleCloseFlag_AbortTransmission, BLE_ERROR_FRAGMENT_ACK_TIMED_OUT);
1626 void BLEEndPoint::HandleSendAckTimeout(chip::System::Layer * systemLayer, void * appState, chip::System::Error err)
1628 BLEEndPoint * ep = static_cast<BLEEndPoint *>(appState);
1630 // Check for event-based timer race condition.
1631 if (ep->mTimerStateFlags.Has(TimerStateFlag::kSendAckTimerRunning))
1633 ep->mTimerStateFlags.Clear(TimerStateFlag::kSendAckTimerRunning);
1635 // If previous stand-alone ack isn't still in flight...
1636 if (!ep->mConnStateFlags.Has(ConnectionStateFlag::kStandAloneAckInFlight))
1638 BLE_ERROR sendErr = ep->DriveStandAloneAck();
1640 if (sendErr != BLE_NO_ERROR)
1642 ep->DoClose(kBleCloseFlag_AbortTransmission, sendErr);
1648 void BLEEndPoint::HandleUnsubscribeTimeout(chip::System::Layer * systemLayer, void * appState, chip::System::Error err)
1650 BLEEndPoint * ep = static_cast<BLEEndPoint *>(appState);
1652 // Check for event-based timer race condition.
1653 if (ep->mTimerStateFlags.Has(TimerStateFlag::kUnsubscribeTimerRunning))
1655 ChipLogError(Ble, "unsubscribe timed out, ble ep %p", ep);
1656 ep->mTimerStateFlags.Clear(TimerStateFlag::kUnsubscribeTimerRunning);
1657 ep->HandleUnsubscribeComplete();
1661 } /* namespace Ble */
1662 } /* namespace chip */
1664 #endif /* CONFIG_NETWORK_LAYER_BLE */