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