/src/openweave-core/src/ble/BleLayer.cpp
Line | Count | Source |
1 | | /* |
2 | | * |
3 | | * Copyright (c) 2014-2017 Nest Labs, Inc. |
4 | | * All rights reserved. |
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 file implements objects which provide an abstraction layer between |
22 | | * a platform's Bluetooth Low Energy (BLE) implementation and the Weave |
23 | | * stack. |
24 | | * |
25 | | * The BleLayer obect accepts BLE data and control input from the |
26 | | * application via a functional interface. It performs the fragmentation |
27 | | * and reassembly required to transmit Weave message via a BLE GATT |
28 | | * characteristic interface, and drives incoming messages up the Weave |
29 | | * stack. |
30 | | * |
31 | | * During initialization, the BleLayer object requires a pointer to the |
32 | | * platform's implementation of the BlePlatformDelegate and |
33 | | * BleApplicationDelegate objects. |
34 | | * |
35 | | * The BlePlatformDelegate provides the Weave stack with an interface |
36 | | * by which to form and cancel GATT subscriptions, read and write |
37 | | * GATT characteristic values, send GATT characteristic notifications, |
38 | | * respond to GATT read requests, and close BLE connections. |
39 | | * |
40 | | * The BleApplicationDelegate provides a mechanism for Weave to inform |
41 | | * the application when it has finished using a given BLE connection, |
42 | | * i.e when the WeaveConnection object wrapping this connection has |
43 | | * closed. This allows the application to either close the BLE connection |
44 | | * or continue to keep it open for non-Weave purposes. |
45 | | * |
46 | | * To enable Weave over BLE for a new platform, the application developer |
47 | | * must provide an implementation for both delegates, provides points to |
48 | | * instances of these delegates on startup, and ensure that the |
49 | | * application calls the necessary BleLayer functions when appropriate to |
50 | | * drive BLE data and control input up the stack. |
51 | | */ |
52 | | |
53 | | #include <BleLayer/BleConfig.h> |
54 | | |
55 | | #if CONFIG_NETWORK_LAYER_BLE |
56 | | |
57 | | #include <string.h> |
58 | | |
59 | | #include <BleLayer/BlePlatformDelegate.h> |
60 | | #include <BleLayer/BleApplicationDelegate.h> |
61 | | #include <BleLayer/BleLayer.h> |
62 | | #include <BleLayer/BleUUID.h> |
63 | | #include <BleLayer/BLEEndPoint.h> |
64 | | |
65 | | #include <Weave/Core/WeaveEncoding.h> |
66 | | #include <Weave/Support/logging/WeaveLogging.h> |
67 | | #include <Weave/Support/CodeUtils.h> |
68 | | |
69 | | // clang-format off |
70 | | |
71 | 0 | #define CAPABILITIES_REQUEST_MAGICNUM_LEN 2 |
72 | 0 | #define CAPABILITIES_REQUEST_L2CAP_MTU_LEN 2 |
73 | 0 | #define CAPABILITIES_REQUEST_SUPPORTED_VERSIONS_LEN 4 |
74 | 0 | #define CAPABILITIES_REQUEST_WINDOW_SIZE_LEN 1 |
75 | 0 | #define CAPABILITIES_REQUEST_LEN (CAPABILITIES_REQUEST_MAGICNUM_LEN + \ |
76 | 0 | CAPABILITIES_REQUEST_L2CAP_MTU_LEN + \ |
77 | 0 | CAPABILITIES_REQUEST_SUPPORTED_VERSIONS_LEN + \ |
78 | 0 | CAPABILITIES_REQUEST_WINDOW_SIZE_LEN) |
79 | | |
80 | 0 | #define CAPABILITIES_RESPONSE_MAGICNUM_LEN 2 |
81 | 0 | #define CAPABILITIES_RESPONSE_L2CAP_MTU_LEN 2 |
82 | 0 | #define CAPABILITIES_RESPONSE_SELECTED_PROTOCOL_VERSION_LEN 1 |
83 | 0 | #define CAPABILITIES_RESPONSE_WINDOW_SIZE_LEN 1 |
84 | 0 | #define CAPABILITIES_RESPONSE_LEN (CAPABILITIES_RESPONSE_MAGICNUM_LEN + \ |
85 | 0 | CAPABILITIES_RESPONSE_L2CAP_MTU_LEN + \ |
86 | 0 | CAPABILITIES_RESPONSE_SELECTED_PROTOCOL_VERSION_LEN + \ |
87 | 0 | CAPABILITIES_RESPONSE_WINDOW_SIZE_LEN) |
88 | | |
89 | | // Magic values expected in first 2 bytes of valid BLE transport capabilities request or response: |
90 | 0 | #define CAPABILITIES_MSG_CHECK_BYTE_1 'n' |
91 | 0 | #define CAPABILITIES_MSG_CHECK_BYTE_2 'l' |
92 | | |
93 | | // clang-format on |
94 | | |
95 | | namespace nl { |
96 | | namespace Ble { |
97 | | |
98 | | class BleEndPointPool |
99 | | { |
100 | | public: |
101 | 0 | int Size() const { return BLE_LAYER_NUM_BLE_ENDPOINTS; } |
102 | | |
103 | | BLEEndPoint * Get(int i) const |
104 | 0 | { |
105 | 0 | static union |
106 | 0 | { |
107 | 0 | uint8_t Pool[sizeof(BLEEndPoint) * BLE_LAYER_NUM_BLE_ENDPOINTS]; |
108 | 0 | BLEEndPoint::AlignT ForceAlignment; |
109 | 0 | } sEndPointPool; |
110 | |
|
111 | 0 | if (i < BLE_LAYER_NUM_BLE_ENDPOINTS) |
112 | 0 | { |
113 | 0 | return (BLEEndPoint *) (sEndPointPool.Pool + (sizeof(BLEEndPoint) * i)); |
114 | 0 | } |
115 | 0 | else |
116 | 0 | { |
117 | 0 | return NULL; |
118 | 0 | } |
119 | 0 | } |
120 | | |
121 | | BLEEndPoint * Find(BLE_CONNECTION_OBJECT c) |
122 | 0 | { |
123 | 0 | if (c == BLE_CONNECTION_UNINITIALIZED) |
124 | 0 | { |
125 | 0 | return NULL; |
126 | 0 | } |
127 | | |
128 | 0 | for (int i = 0; i < BLE_LAYER_NUM_BLE_ENDPOINTS; i++) |
129 | 0 | { |
130 | 0 | BLEEndPoint * elem = Get(i); |
131 | 0 | if (elem->mBle != NULL && elem->mConnObj == c) |
132 | 0 | { |
133 | 0 | return elem; |
134 | 0 | } |
135 | 0 | } |
136 | | |
137 | 0 | return NULL; |
138 | 0 | } |
139 | | |
140 | | BLEEndPoint * GetFree() const |
141 | 0 | { |
142 | 0 | for (int i = 0; i < BLE_LAYER_NUM_BLE_ENDPOINTS; i++) |
143 | 0 | { |
144 | 0 | BLEEndPoint * elem = Get(i); |
145 | 0 | if (elem->mBle == NULL) |
146 | 0 | { |
147 | 0 | return elem; |
148 | 0 | } |
149 | 0 | } |
150 | 0 | return NULL; |
151 | 0 | } |
152 | | }; |
153 | | |
154 | | // EndPoint Pools |
155 | | // |
156 | | static BleEndPointPool sBLEEndPointPool; |
157 | | |
158 | | // UUIDs used internally by BleLayer: |
159 | | |
160 | | const WeaveBleUUID BleLayer::WEAVE_BLE_CHAR_1_ID = { { // 18EE2EF5-263D-4559-959F-4F9C429F9D11 |
161 | | 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, |
162 | | 0x9F, 0x9D, 0x11 } }; |
163 | | |
164 | | const WeaveBleUUID BleLayer::WEAVE_BLE_CHAR_2_ID = { { // 18EE2EF5-263D-4559-959F-4F9C429F9D12 |
165 | | 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, |
166 | | 0x9F, 0x9D, 0x12 } }; |
167 | | |
168 | | void BleLayerObject::Release() |
169 | 0 | { |
170 | | // Decrement the ref count. When it reaches zero, NULL out the pointer to the Weave::System::Layer |
171 | | // object. This effectively declared the object free and ready for re-allocation. |
172 | 0 | mRefCount--; |
173 | 0 | if (mRefCount == 0) |
174 | 0 | { |
175 | 0 | mBle = NULL; |
176 | 0 | } |
177 | 0 | } |
178 | | |
179 | | // BleTransportCapabilitiesRequestMessage implementation: |
180 | | |
181 | | void BleTransportCapabilitiesRequestMessage::SetSupportedProtocolVersion(uint8_t index, uint8_t version) |
182 | 0 | { |
183 | 0 | uint8_t mask; |
184 | | |
185 | | // If even-index, store version in lower 4 bits; else, higher 4 bits. |
186 | 0 | if (index % 2 == 0) |
187 | 0 | { |
188 | 0 | mask = 0x0F; |
189 | 0 | } |
190 | 0 | else |
191 | 0 | { |
192 | 0 | mask = 0xF0; |
193 | 0 | version = version << 4; |
194 | 0 | } |
195 | |
|
196 | 0 | version &= mask; |
197 | |
|
198 | 0 | mSupportedProtocolVersions[(index / 2)] &= ~mask; // Clear version at index; leave other version in same byte alone |
199 | 0 | mSupportedProtocolVersions[(index / 2)] |= version; |
200 | 0 | } |
201 | | |
202 | | BLE_ERROR BleTransportCapabilitiesRequestMessage::Encode(PacketBuffer * msgBuf) const |
203 | 0 | { |
204 | 0 | uint8_t * p = msgBuf->Start(); |
205 | 0 | BLE_ERROR err = BLE_NO_ERROR; |
206 | | |
207 | | // Verify we can write the fixed-length request without running into the end of the buffer. |
208 | 0 | VerifyOrExit(msgBuf->MaxDataLength() >= CAPABILITIES_REQUEST_LEN, err = BLE_ERROR_NO_MEMORY); |
209 | | |
210 | 0 | nl::Weave::Encoding::Write8(p, CAPABILITIES_MSG_CHECK_BYTE_1); |
211 | 0 | nl::Weave::Encoding::Write8(p, CAPABILITIES_MSG_CHECK_BYTE_2); |
212 | |
|
213 | 0 | for (int i = 0; i < CAPABILITIES_REQUEST_SUPPORTED_VERSIONS_LEN; i++) |
214 | 0 | { |
215 | 0 | nl::Weave::Encoding::Write8(p, mSupportedProtocolVersions[i]); |
216 | 0 | } |
217 | |
|
218 | 0 | nl::Weave::Encoding::LittleEndian::Write16(p, mMtu); |
219 | 0 | nl::Weave::Encoding::Write8(p, mWindowSize); |
220 | |
|
221 | 0 | msgBuf->SetDataLength(CAPABILITIES_REQUEST_LEN); |
222 | |
|
223 | 0 | exit: |
224 | 0 | return err; |
225 | 0 | } |
226 | | |
227 | | BLE_ERROR BleTransportCapabilitiesRequestMessage::Decode(const PacketBuffer & msgBuf, BleTransportCapabilitiesRequestMessage & msg) |
228 | 0 | { |
229 | 0 | const uint8_t * p = msgBuf.Start(); |
230 | 0 | BLE_ERROR err = BLE_NO_ERROR; |
231 | | |
232 | | // Verify we can read the fixed-length request without running into the end of the buffer. |
233 | 0 | VerifyOrExit(msgBuf.DataLength() >= CAPABILITIES_REQUEST_LEN, err = BLE_ERROR_MESSAGE_INCOMPLETE); |
234 | | |
235 | 0 | VerifyOrExit(CAPABILITIES_MSG_CHECK_BYTE_1 == nl::Weave::Encoding::Read8(p), err = BLE_ERROR_INVALID_MESSAGE); |
236 | 0 | VerifyOrExit(CAPABILITIES_MSG_CHECK_BYTE_2 == nl::Weave::Encoding::Read8(p), err = BLE_ERROR_INVALID_MESSAGE); |
237 | | |
238 | 0 | for (int i = 0; i < CAPABILITIES_REQUEST_SUPPORTED_VERSIONS_LEN; i++) |
239 | 0 | { |
240 | 0 | msg.mSupportedProtocolVersions[i] = nl::Weave::Encoding::Read8(p); |
241 | 0 | } |
242 | |
|
243 | 0 | msg.mMtu = nl::Weave::Encoding::LittleEndian::Read16(p); |
244 | 0 | msg.mWindowSize = nl::Weave::Encoding::Read8(p); |
245 | |
|
246 | 0 | exit: |
247 | 0 | return err; |
248 | 0 | } |
249 | | |
250 | | // BleTransportCapabilitiesResponseMessage implementation: |
251 | | |
252 | | BLE_ERROR BleTransportCapabilitiesResponseMessage::Encode(PacketBuffer * msgBuf) const |
253 | 0 | { |
254 | 0 | uint8_t * p = msgBuf->Start(); |
255 | 0 | BLE_ERROR err = BLE_NO_ERROR; |
256 | | |
257 | | // Verify we can write the fixed-length request without running into the end of the buffer. |
258 | 0 | VerifyOrExit(msgBuf->MaxDataLength() >= CAPABILITIES_RESPONSE_LEN, err = BLE_ERROR_NO_MEMORY); |
259 | | |
260 | 0 | nl::Weave::Encoding::Write8(p, CAPABILITIES_MSG_CHECK_BYTE_1); |
261 | 0 | nl::Weave::Encoding::Write8(p, CAPABILITIES_MSG_CHECK_BYTE_2); |
262 | |
|
263 | 0 | nl::Weave::Encoding::Write8(p, mSelectedProtocolVersion); |
264 | 0 | nl::Weave::Encoding::LittleEndian::Write16(p, mFragmentSize); |
265 | 0 | nl::Weave::Encoding::Write8(p, mWindowSize); |
266 | |
|
267 | 0 | msgBuf->SetDataLength(CAPABILITIES_RESPONSE_LEN); |
268 | |
|
269 | 0 | exit: |
270 | 0 | return err; |
271 | 0 | } |
272 | | |
273 | | BLE_ERROR BleTransportCapabilitiesResponseMessage::Decode(const PacketBuffer & msgBuf, |
274 | | BleTransportCapabilitiesResponseMessage & msg) |
275 | 0 | { |
276 | 0 | const uint8_t * p = msgBuf.Start(); |
277 | 0 | BLE_ERROR err = BLE_NO_ERROR; |
278 | | |
279 | | // Verify we can read the fixed-length response without running into the end of the buffer. |
280 | 0 | VerifyOrExit(msgBuf.DataLength() >= CAPABILITIES_RESPONSE_LEN, err = BLE_ERROR_MESSAGE_INCOMPLETE); |
281 | | |
282 | 0 | VerifyOrExit(CAPABILITIES_MSG_CHECK_BYTE_1 == nl::Weave::Encoding::Read8(p), err = BLE_ERROR_INVALID_MESSAGE); |
283 | 0 | VerifyOrExit(CAPABILITIES_MSG_CHECK_BYTE_2 == nl::Weave::Encoding::Read8(p), err = BLE_ERROR_INVALID_MESSAGE); |
284 | | |
285 | 0 | msg.mSelectedProtocolVersion = nl::Weave::Encoding::Read8(p); |
286 | 0 | msg.mFragmentSize = nl::Weave::Encoding::LittleEndian::Read16(p); |
287 | 0 | msg.mWindowSize = nl::Weave::Encoding::Read8(p); |
288 | |
|
289 | 0 | exit: |
290 | 0 | return err; |
291 | 0 | } |
292 | | |
293 | | // BleLayer implementation: |
294 | | |
295 | | BleLayer::BleLayer() |
296 | 10 | { |
297 | 10 | mState = kState_NotInitialized; |
298 | 10 | } |
299 | | |
300 | | BLE_ERROR BleLayer::Init(BlePlatformDelegate * platformDelegate, BleApplicationDelegate * appDelegate, |
301 | | Weave::System::Layer * systemLayer) |
302 | 0 | { |
303 | 0 | BLE_ERROR err = BLE_NO_ERROR; |
304 | |
|
305 | 0 | RegisterBleLayerErrorFormatter(); |
306 | |
|
307 | 0 | VerifyOrExit(platformDelegate != NULL, err = BLE_ERROR_BAD_ARGS); |
308 | 0 | VerifyOrExit(appDelegate != NULL, err = BLE_ERROR_BAD_ARGS); |
309 | 0 | VerifyOrExit(systemLayer != NULL, err = BLE_ERROR_BAD_ARGS); |
310 | | |
311 | 0 | if (mState != kState_NotInitialized) |
312 | 0 | { |
313 | 0 | return BLE_ERROR_INCORRECT_STATE; |
314 | 0 | } |
315 | | |
316 | 0 | mPlatformDelegate = platformDelegate; |
317 | 0 | mApplicationDelegate = appDelegate; |
318 | 0 | mSystemLayer = systemLayer; |
319 | |
|
320 | 0 | memset(&sBLEEndPointPool, 0, sizeof(sBLEEndPointPool)); |
321 | |
|
322 | 0 | mState = kState_Initialized; |
323 | |
|
324 | | #if WEAVE_ENABLE_WOBLE_TEST |
325 | | mTestBleEndPoint = NULL; |
326 | | #endif |
327 | |
|
328 | 0 | exit: |
329 | 0 | return err; |
330 | 0 | } |
331 | | |
332 | | BLE_ERROR BleLayer::Shutdown() |
333 | 0 | { |
334 | 0 | mState = kState_NotInitialized; |
335 | | |
336 | | // Close and free all BLE end points. |
337 | 0 | for (int i = 0; i < BLE_LAYER_NUM_BLE_ENDPOINTS; i++) |
338 | 0 | { |
339 | 0 | BLEEndPoint * elem = sBLEEndPointPool.Get(i); |
340 | | |
341 | | // If end point was initialized, and has not since been freed... |
342 | 0 | if (elem->mBle != NULL) |
343 | 0 | { |
344 | | // If end point hasn't already been closed... |
345 | 0 | if (elem->mState != BLEEndPoint::kState_Closed) |
346 | 0 | { |
347 | | // Close end point such that callbacks are suppressed and pending transmissions aborted. |
348 | 0 | elem->Abort(); |
349 | 0 | } |
350 | | |
351 | | // If end point was closed, but is still waiting for GATT unsubscribe to complete, free it anyway. |
352 | | // This cancels the unsubscribe timer (plus all the end point's other timers). |
353 | 0 | if (elem->IsUnsubscribePending()) |
354 | 0 | { |
355 | 0 | elem->Free(); |
356 | 0 | } |
357 | 0 | } |
358 | 0 | } |
359 | |
|
360 | 0 | return BLE_NO_ERROR; |
361 | 0 | } |
362 | | |
363 | | BLE_ERROR BleLayer::NewBleEndPoint(BLEEndPoint ** retEndPoint, BLE_CONNECTION_OBJECT connObj, BleRole role, bool autoClose) |
364 | 0 | { |
365 | 0 | *retEndPoint = NULL; |
366 | |
|
367 | 0 | if (mState != kState_Initialized) |
368 | 0 | { |
369 | 0 | return BLE_ERROR_INCORRECT_STATE; |
370 | 0 | } |
371 | | |
372 | 0 | if (connObj == BLE_CONNECTION_UNINITIALIZED) |
373 | 0 | { |
374 | 0 | return BLE_ERROR_BAD_ARGS; |
375 | 0 | } |
376 | | |
377 | 0 | *retEndPoint = sBLEEndPointPool.GetFree(); |
378 | 0 | if (*retEndPoint == NULL) |
379 | 0 | { |
380 | 0 | WeaveLogError(Ble, "%s endpoint pool FULL", "Ble"); |
381 | 0 | return BLE_ERROR_NO_ENDPOINTS; |
382 | 0 | } |
383 | | |
384 | 0 | (*retEndPoint)->Init(this, connObj, role, autoClose); |
385 | |
|
386 | | #if WEAVE_ENABLE_WOBLE_TEST |
387 | | mTestBleEndPoint = *retEndPoint; |
388 | | #endif |
389 | |
|
390 | 0 | return BLE_NO_ERROR; |
391 | 0 | } |
392 | | |
393 | | // Handle remote central's initiation of Weave over BLE protocol handshake. |
394 | | BLE_ERROR BleLayer::HandleBleTransportConnectionInitiated(BLE_CONNECTION_OBJECT connObj, PacketBuffer * pBuf) |
395 | 0 | { |
396 | 0 | BLE_ERROR err = BLE_NO_ERROR; |
397 | 0 | BLEEndPoint * newEndPoint = NULL; |
398 | | |
399 | | // Only BLE peripherals can receive GATT writes, so specify this role in our creation of the BLEEndPoint. |
400 | | // Set autoClose = false. Peripherals only notify the application when an end point releases a BLE connection. |
401 | 0 | err = NewBleEndPoint(&newEndPoint, connObj, kBleRole_Peripheral, false); |
402 | 0 | SuccessOrExit(err); |
403 | | |
404 | 0 | newEndPoint->mAppState = mAppState; |
405 | |
|
406 | 0 | err = newEndPoint->Receive(pBuf); |
407 | 0 | pBuf = NULL; |
408 | 0 | SuccessOrExit(err); // If we fail here, end point will have already released connection and freed itself. |
409 | | |
410 | 0 | exit: |
411 | 0 | if (pBuf != NULL) |
412 | 0 | { |
413 | 0 | PacketBuffer::Free(pBuf); |
414 | 0 | } |
415 | | |
416 | | // If we failed to allocate a new end point, release underlying BLE connection. Central's handshake will time out |
417 | | // if the application decides to keep the BLE connection open. |
418 | 0 | if (newEndPoint == NULL) |
419 | 0 | { |
420 | 0 | mApplicationDelegate->NotifyWeaveConnectionClosed(connObj); |
421 | 0 | } |
422 | |
|
423 | 0 | if (err != BLE_NO_ERROR) |
424 | 0 | { |
425 | 0 | WeaveLogError(Ble, "HandleWeaveConnectionReceived failed, err = %d", err); |
426 | 0 | } |
427 | |
|
428 | 0 | return err; |
429 | 0 | } |
430 | | |
431 | | bool BleLayer::HandleWriteReceived(BLE_CONNECTION_OBJECT connObj, const WeaveBleUUID * svcId, const WeaveBleUUID * charId, |
432 | | PacketBuffer * pBuf) |
433 | 0 | { |
434 | 0 | if (!UUIDsMatch(&WEAVE_BLE_SVC_ID, svcId)) |
435 | 0 | { |
436 | 0 | WeaveLogError(Ble, "ble write rcvd on unknown svc id"); |
437 | 0 | ExitNow(); |
438 | 0 | } |
439 | | |
440 | 0 | if (UUIDsMatch(&WEAVE_BLE_CHAR_1_ID, charId)) |
441 | 0 | { |
442 | 0 | if (pBuf == NULL) |
443 | 0 | { |
444 | 0 | WeaveLogError(Ble, "rcvd null ble write"); |
445 | 0 | ExitNow(); |
446 | 0 | } |
447 | | |
448 | | // Find matching connection end point. |
449 | 0 | BLEEndPoint * endPoint = sBLEEndPointPool.Find(connObj); |
450 | |
|
451 | 0 | if (endPoint != NULL) |
452 | 0 | { |
453 | 0 | BLE_ERROR status = endPoint->Receive(pBuf); |
454 | 0 | pBuf = NULL; |
455 | 0 | if (status != BLE_NO_ERROR) |
456 | 0 | { |
457 | 0 | WeaveLogError(Ble, "BLEEndPoint rcv failed, err = %d", status); |
458 | 0 | } |
459 | 0 | } |
460 | 0 | else |
461 | 0 | { |
462 | 0 | BLE_ERROR status = HandleBleTransportConnectionInitiated(connObj, pBuf); |
463 | 0 | pBuf = NULL; |
464 | 0 | if (status != BLE_NO_ERROR) |
465 | 0 | { |
466 | 0 | WeaveLogError(Ble, "failed handle new Weave BLE connection, status = %d", status); |
467 | 0 | } |
468 | 0 | } |
469 | 0 | } |
470 | 0 | else |
471 | 0 | { |
472 | 0 | WeaveLogError(Ble, "ble write rcvd on unknown char"); |
473 | 0 | } |
474 | | |
475 | 0 | exit: |
476 | 0 | if (pBuf != NULL) |
477 | 0 | { |
478 | 0 | PacketBuffer::Free(pBuf); |
479 | 0 | } |
480 | |
|
481 | 0 | return true; |
482 | 0 | } |
483 | | |
484 | | bool BleLayer::HandleIndicationReceived(BLE_CONNECTION_OBJECT connObj, const WeaveBleUUID * svcId, const WeaveBleUUID * charId, |
485 | | PacketBuffer * pBuf) |
486 | 0 | { |
487 | 0 | if (!UUIDsMatch(&WEAVE_BLE_SVC_ID, svcId)) |
488 | 0 | { |
489 | 0 | return false; |
490 | 0 | } |
491 | | |
492 | 0 | if (UUIDsMatch(&WEAVE_BLE_CHAR_2_ID, charId)) |
493 | 0 | { |
494 | 0 | if (pBuf == NULL) |
495 | 0 | { |
496 | 0 | WeaveLogError(Ble, "rcvd null ble indication"); |
497 | 0 | ExitNow(); |
498 | 0 | } |
499 | | |
500 | | // find matching connection end point. |
501 | 0 | BLEEndPoint * endPoint = sBLEEndPointPool.Find(connObj); |
502 | |
|
503 | 0 | if (endPoint != NULL) |
504 | 0 | { |
505 | 0 | BLE_ERROR status = endPoint->Receive(pBuf); |
506 | 0 | pBuf = NULL; |
507 | 0 | if (status != BLE_NO_ERROR) |
508 | 0 | { |
509 | 0 | WeaveLogError(Ble, "BLEEndPoint rcv failed, err = %d", status); |
510 | 0 | } |
511 | 0 | } |
512 | 0 | else |
513 | 0 | { |
514 | 0 | WeaveLogDetail(Ble, "no endpoint for rcvd indication"); |
515 | 0 | } |
516 | 0 | } |
517 | 0 | else |
518 | 0 | { |
519 | 0 | WeaveLogError(Ble, "ble ind rcvd on unknown char"); |
520 | 0 | } |
521 | | |
522 | 0 | exit: |
523 | 0 | if (pBuf != NULL) |
524 | 0 | { |
525 | 0 | PacketBuffer::Free(pBuf); |
526 | 0 | } |
527 | |
|
528 | 0 | return true; |
529 | 0 | } |
530 | | |
531 | | bool BleLayer::HandleWriteConfirmation(BLE_CONNECTION_OBJECT connObj, const WeaveBleUUID * svcId, const WeaveBleUUID * charId) |
532 | 0 | { |
533 | 0 | if (!UUIDsMatch(&WEAVE_BLE_SVC_ID, svcId)) |
534 | 0 | { |
535 | 0 | return false; |
536 | 0 | } |
537 | | |
538 | 0 | if (UUIDsMatch(&WEAVE_BLE_CHAR_1_ID, charId)) |
539 | 0 | { |
540 | 0 | HandleAckReceived(connObj); |
541 | 0 | } |
542 | 0 | else |
543 | 0 | { |
544 | 0 | WeaveLogError(Ble, "ble write con rcvd on unknown char"); |
545 | 0 | } |
546 | |
|
547 | 0 | return true; |
548 | 0 | } |
549 | | |
550 | | bool BleLayer::HandleIndicationConfirmation(BLE_CONNECTION_OBJECT connObj, const WeaveBleUUID * svcId, const WeaveBleUUID * charId) |
551 | 0 | { |
552 | 0 | if (!UUIDsMatch(&WEAVE_BLE_SVC_ID, svcId)) |
553 | 0 | { |
554 | 0 | return false; |
555 | 0 | } |
556 | | |
557 | 0 | if (UUIDsMatch(&WEAVE_BLE_CHAR_2_ID, charId)) |
558 | 0 | { |
559 | 0 | HandleAckReceived(connObj); |
560 | 0 | } |
561 | 0 | else |
562 | 0 | { |
563 | 0 | WeaveLogError(Ble, "ble ind con rcvd on unknown char"); |
564 | 0 | } |
565 | |
|
566 | 0 | return true; |
567 | 0 | } |
568 | | |
569 | | void BleLayer::HandleAckReceived(BLE_CONNECTION_OBJECT connObj) |
570 | 0 | { |
571 | | // find matching connection end point. |
572 | 0 | BLEEndPoint * endPoint = sBLEEndPointPool.Find(connObj); |
573 | |
|
574 | 0 | if (endPoint != NULL) |
575 | 0 | { |
576 | 0 | BLE_ERROR status = endPoint->HandleGattSendConfirmationReceived(); |
577 | |
|
578 | 0 | if (status != BLE_NO_ERROR) |
579 | 0 | { |
580 | 0 | WeaveLogError(Ble, "endpoint conf recvd failed, err = %d", status); |
581 | 0 | } |
582 | 0 | } |
583 | 0 | else |
584 | 0 | { |
585 | 0 | WeaveLogError(Ble, "no endpoint for BLE sent data ack"); |
586 | 0 | } |
587 | 0 | } |
588 | | |
589 | | bool BleLayer::HandleSubscribeReceived(BLE_CONNECTION_OBJECT connObj, const WeaveBleUUID * svcId, const WeaveBleUUID * charId) |
590 | 0 | { |
591 | 0 | if (!UUIDsMatch(&WEAVE_BLE_SVC_ID, svcId)) |
592 | 0 | { |
593 | 0 | return false; |
594 | 0 | } |
595 | | |
596 | 0 | if (UUIDsMatch(&WEAVE_BLE_CHAR_2_ID, charId)) |
597 | 0 | { |
598 | | // Find end point already associated with BLE connection, if any. |
599 | 0 | BLEEndPoint * endPoint = sBLEEndPointPool.Find(connObj); |
600 | |
|
601 | 0 | if (endPoint != NULL) |
602 | 0 | { |
603 | 0 | endPoint->HandleSubscribeReceived(); |
604 | 0 | } |
605 | 0 | else |
606 | 0 | { |
607 | 0 | WeaveLogError(Ble, "no endpoint for sub recvd"); |
608 | 0 | } |
609 | 0 | } |
610 | |
|
611 | 0 | return true; |
612 | 0 | } |
613 | | |
614 | | bool BleLayer::HandleSubscribeComplete(BLE_CONNECTION_OBJECT connObj, const WeaveBleUUID * svcId, const WeaveBleUUID * charId) |
615 | 0 | { |
616 | 0 | if (!UUIDsMatch(&WEAVE_BLE_SVC_ID, svcId)) |
617 | 0 | { |
618 | 0 | return false; |
619 | 0 | } |
620 | | |
621 | 0 | if (UUIDsMatch(&WEAVE_BLE_CHAR_2_ID, charId)) |
622 | 0 | { |
623 | 0 | BLEEndPoint * endPoint = sBLEEndPointPool.Find(connObj); |
624 | |
|
625 | 0 | if (endPoint != NULL) |
626 | 0 | { |
627 | 0 | endPoint->HandleSubscribeComplete(); |
628 | 0 | } |
629 | 0 | else |
630 | 0 | { |
631 | 0 | WeaveLogError(Ble, "no endpoint for sub complete"); |
632 | 0 | } |
633 | 0 | } |
634 | |
|
635 | 0 | return true; |
636 | 0 | } |
637 | | |
638 | | bool BleLayer::HandleUnsubscribeReceived(BLE_CONNECTION_OBJECT connObj, const WeaveBleUUID * svcId, const WeaveBleUUID * charId) |
639 | 0 | { |
640 | 0 | if (!UUIDsMatch(&WEAVE_BLE_SVC_ID, svcId)) |
641 | 0 | { |
642 | 0 | return false; |
643 | 0 | } |
644 | | |
645 | 0 | if (UUIDsMatch(&WEAVE_BLE_CHAR_2_ID, charId)) |
646 | 0 | { |
647 | | // Find end point already associated with BLE connection, if any. |
648 | 0 | BLEEndPoint * endPoint = sBLEEndPointPool.Find(connObj); |
649 | |
|
650 | 0 | if (endPoint != NULL) |
651 | 0 | { |
652 | 0 | endPoint->DoClose(kBleCloseFlag_AbortTransmission, BLE_ERROR_CENTRAL_UNSUBSCRIBED); |
653 | 0 | } |
654 | 0 | else |
655 | 0 | { |
656 | 0 | WeaveLogError(Ble, "no endpoint for unsub recvd"); |
657 | 0 | } |
658 | 0 | } |
659 | |
|
660 | 0 | return true; |
661 | 0 | } |
662 | | |
663 | | bool BleLayer::HandleUnsubscribeComplete(BLE_CONNECTION_OBJECT connObj, const WeaveBleUUID * svcId, const WeaveBleUUID * charId) |
664 | 0 | { |
665 | 0 | if (!UUIDsMatch(&WEAVE_BLE_SVC_ID, svcId)) |
666 | 0 | { |
667 | 0 | return false; |
668 | 0 | } |
669 | | |
670 | 0 | if (UUIDsMatch(&WEAVE_BLE_CHAR_2_ID, charId)) |
671 | 0 | { |
672 | | // Find end point already associated with BLE connection, if any. |
673 | 0 | BLEEndPoint * endPoint = sBLEEndPointPool.Find(connObj); |
674 | |
|
675 | 0 | if (endPoint != NULL) |
676 | 0 | { |
677 | 0 | endPoint->HandleUnsubscribeComplete(); |
678 | 0 | } |
679 | 0 | else |
680 | 0 | { |
681 | 0 | WeaveLogError(Ble, "no endpoint for unsub complete"); |
682 | 0 | } |
683 | 0 | } |
684 | |
|
685 | 0 | return true; |
686 | 0 | } |
687 | | |
688 | | void BleLayer::HandleConnectionError(BLE_CONNECTION_OBJECT connObj, BLE_ERROR err) |
689 | 0 | { |
690 | | // BLE connection has failed somehow, we must find and abort matching connection end point. |
691 | 0 | BLEEndPoint * endPoint = sBLEEndPointPool.Find(connObj); |
692 | |
|
693 | 0 | if (endPoint != NULL) |
694 | 0 | { |
695 | 0 | if (err == BLE_ERROR_GATT_UNSUBSCRIBE_FAILED && endPoint->IsUnsubscribePending()) |
696 | 0 | { |
697 | | // If end point was already closed and just waiting for unsubscribe to complete, free it. Call to Free() |
698 | | // stops unsubscribe timer. |
699 | 0 | endPoint->Free(); |
700 | 0 | } |
701 | 0 | else |
702 | 0 | { |
703 | 0 | endPoint->DoClose(kBleCloseFlag_AbortTransmission, err); |
704 | 0 | } |
705 | 0 | } |
706 | 0 | } |
707 | | |
708 | | BleTransportProtocolVersion BleLayer::GetHighestSupportedProtocolVersion(const BleTransportCapabilitiesRequestMessage & reqMsg) |
709 | 0 | { |
710 | 0 | BleTransportProtocolVersion retVersion = kBleTransportProtocolVersion_None; |
711 | |
|
712 | 0 | uint8_t shift_width = 4; |
713 | |
|
714 | 0 | for (int i = 0; i < NUM_SUPPORTED_PROTOCOL_VERSIONS; i++) |
715 | 0 | { |
716 | 0 | shift_width ^= 4; |
717 | |
|
718 | 0 | uint8_t version = reqMsg.mSupportedProtocolVersions[(i / 2)]; |
719 | 0 | version = (version >> shift_width) & 0x0F; // Grab just the nibble we want. |
720 | |
|
721 | 0 | if ((version >= NL_BLE_TRANSPORT_PROTOCOL_MIN_SUPPORTED_VERSION) && |
722 | 0 | (version <= NL_BLE_TRANSPORT_PROTOCOL_MAX_SUPPORTED_VERSION) && (version > retVersion)) |
723 | 0 | { |
724 | 0 | retVersion = static_cast<BleTransportProtocolVersion>(version); |
725 | 0 | } |
726 | 0 | else if (version == kBleTransportProtocolVersion_None) // Signifies end of supported versions list |
727 | 0 | { |
728 | 0 | break; |
729 | 0 | } |
730 | 0 | } |
731 | |
|
732 | 0 | return retVersion; |
733 | 0 | } |
734 | | |
735 | | } /* namespace Ble */ |
736 | | } /* namespace nl */ |
737 | | |
738 | | #endif /* CONFIG_NETWORK_LAYER_BLE */ |