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