| /* |
| * |
| * Copyright (c) 2017-2018 Nest Labs, Inc. |
| * All rights reserved. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| /** |
| * @file |
| * This file defines WoBluez peripheral interface implementation that hands the wrapper talking with BleLayer via the |
| * corresponding platform interface function when the application passively receives an incoming BLE connection. |
| * |
| */ |
| |
| #include "WoBluez.h" |
| #include "BluezHelperCode.h" |
| |
| #include <InetLayer/InetLayer.h> |
| #include <Weave/Core/WeaveCore.h> |
| #include <Weave/Profiles/echo/WeaveEcho.h> |
| #include <Weave/Support/CodeUtils.h> |
| #include <Weave/Support/ErrorStr.h> |
| |
| #if CONFIG_BLE_PLATFORM_BLUEZ |
| |
| namespace nl { |
| namespace Ble { |
| namespace Platform { |
| namespace BlueZ { |
| |
| // TODO: use single /ble definition of this |
| const WeaveBleUUID WEAVE_BLE_CHAR_1_ID = { { // 18EE2EF5-263D-4559-959F-4F9C429F9D11 |
| 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F, |
| 0x9D, 0x11 } }; |
| |
| const WeaveBleUUID WEAVE_BLE_CHAR_2_ID = { { // 18EE2EF5-263D-4559-959F-4F9C429F9D12 |
| 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F, |
| 0x9D, 0x12 } }; |
| |
| void WoBLEz_NewConnection(void * data) |
| { |
| WeaveLogProgress(Ble, "WoBLEz_NewConnection: %p", data); |
| } |
| |
| void WoBLEz_WriteReceived(void * data, const uint8_t * value, size_t len) |
| { |
| // Peripheral behaviour |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| nl::Weave::System::PacketBuffer * msgBuf = NULL; |
| nl::Weave::System::Error syserr = WEAVE_SYSTEM_NO_ERROR; |
| InEventParam * params = NULL; |
| |
| msgBuf = nl::Weave::System::PacketBuffer::New(); |
| |
| VerifyOrExit(msgBuf != NULL, err = WEAVE_ERROR_NO_MEMORY); |
| VerifyOrExit(msgBuf->AvailableDataLength() >= len, err = WEAVE_ERROR_BUFFER_TOO_SMALL); |
| |
| syserr = gBluezBlePlatformDelegate->NewEventParams(¶ms); |
| SuccessOrExit(syserr); |
| |
| memcpy(msgBuf->Start(), value, len); |
| msgBuf->SetDataLength(len); |
| |
| params->EventType = InEventParam::EventTypeEnum::kEvent_WriteReceived; |
| params->ConnectionObject = data; |
| params->WriteReceived.SvcId = &(nl::Ble::WEAVE_BLE_SVC_ID); |
| params->WriteReceived.CharId = &(WEAVE_BLE_CHAR_1_ID); |
| params->WriteReceived.MsgBuf = msgBuf; |
| |
| syserr = gBluezBlePlatformDelegate->SendToWeaveThread(params); |
| SuccessOrExit(syserr); |
| |
| if (gBluezBleApplicationDelegate != NULL) |
| { |
| gBluezBleApplicationDelegate->NotifyBleActivity(kWoBlePktRx); |
| } |
| params = NULL; |
| msgBuf = NULL; |
| |
| exit: |
| if (syserr != WEAVE_SYSTEM_NO_ERROR) |
| { |
| WeaveLogError(Ble, "WoBLEz_WriteReceived syserr: %d", syserr); |
| } |
| |
| if (params != NULL) |
| { |
| gBluezBlePlatformDelegate->ReleaseEventParams(params); |
| } |
| |
| if (err != WEAVE_NO_ERROR) |
| { |
| WeaveLogError(Ble, "WoBLEz_WriteReceived failed: %d", err); |
| } |
| |
| if (NULL != msgBuf) |
| { |
| nl::Weave::System::PacketBuffer::Free(msgBuf); |
| } |
| } |
| |
| int WoBLEz_SendIndication(void * aClosure) |
| { |
| BluezServerEndpoint * endpoint = gBluezServerEndpoint; |
| nl::Weave::System::PacketBuffer * msgBuf = static_cast<nl::Weave::System::PacketBuffer *>(aClosure); |
| uint8_t * buffer = msgBuf->Start(); |
| size_t len = msgBuf->DataLength(); |
| #if BLE_CONFIG_BLUEZ_MTU_FEATURE |
| struct iovec ioData; |
| #endif // BLE_CONFIG_BLUEZ_MTU_FEATURE |
| |
| g_free(endpoint->weaveC2->value); |
| endpoint->weaveC2->valueLen = len; |
| endpoint->weaveC2->value = static_cast<uint8_t *>(g_memdup(buffer, len)); |
| |
| #if BLE_CONFIG_BLUEZ_MTU_FEATURE |
| if (endpoint->weaveC2->indicatePipeIO) |
| { |
| ioData.iov_base = static_cast<void *>(endpoint->weaveC2->value); |
| ioData.iov_len = endpoint->weaveC2->valueLen; |
| |
| if (io_send(endpoint->weaveC2->indicatePipeIO, &ioData, 1) < 0) |
| { |
| WeaveLogError(Ble, "weave C2 fails to write into pipe"); |
| } |
| } |
| #else // BLE_CONFIG_BLUEZ_MTU_FEATURE, |
| g_dbus_emit_property_changed(endpoint->weaveC2->dbusConn, endpoint->weaveC2->path, CHARACTERISTIC_INTERFACE, "Value"); |
| #endif // BLE_CONFIG_BLUEZ_MTU_FEATURE |
| |
| if (gBluezBleApplicationDelegate != NULL) |
| { |
| gBluezBleApplicationDelegate->NotifyBleActivity(kWoBlePktTx); |
| } |
| nl::Weave::System::PacketBuffer::Free(msgBuf); |
| |
| return G_SOURCE_REMOVE; |
| } |
| |
| bool WoBLEz_ScheduleSendIndication(void * data, nl::Weave::System::PacketBuffer * msgBuf) |
| { |
| const char * msg = NULL; |
| bool success = false; |
| BluezServerEndpoint * endpoint = static_cast<BluezServerEndpoint *>(data); |
| |
| VerifyOrExit(endpoint != NULL, msg = "endpoint is NULL in WoBLEz_SendIndication"); |
| VerifyOrExit(endpoint == gBluezServerEndpoint, msg = "Unexpected endpoint in WoBLEz_SendIndication"); |
| VerifyOrExit(endpoint->weaveC2 != NULL, msg = "weaveC2 is NULL in WoBLEz_SendIndication"); |
| |
| success = RunOnBluezIOThread(WoBLEz_SendIndication, msgBuf); |
| |
| exit: |
| |
| if (NULL != msg) |
| { |
| WeaveLogError(Ble, msg); |
| } |
| |
| if (!success && msgBuf != NULL) |
| { |
| nl::Weave::System::PacketBuffer::Free(msgBuf); |
| } |
| |
| return success; |
| } |
| |
| void WoBLEz_ConnectionClosed(void * data) |
| { |
| InEventParam * params = NULL; |
| nl::Weave::System::Error err = WEAVE_SYSTEM_NO_ERROR; |
| |
| if (data == NULL) |
| { |
| WeaveLogProgress(Ble, "WoBLEz connection has closed"); |
| ExitNow(); |
| } |
| WeaveLogProgress(Ble, "WoBLEz_ConnectionClosed: %p", data); |
| |
| err = gBluezBlePlatformDelegate->NewEventParams(¶ms); |
| SuccessOrExit(err); |
| |
| params->EventType = InEventParam::EventTypeEnum::kEvent_ConnectionError; |
| params->ConnectionObject = data; |
| params->ConnectionError.mErr = BLE_ERROR_REMOTE_DEVICE_DISCONNECTED; |
| |
| err = gBluezBlePlatformDelegate->SendToWeaveThread(params); |
| SuccessOrExit(err); |
| |
| params = NULL; |
| |
| exit: |
| if (err != WEAVE_SYSTEM_NO_ERROR) |
| { |
| WeaveLogError(Ble, "WoBLEz_ConnectionClosed err: %d", err); |
| } |
| |
| if (params != NULL) |
| { |
| gBluezBlePlatformDelegate->ReleaseEventParams(params); |
| } |
| } |
| |
| void WoBLEz_SubscriptionChange(void * data) |
| { |
| InEventParam * params = NULL; |
| nl::Weave::System::Error err = WEAVE_SYSTEM_NO_ERROR; |
| BluezServerEndpoint * endpoint = static_cast<BluezServerEndpoint *>(data); |
| const char * msg = NULL; |
| |
| VerifyOrExit(endpoint != NULL, msg = "endpoint is NULL in WoBLEz_SubscriptionChange"); |
| VerifyOrExit(endpoint == gBluezServerEndpoint, msg = "Unexpected endpoint in WoBLEz_SubscriptionChange"); |
| VerifyOrExit(endpoint->weaveC2 != NULL, msg = "weaveC2 is NULL in WoBLEz_SubscriptionChange"); |
| |
| err = gBluezBlePlatformDelegate->NewEventParams(¶ms); |
| SuccessOrExit(err); |
| |
| params->EventType = endpoint->weaveC2->isNotifying ? InEventParam::EventTypeEnum::kEvent_SubscribeReceived |
| : InEventParam::EventTypeEnum::kEvent_UnsubscribeReceived; |
| params->ConnectionObject = data; |
| params->SubscriptionChange.SvcId = &(nl::Ble::WEAVE_BLE_SVC_ID); |
| params->SubscriptionChange.CharId = &(WEAVE_BLE_CHAR_2_ID); |
| |
| err = gBluezBlePlatformDelegate->SendToWeaveThread(params); |
| SuccessOrExit(err); |
| |
| params = NULL; |
| |
| exit: |
| |
| if (err != WEAVE_SYSTEM_NO_ERROR) |
| { |
| WeaveLogError(Ble, "WoBLEz_ConnectionClosed err: %d", err); |
| } |
| |
| if (params != NULL) |
| { |
| gBluezBlePlatformDelegate->ReleaseEventParams(params); |
| } |
| |
| if (NULL != msg) |
| { |
| WeaveLogError(Ble, msg); |
| } |
| } |
| |
| void WoBLEz_IndicationConfirmation(void * data) |
| { |
| InEventParam * params = NULL; |
| nl::Weave::System::Error err = WEAVE_SYSTEM_NO_ERROR; |
| |
| err = gBluezBlePlatformDelegate->NewEventParams(¶ms); |
| SuccessOrExit(err); |
| |
| params->EventType = InEventParam::EventTypeEnum::kEvent_IndicationConfirmation; |
| params->ConnectionObject = data; |
| params->IndicationConfirmation.SvcId = &(nl::Ble::WEAVE_BLE_SVC_ID); |
| params->IndicationConfirmation.CharId = &(WEAVE_BLE_CHAR_2_ID); |
| |
| err = gBluezBlePlatformDelegate->SendToWeaveThread(params); |
| SuccessOrExit(err); |
| |
| params = NULL; |
| |
| exit: |
| if (err != WEAVE_SYSTEM_NO_ERROR) |
| { |
| WeaveLogError(Ble, "WoBLEz_IndicationConfirmation err: %d", err); |
| } |
| |
| if (params != NULL) |
| { |
| gBluezBlePlatformDelegate->ReleaseEventParams(params); |
| } |
| } |
| |
| } // namespace BlueZ |
| } /* namespace Platform */ |
| } /* namespace Ble */ |
| } /* namespace nl */ |
| |
| #endif /* CONFIG_BLE_PLATFORM_BLUEZ */ |