From 627b6ec2286aeb30bce655e5379bef7f56cb820c Mon Sep 17 00:00:00 2001 From: HaseenaSainul <41037131+HaseenaSainul@users.noreply.github.com> Date: Tue, 27 Aug 2024 18:09:54 +0530 Subject: [PATCH] ThunderLibraries Moved to Thunder extension (#47) Co-authored-by: Mateusz Daniluk <121170681+VeithMetro@users.noreply.github.com> --- Source/CMakeLists.txt | 14 +- Source/bluetooth/BluetoothUtils.cpp | 218 --- Source/bluetooth/BluetoothUtils.h | 61 - Source/bluetooth/CMakeLists.txt | 135 -- Source/bluetooth/Debug.h | 29 - Source/bluetooth/Definitions.cpp | 117 -- Source/bluetooth/HCISocket.cpp | 1391 ----------------- Source/bluetooth/HCISocket.h | 1311 ---------------- Source/bluetooth/IDriver.h | 43 - Source/bluetooth/Module.cpp | 22 - Source/bluetooth/Module.h | 39 - Source/bluetooth/UUID.cpp | 30 - Source/bluetooth/UUID.h | 215 --- Source/bluetooth/audio/AVDTPProfile.cpp | 464 ------ Source/bluetooth/audio/AVDTPProfile.h | 529 ------- Source/bluetooth/audio/AVDTPSocket.cpp | 195 --- Source/bluetooth/audio/AVDTPSocket.h | 693 -------- Source/bluetooth/audio/CMakeLists.txt | 128 -- Source/bluetooth/audio/DataRecord.h | 502 ------ Source/bluetooth/audio/IAudioCodec.h | 74 - .../bluetooth/audio/IAudioContentProtection.h | 56 - Source/bluetooth/audio/Module.cpp | 22 - Source/bluetooth/audio/Module.h | 39 - Source/bluetooth/audio/RTPSocket.h | 308 ---- Source/bluetooth/audio/SDPProfile.cpp | 927 ----------- Source/bluetooth/audio/SDPProfile.h | 1278 --------------- Source/bluetooth/audio/SDPSocket.cpp | 232 --- Source/bluetooth/audio/SDPSocket.h | 913 ----------- Source/bluetooth/audio/bluetooth_audio.h | 39 - Source/bluetooth/audio/cmake/FindSBC.cmake | 34 - Source/bluetooth/audio/codecs/SBC.cpp | 654 -------- Source/bluetooth/audio/codecs/SBC.h | 375 ----- Source/bluetooth/bluetooth.h | 33 - .../cmake/FindBluez5UtilHeaders.cmake | 66 - Source/bluetooth/drivers/BCM43XX.cpp | 417 ----- Source/bluetooth/drivers/Basic.cpp | 37 - Source/bluetooth/drivers/SerialDriver.h | 476 ------ Source/bluetooth/gatt/CMakeLists.txt | 107 -- Source/bluetooth/gatt/GATTProfile.cpp | 326 ---- Source/bluetooth/gatt/GATTProfile.h | 883 ----------- Source/bluetooth/gatt/GATTSocket.cpp | 356 ----- Source/bluetooth/gatt/GATTSocket.h | 908 ----------- Source/bluetooth/gatt/Module.cpp | 22 - Source/bluetooth/gatt/Module.h | 37 - Source/bluetooth/gatt/bluetooth_gatt.h | 32 - Source/broadcast/CMakeLists.txt | 133 -- Source/broadcast/Definitions.cpp | 74 - Source/broadcast/Definitions.h | 372 ----- Source/broadcast/Descriptors.h | 229 --- Source/broadcast/EIT.h | 203 --- Source/broadcast/Implementation/V4L/Tuner.cpp | 841 ---------- Source/broadcast/MPEGDescriptor.h | 180 --- Source/broadcast/MPEGSection.h | 283 ---- Source/broadcast/MPEGTable.h | 281 ---- Source/broadcast/Module.cpp | 22 - Source/broadcast/Module.h | 32 - Source/broadcast/NIT.h | 192 --- Source/broadcast/Networks.h | 366 ----- Source/broadcast/ProgramTable.cpp | 102 -- Source/broadcast/ProgramTable.h | 180 --- Source/broadcast/SDT.h | 203 --- Source/broadcast/Schedule.h | 218 --- Source/broadcast/Services.h | 329 ---- Source/broadcast/TDT.h | 140 -- Source/broadcast/TimeDate.h | 227 --- Source/broadcast/TunerAdministrator.cpp | 44 - Source/broadcast/TunerAdministrator.h | 192 --- Source/broadcast/broadcast.h | 41 - Source/broadcast/cmake/FindNEXUS.cmake | 83 - Source/broadcast/cmake/FindNXCLIENT.cmake | 53 - Source/broadcast/test/BroadcastTester.cpp | 165 -- Source/broadcast/test/CMakeLists.txt | 29 - Source/compositorbuffer/CMakeLists.txt | 58 - .../compositorbuffer/example/CMakeLists.txt | 39 - Source/compositorbuffer/example/main.cpp | 303 ---- .../compositorbuffer/CompositorBufferType.h | 515 ------ 76 files changed, 4 insertions(+), 20912 deletions(-) delete mode 100644 Source/bluetooth/BluetoothUtils.cpp delete mode 100644 Source/bluetooth/BluetoothUtils.h delete mode 100644 Source/bluetooth/CMakeLists.txt delete mode 100644 Source/bluetooth/Debug.h delete mode 100644 Source/bluetooth/Definitions.cpp delete mode 100644 Source/bluetooth/HCISocket.cpp delete mode 100644 Source/bluetooth/HCISocket.h delete mode 100644 Source/bluetooth/IDriver.h delete mode 100644 Source/bluetooth/Module.cpp delete mode 100644 Source/bluetooth/Module.h delete mode 100644 Source/bluetooth/UUID.cpp delete mode 100644 Source/bluetooth/UUID.h delete mode 100644 Source/bluetooth/audio/AVDTPProfile.cpp delete mode 100644 Source/bluetooth/audio/AVDTPProfile.h delete mode 100644 Source/bluetooth/audio/AVDTPSocket.cpp delete mode 100644 Source/bluetooth/audio/AVDTPSocket.h delete mode 100644 Source/bluetooth/audio/CMakeLists.txt delete mode 100644 Source/bluetooth/audio/DataRecord.h delete mode 100644 Source/bluetooth/audio/IAudioCodec.h delete mode 100644 Source/bluetooth/audio/IAudioContentProtection.h delete mode 100644 Source/bluetooth/audio/Module.cpp delete mode 100644 Source/bluetooth/audio/Module.h delete mode 100644 Source/bluetooth/audio/RTPSocket.h delete mode 100644 Source/bluetooth/audio/SDPProfile.cpp delete mode 100644 Source/bluetooth/audio/SDPProfile.h delete mode 100644 Source/bluetooth/audio/SDPSocket.cpp delete mode 100644 Source/bluetooth/audio/SDPSocket.h delete mode 100644 Source/bluetooth/audio/bluetooth_audio.h delete mode 100644 Source/bluetooth/audio/cmake/FindSBC.cmake delete mode 100644 Source/bluetooth/audio/codecs/SBC.cpp delete mode 100644 Source/bluetooth/audio/codecs/SBC.h delete mode 100644 Source/bluetooth/bluetooth.h delete mode 100644 Source/bluetooth/cmake/FindBluez5UtilHeaders.cmake delete mode 100644 Source/bluetooth/drivers/BCM43XX.cpp delete mode 100644 Source/bluetooth/drivers/Basic.cpp delete mode 100644 Source/bluetooth/drivers/SerialDriver.h delete mode 100644 Source/bluetooth/gatt/CMakeLists.txt delete mode 100644 Source/bluetooth/gatt/GATTProfile.cpp delete mode 100644 Source/bluetooth/gatt/GATTProfile.h delete mode 100644 Source/bluetooth/gatt/GATTSocket.cpp delete mode 100644 Source/bluetooth/gatt/GATTSocket.h delete mode 100644 Source/bluetooth/gatt/Module.cpp delete mode 100644 Source/bluetooth/gatt/Module.h delete mode 100644 Source/bluetooth/gatt/bluetooth_gatt.h delete mode 100644 Source/broadcast/CMakeLists.txt delete mode 100644 Source/broadcast/Definitions.cpp delete mode 100644 Source/broadcast/Definitions.h delete mode 100644 Source/broadcast/Descriptors.h delete mode 100644 Source/broadcast/EIT.h delete mode 100644 Source/broadcast/Implementation/V4L/Tuner.cpp delete mode 100644 Source/broadcast/MPEGDescriptor.h delete mode 100644 Source/broadcast/MPEGSection.h delete mode 100644 Source/broadcast/MPEGTable.h delete mode 100644 Source/broadcast/Module.cpp delete mode 100644 Source/broadcast/Module.h delete mode 100644 Source/broadcast/NIT.h delete mode 100644 Source/broadcast/Networks.h delete mode 100644 Source/broadcast/ProgramTable.cpp delete mode 100644 Source/broadcast/ProgramTable.h delete mode 100644 Source/broadcast/SDT.h delete mode 100644 Source/broadcast/Schedule.h delete mode 100644 Source/broadcast/Services.h delete mode 100644 Source/broadcast/TDT.h delete mode 100644 Source/broadcast/TimeDate.h delete mode 100644 Source/broadcast/TunerAdministrator.cpp delete mode 100644 Source/broadcast/TunerAdministrator.h delete mode 100644 Source/broadcast/broadcast.h delete mode 100644 Source/broadcast/cmake/FindNEXUS.cmake delete mode 100644 Source/broadcast/cmake/FindNXCLIENT.cmake delete mode 100644 Source/broadcast/test/BroadcastTester.cpp delete mode 100644 Source/broadcast/test/CMakeLists.txt delete mode 100644 Source/compositorbuffer/CMakeLists.txt delete mode 100644 Source/compositorbuffer/example/CMakeLists.txt delete mode 100644 Source/compositorbuffer/example/main.cpp delete mode 100644 Source/compositorbuffer/include/compositorbuffer/CompositorBufferType.h diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index cea9f25..7585ef8 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -15,16 +15,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -option(BLUETOOTH - "Include the bluetooth library." OFF) -option(BROADCAST - "Include the broadcasting library." OFF) +option(ASCONNECTOR + "Include the asconnector library." OFF) -if(BLUETOOTH) - add_subdirectory(bluetooth) -endif() - -if(BROADCAST) - add_subdirectory(broadcast) +if(ASCONNECTOR) + add_subdirectory(asconnector) endif() diff --git a/Source/bluetooth/BluetoothUtils.cpp b/Source/bluetooth/BluetoothUtils.cpp deleted file mode 100644 index 60d387a..0000000 --- a/Source/bluetooth/BluetoothUtils.cpp +++ /dev/null @@ -1,218 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2021 Metrological - * - * 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. - */ - -#include "BluetoothUtils.h" - -namespace Thunder { - -namespace Bluetooth { - -int BtUtilsHciForEachDevice(int flag, int (*func)(int dd, int dev_id, long arg), - long arg) -{ - struct hci_dev_list_req* dl; - struct hci_dev_req* dr; - int dev_id = -1; - int i, sk, err = 0; - - sk = socket(AF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC, BTPROTO_HCI); - if (sk < 0) - return -1; - - dl = static_cast(malloc(HCI_MAX_DEV * sizeof(*dr) + sizeof(*dl))); - if (!dl) { - err = errno; - goto done; - } - - memset(dl, 0, HCI_MAX_DEV * sizeof(*dr) + sizeof(*dl)); - - dl->dev_num = HCI_MAX_DEV; - dr = dl->dev_req; - - if (ioctl(sk, HCIGETDEVLIST, (void*)dl) < 0) { - err = errno; - goto free; - } - - for (i = 0; i < dl->dev_num; i++, dr++) { - if (BtUtilsHciTestBit(flag, &dr->dev_opt)) - if (!func || func(sk, dr->dev_id, arg)) { - dev_id = dr->dev_id; - break; - } - } - - if (dev_id < 0) - err = ENODEV; - -free: - free(dl); - -done: - close(sk); - errno = err; - - return dev_id; -} - -int BtUtilsHciDevInfo(int dev_id, struct hci_dev_info* di) -{ - int dd, err, ret; - - dd = socket(AF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC, BTPROTO_HCI); - if (dd < 0) - return dd; - - memset(di, 0, sizeof(struct hci_dev_info)); - - di->dev_id = dev_id; - ret = ioctl(dd, HCIGETDEVINFO, (void*)di); - - err = errno; - close(dd); - errno = err; - - return ret; -} - -int BtUtilsHciDevba(int dev_id, bdaddr_t* bdaddr) -{ - struct hci_dev_info di; - - memset(&di, 0, sizeof(di)); - - if (BtUtilsHciDevInfo(dev_id, &di)) - return -1; - - if (!BtUtilsHciTestBit(HCI_UP, &di.flags)) { - errno = ENETDOWN; - return -1; - } - - bacpy(bdaddr, &di.bdaddr); - - return 0; -} - -int BtUtilsOtherBdaddr(int dd, int dev_id, long arg) -{ - struct hci_dev_info di; - di.dev_id = static_cast(dev_id); - - if (ioctl(dd, HCIGETDEVINFO, (void*)&di)) - return 0; - - if (BtUtilsHciTestBit(HCI_RAW, &di.flags)) - return 0; - - return bacmp((bdaddr_t*)arg, &di.bdaddr); -} - -int BtUtilsSameBdaddr(int dd, int dev_id, long arg) -{ - struct hci_dev_info di; - di.dev_id = static_cast(dev_id); - - if (ioctl(dd, HCIGETDEVINFO, (void*)&di)) - return 0; - - return !bacmp((bdaddr_t*)arg, &di.bdaddr); -} - -int BtUtilsHciGetRoute(bdaddr_t* bdaddr) -{ - int dev_id; - bdaddr_t* bdaddr_any = static_cast(calloc(1, sizeof(*bdaddr))); - - dev_id = BtUtilsHciForEachDevice(HCI_UP, BtUtilsOtherBdaddr, - (long)(bdaddr ? bdaddr : bdaddr_any)); - if (dev_id < 0) - dev_id = BtUtilsHciForEachDevice(HCI_UP, BtUtilsSameBdaddr, - (long)(bdaddr ? bdaddr : bdaddr_any)); - - free(bdaddr_any); - - return dev_id; -} - -int BtUtilsBa2Str(const bdaddr_t* ba, char* str) -{ - return sprintf(str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X", - ba->b[5], ba->b[4], ba->b[3], ba->b[2], ba->b[1], ba->b[0]); -} - -int BtUtilsBachk(const char* str) -{ - if (!str) - return -1; - - if (strlen(str) != 17) - return -1; - - while (*str) { - if (!isxdigit(*str++)) - return -1; - - if (!isxdigit(*str++)) - return -1; - - if (*str == 0) - break; - - if (*str++ != ':') - return -1; - } - - return 0; -} - -int BtUtilsStr2Ba(const char* str, bdaddr_t* ba) -{ - int i; - - if (BtUtilsBachk(str) < 0) { - memset(ba, 0, sizeof(*ba)); - return -1; - } - - for (i = 5; i >= 0; i--, str += 3) - ba->b[i] = strtol(str, NULL, 16); - - return 0; -} - -int BtUtilsBa2Oui(const bdaddr_t* ba, char* str) -{ - return sprintf(str, "%2.2X-%2.2X-%2.2X", ba->b[5], ba->b[4], ba->b[3]); -} - -void BtUtilsBaswap(bdaddr_t* dst, const bdaddr_t* src) -{ - register unsigned char* d = (unsigned char*)dst; - register const unsigned char* s = (const unsigned char*)src; - register int i; - - for (i = 0; i < 6; i++) - d[i] = s[5 - i]; -} - -} // namespace Bluetooth - -} // namespace Thunder diff --git a/Source/bluetooth/BluetoothUtils.h b/Source/bluetooth/BluetoothUtils.h deleted file mode 100644 index 28ee13a..0000000 --- a/Source/bluetooth/BluetoothUtils.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2021 Metrological - * - * 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. - */ - -#pragma once - -#include "Module.h" - -namespace Thunder { - -namespace Bluetooth { - -EXTERNAL int BtUtilsHciDevba(int dev_id, bdaddr_t *bdaddr); -EXTERNAL int BtUtilsHciGetRoute(bdaddr_t *bdaddr); -EXTERNAL int BtUtilsBa2Str(const bdaddr_t *ba, char *str); -EXTERNAL int BtUtilsStr2Ba(const char *str, bdaddr_t *ba); -EXTERNAL int BtUtilsBa2Oui(const bdaddr_t *ba, char *str); - -inline void BtUtilsHciFilterClear(struct hci_filter *f) -{ - memset(f, 0, sizeof(*f)); -} - -inline void BtUtilsHciSetBit(int nr, void *addr) -{ - *((uint32_t *) addr + (nr >> 5)) |= (1 << (nr & 31)); -} - -inline int BtUtilsHciTestBit(int nr, void *addr) -{ - return *((uint32_t *) addr + (nr >> 5)) & (1 << (nr & 31)); -} - -inline void BtUtilsHciFilterSetEvent(int e, struct hci_filter *f) -{ - BtUtilsHciSetBit((e & HCI_FLT_EVENT_BITS), &f->event_mask); -} - -inline void BtUtilsHciFilterSetPtype(int t, struct hci_filter *f) -{ - BtUtilsHciSetBit((t == HCI_VENDOR_PKT) ? 0 : (t & HCI_FLT_TYPE_BITS), &f->type_mask); -} - -} // namespace Bluetooth - -} // namespace Thunder diff --git a/Source/bluetooth/CMakeLists.txt b/Source/bluetooth/CMakeLists.txt deleted file mode 100644 index 681db6b..0000000 --- a/Source/bluetooth/CMakeLists.txt +++ /dev/null @@ -1,135 +0,0 @@ -# If not stated otherwise in this file or this component's license file the -# following copyright and licenses apply: -# -# Copyright 2020 Metrological -# -# 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. - -cmake_minimum_required(VERSION 3.15) - -find_package(Thunder) -find_package(${NAMESPACE}Core REQUIRED) -find_package(${NAMESPACE}Messaging REQUIRED) -find_package(CompileSettingsDebug CONFIG REQUIRED) - -project(${NAMESPACE}Bluetooth - VERSION 1.0.0 - DESCRIPTION "Bluetooth abstraction that communicates directly to a HCI socket" - LANGUAGES CXX) - -set(TARGET ${PROJECT_NAME}) -message("Setup ${TARGET} v${PROJECT_VERSION}") - -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") - -option(BCM43XX "Select the serial driver for bluetooth modules found on RaspberryPi's" OFF) -option(BLUETOOTH_GATT_SUPPORT "Include GATT support" OFF) -option(BLUETOOTH_AUDIO_SUPPORT "Include audio sink/source support" OFF) - -find_package(Bluez5UtilHeaders REQUIRED) - -add_library(${TARGET} - HCISocket.cpp - UUID.cpp - Definitions.cpp - BluetoothUtils.cpp - Module.cpp -) - -set(PUBLIC_HEADERS - IDriver.h - HCISocket.h - UUID.h - Debug.h - BluetoothUtils.h - Module.h - bluetooth.h -) - -if(BCM43XX) - target_sources(${TARGET} PRIVATE drivers/BCM43XX.cpp) -else() - target_sources(${TARGET} PRIVATE drivers/Basic.cpp) -endif() - -target_link_libraries(${TARGET} - PRIVATE - CompileSettingsDebug::CompileSettingsDebug - ${NAMESPACE}Core::${NAMESPACE}Core - ${NAMESPACE}Messaging::${NAMESPACE}Messaging - Bluez5UtilHeaders::Bluez5UtilHeaders -) - -set_target_properties(${TARGET} - PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES - FRAMEWORK FALSE - PUBLIC_HEADER "${PUBLIC_HEADERS}" # specify the public headers - VERSION ${PROJECT_VERSION} - SOVERSION ${PROJECT_VERSION_MAJOR} -) - -target_include_directories(${TARGET} - PUBLIC - $ - $ - $ - PRIVATE - "${CMAKE_CURRENT_SOURCE_DIR}/drivers" -) - -target_compile_options(${TARGET} - PRIVATE - -Wno-psabi - -fdiagnostics-color=always -) - -# -# From Bluez >= v5.64 the mgmt_ltk_info struct is changed due to inclusive language changes. -# https://github.com/bluez/bluez/commit/b7d6a7d25628e9b521a29a5c133fcadcedeb2102 -# -include(CheckStructHasMember) -check_struct_has_member("struct mgmt_ltk_info" central "../include/bluetooth/bluetooth.h;../include/bluetooth/mgmt.h" NO_INCLUSIVE_LANGUAGE LANGUAGE C) - -if(${NO_INCLUSIVE_LANGUAGE}) - message(STATUS "Your version of bluez don't uses inclusive language anymore") - target_compile_definitions(${TARGET} PUBLIC NO_INCLUSIVE_LANGUAGE) -endif() - -install( - TARGETS ${TARGET} EXPORT ${TARGET}Targets - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT ${NAMESPACE}_Development - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT ${NAMESPACE}_Runtime NAMELINK_COMPONENT ${NAMESPACE}_Development - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${NAMESPACE}_Runtime - FRAMEWORK DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${NAMESPACE}_Runtime - PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${NAMESPACE}/bluetooth COMPONENT ${NAMESPACE}_Development - INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${NAMESPACE} -) - -InstallPackageConfig( - TARGETS ${TARGET} - DESCRIPTION "Bluetooth library" -) - -InstallCMakeConfig( - TARGETS ${TARGET} -) - -if(BLUETOOTH_GATT_SUPPORT) - add_subdirectory(gatt) -endif() - -if(BLUETOOTH_AUDIO_SUPPORT) - add_subdirectory(audio) -endif() diff --git a/Source/bluetooth/Debug.h b/Source/bluetooth/Debug.h deleted file mode 100644 index b14b924..0000000 --- a/Source/bluetooth/Debug.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#pragma once - -// #define BLUETOOTH_CMD_DUMP - -#if defined(BLUETOOTH_CMD_DUMP) -#define CMD_DUMP(descr, buffer, length) \ - do { fprintf(stderr, "%s [%i]: ", descr, length); for (int i = 0; i < length; i++) { printf("%02x:", buffer[i]); } printf("\n"); } while(0) -#else -#define CMD_DUMP(descr, buffer, length) -#endif diff --git a/Source/bluetooth/Definitions.cpp b/Source/bluetooth/Definitions.cpp deleted file mode 100644 index 76e2550..0000000 --- a/Source/bluetooth/Definitions.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#include "Module.h" - -namespace Thunder { - -namespace Bluetooth { - - /* LMP features mapping */ - struct ConversionTable { - uint16_t id; - const TCHAR* text; - }; - - static ConversionTable lmp_features_map[] = { - /* Byte 0 */ - { LMP_3SLOT | 0x0000, _T("3-slot packets") }, /* Bit 0 */ - { LMP_5SLOT | 0x0000, _T("5-slot packets") }, /* Bit 1 */ - { LMP_ENCRYPT | 0x0000, _T("encryption") }, /* Bit 2 */ - { LMP_SOFFSET | 0x0000, _T("slot offset") }, /* Bit 3 */ - { LMP_TACCURACY | 0x0000, _T("timing accuracy") }, /* Bit 4 */ - { LMP_RSWITCH | 0x0000, _T("role switch") }, /* Bit 5 */ - { LMP_HOLD | 0x0000, _T("hold mode") }, /* Bit 6 */ - { LMP_SNIFF | 0x0000, _T("sniff mode") }, /* Bit 7 */ - - /* Byte 1 */ - { LMP_PARK | 0x0100, _T("park state") }, /* Bit 0 */ - { LMP_RSSI | 0x0100, _T("RSSI") }, /* Bit 1 */ - { LMP_QUALITY | 0x0100, _T("channel quality") }, /* Bit 2 */ - { LMP_SCO | 0x0100, _T("SCO link") }, /* Bit 3 */ - { LMP_HV2 | 0x0100, _T("HV2 packets") }, /* Bit 4 */ - { LMP_HV3 | 0x0100, _T("HV3 packets") }, /* Bit 5 */ - { LMP_ULAW | 0x0100, _T("u-law log") }, /* Bit 6 */ - { LMP_ALAW | 0x0100, _T("A-law log") }, /* Bit 7 */ - - /* Byte 2 */ - { LMP_CVSD | 0x0200, _T("CVSD") }, /* Bit 0 */ - { LMP_PSCHEME | 0x0200, _T("paging scheme") }, /* Bit 1 */ - { LMP_PCONTROL | 0x0200, _T("power control") }, /* Bit 2 */ - { LMP_TRSP_SCO | 0x0200, _T("transparent SCO") }, /* Bit 3 */ - { LMP_BCAST_ENC | 0x0200, _T("broadcast encrypt") }, /* Bit 7 */ - - /* Byte 3 */ - { LMP_EDR_ACL_2M | 0x0300, _T("EDR ACL 2 Mbps") }, /* Bit 1 */ - { LMP_EDR_ACL_3M | 0x0300, _T("EDR ACL 3 Mbps") }, /* Bit 2 */ - { LMP_ENH_ISCAN | 0x0300, _T("enhanced iscan") }, /* Bit 3 */ - { LMP_ILACE_ISCAN | 0x0300, _T("interlaced iscan") }, /* Bit 4 */ - { LMP_ILACE_PSCAN | 0x0300, _T("interlaced pscan") }, /* Bit 5 */ - { LMP_RSSI_INQ | 0x0300, _T("inquiry with RSSI") }, /* Bit 6 */ - { LMP_ESCO | 0x0300, _T("extended SCO") }, /* Bit 7 */ - - /* Byte 4 */ - { LMP_EV4 | 0x0400, _T("EV4 packets") }, /* Bit 0 */ - { LMP_EV5 | 0x0400, _T("EV5 packets") }, /* Bit 1 */ - { LMP_AFH_CAP_SLV | 0x0400, _T("AFH cap. slave") }, /* Bit 3 */ - { LMP_AFH_CLS_SLV | 0x0400, _T("AFH class. slave") }, /* Bit 4 */ - { LMP_NO_BREDR | 0x0400, _T("BR/EDR not supp.") }, /* Bit 5 */ - { LMP_LE | 0x0400, _T("LE support") }, /* Bit 6 */ - { LMP_EDR_3SLOT | 0x0400, _T("3-slot EDR ACL") }, /* Bit 7 */ - - /* Byte 5 */ - { LMP_EDR_5SLOT | 0x0500, _T("5-slot EDR ACL") }, /* Bit 0 */ - { LMP_SNIFF_SUBR | 0x0500, _T("sniff subrating") }, /* Bit 1 */ - { LMP_PAUSE_ENC | 0x0500, _T("pause encryption") }, /* Bit 2 */ - { LMP_AFH_CAP_MST | 0x0500, _T("AFH cap. master") }, /* Bit 3 */ - { LMP_AFH_CLS_MST | 0x0500, _T("AFH class. master") }, /* Bit 4 */ - { LMP_EDR_ESCO_2M | 0x0500, _T("EDR eSCO 2 Mbps") }, /* Bit 5 */ - { LMP_EDR_ESCO_3M | 0x0500, _T("EDR eSCO 3 Mbps") }, /* Bit 6 */ - { LMP_EDR_3S_ESCO | 0x0500, _T("3-slot EDR eSCO") }, /* Bit 7 */ - - /* Byte 6 */ - { LMP_EXT_INQ | 0x0600, _T("extended inquiry") }, /* Bit 0 */ - { LMP_LE_BREDR | 0x0600, _T("LE and BR/EDR") }, /* Bit 1 */ - { LMP_SIMPLE_PAIR | 0x0600, _T("simple pairing") }, /* Bit 3 */ - { LMP_ENCAPS_PDU | 0x0600, _T("encapsulated PDU") }, /* Bit 4 */ - { LMP_ERR_DAT_REP | 0x0600, _T("err. data report") }, /* Bit 5 */ - { LMP_NFLUSH_PKTS | 0x0600, _T("non-flush flag") }, /* Bit 6 */ - - /* Byte 7 */ - { LMP_LSTO | 0x0700, _T("LSTO") }, /* Bit 1 */ - { LMP_INQ_TX_PWR | 0x0700, _T("inquiry TX power") }, /* Bit 2 */ - { LMP_EPC | 0x0700, _T("EPC") }, /* Bit 2 */ - { LMP_EXT_FEAT | 0x0700, _T("extended features") }, /* Bit 7 */ - - { 0x0000, nullptr } - }; - - const TCHAR* FeatureToText(const uint16_t index) - { - ConversionTable* pos = lmp_features_map; - - while ((pos->text != nullptr) && (pos->id != index)) { - pos++; - } - - return (pos->text != nullptr ? pos->text : _T("reserved")); - } - -} } // namespace Thunder::Bluetooth - diff --git a/Source/bluetooth/HCISocket.cpp b/Source/bluetooth/HCISocket.cpp deleted file mode 100644 index 834bd00..0000000 --- a/Source/bluetooth/HCISocket.cpp +++ /dev/null @@ -1,1391 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#include "HCISocket.h" - -namespace Thunder { - -ENUM_CONVERSION_BEGIN(Bluetooth::Address::type) - { Bluetooth::Address::BREDR_ADDRESS, _TXT(_T("bredr")) }, - { Bluetooth::Address::LE_PUBLIC_ADDRESS, _TXT(_T("le_public")) }, - { Bluetooth::Address::LE_RANDOM_ADDRESS, _TXT(_T("le_random")) }, -ENUM_CONVERSION_END(Bluetooth::Address::type) - -namespace Bluetooth { - -uint32_t HCISocket::Advertising(const bool enable, const uint8_t mode) -{ - uint32_t result = Core::ERROR_ILLEGAL_STATE; - - if (enable == true) { - if (IsAdvertising() == false) { - result = Core::ERROR_BAD_REQUEST; - Command::AdvertisingParametersLE parameters; - - parameters->min_interval = htobs(0x0800); - parameters->max_interval = htobs(0x0800); - parameters->advtype = mode; - parameters->chan_map = 7; - - if (Exchange(MAX_ACTION_TIMEOUT, parameters, parameters) == Core::ERROR_NONE) { - // if ((temp == Core::ERROR_NONE) && (parameters.Response() == 0)) { - - Command::AdvertisingEnableLE advertising; - - advertising->enable = 1; - - if (Exchange(MAX_ACTION_TIMEOUT, advertising, advertising) == Core::ERROR_NONE) { // && (advertising.Response() == 0)) { - _state.SetState(static_cast(_state.GetState() | ADVERTISING)); - result = Core::ERROR_NONE; - } - } - } - } else if (IsAdvertising() == true) { - result = Core::ERROR_BAD_REQUEST; - Command::AdvertisingEnableLE advertising; - - advertising->enable = 0; - - if ((Exchange(MAX_ACTION_TIMEOUT, advertising, advertising) == Core::ERROR_NONE) && (advertising.Response() == 0)) { - _state.SetState(static_cast(_state.GetState() & (~ADVERTISING))); - result = Core::ERROR_NONE; - } - } - return (result); -} - -uint32_t HCISocket::Inquiry(const uint16_t scanTime, const bool limited) -{ - uint32_t result = Core::ERROR_ILLEGAL_STATE; - - _state.Lock(); - - if (((_state & ACTION_MASK) == 0) || ((_state & ACTION_MASK) == SCANNING)) { - /* The inquiry API limits the scan time to 326 seconds, so split it into mutliple inquiries if neccessary. */ - const uint16_t lapTime = 30; /* sec */ - uint16_t timeLeft = scanTime; - - Command::Inquiry inquiry; - Command::InquiryCancel inquiryCancel; - - inquiry->num_rsp = 255; - inquiry->length = 30; /* in 1.28s == 35s */ - - ASSERT(((uint32_t)inquiry->length * 128 / 100) > lapTime + 1); - - inquiry->lap[0] = (limited == true? 0x00 : 0x33); - inquiry->lap[1] = 0x8B; - inquiry->lap[2] = 0x9e; - - while (timeLeft > 0) { - if (Exchange(MAX_ACTION_TIMEOUT, inquiry, inquiry) == Core::ERROR_NONE) { - if (inquiry.Response() == 0) { - _state.SetState(static_cast(_state.GetState() | INQUIRING)); - - _state.Unlock(); - - // This is not super-precise, but it doesn't have to be. - uint16_t roundTime = (timeLeft > lapTime? lapTime : timeLeft); - if (_state.WaitState(ABORT_INQUIRING, (roundTime * 1000)) == true) { - roundTime = timeLeft; // essentially break - } - timeLeft -= roundTime; - - _state.Lock(); - - Exchange(MAX_ACTION_TIMEOUT, inquiryCancel, inquiryCancel); - _state.SetState(static_cast(_state.GetState() & (~(ABORT_INQUIRING | INQUIRING)))); - - result = Core::ERROR_NONE; - } else { - TRACE(Trace::Error, (_T("Inquiry command failed [0x%02x]"), inquiry.Response())); - result = Core::ERROR_ASYNC_FAILED; - break; - } - } else { - result = Core::ERROR_ASYNC_FAILED; - break; - } - } - } else { - TRACE_L1("Busy, controller is now inquiring or pairing"); - } - - _state.Unlock(); - - return (result); -} - -uint32_t HCISocket::AbortInquiry() -{ - uint32_t result = Core::ERROR_ILLEGAL_STATE; - - _state.Lock(); - - if ((_state & INQUIRING) != 0) { - _state.SetState(static_cast(_state.GetState() | ABORT_INQUIRING)); - result = Core::ERROR_NONE; - } - - _state.Unlock(); - - return (result); -} - -uint32_t HCISocket::Scan(const uint16_t scanTime, const bool limited, const bool passive) -{ - uint32_t result = Core::ERROR_ILLEGAL_STATE; - - _state.Lock(); - - if (((_state & ACTION_MASK) == 0) || ((_state & ACTION_MASK) == INQUIRING)) { - Command::ScanParametersLE parameters; - const uint16_t window = (limited? 0x12 : 0x10 /* 10ms */); - // Make sure window is smaller than interval, so the link layer has time for other Bluetooth operations during scanning. - parameters->type = (passive? SCAN_TYPE_PASSIVE : SCAN_TYPE_ACTIVE); - parameters->window = htobs(window); - parameters->interval = htobs(passive? (8 * window) : (4 * window)); - parameters->own_bdaddr_type = LE_PUBLIC_ADDRESS; - parameters->filter = SCAN_FILTER_POLICY_ALL; - - if (Exchange(MAX_ACTION_TIMEOUT, parameters, parameters) == Core::ERROR_NONE) { - if (parameters.Response() == 0) { - Command::ScanEnableLE scanner; - scanner->enable = 1; - scanner->filter_dup = SCAN_FILTER_DUPLICATES_ENABLE; - - if (Exchange(MAX_ACTION_TIMEOUT, scanner, scanner) == Core::ERROR_NONE) { - if (scanner.Response() == 0) { - _state.SetState(static_cast(_state.GetState() | SCANNING)); - - // Now lets wait for the scanning period.. - _state.Unlock(); - - _state.WaitState(ABORT_SCANNING, scanTime * 1000); - - _state.Lock(); - - scanner->enable = 0; - Exchange(MAX_ACTION_TIMEOUT, scanner, scanner); - - _state.SetState(static_cast(_state.GetState() & (~(ABORT_SCANNING | SCANNING)))); - result = Core::ERROR_NONE; - } else { - TRACE(Trace::Error, (_T("ScanEnableLE command failed [0x%02x]"), scanner.Response())); - result = Core::ERROR_ASYNC_FAILED; - } - } - } else { - TRACE(Trace::Error, (_T("ScanParametersLE command failed [0x%02x]"), parameters.Response())); - result = Core::ERROR_ASYNC_FAILED; - } - } - } else { - TRACE_L1("Busy, controller is now scanning or pairing"); - } - - _state.Unlock(); - - return (result); -} - -uint32_t HCISocket::AbortScan() -{ - uint32_t result = Core::ERROR_ILLEGAL_STATE; - - _state.Lock(); - - if ((_state & SCANNING) != 0) { - _state.SetState(static_cast(_state.GetState() | ABORT_SCANNING)); - result = Core::ERROR_NONE; - } - - _state.Unlock(); - - return (result); -} - -uint32_t HCISocket::Discovery(const bool enable) -{ - uint32_t result = Core::ERROR_ILLEGAL_STATE; - - _state.Lock(); - - if ((_state & ACTION_MASK) == 0) { - if (((enable == true) && (IsDiscovering() == true)) || ((enable == false) && (IsDiscovering() == false))) { - TRACE_L1("Target LE discovery mode already set..."); - } else { - if (enable == true) { - Command::ScanParametersLE parameters; - const uint16_t window = 0x10; // 10ms - parameters->type = SCAN_TYPE_PASSIVE; - // Make sure window is smaller than interval, so the link layer has time for other Bluetooth operations during scanning. - parameters->interval = htobs(8 * window); - parameters->window = htobs(window); - parameters->own_bdaddr_type = LE_PUBLIC_ADDRESS; - parameters->filter = SCAN_FILTER_POLICY_ALL; - - uint32_t rv = Exchange(MAX_ACTION_TIMEOUT, parameters, parameters); - if (rv == Core::ERROR_NONE) { - if (parameters.Response() == 0) { - result = Core::ERROR_NONE; - } else { - TRACE(Trace::Error, (_T("ScanParametersLE command failed [0x%02x]"), parameters.Response())); - result = Core::ERROR_ASYNC_FAILED; - } - } - } - - if ((result == Core::ERROR_NONE) || (enable == false)) { - Command::ScanEnableLE scanner; - scanner->enable = enable; - scanner->filter_dup = SCAN_FILTER_DUPLICATES_ENABLE; - - if (Exchange(MAX_ACTION_TIMEOUT, scanner, scanner) == Core::ERROR_NONE) { - if (scanner.Response() == 0) { - _state.SetState(static_cast(enable? (_state.GetState() | DISCOVERING) : (_state.GetState() & (~DISCOVERING)))); - result = Core::ERROR_NONE; - } else { - TRACE(Trace::Error, (_T("ScanEnableLE command failed [0x%02x]"), scanner.Response())); - result = Core::ERROR_ASYNC_FAILED; - } - } - } - } - } else { - TRACE_L1("Busy, controller is now scanning or pairing"); - } - - _state.Unlock(); - - return (result); -} - -uint32_t HCISocket::ReadStoredLinkKeys(const Address adr, const bool all, LinkKeys& list VARIABLE_IS_NOT_USED) -{ - Command::ReadStoredLinkKey parameters; - - ::memcpy(&(parameters->bdaddr), adr.Data(), sizeof(parameters->bdaddr)); - parameters->read_all = (all ? 0x1 : 0x0); - - return (Exchange(MAX_ACTION_TIMEOUT, parameters, parameters)); -} - -/* virtual */ void HCISocket::StateChange() -{ - Core::SynchronousChannelType::StateChange(); - if (IsOpen() == true) { - BtUtilsHciFilterClear(&_filter); - BtUtilsHciFilterSetPtype(HCI_EVENT_PKT, &_filter); - BtUtilsHciFilterSetEvent(EVT_LE_META_EVENT, &_filter); - BtUtilsHciFilterSetEvent(EVT_CMD_STATUS, &_filter); - BtUtilsHciFilterSetEvent(EVT_CMD_COMPLETE, &_filter); - BtUtilsHciFilterSetEvent(EVT_PIN_CODE_REQ, &_filter); - BtUtilsHciFilterSetEvent(EVT_LINK_KEY_REQ, &_filter); - BtUtilsHciFilterSetEvent(EVT_LINK_KEY_NOTIFY, &_filter); - BtUtilsHciFilterSetEvent(EVT_RETURN_LINK_KEYS, &_filter); - BtUtilsHciFilterSetEvent(EVT_IO_CAPABILITY_REQUEST, &_filter); - BtUtilsHciFilterSetEvent(EVT_IO_CAPABILITY_RESPONSE, &_filter); - BtUtilsHciFilterSetEvent(EVT_USER_CONFIRM_REQUEST, &_filter); - BtUtilsHciFilterSetEvent(EVT_USER_PASSKEY_REQUEST, &_filter); - BtUtilsHciFilterSetEvent(EVT_REMOTE_OOB_DATA_REQUEST, &_filter); - BtUtilsHciFilterSetEvent(EVT_USER_PASSKEY_NOTIFY, &_filter); - BtUtilsHciFilterSetEvent(EVT_KEYPRESS_NOTIFY, &_filter); - BtUtilsHciFilterSetEvent(EVT_SIMPLE_PAIRING_COMPLETE, &_filter); - BtUtilsHciFilterSetEvent(EVT_AUTH_COMPLETE, &_filter); - BtUtilsHciFilterSetEvent(EVT_REMOTE_NAME_REQ_COMPLETE, &_filter); - BtUtilsHciFilterSetEvent(EVT_READ_REMOTE_VERSION_COMPLETE, &_filter); - BtUtilsHciFilterSetEvent(EVT_READ_REMOTE_FEATURES_COMPLETE, &_filter); - BtUtilsHciFilterSetEvent(EVT_REMOTE_HOST_FEATURES_NOTIFY, &_filter); - BtUtilsHciFilterSetEvent(EVT_INQUIRY_COMPLETE, &_filter); - BtUtilsHciFilterSetEvent(EVT_INQUIRY_RESULT, &_filter); - BtUtilsHciFilterSetEvent(EVT_INQUIRY_RESULT_WITH_RSSI, &_filter); - BtUtilsHciFilterSetEvent(EVT_EXTENDED_INQUIRY_RESULT, &_filter); - BtUtilsHciFilterSetEvent(EVT_CONN_REQUEST, &_filter); - BtUtilsHciFilterSetEvent(EVT_CONN_COMPLETE, &_filter); - BtUtilsHciFilterSetEvent(EVT_DISCONN_COMPLETE, &_filter); - - if (setsockopt(Handle(), SOL_HCI, HCI_FILTER, &_filter, sizeof(_filter)) < 0) { - TRACE(Trace::Error, (_T("Can't set HCI filter: %s (%d)"), strerror(errno), errno)); - } else { - TRACE(Trace::Information, (_T("HCI Filter set!"))); - } - } -} - -template void HCISocket::DeserializeScanResponse(const uint8_t* data) -{ - const uint8_t* segment = data; - uint8_t entries = *segment++; - - for (uint8_t loop = 0; loop < entries; loop++) { - const EVENT* info = reinterpret_cast(segment); - Update(*info); - segment += sizeof(EVENT); - } -} - -template<> void HCISocket::DeserializeScanResponse(const uint8_t* data) -{ - const uint8_t* segment = data; - uint8_t entries = *segment++; - - for (uint8_t loop = 0; loop < entries; loop++) { - const le_advertising_info* info = reinterpret_cast(segment); - Update(*info); - segment += (sizeof(le_advertising_info) + info->length); - } -} - -/* virtual */ uint16_t HCISocket::Deserialize(const uint8_t* dataFrame, const uint16_t availableData) -{ - CMD_DUMP("HCI event received", dataFrame, availableData); - - uint16_t result = 0; - const hci_event_hdr* hdr = reinterpret_cast(&(dataFrame[1])); - - if ( (availableData > sizeof(hci_event_hdr)) && (availableData > (sizeof(hci_event_hdr) + hdr->plen)) ) { - const uint8_t* ptr = reinterpret_cast(&(dataFrame[1 + sizeof(hci_event_hdr)])); - - result = 1 + sizeof(hci_event_hdr) + hdr->plen; - - // Deserialize scan response events - if ((hdr->evt == EVT_LE_META_EVENT) && (reinterpret_cast(ptr)->subevent == EVT_LE_ADVERTISING_REPORT)) { - DeserializeScanResponse(reinterpret_cast(ptr)->data); - } else if (hdr->evt == EVT_INQUIRY_RESULT) { - DeserializeScanResponse(ptr); - } else if (hdr->evt == EVT_INQUIRY_RESULT_WITH_RSSI) { - DeserializeScanResponse(ptr); - } else if (hdr->evt == EVT_EXTENDED_INQUIRY_RESULT) { - DeserializeScanResponse(ptr); - } else { - // All other events - Update(*hdr); - } - } - else { - TRACE_L1("EVT_HCI: Message too short => (hci_event_hdr)"); - } - - return (result); -} - -/* virtual */ void HCISocket::Update(const hci_event_hdr&) -{ -} - -/* virtual */ void HCISocket::Update(const inquiry_info&) -{ -} - -/* virtual */ void HCISocket::Update(const inquiry_info_with_rssi&) -{ -} - -/* virtual */ void HCISocket::Update(const extended_inquiry_info&) -{ -} - -/* virtual */ void HCISocket::Update(const le_advertising_info&) -{ -} - -void EIR::Ingest(const uint8_t buffer[], const uint16_t bufferLength) -{ - std::string store; - uint8_t offset = 0; - - while (((offset + buffer[offset]) <= bufferLength) && (buffer[offset+1] != 0)) { - const uint8_t length = (buffer[offset] - 1); - if (length == 0) { - break; - } - - const uint8_t type = buffer[offset + 1]; - const uint8_t* const data = &buffer[offset + 2]; - - if (type == EIR_NAME_SHORT) { - _shortName = std::string(reinterpret_cast(data), length); - } else if (type == EIR_NAME_COMPLETE) { - _completeName = std::string(reinterpret_cast(data), length); - } else if (type == EIR_CLASS_OF_DEV) { - _class = (data[0] | (data[1] << 8) | (data[2] << 16)); - } else if ((type == EIR_UUID16_SOME) || (type == EIR_UUID16_ALL)) { - for (uint8_t i = 0; i < (length / 2); i++) { - _UUIDs.emplace_back(btohs(*reinterpret_cast(data + (i * 2)))); - } - } else if ((type == EIR_UUID128_SOME) || (type == EIR_UUID128_ALL)) { - for (uint8_t i = 0; i < (length / 16); i++) { - _UUIDs.emplace_back(data + (i * 16)); - } - } - - offset += (1 /* length */ + 1 /* type */ + length); - } -} - -// -------------------------------------------------------------------------------------------------- -// ManagementSocket !!! -// -------------------------------------------------------------------------------------------------- - -// ------------------------------------------------------------------------ -// Create definitions for the Management commands -// ------------------------------------------------------------------------ -// https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/mgmt-api.txt -// ------------------------------------------------------------------------ - -template -class ManagementType : public Core::IOutbound, public Core::IInbound { -protected: - ManagementType(uint8_t buffer[]) : _buffer(buffer) { - } - -public: - ManagementType() = delete; - ManagementType(const ManagementType&) = delete; - ManagementType& operator=(const ManagementType&) = delete; - ManagementType(const uint16_t size, uint8_t buffer[], const uint16_t adapterIndex) - : _size(size), _buffer(buffer), _offset(_size), _error(~0), _inboundSize(0) - { - _buffer[0] = (OPCODE & 0xFF); - _buffer[1] = (OPCODE >> 8) & 0xFF; - _buffer[2] = (adapterIndex & 0xFF); - _buffer[3] = ((adapterIndex >> 8) & 0xFF); - _buffer[4] = static_cast((size - sizeof(mgmt_hdr)) & 0xFF); - _buffer[5] = static_cast((size >> 8) & 0xFF); - } - virtual ~ManagementType() - { - } - -public: - void Clear() - { - ::memset(&(_buffer[sizeof(mgmt_hdr)]), 0, _size - sizeof(mgmt_hdr)); - } - OUTBOUND* operator->() - { - return (reinterpret_cast(&(_buffer[sizeof(mgmt_hdr)]))); - } - uint16_t Result() const - { - return (_error); - } - const INBOUND& Response() - { - return (_inbound); - } - uint16_t Loaded () const - { - return (_inboundSize); - } - -private: - virtual void Reload() const override - { - _error = ~0; - _offset = 0; - _inboundSize = 0; - } - virtual uint16_t Serialize(uint8_t stream[], const uint16_t length) const override - { - uint16_t result = std::min(static_cast(_size - _offset), length); - if (result > 0) { - - ::memcpy(stream, &(_buffer[_offset]), result); - _offset += result; - - CMD_DUMP("MGMT sent", stream, result); - } - return (result); - } - virtual uint16_t Deserialize(const uint8_t stream[], const uint16_t length) override - { - CMD_DUMP("MGMT received", stream, length); - - uint16_t result = 0; - if (length >= sizeof(mgmt_hdr)) { - - const mgmt_hdr* hdr = reinterpret_cast(stream); - uint16_t opCode = btohs(hdr->opcode); - uint16_t payload = btohs(hdr->len); - - if (opCode == MGMT_EV_CMD_STATUS) { - uint16_t len = (length - sizeof(mgmt_hdr)); - const mgmt_ev_cmd_status* data = reinterpret_cast(&(stream[sizeof(mgmt_hdr)])); - if (btohs(data->opcode) == OPCODE) { - if (len < sizeof(mgmt_ev_cmd_status)) { - TRACE_L1("MGMT_EV_CMD_STATUS: Message too short; opcode=%04X", data->opcode); - _error = Core::ERROR_GENERAL; - } else { - TRACE_L2("MGMT_EV_CMD_STATUS: opcode=0x%04X, status=%d", data->opcode, data->status); - _error = data->status; - } - result = length; - } - } - else if (opCode == MGMT_EV_CMD_COMPLETE) { - const mgmt_ev_cmd_complete* data = reinterpret_cast(&(stream[sizeof(mgmt_hdr)])); - if (btohs(data->opcode) == OPCODE) { - uint16_t len = (length - sizeof(mgmt_hdr)); - if (len < sizeof(mgmt_ev_cmd_complete)) { - TRACE_L1("MGMT_EV_CMD_COMPLETE: Message too short; opcode=%04X", data->opcode); - _error = Core::ERROR_GENERAL; - } else { - _inboundSize = std::min( - static_cast(sizeof(INBOUND)), - static_cast(payload - sizeof(mgmt_ev_cmd_complete))); - - _inboundSize = std::min(_inboundSize, static_cast(len - sizeof(mgmt_ev_cmd_complete))); - ::memcpy(reinterpret_cast(&_inbound), data->data, _inboundSize); - - TRACE_L2("MGMT_EV_CMD_COMPLETE: opcode=0x%04X, status=%d", data->opcode, data->status); - _error = data->status; - } - result = length; - } - } - } - return (result); - } - virtual state IsCompleted() const override - { - return (_error != static_cast(~0) ? state::COMPLETED : state::INPROGRESS); - } - -private: - uint16_t _size; - uint8_t* _buffer; - mutable uint16_t _offset; - mutable uint16_t _error; - mutable uint16_t _inboundSize; - INBOUND _inbound; -}; - -template -class ManagementFixedType : public ManagementType { -public: - ManagementFixedType() = delete; - ManagementFixedType(const ManagementFixedType&) = delete; - ManagementFixedType& operator=(const ManagementFixedType&) = delete; - - ManagementFixedType(const uint16_t adapterIndex) - : ManagementType (sizeof(_buffer), _buffer, adapterIndex) { - this->Clear(); - } - ~ManagementFixedType() { - } - -private: - uint8_t _buffer[sizeof(mgmt_hdr) + (std::is_same::value ? 0 : sizeof(OUTBOUND))]; -}; - -template -class ManagementListType : public ManagementType { -private: - ManagementListType(const uint16_t size, uint8_t buffer[], const uint16_t adapterIndex) - : ManagementType (size, buffer, adapterIndex), _buffer(buffer) { - } -public: - ManagementListType() = delete; - ManagementListType(const ManagementListType&) = delete; - ManagementListType& operator=(const ManagementListType&) = delete; - - ManagementListType(ManagementListType&& copy) - : ManagementType (copy._buffer){ - } - - static ManagementListType Instance(const uint16_t adapterIndex, const LISTTYPE& list) { - uint16_t listLength = (list.Entries() * LISTTYPE::Length()); - uint16_t length = sizeof(mgmt_hdr) + sizeof(OUTBOUND) + listLength; - uint8_t* buffer = new uint8_t[length]; - ASSERT(buffer != nullptr); - - ManagementListType result(length, buffer, adapterIndex); - result.Clear(); - list.Clone(listLength, &(buffer[sizeof(mgmt_hdr) + sizeof(OUTBOUND)])); - return (result); - } - - ~ManagementListType() { - if (_buffer != nullptr) { - delete [] _buffer; - } - _buffer = nullptr; - } - -private: - uint8_t* _buffer; -}; - -/* 500 ms to execute a management command. Should be enough for a kernel message exchange. */ -static uint32_t MANAGMENT_TIMEOUT = 500; - -static constexpr uint8_t DISABLE_MODE = 0x00; -static constexpr uint8_t ENABLE_MODE = 0x01; -static constexpr uint8_t LIMITED_MODE = 0x02; - -namespace Management { - - typedef ManagementFixedType Settings; - - typedef ManagementFixedType Power; - - typedef ManagementFixedType Connectable; - typedef ManagementFixedType FastConnectable; - typedef ManagementFixedType Bondable; - typedef ManagementFixedType SimplePairing; - typedef ManagementFixedType SecureConnection; - typedef ManagementFixedType HighSpeed; - typedef ManagementFixedType SecureLink; - typedef ManagementFixedType LowEnergy; - typedef ManagementFixedType Advertising; - typedef ManagementFixedType Connectable; - typedef ManagementFixedType Discoverable; - typedef ManagementFixedType PublicAddress; - - typedef ManagementFixedType DeviceName; - typedef ManagementFixedType DeviceClass; - typedef ManagementFixedType AddUUID; - typedef ManagementFixedType RemoveUUID; - - typedef ManagementFixedType AddAdvertising; - typedef ManagementFixedType RemoveAdvertising; - - // Kernel-side discovery and auto-connection - typedef ManagementFixedType StartDiscovery; - typedef ManagementFixedType StopDiscovery; - typedef ManagementFixedType Block; - typedef ManagementFixedType Unblock; - typedef ManagementFixedType AddDevice; - typedef ManagementFixedType RemoveDevice; - - typedef ManagementFixedType Pair; - typedef ManagementFixedType Unpair; - typedef ManagementFixedType PairAbort; - - typedef ManagementFixedType UserPINCodeReply; - typedef ManagementFixedType UserPINCodeNegReply; - typedef ManagementFixedType UserConfirmReply; - typedef ManagementFixedType UserConfirmNegReply; - typedef ManagementFixedType UserPasskeyReply; - typedef ManagementFixedType UserPasskeyNegReply; - - typedef ManagementFixedType Privacy; - typedef ManagementFixedType Indexes; - typedef ManagementListType LinkKeys; - typedef ManagementListType LongTermKeys; - typedef ManagementListType IdentityKeys; -} - -/* static */ void ManagementSocket::Devices(std::list& adapters) -{ - Management::Indexes message(HCI_DEV_NONE); - ManagementSocket globalPort; - - if (globalPort.Exchange(MANAGMENT_TIMEOUT, message, message) == Core::ERROR_NONE) { - if (message.Result() == Core::ERROR_NONE) { - for (uint16_t index = 0; index < message.Response()[0]; index++) { - adapters.push_back(message.Response()[index+1]); - } - } else { - TRACE_GLOBAL(Trace::Error, (_T("ReadIndexList command failed [0x%02x]"), message.Result())); - } - } -} - -uint32_t ManagementSocket::Name(const string& shortName, const string& longName) -{ - Management::DeviceName message(_deviceId); - std::string shortName2(shortName.substr(0, sizeof(message->short_name) - 1)); - std::string longName2(longName.substr(0, sizeof(message->name) - 1)); - - ::strcpy(reinterpret_cast(message->short_name), shortName2.c_str()); - ::strcpy(reinterpret_cast(message->name), longName2.c_str()); - - uint32_t result = Exchange(MANAGMENT_TIMEOUT, message, message); - if ((result == Core::ERROR_NONE) && (message.Result() != MGMT_STATUS_SUCCESS)) { - TRACE(Trace::Error, (_T("SetLocalName command failed [0x%02x]"), message.Result())); - result = Core::ERROR_ASYNC_FAILED; - } - - return (result); -} - - -// COD value us composed out of major/minor from this method and OR'd values of -// service bits from each UUID added with AddUUID() -uint32_t ManagementSocket::DeviceClass(const uint8_t major, const uint8_t minor) -{ - Management::DeviceClass message(_deviceId); - message->major = (major & 0x1F); - message->minor = (minor << 2); - - uint32_t result = Exchange(MANAGMENT_TIMEOUT, message, message); - if ((result == Core::ERROR_NONE) && (message.Result() != MGMT_STATUS_SUCCESS)) { - TRACE(Trace::Error, (_T("SetDevClass command failed [0x%02x]"), message.Result())); - result = Core::ERROR_ASYNC_FAILED; - } - - return (result); -} - -uint32_t ManagementSocket::AddUUID(const UUID& uuid, const uint8_t codServiceBits) -{ - ASSERT(uuid.IsValid() == true); - - Management::AddUUID message(_deviceId); - ::memcpy(message->uuid, uuid.Full(), sizeof(message->uuid)); - message->svc_hint = codServiceBits; - - uint32_t result = Exchange(MANAGMENT_TIMEOUT, message, message); - if ((result == Core::ERROR_NONE) && (message.Result() != MGMT_STATUS_SUCCESS)) { - TRACE(Trace::Error, (_T("AddUUID command failed [0x%02x]"), message.Result())); - result = Core::ERROR_ASYNC_FAILED; - } - - return (result); -} - -uint32_t ManagementSocket::RemoveUUID(const UUID& uuid) -{ - ASSERT(uuid.IsValid() == true); - - Management::RemoveUUID message(_deviceId); - ::memcpy(message->uuid, uuid.Full(), sizeof(message->uuid)); - - uint32_t result = Exchange(MANAGMENT_TIMEOUT, message, message); - if ((result == Core::ERROR_NONE) && (message.Result() != MGMT_STATUS_SUCCESS)) { - TRACE(Trace::Error, (_T("RemoveUUID command failed [0x%02x]"), message.Result())); - result = Core::ERROR_ASYNC_FAILED; - } - - return (result); -} - -uint32_t ManagementSocket::AddAdvertising(uint8_t& instance, const bool limited, const bool connectable, const uint16_t duration) -{ - Management::AddAdvertising message(_deviceId); - message->instance = 1; // only one advertising at a time - message->flags = ((limited? 4 : 2) | (connectable? 1 : 0)); - message->duration = 0; - message->timeout = duration; - message->adv_data_len = 0; - message->scan_rsp_len = 0; - - uint32_t result = Exchange(MANAGMENT_TIMEOUT, message, message); - if ((result == Core::ERROR_NONE) && (message.Result() != MGMT_STATUS_SUCCESS)) { - TRACE(Trace::Error, (_T("AddAdvertising command failed [0x%02x]"), message.Result())); - result = Core::ERROR_ASYNC_FAILED; - } else { - instance = message->instance; - } - - return (result); -} - -uint32_t ManagementSocket::RemoveAdvertising() -{ - Management::RemoveAdvertising message(_deviceId); - message->instance = 0; - - uint32_t result = Exchange(MANAGMENT_TIMEOUT, message, message); - if ((result == Core::ERROR_NONE) && (message.Result() != MGMT_STATUS_SUCCESS)) { - TRACE(Trace::Error, (_T("RemoveAdvertising command failed [0x%02x]"), message.Result())); - result = Core::ERROR_ASYNC_FAILED; - } - - return (result); -} - -uint32_t ManagementSocket::Discoverable(const bool enabled, const bool limited, const uint16_t duration) -{ - ASSERT((enabled == true) || (duration == 0)); - ASSERT((limited == false) || (duration > 0)); - - Management::Discoverable message(_deviceId); - message->val = (enabled ? (limited? LIMITED_MODE : ENABLE_MODE) : DISABLE_MODE); - message->timeout = htobs(duration); - - uint32_t result = Exchange(MANAGMENT_TIMEOUT, message, message); - if ((result == Core::ERROR_NONE) && (message.Result() != MGMT_STATUS_SUCCESS)) { - TRACE(Trace::Error, (_T("SetDiscoverable command failed [0x%02x]"), message.Result())); - result = Core::ERROR_ASYNC_FAILED; - } - - return (result); -} - -uint32_t ManagementSocket::Power(const bool enabled) -{ - Management::Power message(_deviceId); - message->val = (enabled ? ENABLE_MODE : DISABLE_MODE); - - uint32_t result = Exchange(MANAGMENT_TIMEOUT, message, message); - if ((result == Core::ERROR_NONE) && (message.Result() != MGMT_STATUS_SUCCESS)) { - TRACE(Trace::Error, (_T("SetPowered command failed [0x%02x]"), message.Result())); - result = Core::ERROR_ASYNC_FAILED; - } - - return (result); -} - -uint32_t ManagementSocket::Connectable(const bool enabled) -{ - Management::Connectable message(_deviceId); - message->val = (enabled ? ENABLE_MODE : DISABLE_MODE); - - uint32_t result = Exchange(MANAGMENT_TIMEOUT, message, message); - if ((result == Core::ERROR_NONE) && (message.Result() != MGMT_STATUS_SUCCESS)) { - TRACE(Trace::Error, (_T("SetConnectable command failed [0x%02x]"), message.Result())); - result = Core::ERROR_ASYNC_FAILED; - } - - return (result); -} - -uint32_t ManagementSocket::FastConnectable(const bool enabled) -{ - Management::FastConnectable message(_deviceId); - message->val = (enabled ? ENABLE_MODE : DISABLE_MODE); - - uint32_t result = Exchange(MANAGMENT_TIMEOUT, message, message); - if ((result == Core::ERROR_NONE) && (message.Result() != MGMT_STATUS_SUCCESS)) { - TRACE(Trace::Error, (_T("SetFastConnectable command failed [0x%02x]"), message.Result())); - result = Core::ERROR_ASYNC_FAILED; - } - - return (result); -} - -uint32_t ManagementSocket::Block(const Address& address, const Address::type type) -{ - Management::Block message(_deviceId); - message->addr.type = type; - ::memcpy(&(message->addr.bdaddr), address.Data(), sizeof(message->addr.bdaddr)); - - uint32_t result = Exchange(MANAGMENT_TIMEOUT, message, message); - if ((result == Core::ERROR_NONE) && (message.Result() != MGMT_STATUS_SUCCESS)) { - TRACE(Trace::Error, (_T("BlockDevice command failed [0x%02x]"), message.Result())); - result = Core::ERROR_ASYNC_FAILED; - } - - return (result); -} - -uint32_t ManagementSocket::Unblock(const Address& address, const Address::type type) -{ - Management::Unblock message(_deviceId); - message->addr.type = type; - ::memcpy(&(message->addr.bdaddr), address.Data(), sizeof(message->addr.bdaddr)); - - uint32_t result = Exchange(MANAGMENT_TIMEOUT, message, message); - if ((result == Core::ERROR_NONE) && (message.Result() != MGMT_STATUS_SUCCESS)) { - TRACE(Trace::Error, (_T("UnblockDevice command failed [0x%02x]"), message.Result())); - result = Core::ERROR_ASYNC_FAILED; - } - - return (result); -} - -uint32_t ManagementSocket::AddDevice(const Address& address, const Address::type type, const autoconnmode value) -{ - Management::AddDevice message(_deviceId); - message->action = value; - message->addr.type = type; - ::memcpy(&(message->addr.bdaddr), address.Data(), sizeof(message->addr.bdaddr)); - - uint32_t result = Exchange(MANAGMENT_TIMEOUT, message, message); - if ((result == Core::ERROR_NONE) && (message.Result() != MGMT_STATUS_SUCCESS)) { - TRACE(Trace::Error, (_T("AddDevice command failed [0x%02x]"), message.Result())); - result = Core::ERROR_ASYNC_FAILED; - } - - return (result); -} - -uint32_t ManagementSocket::RemoveDevice(const Address& address, const Address::type type) -{ - Management::RemoveDevice message(_deviceId); - message->addr.type = type; - ::memcpy(&(message->addr.bdaddr), address.Data(), sizeof(message->addr.bdaddr)); - - uint32_t result = Exchange(MANAGMENT_TIMEOUT, message, message); - if ((result == Core::ERROR_NONE) && (message.Result() != MGMT_STATUS_SUCCESS)) { - TRACE(Trace::Error, (_T("RemoveDevice command failed [0x%02x]"), message.Result())); - result = Core::ERROR_ASYNC_FAILED; - } - - return (result); -} - -uint32_t ManagementSocket::Privacy(const uint8_t mode, const uint8_t identity[16]) -{ - uint32_t result = Core::ERROR_NONE; - - ASSERT((mode == 0) || (identity != nullptr)); - - Management::Privacy message(_deviceId); - message->privacy = mode; - if ((identity != nullptr) && (mode != 0)) { - ::memcpy(message->irk, identity, sizeof(message->irk)); - } - - result = Exchange(MANAGMENT_TIMEOUT, message, message); - if ((result == Core::ERROR_NONE) && (message.Result() != MGMT_STATUS_SUCCESS)) { - TRACE(Trace::Error, (_T("SetPrivacy command failed [0x%02x]"), message.Result())); - result = Core::ERROR_ASYNC_FAILED; - } - - return (result); -} - -uint32_t ManagementSocket::Bondable(const bool enabled) -{ - Management::Bondable message(_deviceId); - message->val = (enabled ? ENABLE_MODE : DISABLE_MODE); - - uint32_t result = Exchange(MANAGMENT_TIMEOUT, message, message); - if ((result == Core::ERROR_NONE) && (message.Result() != MGMT_STATUS_SUCCESS)) { - TRACE(Trace::Error, (_T("SetBondable command failed [0x%02x]"), message.Result())); - result = Core::ERROR_ASYNC_FAILED; - } - - return (result); -} - -uint32_t ManagementSocket::Advertising(const bool enabled, const bool connectable) -{ - Management::Advertising message(_deviceId); - message->val = (enabled ? (connectable? 2 : 1) : DISABLE_MODE); - - uint32_t result = Exchange(MANAGMENT_TIMEOUT, message, message); - if ((result == Core::ERROR_NONE) && (message.Result() != MGMT_STATUS_SUCCESS)) { - TRACE(Trace::Error, (_T("SetAdvertising command failed [0x%02x]"), message.Result())); - result = Core::ERROR_ASYNC_FAILED; - } - - return (result); -} - -uint32_t ManagementSocket::SimplePairing(const bool enabled) -{ - Management::SimplePairing message(_deviceId); - message->val = (enabled ? ENABLE_MODE : DISABLE_MODE); - - uint32_t result = Exchange(MANAGMENT_TIMEOUT, message, message); - if ((result == Core::ERROR_NONE) && (message.Result() != MGMT_STATUS_SUCCESS)) { - TRACE(Trace::Error, (_T("SetSSP command failed [0x%02x]"), message.Result())); - result = Core::ERROR_ASYNC_FAILED; - } - - return (result); -} - -uint32_t ManagementSocket::HighSpeed(const bool enabled) -{ - Management::HighSpeed message(_deviceId); - message->val = (enabled ? ENABLE_MODE : DISABLE_MODE); - - uint32_t result = Exchange(MANAGMENT_TIMEOUT, message, message); - if ((result == Core::ERROR_NONE) && (message.Result() != MGMT_STATUS_SUCCESS)) { - TRACE(Trace::Error, (_T("SetHS command failed [0x%02x]"), message.Result())); - result = Core::ERROR_ASYNC_FAILED; - } - - return (result); -} - -uint32_t ManagementSocket::LowEnergy(const bool enabled) -{ - Management::LowEnergy message(_deviceId); - message->val = (enabled ? ENABLE_MODE : DISABLE_MODE); - - uint32_t result = Exchange(MANAGMENT_TIMEOUT, message, message); - if ((result == Core::ERROR_NONE) && (message.Result() != MGMT_STATUS_SUCCESS)) { - TRACE(Trace::Error, (_T("SetLE command failed [0x%02x]"), message.Result())); - result = Core::ERROR_ASYNC_FAILED; - } - - return (result); -} - -uint32_t ManagementSocket::SecureLink(const bool enabled) -{ - Management::SecureLink message(_deviceId); - message->val = (enabled ? ENABLE_MODE : DISABLE_MODE); - - uint32_t result = Exchange(MANAGMENT_TIMEOUT, message, message); - if ((result == Core::ERROR_NONE) && (message.Result() != MGMT_STATUS_SUCCESS)) { - TRACE(Trace::Error, (_T("SetSecureLink command failed [0x%02x]"), message.Result())); - result = Core::ERROR_ASYNC_FAILED; - } - - return (result); -} - -uint32_t ManagementSocket::SecureConnection(const bool enabled) -{ - Management::SecureConnection message(_deviceId); - message->val = (enabled ? ENABLE_MODE : DISABLE_MODE); - - uint32_t result = Exchange(MANAGMENT_TIMEOUT, message, message); - if ((result == Core::ERROR_NONE) && (message.Result() != MGMT_STATUS_SUCCESS)) { - TRACE(Trace::Error, (_T("SetSecureConn command failed [0x%02x]"), message.Result())); - result = Core::ERROR_ASYNC_FAILED; - } - - return (result); -} - -uint32_t ManagementSocket::PublicAddress(const Address& address) -{ - Management::PublicAddress message(_deviceId); - ::memcpy(&(message->bdaddr), address.Data(), sizeof(message->bdaddr)); - - uint32_t result = Exchange(MANAGMENT_TIMEOUT, message, message); - if ((result == Core::ERROR_NONE) && (message.Result() != MGMT_STATUS_SUCCESS)) { - TRACE(Trace::Error, (_T("SetPublicAddress command failed [0x%02x]"), message.Result())); - result = Core::ERROR_ASYNC_FAILED; - } - - return (result); -} - -uint32_t ManagementSocket::LinkKey(const LinkKeys& keys, const bool debugKeys) -{ - Management::LinkKeys message = Management::LinkKeys::Instance(_deviceId, keys); - message->key_count = htobs(keys.Entries()); - message->debug_keys = (debugKeys ? ENABLE_MODE : DISABLE_MODE); - - uint32_t result = Exchange(MANAGMENT_TIMEOUT, message, message); - if ((result == Core::ERROR_NONE) && (message.Result() != MGMT_STATUS_SUCCESS)) { - TRACE(Trace::Error, (_T("SetLinkKey command failed [0x%02x]"), message.Result())); - result = Core::ERROR_ASYNC_FAILED; - } - - return (result); -} - -uint32_t ManagementSocket::LongTermKey(const LongTermKeys& keys) -{ - Management::LongTermKeys message = Management::LongTermKeys::Instance(_deviceId, keys); - message->key_count = htobs(keys.Entries()); - - uint32_t result = Exchange(MANAGMENT_TIMEOUT, message, message); - if ((result == Core::ERROR_NONE) && (message.Result() != MGMT_STATUS_SUCCESS)) { - TRACE(Trace::Error, (_T("SetLongTermKey command failed [0x%02x]"), message.Result())); - result = Core::ERROR_ASYNC_FAILED; - } - - return (result); -} - -uint32_t ManagementSocket::IdentityKey(const IdentityKeys& keys) -{ - Management::IdentityKeys message = Management::IdentityKeys::Instance(_deviceId, keys); - message->irk_count = htobs(keys.Entries()); - - uint32_t result = Exchange(MANAGMENT_TIMEOUT, message, message); - if ((result == Core::ERROR_NONE) && (message.Result() != MGMT_STATUS_SUCCESS)) { - TRACE(Trace::Error, (_T("SetIdentityKey command failed [0x%02x]"), message.Result())); - result = Core::ERROR_ASYNC_FAILED; - } - - return (result); -} - -uint32_t ManagementSocket::Discovering(const bool on, const bool regular, const bool lowEnergy) -{ - uint32_t result = Core::ERROR_UNAVAILABLE; - uint32_t commandResult = MGMT_STATUS_FAILED; - const uint8_t mode = (regular ? 1 : 0) | (lowEnergy ? 6 : 0); - - // If you do not select any type, no use calling this method - ASSERT (mode != 0); - - if (on == true) { - Management::StartDiscovery message(_deviceId); - message->type = mode; - result = Exchange(MANAGMENT_TIMEOUT, message, message); - commandResult = message.Result(); - } else { - Management::StopDiscovery message(_deviceId); - message->type = mode; - result = Exchange(MANAGMENT_TIMEOUT, message, message); - commandResult = message.Result(); - } - - if ((result == Core::ERROR_NONE) && (commandResult != MGMT_STATUS_SUCCESS)) { - TRACE(Trace::Error, (_T("StartDiscovery/StopDiscovery command failed [0x%02x]"), commandResult)); - result = Core::ERROR_ASYNC_FAILED; - } - - return (result); -} - -ManagementSocket::Info ManagementSocket::Settings() const -{ - Info result; - Management::Settings message(_deviceId); - - if (const_cast(this)->Exchange(MANAGMENT_TIMEOUT, message, message) == Core::ERROR_NONE) { - result = Info(message.Response()); - } - - return (result); -} - -uint32_t ManagementSocket::Pair(const Address& remote, const Address::type type, const capabilities cap) -{ - Management::Pair command(_deviceId); - - command->addr.bdaddr = *remote.Data(); - command->addr.type = type; - command->io_cap = cap; - - uint32_t result = Exchange(MANAGMENT_TIMEOUT, command, command); - if (result == Core::ERROR_NONE) { - switch (command.Result()) { - case MGMT_STATUS_SUCCESS: - break; - case MGMT_STATUS_ALREADY_PAIRED: - result = Core::ERROR_ALREADY_CONNECTED; - break; - default: - TRACE(Trace::Error, (_T("Pair command failed [0x%02x]"), command.Result())); - result = Core::ERROR_ASYNC_FAILED; - break; - } - } else if (result == Core::ERROR_TIMEDOUT) { - // OP_PAIR does not seem to send CMD_STATUS unfortunately... - result = Core::ERROR_INPROGRESS; - } - - return (result); -} - -uint32_t ManagementSocket::Unpair(const Address& remote, const Address::type type) -{ - Management::Unpair command(_deviceId); - - command->addr.bdaddr = *remote.Data(); - command->addr.type = type; - command->disconnect = 1; - - uint32_t result = Exchange(MANAGMENT_TIMEOUT, command, command); - if (result == Core::ERROR_NONE) { - switch (command.Result()) { - case MGMT_STATUS_SUCCESS: - break; - case MGMT_STATUS_NOT_PAIRED: - result = Core::ERROR_ALREADY_RELEASED; - break; - default: - TRACE(Trace::Error, (_T("Unpair command failed [0x%02x]"), command.Result())); - result = Core::ERROR_ASYNC_FAILED; - break; - } - } - - return (result); -} - -uint32_t ManagementSocket::PairAbort(const Address& remote, const Address::type type) -{ - Management::PairAbort command(_deviceId); - - command->bdaddr = *remote.Data(); - command->type = type; - - uint32_t result = Exchange(MANAGMENT_TIMEOUT, command, command); - if (result == Core::ERROR_NONE) { - switch (command.Result()) { - case MGMT_STATUS_SUCCESS: - break; - case MGMT_STATUS_INVALID_PARAMS: - // Not currently pairing - result = Core::ERROR_ILLEGAL_STATE; - break; - default: - TRACE(Trace::Error, (_T("Pairing abort command failed [0x%02x]"), command.Result())); - result = Core::ERROR_ASYNC_FAILED; - break; - } - } else if (result == Core::ERROR_TIMEDOUT) { - // Seems we need a bit more time... but it's fine. - result = Core::ERROR_INPROGRESS; - } - - return (result); -} - -uint32_t ManagementSocket::UserPINCodeReply(const Address& remote, const Address::type type, const string& pinCode) -{ - uint32_t result = Core::ERROR_UNAVAILABLE; - uint32_t commandResult = MGMT_STATUS_FAILED; - - if (pinCode.empty() == false) { - Management::UserPINCodeReply command(_deviceId); - command->addr.bdaddr = *remote.Data(); - command->addr.type = type; - command->pin_len = std::min(pinCode.length(), sizeof(command->pin_code)); - ::memcpy(command->pin_code, pinCode.c_str(), command->pin_len); - result = Exchange(MANAGMENT_TIMEOUT, command, command); - commandResult = command.Result(); - } else { - Management::UserPINCodeNegReply command(_deviceId); - command->addr.bdaddr = *remote.Data(); - command->addr.type = type; - result = Exchange(MANAGMENT_TIMEOUT, command, command); - commandResult = command.Result(); - } - - if ((result == Core::ERROR_NONE) && (commandResult != MGMT_STATUS_SUCCESS)) { - TRACE(Trace::Error, (_T("UserPINCodeReply/UserPINCodeNegReply command failed [0x%02x]"), commandResult)); - result = Core::ERROR_ASYNC_FAILED; - } - - return (result); -} - -uint32_t ManagementSocket::UserPasskeyReply(const Address& remote, const Address::type type, const uint32_t passkey) -{ - uint32_t result = Core::ERROR_UNAVAILABLE; - uint32_t commandResult = MGMT_STATUS_FAILED; - - if (passkey != static_cast(~0)) { - Management::UserPasskeyReply command(_deviceId); - command->addr.bdaddr = *remote.Data(); - command->addr.type = type; - command->passkey = passkey; - result = Exchange(MANAGMENT_TIMEOUT, command, command); - commandResult = command.Result(); - } else { - Management::UserPasskeyNegReply command(_deviceId); - command->addr.bdaddr = *remote.Data(); - command->addr.type = type; - result = Exchange(MANAGMENT_TIMEOUT, command, command); - commandResult = command.Result(); - } - - if ((result == Core::ERROR_NONE) && (commandResult != MGMT_STATUS_SUCCESS)) { - TRACE(Trace::Error, (_T("UserPassReply/UserPassNegReply command failed [0x%02x]"), commandResult)); - result = Core::ERROR_ASYNC_FAILED; - } - - return (result); -} - -uint32_t ManagementSocket::UserPasskeyConfirmReply(const Address& remote, const Address::type type, const bool confirm) -{ - uint32_t result = Core::ERROR_UNAVAILABLE; - uint32_t commandResult = MGMT_STATUS_FAILED; - - if (confirm == true) { - Management::UserConfirmReply command(_deviceId); - command->addr.bdaddr = *remote.Data(); - command->addr.type = type; - result = Exchange(MANAGMENT_TIMEOUT, command, command); - commandResult = command.Result(); - } else { - Management::UserConfirmNegReply command(_deviceId); - command->addr.bdaddr = *remote.Data(); - command->addr.type = type; - result = Exchange(MANAGMENT_TIMEOUT, command, command); - commandResult = command.Result(); - } - - if ((result == Core::ERROR_NONE) && (commandResult != MGMT_STATUS_SUCCESS)) { - TRACE(Trace::Error, (_T("UserConfirmReply/UserConfirmNegReply command failed [0x%02x]"), commandResult)); - result = Core::ERROR_ASYNC_FAILED; - } - - return (result); -} - -uint32_t ManagementSocket::Notifications(const bool enabled) -{ - uint32_t result = Core::ERROR_UNAVAILABLE; - - if (IsOpen() == true) { - BtUtilsHciFilterClear(&_filter); - - if (enabled == true) { - BtUtilsHciFilterSetPtype(HCI_EVENT_PKT, &_filter); - BtUtilsHciFilterSetEvent(EVT_CMD_STATUS, &_filter); - BtUtilsHciFilterSetEvent(EVT_CMD_COMPLETE, &_filter); - BtUtilsHciFilterSetEvent(EVT_PIN_CODE_REQ, &_filter); - BtUtilsHciFilterSetEvent(EVT_LINK_KEY_REQ, &_filter); - BtUtilsHciFilterSetEvent(EVT_LINK_KEY_NOTIFY, &_filter); - BtUtilsHciFilterSetEvent(EVT_RETURN_LINK_KEYS, &_filter); - BtUtilsHciFilterSetEvent(EVT_IO_CAPABILITY_REQUEST, &_filter); - BtUtilsHciFilterSetEvent(EVT_IO_CAPABILITY_RESPONSE, &_filter); - BtUtilsHciFilterSetEvent(EVT_USER_CONFIRM_REQUEST, &_filter); - BtUtilsHciFilterSetEvent(EVT_USER_PASSKEY_REQUEST, &_filter); - BtUtilsHciFilterSetEvent(EVT_REMOTE_OOB_DATA_REQUEST, &_filter); - BtUtilsHciFilterSetEvent(EVT_USER_PASSKEY_NOTIFY, &_filter); - BtUtilsHciFilterSetEvent(EVT_KEYPRESS_NOTIFY, &_filter); - BtUtilsHciFilterSetEvent(EVT_SIMPLE_PAIRING_COMPLETE, &_filter); - BtUtilsHciFilterSetEvent(EVT_AUTH_COMPLETE, &_filter); - BtUtilsHciFilterSetEvent(EVT_REMOTE_NAME_REQ_COMPLETE, &_filter); - BtUtilsHciFilterSetEvent(EVT_READ_REMOTE_VERSION_COMPLETE, &_filter); - BtUtilsHciFilterSetEvent(EVT_READ_REMOTE_FEATURES_COMPLETE, &_filter); - BtUtilsHciFilterSetEvent(EVT_REMOTE_HOST_FEATURES_NOTIFY, &_filter); - BtUtilsHciFilterSetEvent(EVT_INQUIRY_COMPLETE, &_filter); - BtUtilsHciFilterSetEvent(EVT_INQUIRY_RESULT, &_filter); - BtUtilsHciFilterSetEvent(EVT_INQUIRY_RESULT_WITH_RSSI, &_filter); - BtUtilsHciFilterSetEvent(EVT_EXTENDED_INQUIRY_RESULT, &_filter); - BtUtilsHciFilterSetEvent(EVT_CONN_REQUEST, &_filter); - BtUtilsHciFilterSetEvent(EVT_CONN_COMPLETE, &_filter); - BtUtilsHciFilterSetEvent(EVT_DISCONN_COMPLETE, &_filter); - } - - if (setsockopt(Handle(), SOL_HCI, HCI_FILTER, &_filter, sizeof(_filter)) < 0) { - TRACE(Trace::Error, (_T("Can't set MGMT filter: %s (%d)"), strerror(errno), errno)); - result = Core::ERROR_GENERAL; - } else { - TRACE(Trace::Information, (_T("MGMT Filter set!"))); - result = Core::ERROR_NONE; - } - } - return (result); -} - -/* virtual */ uint16_t ManagementSocket::Deserialize(const uint8_t* dataFrame, const uint16_t availableData) -{ - CMD_DUMP("MGMT event received", dataFrame, availableData); - - if (availableData >= sizeof(mgmt_hdr)) { - const mgmt_hdr* hdr = reinterpret_cast(dataFrame); - Update(*hdr); - } else { - TRACE_L1("EVT_MGMT: Message too short => (hci_event_hdr)"); - } - - return (availableData); -} - -/* virtual */ void ManagementSocket::Update(const mgmt_hdr&) -{ -} - -} // namespace Bluetooth - -} diff --git a/Source/bluetooth/HCISocket.h b/Source/bluetooth/HCISocket.h deleted file mode 100644 index 908c28f..0000000 --- a/Source/bluetooth/HCISocket.h +++ /dev/null @@ -1,1311 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#pragma once - -#include "Module.h" -#include "UUID.h" -#include "BluetoothUtils.h" - -namespace Thunder { - -namespace Bluetooth { - - class EXTERNAL Address { - public: - Address() - : _length(0) - { - } - Address(const uint16_t deviceId) - : _length(0) - { - if (BtUtilsHciDevba(deviceId, &_address) >= 0) { - _length = sizeof(_address); - } - } - Address(const bdaddr_t& address) - : _length(sizeof(_address)) - { - ::memcpy(&_address, &address, sizeof(_address)); - } - Address(const TCHAR address[]) - : _length(sizeof(_address)) - { - ::memset(&_address, 0, sizeof(_address)); - BtUtilsStr2Ba(address, &_address); - } - Address(const Address& address) - : _length(address._length) - { - ::memcpy(&_address, &(address._address), sizeof(_address)); - } - ~Address() - { - } - - enum type : uint8_t { - BREDR_ADDRESS = 0x00, - LE_PUBLIC_ADDRESS = 0x01, - LE_RANDOM_ADDRESS = 0x02 - }; - - public: - Address& operator=(const Address& rhs) - { - _length = rhs._length; - ::memcpy(&_address, &(rhs._address), sizeof(_address)); - return (*this); - } - bool IsValid() const - { - return (_length == sizeof(_address)); - } - static Address Default() - { - int deviceId = BtUtilsHciGetRoute(nullptr); - return ((deviceId >= 0) ? Address(static_cast(deviceId)) : Address()); - } - static Address AnyInterface() - { - static bdaddr_t g_anyAddress = { 0 }; - return (Address(g_anyAddress)); - } - static Address LocalInterface() - { - static bdaddr_t g_localAddress = { 0, 0, 0, 0xFF, 0xFF, 0xFF }; - return (Address(g_localAddress)); - } - const bdaddr_t* Data() const - { - return (IsValid() ? &_address : nullptr); - } - uint8_t Length() const - { - return (_length); - } - Core::NodeId NodeId(const uint16_t channelType) const - { - Core::NodeId result; - int deviceId = BtUtilsHciGetRoute(const_cast(Data())); - - if (deviceId >= 0) { - result = Core::NodeId(static_cast(deviceId), channelType); - } - - return (result); - } - Core::NodeId NodeId(const uint8_t addressType, const uint16_t cid, const uint16_t psm) const - { - return (Core::NodeId(_address, addressType, cid, psm)); - } - bool operator==(const Address& rhs) const - { - return ((_length == rhs._length) && (memcmp(rhs._address.b, _address.b, _length) == 0)); - } - bool operator!=(const Address& rhs) const - { - return (!operator==(rhs)); - } - void OUI(char oui[9]) const - { - BtUtilsBa2Oui(Data(), oui); - } - string ToString() const - { - static constexpr TCHAR _hexArray[] = "0123456789ABCDEF"; - string result; - - if (IsValid() == true) { - for (uint8_t index = 0; index < _length; index++) { - if (result.empty() == false) { - result += ':'; - } - result += _hexArray[(_address.b[(_length - 1) - index] >> 4) & 0x0F]; - result += _hexArray[_address.b[(_length - 1) - index] & 0x0F]; - } - } - - return (result); - } - - private: - bdaddr_t _address; - uint8_t _length; - }; - - class EXTERNAL EIR { - static constexpr uint8_t EIR_UUID16_SOME = 0x02; - static constexpr uint8_t EIR_UUID16_ALL = 0x03; - static constexpr uint8_t EIR_UUID32_SOME = 0x04; - static constexpr uint8_t EIR_UUID32_ALL = 0x05; - static constexpr uint8_t EIR_UUID128_SOME = 0x06; - static constexpr uint8_t EIR_UUID128_ALL = 0x07; - static constexpr uint8_t EIR_NAME_SHORT = 0x08; - static constexpr uint8_t EIR_NAME_COMPLETE = 0x09; - static constexpr uint8_t EIR_CLASS_OF_DEV = 0x0D; - - public: - EIR() - : _shortName() - , _completeName() - , _class(0) - , _UUIDs() - { - } - explicit EIR(const string& name, const uint32_t deviceClass = 0) - : _shortName(name) - , _completeName(name) - , _class(deviceClass) - , _UUIDs() - { - } - EIR(const uint8_t buffer[], const uint16_t bufferLength) - : EIR() - { - Ingest(buffer, bufferLength); - } - EIR(const EIR&) = default; - EIR& operator =(const EIR&) = default; - ~EIR() = default; - - public: - uint32_t Class() const - { - return _class; - } - const string& ShortName() const - { - if (_shortName.empty() == true) { - return (_completeName); - } else { - return (_shortName); - } - } - const string& CompleteName() const - { - if (_completeName.empty() == true) { - return (_shortName); - } else { - return (_completeName); - } - } - const std::list& UUIDs() const - { - return (_UUIDs); - } - - void Ingest(const uint8_t buffer[], const uint16_t bufferLength); - - private: - string _shortName; - string _completeName; - uint32_t _class; - std::list _UUIDs; - }; - - template - class EXTERNAL KeyListType { - public: - typedef KEYTYPE type; - - KeyListType() : _list() { - } - KeyListType(const KeyListType& copy) : _list(copy._list) { - } - ~KeyListType() { - } - - KeyListType& operator= (const KeyListType&) = delete; - - public: - using ConstIterator = Core::IteratorType, const KEYTYPE&, typename std::list::const_iterator>; - - static uint8_t Length() { - return (KEYTYPE::Length()); - } - void Add(const KEYTYPE& key) { - _list.push_back(key); - } - void Add(const KeyListType& keylist) { - auto index = keylist.Elements(); - while (index.Next() == true) { - Add(index.Current()); - } - } - uint8_t Entries() const { - return (_list.size()); - } - void Clear() { - _list.clear(); - } - bool IsValid() const { - auto index = Elements(); - while (index.Next() == true) { - if (index.Current().IsValid() != true) { - return (false); - } - } - return (true); - } - uint16_t Clone(const uint16_t length, uint8_t buffer[]) const { - uint16_t result = 0; - typename std::list::const_iterator index (_list.begin()); - while ( (index != _list.end()) && (result <= (length - KEYTYPE::Length())) ) { - ::memcpy(&(buffer[result]), index->Data(), KEYTYPE::Length()); - result += KEYTYPE::Length(); - index++; - } - return (result); - } - ConstIterator Elements() const { - return (ConstIterator(_list)); - } - - private: - std::list _list; - }; - - class EXTERNAL LinkKey { - public: - LinkKey() { - ::memset(&_key, 0, sizeof(_key)); - _key.addr.type = ~0; - } - LinkKey(const Address& address, const uint8_t key[16], const uint8_t pinLength, const uint8_t type) { - ::memcpy(&(_key.addr.bdaddr), address.Data(), sizeof(_key.addr.bdaddr)); - ::memcpy(&(_key.val), key, sizeof(_key.val)); - _key.addr.type = BDADDR_BREDR; - _key.pin_len = pinLength; - _key.type = type; - } - LinkKey(const uint8_t buffer[], const uint16_t length) { - if (length == sizeof(_key)) { - ::memcpy(&_key, buffer, sizeof(_key)); - } else { - LinkKey(); - } - } - LinkKey(const Address& address, const uint8_t address_type, const string& keyString) { - ::memcpy(&(_key.addr.bdaddr), address.Data(), sizeof(_key.addr.bdaddr)); - _key.addr.type = address_type; - - uint16_t length = sizeof(_key) - sizeof(_key.addr); - Core::FromString(keyString, &(reinterpret_cast(&_key)[sizeof(_key.addr)]), length, nullptr); - if (length != (sizeof(_key) - sizeof(_key.addr))) { - // Seems the value is not properly restored, invalidate the object!! - _key.pin_len = 0xFF; - } - } - LinkKey(const LinkKey& copy) { - ::memcpy(&_key, ©._key, sizeof(_key)); - } - ~LinkKey() { - } - - public: - bool IsValid() const { - return ((PinLength() <= 16) && (Type() <= 8) && (LocatorType() == Bluetooth::Address::BREDR_ADDRESS)); - } - Address Locator() const { - return (_key.addr.bdaddr); - } - uint8_t LocatorType() const { - return (_key.addr.type); - } - uint8_t PinLength() const { - return(_key.pin_len); - } - uint8_t Type() const { - return(_key.type); - } - const uint8_t* Key() const { - return (_key.val); - } - const uint8_t* Data() const { - return (reinterpret_cast(&_key)); - } - static uint8_t Length() { - return (sizeof(_key)); - } - string ToString() const { - string baseKey; - Core::ToString(&(reinterpret_cast(&_key)[sizeof(_key.addr)]), sizeof(_key) - sizeof(_key.addr), false, baseKey); - return (baseKey); - } - - private: - struct mgmt_link_key_info _key; - }; - - class EXTERNAL LongTermKey { - public: - LongTermKey() { - ::memset(&_key, 0, sizeof(_key)); - _key.addr.type = ~0; - } - LongTermKey(const Address& address, const uint8_t address_type, const uint8_t type, const uint8_t master, const uint8_t encryptionSize, - const uint16_t diversifier, const uint64_t random, const uint8_t value[16]) - { - ::memcpy(&(_key.addr.bdaddr), address.Data(), sizeof(_key.addr.bdaddr)); - ::memcpy(&(_key.val), value, sizeof(_key.val)); - _key.addr.type = address_type; - _key.type = type; -#ifdef NO_INCLUSIVE_LANGUAGE - _key.central = master; -#else - _key.master = master; -#endif - _key.enc_size = encryptionSize; - _key.ediv = htobs(diversifier); // 16 bits - _key.rand = htobll(random); // 64 bits - } - LongTermKey(const uint8_t buffer[], const uint16_t length) { - if (length == sizeof(_key)) { - ::memcpy(&_key, buffer, sizeof(_key)); - } else { - LongTermKey(); - } - } - LongTermKey(const Address& address, const uint8_t address_type, const string& keyString) { - ::memcpy(&(_key.addr.bdaddr), address.Data(), sizeof(_key.addr.bdaddr)); - _key.addr.type = address_type; - - uint16_t length = sizeof(_key) - sizeof(_key.addr); - Core::FromString(keyString, &(reinterpret_cast(&_key)[sizeof(_key.addr)]), length, nullptr); - if (length != (sizeof(_key) - sizeof(_key.addr))) { - // Seems the value is not properly restored, invalidate the object!! - _key.enc_size = 0; - } - } - LongTermKey(const LongTermKey& copy) { - ::memcpy(&_key, ©._key, sizeof(_key)); - } - ~LongTermKey() { - } - - public: - bool IsValid() const { - return ((EncryptionSize() == sizeof(_key.val)) && (Authenticated() <= 4) && (Master() <= 1) - && ((LocatorType() == Address::LE_PUBLIC_ADDRESS) || ((LocatorType() == Address::LE_RANDOM_ADDRESS) && (_key.addr.bdaddr.b[5] & 0xc0) /* static random */))); - } - Address Locator() const { - return (_key.addr.bdaddr); - } - uint8_t LocatorType() const { - return (_key.addr.type); - } - uint8_t Master() const { -#ifdef NO_INCLUSIVE_LANGUAGE - return(_key.central); -#else - return(_key.master); -#endif - } - uint8_t Authenticated() const { - return(_key.type); - } - uint8_t EncryptionSize() const { - return(_key.enc_size); - } - uint16_t Diversifier() const { - return(btohs(_key.ediv)); - } - uint64_t Random() const { - return(btohll(_key.rand)); - } - const uint8_t* Value() const { - return (_key.val); - } - const uint8_t* Data() const { - return (reinterpret_cast(&_key)); - } - static uint8_t Length() { - return (sizeof(_key)); - } - string ToString() const { - string baseKey; - Core::ToString(&(reinterpret_cast(&_key)[sizeof(_key.addr)]), sizeof(_key) - sizeof(_key.addr), false, baseKey); - return (baseKey); - } - - private: - struct mgmt_ltk_info _key; - }; - - class EXTERNAL IdentityKey { - public: - IdentityKey() { - ::memset(&_key, 0, sizeof(_key)); - _key.addr.type = ~0; - } - IdentityKey(const Address& address, const uint8_t addressType, const uint8_t value[16]) { - ::memcpy(&(_key.addr.bdaddr), address.Data(), sizeof(_key.addr.bdaddr)); - ::memcpy(&(_key.val), value, sizeof(_key.val)); - _key.addr.type = addressType; - } - IdentityKey(const uint8_t buffer[], const uint16_t length) { - if (length == sizeof(_key)) { - ::memcpy(&_key, buffer, sizeof(_key)); - } else { - IdentityKey(); - } - } - IdentityKey(const Address& address, const uint8_t address_type, const string& keyString) { - ::memcpy(&(_key.addr.bdaddr), address.Data(), sizeof(_key.addr.bdaddr)); - _key.addr.type = address_type; - - uint16_t length = sizeof(_key) - sizeof(_key.addr); - Core::FromString(keyString, &(reinterpret_cast(&_key)[sizeof(_key.addr)]), length, nullptr); - if (length != (sizeof(_key) - sizeof(_key.addr))) { - // Seems the value is not properly restored, invalidate the object!! - _key.addr.type = 0xFF; - } - } - IdentityKey(const IdentityKey& copy) { - ::memcpy(&_key, ©._key, sizeof(_key)); - } - ~IdentityKey() { - } - - public: - bool IsValid() const { - return ((LocatorType() == Address::LE_PUBLIC_ADDRESS) || ((LocatorType() == Address::LE_RANDOM_ADDRESS) && (_key.addr.bdaddr.b[5] & 0xc0) /* static random */)); - } - Address Locator() const { - return (_key.addr.bdaddr); - } - uint8_t LocatorType() const { - return (_key.addr.type); - } - const uint8_t* Value() const { - return (_key.val); - } - const uint8_t* Data() const { - return (reinterpret_cast(&_key)); - } - static uint8_t Length() { - return (sizeof(_key)); - } - string ToString() const { - string baseKey; - Core::ToString(&(reinterpret_cast(&_key)[sizeof(_key.addr)]), sizeof(_key) - sizeof(_key.addr), false, baseKey); - return (baseKey); - } - - private: - struct mgmt_irk_info _key; - }; - - class EXTERNAL SignatureKey { - public: - SignatureKey() { - ::memset(&_key, 0, sizeof(_key)); - _key.addr.type = ~0; - } - SignatureKey(const Address& address, const uint8_t address_type, const uint8_t type, const uint8_t value[16]) { - ::memcpy(&(_key.addr.bdaddr), address.Data(), sizeof(_key.addr.bdaddr)); - ::memcpy(&(_key.val), value, sizeof(_key.val)); - _key.addr.type = address_type; - _key.type = type; - } - SignatureKey(const uint8_t buffer[], const uint16_t length) { - if (length == sizeof(_key)) { - ::memcpy(&_key, buffer, sizeof(_key)); - } else { - SignatureKey(); - } - } - SignatureKey(const Address& address, const uint8_t address_type, const string& keyString) { - ::memcpy(&(_key.addr.bdaddr), address.Data(), sizeof(_key.addr.bdaddr)); - _key.addr.type = address_type; - - uint16_t length = sizeof(_key) - sizeof(_key.addr); - Core::FromString(keyString, &(reinterpret_cast(&_key)[sizeof(_key.addr)]), length, nullptr); - if (length != (sizeof(_key) - sizeof(_key.addr))) { - // Seems the value is not properly restored, invalidate the object!! - _key.type = 0xFF; - } - } - SignatureKey(const SignatureKey& copy) { - ::memcpy(&_key, ©._key, sizeof(_key)); - } - ~SignatureKey() { - } - - public: - bool IsValid() const { - return ((Type() <= 3) - && ((LocatorType() == Address::LE_PUBLIC_ADDRESS) || ((LocatorType() == Address::LE_RANDOM_ADDRESS)))); - } - Address Locator() const { - return (_key.addr.bdaddr); - } - uint8_t LocatorType() const { - return (_key.addr.type); - } - uint8_t Type() const { - return(_key.type); - } - const uint8_t* Value() const { - return (_key.val); - } - const uint8_t* Data() const { - return (reinterpret_cast(&_key)); - } - static uint8_t Length() { - return (sizeof(_key)); - } - string ToString() const { - string baseKey; - Core::ToString(&(reinterpret_cast(&_key)[sizeof(_key.addr)]), sizeof(_key) - sizeof(_key.addr), false, baseKey); - return (baseKey); - } - - private: - struct mgmt_csrk_info _key; - }; - - typedef KeyListType LinkKeys; - typedef KeyListType LongTermKeys; - typedef KeyListType IdentityKeys; - typedef KeyListType SignatureKeys; - - - class EXTERNAL HCISocket : public Core::SynchronousChannelType { - private: - static constexpr int SCAN_TIMEOUT = 1000; - static constexpr uint8_t SCAN_TYPE_PASSIVE = 0x00; - static constexpr uint8_t SCAN_TYPE_ACTIVE = 0x01; - static constexpr uint8_t SCAN_FILTER_POLICY_ALL = 0x00; - static constexpr uint8_t SCAN_FILTER_DUPLICATES_DISABLE = 0x00; - static constexpr uint8_t SCAN_FILTER_DUPLICATES_ENABLE = 0x01; - static constexpr uint32_t MAX_ACTION_TIMEOUT = 2000; /* 2 Seconds for commands to complete ? */ - - public: - - template(~0)> - class CommandType : public Core::IOutbound, public Core::IInbound { - private: - CommandType& operator=(const CommandType&) = delete; - - public: - enum : uint16_t { ID = OPCODE }; - - public: - CommandType() - : _offset(sizeof(_buffer)) - , _error(~0) - { - _buffer[0] = HCI_COMMAND_PKT; - _buffer[1] = (OPCODE & 0xFF); - _buffer[2] = ((OPCODE >> 8) & 0xFF); - _buffer[3] = static_cast(sizeof(OUTBOUND)); - - ::memset(&_response, 0, sizeof(_response)); - } - CommandType(const CommandType& copy) - : _offset(copy._offset) - , _error(~0) - { - ::memcpy(_buffer, copy._buffer, sizeof(_buffer)); - ::memcpy(&_response, ©._response, sizeof(_response)); - } - virtual ~CommandType() - { - } - - public: - inline void Clear() - { - ::memset(&(_buffer[4]), 0, sizeof(_buffer) - 4); - } - inline uint32_t Result() const - { - return (_error); - } - virtual void Reload() const override - { - _offset = 0; - } - virtual uint16_t Serialize(uint8_t stream[], const uint16_t length) const override - { - uint16_t result = std::min(static_cast(sizeof(_buffer) - _offset), length); - if (result > 0) { - - ::memcpy(stream, &(_buffer[_offset]), result); - _offset += result; - - CMD_DUMP("HCI sent", stream, result); - } - return (result); - } - OUTBOUND* operator->() - { - return (reinterpret_cast(&(_buffer[4]))); - } - const INBOUND& Response() const - { - return (_response); - } - - private: - virtual Core::IInbound::state IsCompleted() const override - { - return (_error != static_cast(~0) ? Core::IInbound::COMPLETED : Core::IInbound::INPROGRESS); - } - virtual uint16_t Deserialize(const uint8_t stream[], const uint16_t length) override - { - CMD_DUMP("HCI received", stream, length); - - uint16_t result = 0; - if (length >= (HCI_EVENT_HDR_SIZE + 1)) { - const hci_event_hdr* hdr = reinterpret_cast(&(stream[1])); - const uint8_t* ptr = reinterpret_cast(&(stream[1 + HCI_EVENT_HDR_SIZE])); - uint16_t len = (length - (1 + HCI_EVENT_HDR_SIZE)); - - if (hdr->evt == EVT_CMD_STATUS) { - const evt_cmd_status* cs = reinterpret_cast(ptr); - if (btohs(cs->opcode) == OPCODE) { - - if (cs->status == 0) { - // See if we are waiting for an event... - if (RESPONSECODE == static_cast(~0)) { - _error = 0; - } - } else { - _error = cs->status; - } - - result = length; - } - } else if (hdr->evt == EVT_CMD_COMPLETE) { - const evt_cmd_complete* cc = reinterpret_cast(ptr); - if (btohs(cc->opcode) == OPCODE) { - - if (len <= EVT_CMD_COMPLETE_SIZE) { - _error = ~0; - } else { - // See if we are waiting for an event... - if (RESPONSECODE == static_cast(~0)) { - _error = 0; - uint16_t toCopy = std::min(static_cast(sizeof(_response)), static_cast(len - EVT_CMD_COMPLETE_SIZE)); - ::memcpy(&_response, &(ptr[EVT_CMD_COMPLETE_SIZE]), toCopy); - } - } - result = length; - } - } else if ((hdr->evt == EVT_LE_META_EVENT) && (cmd_opcode_ogf(OPCODE) == OGF_LE_CTL)) { - const evt_le_meta_event* eventMetaData = reinterpret_cast(ptr); - if (eventMetaData->subevent == RESPONSECODE) { - uint16_t toCopy = std::min(static_cast(sizeof(_response)), static_cast(len - EVT_LE_META_EVENT_SIZE)); - ::memcpy(&_response, &(ptr[EVT_LE_META_EVENT_SIZE]), toCopy); - _error = 0; - result = length; - } - } else if (hdr->evt == RESPONSECODE) { - ::memcpy(&_response, ptr, std::min(static_cast(sizeof(_response)), len)); - _error = 0; - result = length; - } - } - return (result); - } - - private: - mutable uint16_t _offset; - uint8_t _buffer[1 + 3 + sizeof(OUTBOUND)]; - INBOUND _response; - uint16_t _error; - }; - - public: - class EXTERNAL FeatureIterator { - public: - FeatureIterator() - : _index(-1) - { - ::memset(_features, 0, sizeof(_features)); - } - FeatureIterator(const uint8_t length, const uint8_t data[]) - : _index(-1) - { - uint8_t copyLength = std::min(length, static_cast(sizeof(_features))); - ::memcpy(_features, data, copyLength); - if (copyLength < sizeof(_features)) { - ::memset(&_features[copyLength], 0, (sizeof(_features) - copyLength)); - } - } - FeatureIterator(const FeatureIterator& copy) - : _index(copy._index) - { - ::memcpy(_features, copy._features, sizeof(_features)); - } - ~FeatureIterator() - { - } - - public: - FeatureIterator& operator=(const FeatureIterator& rhs) - { - _index = rhs._index; - ::memcpy(_features, rhs._features, sizeof(_features)); - - return (*this); - } - - void Reset() - { - _index = -1; - } - bool IsValid() const - { - return ((_index >= 0) && (_index < static_cast(sizeof(_features) * 8))); - } - bool Next() - { - _index++; - - while ((_index < static_cast(sizeof(_features) * 8)) && ((_features[_index >> 3] & (1 << (_index & 0x7))) == 0)) { - _index++; - } - return (_index < static_cast(sizeof(_features) * 8)); - } - uint8_t Feature() const - { - return (_index); - } - const TCHAR* Text() const - { - uint16_t index = (((index & 0xF8) << 5) | (1 << (_index & 0x7))); - return (FeatureToText(index)); - } - bool HasFeatures(const uint8_t byte, uint8_t bit) const - { - return (byte < sizeof(_features) ? (_features[byte] & bit) != 0 : false); - } - - private: - const TCHAR* FeatureToText(const uint16_t index) const; - - private: - int16_t _index; - uint8_t _features[8]; - }; - - // ------------------------------------------------------------------------ - // Create definitions for the HCI commands - // ------------------------------------------------------------------------ - struct Command { -PUSH_WARNING(DISABLE_WARNING_PEDANTIC) - using Void = char[0]; -POP_WARNING() - typedef CommandType - Inquiry; - - typedef CommandType - InquiryCancel; - - typedef CommandType - Connect; - - typedef CommandType - Authenticate; - - typedef CommandType - UserConfirmReply; - - typedef CommandType - UserConfirmNegReply; - - typedef CommandType - Disconnect; - - typedef CommandType - ConnectLE; - - typedef CommandType - ConnectLECancel; - - typedef CommandType - Encrypt; - - typedef CommandType - EncryptLE; - - typedef CommandType - RemoteName; - - typedef CommandType - ScanParametersLE; - - typedef CommandType - ScanEnableLE; - - typedef CommandType - ClearWhiteList; - - typedef CommandType - ReadWhiteListSize; - - typedef CommandType - AddDeviceToWhiteList; - - typedef CommandType - RemoveDeviceFromWhiteList; - - typedef CommandType - RemoteFeaturesLE; - - typedef CommandType - AdvertisingParametersLE; - - typedef CommandType - AdvertisingEnableLE; - - typedef CommandType - ConnectionUpdate; - - typedef CommandType - ReadStoredLinkKey; - }; - - enum state : uint16_t { - IDLE = 0x0000, - SCANNING = 0x0001, - INQUIRING = 0x0002, - PAIRING = 0x0004, - DISCOVERING = 0x1000, - ADVERTISING = 0x2000, - ABORT_SCANNING = 0x4000, - ABORT_INQUIRING = 0x8000 - }; - - static constexpr uint16_t ACTION_MASK = 0x0FFF; - - public: - HCISocket(const HCISocket&) = delete; - HCISocket& operator=(const HCISocket&) = delete; - - HCISocket() - : Core::SynchronousChannelType(SocketPort::RAW, Core::NodeId(), Core::NodeId(), 1024, 1024) - , _state(IDLE) - { - } - HCISocket(const Core::NodeId& sourceNode) - : Core::SynchronousChannelType(SocketPort::RAW, sourceNode, Core::NodeId(), 1024, 1024) - , _state(IDLE) - { - } - virtual ~HCISocket() - { - Close(Core::infinite); - } - - public: - bool IsScanning() const // BLE - { - return ((_state & SCANNING) != 0); - } - bool IsInquiring() const // BR/EDR - { - return ((_state & INQUIRING) != 0); - } - bool IsAdvertising() const // BLE - { - return ((_state & ADVERTISING) != 0); - } - bool IsDiscovering() const // BR/EDR - { - return ((_state & DISCOVERING) != 0); - } - - // User-land advertising - uint32_t Advertising(const bool enable, const uint8_t mode); - - // User-land BLE background discovery - uint32_t Discovery(const bool enable); - - // BR/EDR scanning - uint32_t Inquiry(const uint16_t scanTime, const bool limited); - uint32_t AbortInquiry(); - - // BLE scanning - uint32_t Scan(const uint16_t scanTime, const bool limited, const bool passive); - uint32_t AbortScan(); - - uint32_t ReadStoredLinkKeys(const Address adr, const bool all, LinkKeys& keys); - - public: - template - void Execute(const uint32_t waitTime, const COMMAND& cmd, std::function handler) - { - class Handler : public Core::IOutbound::ICallback { - public: - Handler() = delete; - Handler(const Handler&) = delete; - Handler(const COMMAND& cmd, const std::function handler) - : _cmd(cmd) - , _handler(handler){ - } - virtual ~Handler() { - } - - public: - COMMAND& Cmd() { - return (_cmd); - } - void Updated(const Core::IOutbound& data, const uint32_t error_code) override { - //ASSERT(_cmd == data); - _handler(_cmd, error_code); - delete this; - } - - private: - COMMAND _cmd; - std::function _handler; - }; - Handler* entry = new Handler(cmd, handler); - - Send(waitTime, entry->Cmd(), entry, &(entry->Cmd())); - } - - protected: - virtual void Update(const hci_event_hdr& eventData); - virtual void Update(const inquiry_info& eventData); - virtual void Update(const inquiry_info_with_rssi& eventData); - virtual void Update(const extended_inquiry_info& eventData); - virtual void Update(const le_advertising_info& eventData); - - private: - template void DeserializeScanResponse(const uint8_t* ptr); - - private: - virtual void StateChange() override; - virtual uint16_t Deserialize(const uint8_t* dataFrame, const uint16_t availableData) override; - void SetOpcode(const uint16_t opcode); - - private: - Core::StateTrigger _state; - struct hci_filter _filter; - }; - - class EXTERNAL ManagementSocket : public Core::SynchronousChannelType { - public: - class EXTERNAL Info { - public: - class EXTERNAL Properties { - public: - Properties() : _value(0) {} - Properties(const uint32_t value) : _value(value) {} - Properties(const Properties& copy) : _value(copy._value) {} - ~Properties() {} - - Properties& operator= (const Properties& rhs) { - _value = rhs._value; - return (*this); - } - - public: - bool IsPowered() const { - return ((_value & MGMT_SETTING_POWERED) != 0); - } - bool IsConnectable() const { - return ((_value & MGMT_SETTING_CONNECTABLE) != 0); - } - bool IsFastConnectable() const { - return ((_value & MGMT_SETTING_FAST_CONNECTABLE) != 0); - } - bool IsDiscoverable() const { - return ((_value & MGMT_SETTING_DISCOVERABLE) != 0); - } - bool IsBondable() const { - return ((_value & MGMT_SETTING_BONDABLE) != 0); - } - bool HasLinkLevelSecurity() const { - return ((_value & MGMT_SETTING_LINK_SECURITY) != 0); - } - bool HasSecureSimplePairing() const { - return ((_value & MGMT_SETTING_SSP) != 0); - } - bool HasBasicEnhancedRate() const { - return ((_value & MGMT_SETTING_BREDR) != 0); - } - bool HasHighSpeed() const { - return ((_value & MGMT_SETTING_HS) != 0); - } - bool HasLowEnergy() const { - return ((_value & MGMT_SETTING_LE) != 0); - } - bool IsAdvertising() const { - return ((_value & MGMT_SETTING_ADVERTISING) != 0); - } - bool HasSecureConnections() const { - return ((_value & MGMT_SETTING_SECURE_CONN) != 0); - } - bool HasDebugKeys() const { - return ((_value & MGMT_SETTING_DEBUG_KEYS) != 0); - } - bool HasPrivacy() const { - return ((_value & MGMT_SETTING_PRIVACY) != 0); - } - bool HasConfiguration() const { - return ((_value & MGMT_SETTING_CONFIGURATION) != 0); - } - bool HasStaticAddress() const { - return ((_value & MGMT_SETTING_STATIC_ADDRESS) != 0); - } - - private: - uint32_t _value; - }; - public: - Info() - : _address() - , _version(0) - , _manufacturer(0) - , _supported(0) - , _settings(0) - , _deviceClass(0) - , _name() - , _shortName() - { - } - Info(const Info& copy) - : _address(copy._address) - , _version(copy._version) - , _manufacturer(copy._manufacturer) - , _supported(copy._supported) - , _settings(copy._settings) - , _deviceClass(copy._deviceClass) - , _name(copy._name) - , _shortName(copy._shortName) - { - } - Info(const mgmt_rp_read_info& copy) - : _address(copy.bdaddr) - , _version(copy.version) - , _manufacturer(copy.manufacturer) - , _supported(copy.supported_settings) - , _settings(copy.current_settings) - , _deviceClass((copy.dev_class[2] << 16) | (copy.dev_class[1] << 8) | copy.dev_class[0]) - , _name(Core::ToString(reinterpret_cast(copy.name))) - , _shortName(Core::ToString(reinterpret_cast(copy.short_name))) - { - } - Info& operator= (const Info& rhs) { - _address = rhs._address; - _version = rhs._version; - _manufacturer = rhs._manufacturer; - _supported = rhs._supported; - _settings = rhs._settings; - _deviceClass = rhs._deviceClass; - _name = rhs._name; - _shortName = rhs._shortName; - - return (*this); - } - - ~Info() - { - } - - public: - const Bluetooth::Address& Address() const { - return (_address); - } - uint8_t Version () const { - return (_version); - } - uint16_t Manufacturer() const { - return (_manufacturer); - } - Properties Supported () const { - return (Properties(_supported)); - } - Properties Actuals() const { - return (Properties(_settings)); - } - uint32_t DeviceClass() const { - return (_deviceClass); - } - const string& ShortName() const { - return (_shortName); - } - const string& Name() const { - return (_name); - } - - private: - Bluetooth::Address _address; - uint8_t _version; - uint16_t _manufacturer; - uint32_t _supported; - uint32_t _settings; - uint32_t _deviceClass; - string _name; - string _shortName; - }; - - enum capabilities : uint8_t { - DISPLAY_ONLY = 0x00, - DISPLAY_YES_NO = 0x01, - KEYBOARD_ONLY = 0x02, - NO_INPUT_NO_OUTPUT = 0x03, - KEYBOARD_DISPLAY = 0x04, - INVALID = 0xFF - }; - - enum autoconnmode : uint8_t { - REPORT = 0x00, - DIRECT = 0x01, // reconnect on direct advertisement - ALWAYS = 0x02 - }; - - public: - ManagementSocket(const ManagementSocket&) = delete; - ManagementSocket& operator=(const ManagementSocket&) = delete; - - ManagementSocket() - : Core::SynchronousChannelType(SocketPort::RAW, Core::NodeId(HCI_DEV_NONE, HCI_CHANNEL_CONTROL), Core::NodeId(), 1024, 1024) - , _deviceId(~0) - { - if (Core::SynchronousChannelType::Open(Core::infinite) != Core::ERROR_NONE) { - } - } - virtual ~ManagementSocket() - { - Core::SynchronousChannelType::Close(Core::infinite); - } - - public: - static void Devices(std::list& list); - - void DeviceId (const uint16_t deviceId) - { - ASSERT((_deviceId == static_cast(~0)) ^ (deviceId == static_cast(~0))); - - _deviceId = deviceId; - } - uint16_t DeviceId() const - { - return (_deviceId); - } - static bool Up(const uint16_t deviceId) - { - bool result = false; - int descriptor; - - if ((descriptor = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0) { - TRACE_L1("Could not open a socket. Error: %d", errno); - } - else { - if ( (::ioctl(descriptor, HCIDEVUP, deviceId) == 0) || (errno == EALREADY) ) { - result = true; - } - else { - TRACE_L1("Could not bring up the interface [%d]. Error: %d", deviceId, errno); - } - ::close(descriptor); - } - return (result); - } - static bool Down(const uint16_t deviceId) - { - bool result = false; - int descriptor; - if ((descriptor = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0) { - TRACE_L1("Could not open a socket. Error: %d", errno); - } - else { - if ( (::ioctl(descriptor, HCIDEVDOWN, deviceId) == 0) || (errno == EALREADY) ) { - result = true; - } - else { - TRACE_L1("Could not bring down the interface [%d]. Error: %d", deviceId, errno); - } - ::close(descriptor); - } - return (result); - } - - public: - Info Settings() const; - - uint32_t Power(bool enabled); - - uint32_t Bondable(bool enabled); - uint32_t Connectable(const bool enabled); - uint32_t FastConnectable(const bool enabled); - uint32_t Discoverable(const bool enabled, const bool limited = false, const uint16_t duration = 0 /* infinite */); - uint32_t Advertising(bool enabled, const bool connectable = false); - uint32_t SimplePairing(bool enabled); - uint32_t HighSpeed(bool enabled); - uint32_t LowEnergy(bool enabled); - uint32_t SecureLink(bool enabled); - uint32_t SecureConnection(bool enabled); - uint32_t PublicAddress(const Address& address); - - uint32_t Name(const string& shortName, const string& longName); - uint32_t DeviceClass(const uint8_t major, const uint8_t minor); - uint32_t AddUUID(const UUID& uuid, const uint8_t codServiceBits); - uint32_t RemoveUUID(const UUID& uuid); - - // Prefer this over Advertising(true) - uint32_t AddAdvertising(uint8_t& instance, const bool limited = false, const bool connectable = true, const uint16_t duration = 0 /* inifite */); - uint32_t RemoveAdvertising(); - - // Kernel-side BLE discovery and autoconnection - uint32_t Discovering(const bool on, const bool regular, const bool LowEnergy); - uint32_t Block(const Address& address, const Address::type type); - uint32_t Unblock(const Address& address, const Address::type type); - uint32_t AddDevice(const Address& address, const Address::type type, const autoconnmode value = REPORT); - uint32_t RemoveDevice(const Address& address, const Address::type type); - - uint32_t Pair(const Address& remote, const Address::type type, const capabilities cap = NO_INPUT_NO_OUTPUT); - uint32_t Unpair(const Address& remote, const Address::type type); - uint32_t PairAbort(const Address& remote, const Address::type type); - - uint32_t UserPINCodeReply(const Address& remote, const Address::type type, const string& pinCode); - uint32_t UserPasskeyReply(const Address& remote, const Address::type type, const uint32_t passkey); - uint32_t UserPasskeyConfirmReply(const Address& remote, const Address::type type, const bool confirm); - - uint32_t Privacy(const uint8_t mode, const uint8_t identity[16] = nullptr); - uint32_t LinkKey(const LinkKeys& keys, const bool debugKeys = false); - uint32_t LongTermKey(const LongTermKeys& keys); - uint32_t IdentityKey(const IdentityKeys& keys); - - public: - uint32_t Notifications(const bool enabled); - - protected: - virtual void Update(const mgmt_hdr& eventData); - - private: - virtual uint16_t Deserialize(const uint8_t* dataFrame, const uint16_t availableData) override; - - private: - uint16_t _deviceId; - struct hci_filter _filter; - }; - - -} // namespace Bluetooth - -} // namespace Thunder diff --git a/Source/bluetooth/IDriver.h b/Source/bluetooth/IDriver.h deleted file mode 100644 index 2ffa293..0000000 --- a/Source/bluetooth/IDriver.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#pragma once - -#ifndef EXTERNAL -#ifdef _MSVC_LANG -#ifdef BLUETOOTH_EXPORTS -#define EXTERNAL __declspec(dllexport) -#else -#define EXTERNAL __declspec(dllimport) -#endif -#else -#define EXTERNAL __attribute__ ((visibility ("default"))) -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -EXTERNAL const char* construct_bluetooth_driver(const char* config); -EXTERNAL void destruct_bluetooth_driver(); - -#ifdef __cplusplus -} -#endif diff --git a/Source/bluetooth/Module.cpp b/Source/bluetooth/Module.cpp deleted file mode 100644 index 393d6a2..0000000 --- a/Source/bluetooth/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) diff --git a/Source/bluetooth/Module.h b/Source/bluetooth/Module.h deleted file mode 100644 index 499c739..0000000 --- a/Source/bluetooth/Module.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#pragma once - -#ifndef MODULE_NAME -#define MODULE_NAME Bluetooth -#endif - -#include -#include - -#include <../include/bluetooth/bluetooth.h> -#include <../include/bluetooth/hci.h> -#include <../include/bluetooth/mgmt.h> -#include <../include/bluetooth/l2cap.h> - -#include "Debug.h" - -#if defined(__WINDOWS__) && defined(BLUETOOTH_EXPORTS) -#undef EXTERNAL -#define EXTERNAL EXTERNAL_EXPORT -#endif diff --git a/Source/bluetooth/UUID.cpp b/Source/bluetooth/UUID.cpp deleted file mode 100644 index 41a590f..0000000 --- a/Source/bluetooth/UUID.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#include "UUID.h" - -namespace Thunder { - -namespace Bluetooth { - -/* static */ const uint8_t UUID::BASE[] = { 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - -} // namespace Bluetooth - -} diff --git a/Source/bluetooth/UUID.h b/Source/bluetooth/UUID.h deleted file mode 100644 index 740086d..0000000 --- a/Source/bluetooth/UUID.h +++ /dev/null @@ -1,215 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#pragma once - -#include "Module.h" - -namespace Thunder { - -namespace Bluetooth { - - class EXTERNAL UUID { - private: - static const uint8_t BASE[]; - - public: - UUID() - { - _uuid[0] = 0; - } - UUID(const uint32_t uuid) - { - _uuid[0] = (uuid < 0x10000? 2 : 16); - ::memcpy(&(_uuid[1]), BASE, sizeof(_uuid) - 5); - _uuid[13] = (uuid & 0xFF); - _uuid[14] = (uuid >> 8) & 0xFF; - _uuid[15] = (uuid >> 16) & 0xFF; - _uuid[16] = (uuid >> 24) & 0xFF; - } - explicit UUID(const uint8_t uuid[16]) - { - ::memcpy(&(_uuid[1]), uuid, 16); - - // See if this contains the Base, cause than it can be a short... - if ((::memcmp(BASE, uuid, 12) == 0) && (uuid[14] == 0) && (uuid[15] == 0)) { - _uuid[0] = 2; - } - else { - _uuid[0] = 16; - } - } - explicit UUID(const string& uuidStr) - { - FromString(uuidStr); - } - UUID(const UUID& copy) - { - ::memcpy(_uuid, copy._uuid, sizeof(_uuid)); - } - ~UUID() - { - } - - UUID& operator=(const UUID& rhs) - { - ::memcpy(_uuid, rhs._uuid, sizeof(_uuid)); - return (*this); - } - - public: - bool IsValid() const - { - return (_uuid[0] != 0); - } - uint16_t Short() const - { - ASSERT(_uuid[0] == 2); - return ((_uuid[14] << 8) | _uuid[13]); - } - const uint8_t* Full() const - { - return (&_uuid[1]); - } - bool operator==(const UUID& rhs) const - { - return ((rhs._uuid[0] == _uuid[0]) && - ((_uuid[0] == 2) ? ((rhs._uuid[13] == _uuid[13]) && (rhs._uuid[14] == _uuid[14])) : - (::memcmp(_uuid, rhs._uuid, _uuid[0] + 1) == 0))); - } - bool operator!=(const UUID& rhs) const - { - return !(operator==(rhs)); - } - bool operator==(const uint16_t shortUuid) const - { - return ((HasShort() == true) && (Short() == shortUuid)); - } - bool operator!=(const uint16_t shortUuid) const - { - return !(operator==(shortUuid)); - } - bool operator<(const UUID& rhs) const - { - for (uint8_t i = 16; i > 0; i--) { - if (_uuid[i] != rhs._uuid[i]) { - return(_uuid[i] < rhs._uuid[i]); - } - } - return (false); - } - bool HasShort() const - { - return (_uuid[0] == 2); - } - uint8_t Length() const - { - return (_uuid[0]); - } - const uint8_t* Data() const - { - return (_uuid[0] == 2 ? &(_uuid[13]) : &(_uuid[1])); - } - string ToString(const bool full = false) const - { - static const TCHAR hexArray[] = "0123456789abcdef"; - - uint8_t index = 0; - string result; - - if ((HasShort() == false) || (full == true)) { - result.resize(36); - for (uint8_t byte = 12 + 4; byte > 12; byte--) { - result[index++] = hexArray[_uuid[byte] >> 4]; - result[index++] = hexArray[_uuid[byte] & 0xF]; - } - result[index++] = '-'; - for (uint8_t byte = 10 + 2; byte > 10; byte--) { - result[index++] = hexArray[_uuid[byte] >> 4]; - result[index++] = hexArray[_uuid[byte] & 0xF]; - } - result[index++] = '-'; - for (uint8_t byte = 8 + 2; byte > 8; byte--) { - result[index++] = hexArray[_uuid[byte] >> 4]; - result[index++] = hexArray[_uuid[byte] & 0xF]; - } - result[index++] = '-'; - for (uint8_t byte = 6 + 2; byte > 6; byte--) { - result[index++] = hexArray[_uuid[byte] >> 4]; - result[index++] = hexArray[_uuid[byte] & 0xF]; - } - result[index++] = '-'; - for (uint8_t byte = 0 + 6; byte > 0; byte--) { - result[index++] = hexArray[_uuid[byte] >> 4]; - result[index++] = hexArray[_uuid[byte] & 0xF]; - } - } - else { - result.resize(4); - - for (uint8_t byte = 12 + 2; byte > 12; byte--) { - result[index++] = hexArray[_uuid[byte] >> 4]; - result[index++] = hexArray[_uuid[byte] & 0xF]; - } - } - return (result); - } - bool FromString(const string& uuidStr) - { - if ((uuidStr.length() == 4) || (uuidStr.length() == ((16 * 2) + 4))) { - uint8_t buf[16]; - const uint16_t size = uuidStr.length(); - uint8_t* p = (buf + sizeof(buf)); - int16_t idx = 0; - - if (size == 4) { - memcpy(buf, BASE, sizeof(buf)); - p -= 2; - } - - while (idx < size) { - if ((idx == 8) || (idx == 13) || (idx == 18) || (idx == 23)) { - if (uuidStr[idx] != '-') { - break; - } else { - idx++; - } - } else { - (*--p) = ((Core::FromHexDigits(uuidStr[idx]) << 4) | Core::FromHexDigits(uuidStr[idx + 1])); - idx += 2; - } - } - - if (idx == size) { - (*this) = UUID(buf); - return true; - } - } - - return false; - } - - private: - uint8_t _uuid[17]; - }; - -} // namespace Bluetooth - -} - diff --git a/Source/bluetooth/audio/AVDTPProfile.cpp b/Source/bluetooth/audio/AVDTPProfile.cpp deleted file mode 100644 index d716ef7..0000000 --- a/Source/bluetooth/audio/AVDTPProfile.cpp +++ /dev/null @@ -1,464 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2021 Metrological - * - * 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. - */ - -#include "Module.h" -#include "AVDTPProfile.h" - -namespace Thunder { - -namespace Bluetooth { - -namespace AVDTP { - - // Client methods - // -------------------------------- - - uint32_t Client::Discover(const std::function& reportCb) const - { - uint32_t result; - std::list endpoints; - - _command.Set(Signal::AVDTP_DISCOVER); - - // First issue a DISCOVER signal. - result = Execute(_command, [&](const Payload& payload) { - // Pick up end point data... - while (payload.Available() >= 2) { - uint8_t data[2]; - payload.Pop(data[0]); - payload.Pop(data[1]); - endpoints.emplace_back(data); - } - - if (payload.Available() != 0) { - TRACE_L1("Unexpected data in payload!"); - } - }); - - if (result == Core::ERROR_NONE) { - // Then for each of the stream points discovered issue a GET_CAPABILITIES signal. - for (auto& sep : endpoints) { - _command.Set(Signal::AVDTP_GET_CAPABILITIES, sep.Id()); - - Execute(_command, [&](const Payload& payload) { - // Pick up capability data for each category listed... - while (payload.Available() >= 2) { - StreamEndPoint::Service::categorytype category{}; - uint8_t length{}; - Buffer params; - - // Capabilities are stored as {category:length:params} triplets. - payload.Pop(category); - payload.Pop(length); - - if (length > 0) { - payload.Pop(params, length); - } - - sep.Add(StreamEndPoint::capability, category, std::move(params)); - } - - if (payload.Available() != 0) { - TRACE_L1("Unexpected data in payload!"); - } - }); - - // Hand this endpoint over... - reportCb(std::move(sep)); - } - } - - return (result); - } - - uint32_t Client::SetConfiguration(StreamEndPoint& ep, const uint8_t remoteId) - { - auto cb = [&](Payload& payload) { - // For each category set the configuration data... - for (auto const& entry : ep.Configuration()) { - const StreamEndPoint::Service& service = entry.second; - - ASSERT(service.Params().size() <= 255); - - // Configuration data has same structure as capabilities. - payload.Push(service.Category()); - payload.Push(service.Params().size()); - - if (service.Params().size() > 0) { - payload.Push(service.Params()); - } - } - }; - - ASSERT(remoteId != 0); - ASSERT(ep.Id() != 0); - - _command.Set(Signal::AVDTP_SET_CONFIGURATION, remoteId, ep.Id(), cb); - return (Execute(_command)); - } - - uint32_t Client::GetConfiguration(const uint8_t remoteId, const std::function& reportCb) const - { - ASSERT(reportCb != nullptr); - ASSERT(remoteId != 0); - - _command.Set(Signal::AVDTP_GET_CONFIGURATION, remoteId); - - return (Execute(_command, [&](const Payload& payload) { - - // For each category get the configuration data... - while (payload.Available() >= 2) { - StreamEndPoint::Service::categorytype category{}; - uint8_t length{}; - Buffer data; - - payload.Pop(category); - payload.Pop(length); - - if (length > 0) { - payload.Pop(data, length); - } - - reportCb(category, std::move(data)); - } - - ASSERT(payload.Available() == 0); - })); - } - - /* private */ - uint32_t Client::Execute(AVDTP::Socket::CommandType& cmd, const Payload::Inspector& inspectorCb) const - { - uint32_t result = Core::ERROR_ASYNC_FAILED; - - ASSERT(_socket != nullptr); - - if (_socket->Exchange(AVDTP::Socket::CommunicationTimeout, cmd, cmd) == Core::ERROR_NONE) { - - if (cmd.IsAccepted() == false) { - TRACE_L1("Signal %d was rejected! [%d]", cmd.Call().Id() ,cmd.Result().Error()); - } - else { - result = Core::ERROR_NONE; - - if (inspectorCb != nullptr) { - cmd.Result().InspectPayload(inspectorCb); - } - } - } - - return (result); - } - - // Server methods - // -------------------------------- - - void Server::OnDiscover(const Handler& Reply) - { - // Lists all endpoints offered by the signalling server. - // This call cannot fail. - - Reply([&](Payload& payload) { - uint8_t id = 0; - - // Serialize all endpoints... - while (Visit(++id, [&](const StreamEndPoint& ep) { - ep.Serialize(payload); - }) == true); - - // Must be at least on endpoint configured. - // ASSERT(id > 1); - }); - } - - void Server::OnGetCapabilities(const uint8_t seid, const Handler& Reply) - { - // Retrieves basic capabilities of a particular endpoint. - - if (Visit(seid, [&](const StreamEndPoint& ep) { - ASSERT(ep.Capabilities().empty() == false); - - // Serialize this endpoints capabilities... - Reply([&](Payload& payload) { - for (auto const& entry : ep.Capabilities()) { - const StreamEndPoint::Service& service = entry.second; - - if (StreamEndPoint::Service::IsBasicCategory(service.Category()) == true) { - - ASSERT(service.Params().size() <= 255); - - payload.Push(service.Category()); - payload.Push(service.Params().size()); - - if (service.Params().size() > 0) { - payload.Push(service.Params()); - } - } - } - }); - }) == false) { - Reply(Signal::errorcode::BAD_ACP_SEID); - } - } - - void Server::OnGetAllCapabilities(const uint8_t seid, const Handler& Reply) - { - // Retrieves all capabilities of a particular endpoint. - - if (Visit(seid, [&](const StreamEndPoint& ep) { - ASSERT(ep.Capabilities().empty() == false); - - // Serialize this endpoints capabilities... - Reply([&](Payload& payload) { - for (auto const& entry : ep.Capabilities()) { - const StreamEndPoint::Service& service = entry.second; - - ASSERT(service.Params().size() <= 255); - - payload.Push(service.Category()); - payload.Push(service.Params().size()); - - if (service.Params().size() > 0) { - payload.Push(service.Params()); - } - } - }); - }) == false) { - Reply(Signal::errorcode::BAD_ACP_SEID); - } - } - - void Server::OnSetConfiguration(const Signal& signal, const Handler& Reply) - { - // Sets configuration of a particular endpoint. - // Requests the endpoint state change from IDLE to CONFIGURED. - - Signal::errorcode code = Signal::errorcode::SUCCESS; - uint8_t failedCategory = 0; - - uint8_t acpSeid = 0; // ours - uint8_t intSeid = 0; // theirs - - Payload config; - - signal.InspectPayload([&](const Payload& payload) { - if (payload.Available() >= 2) { - payload.Pop(acpSeid); - acpSeid >>= 2; - - payload.Pop(intSeid); - intSeid >>= 2; - - // The rest is the raw config data. - payload.PopAssign(config, payload.Available()); - } - else { - code = Signal::errorcode::BAD_LENGTH; - } - }); - - if (code == Signal::errorcode::SUCCESS) { - code = Signal::errorcode::BAD_ACP_SEID; - - Visit(acpSeid, [&](StreamEndPoint& ep) { - code = DeserializeConfig(config, ep, failedCategory, [](const StreamEndPoint::Service::categorytype category) { - if (StreamEndPoint::Service::IsValidCategory(category) == true) { - return (Signal::errorcode::SUCCESS); - } - else { - return (Signal::errorcode::BAD_SERV_CATEGORY); - } - }); - - if (code == Signal::errorcode::SUCCESS) { - code = ToSignalCode(ep.OnSetConfiguration(failedCategory, &Reply.Channel())); - - if (code == Signal::errorcode::SUCCESS) { - ep.RemoteId(intSeid); - } - } - }); - } - - Reply(code, failedCategory); - } - - void Server::OnReconfigure(const Signal& signal, const Handler& Reply) - { - // Sets partial configuration of a particular endpoint. - // 1) Valid only in OPENED state. - // 2) Only configuration for the "Application Service" can be changed. - - Signal::errorcode code = Signal::errorcode::SUCCESS; - uint8_t failedCategory = 0; - - uint8_t seid = 0; - - Payload config; - - signal.InspectPayload([&](const Payload& payload) { - if (payload.Available() >= 2) { - payload.Pop(seid); - seid >>= 2; - - // The rest is the raw config data. - payload.PopAssign(config, payload.Available()); - } - else { - code = Signal::errorcode::BAD_LENGTH; - } - }); - - if (code == Signal::errorcode::SUCCESS) { - code = Signal::errorcode::BAD_ACP_SEID; - - Visit(seid, [&](StreamEndPoint& ep) { - code = DeserializeConfig(config, ep, failedCategory, [](const StreamEndPoint::Service::categorytype category) { - if (StreamEndPoint::Service::IsValidCategory(category) == false) { - return (Signal::errorcode::BAD_SERV_CATEGORY); - } - else if (StreamEndPoint::Service::IsApplicationCategory(category) == false) { - return (Signal::errorcode::INVALID_CAPABILITIES); - } - else { - return (Signal::errorcode::SUCCESS); - } - }); - - if (code == Signal::errorcode::SUCCESS) { - code = ToSignalCode(ep.OnReconfigure(failedCategory)); - } - }); - } - - Reply(code, failedCategory); - } - - void Server::OnOpen(const uint8_t seid, const Handler& Reply) - { - // Requests the endpoint state change from CONFIGURED to OPENED. - // Once opened the initiator can establish a transport connection. - - Signal::errorcode code = Signal::errorcode::BAD_ACP_SEID; - - Visit(seid, [&](StreamEndPoint& ep) { - code = ToSignalCode(ep.OnOpen()); - }); - - Reply(code); - } - - void Server::OnClose(const uint8_t seid, const Handler& Reply) - { - // Requests the endpoint state change to OPENED to CONFIGURED. - - Signal::errorcode code = Signal::errorcode::BAD_ACP_SEID; - - Visit(seid, [&](StreamEndPoint& ep) { - code = ToSignalCode(ep.OnClose()); - }); - - Reply(code); - } - - void Server::OnStart(const uint8_t seid, const Handler& Reply) - { - // Requests the endpoint state change from OPENED to STARTED. - - Signal::errorcode code = Signal::errorcode::BAD_ACP_SEID; - - Visit(seid, [&](StreamEndPoint& ep) { - code = ToSignalCode(ep.OnStart()); - }); - - Reply(code, seid); - } - - void Server::OnSuspend(const uint8_t seid, const Handler& Reply) - { - // Requests the endpoint state change form STARTED to OPENED. - - Signal::errorcode code = Signal::errorcode::BAD_ACP_SEID; - - Visit(seid, [&](StreamEndPoint& ep) { - code = ToSignalCode(ep.OnSuspend()); - }); - - Reply(code, seid); - } - - void Server::OnAbort(const uint8_t seid, const Handler& Reply) - { - // Requests the endpoint state change to IDLE. - - Signal::errorcode code = Signal::errorcode::BAD_ACP_SEID; - - Visit(seid, [&](StreamEndPoint& ep) { - code = ToSignalCode(ep.OnAbort()); - }); - - Reply(code); - } - - /* private */ - Signal::errorcode Server::DeserializeConfig(const Payload& config, StreamEndPoint& ep, uint8_t& invalidCategory, - const std::function& Verify) - { - // Helper method to deserialize configuration. - // Used by SetConfigure and Reconfigure, but they accept different subset of categories. - - Signal::errorcode code = Signal::errorcode::SUCCESS; - - while (config.Available() >= 2) { - StreamEndPoint::Service::categorytype category{}; - config.Pop(category); - - code = Verify(category); - - if (code != Signal::errorcode::SUCCESS) { - TRACE_L1("Invalid category!"); - invalidCategory = category; - } - else { - Buffer buffer; - uint8_t length{}; - - config.Pop(length); - - if (length > 0) { - config.Pop(buffer, length); - } - - ep.Add(category, std::move(buffer)); - } - } - - if (config.Available() != 0) { - TRACE_L1("Unexpected data in payload!"); - code = Signal::errorcode::BAD_LENGTH; - } - - return (code); - } - -} // namespace AVDTP - -} // namespace Bluetooth - -} diff --git a/Source/bluetooth/audio/AVDTPProfile.h b/Source/bluetooth/audio/AVDTPProfile.h deleted file mode 100644 index 83e66d1..0000000 --- a/Source/bluetooth/audio/AVDTPProfile.h +++ /dev/null @@ -1,529 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2021 Metrological - * - * 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. - */ - -#pragma once - -#include "Module.h" -#include "AVDTPSocket.h" - -namespace Thunder { - -namespace Bluetooth { - -namespace AVDTP { - - class Server; - class Client; - - class EXTERNAL StreamEndPointData { - public: - class EXTERNAL Service { - public: - enum categorytype : uint8_t { - INVALID = 0, - - MEDIA_TRANSPORT = 0x01, - REPORTING = 0x02, - RECOVERY = 0x03, - CONTENT_PROTECTION = 0x04, - HEADER_COMPRESSION = 0x05, - MULTIPLEXING = 0x06, - MEDIA_CODEC = 0x07, - DELAY_REPORTING = 0x08, - }; - - public: - template - Service(const categorytype category, T&& params) - : _category(category) - , _params(std::forward(params)) - { - if ((category > DELAY_REPORTING) || (category == INVALID)) { - TRACE_L1("Invalid category %d", category); - } - } - ~Service() = default; - - public: - categorytype Category() const { - return (_category); - } - const Buffer& Params() const { - return (_params); - } - - public: - static constexpr bool IsValidCategory(const categorytype category) { - return ((category != INVALID) && (category <= DELAY_REPORTING)); - } - static constexpr bool IsBasicCategory(const categorytype category) { - // which are basic capabilities? - return ((category != INVALID) && (category < DELAY_REPORTING)); - } - static constexpr bool IsApplicationCategory(const categorytype category) { - // which are Application Service capabilities? - return ((category == MEDIA_CODEC) || (category == CONTENT_PROTECTION) || (category == DELAY_REPORTING)); - } - static constexpr bool IsTransportCategory(const categorytype category) { - // which are Transport Service capabilities? - return ((category == MEDIA_TRANSPORT) || (category == REPORTING) || (category == RECOVERY) - || (category == HEADER_COMPRESSION) || (category == MULTIPLEXING)); - } - - public: -#ifdef __DEBUG__ - string AsString() const - { - static const char *categoryLabels[] = { - "INVALID", "MEDIA_TRANSPORT", "REPORTINGS", "RECOVERY", - "CONTENT_PROTECTION", "HEADER_COMPRESSION", "MULTIPLEXING", "MEDIA_CODEC", - "DELAY_REPORTING" - }; - - return (Core::Format(_T("%02x '%s' with %d bytes <%s>)"), - _category, categoryLabels[static_cast(_category)], Params().size(), Params().ToString().c_str())); - } -#endif // __DEBUG__ - - private: - const categorytype _category; - const Buffer _params; - }; // class Service - - public: - enum septype : uint8_t { - SOURCE = 0x00, - SINK = 0x01, - }; - - enum mediatype : uint8_t { - AUDIO = 0x00, - VIDEO = 0x01, - MULTIMEDIA = 0x02 - }; - - enum statetype : uint8_t { - IDLE, - CONFIGURED, - OPENED, - STARTED, - CLOSING, - ABORTING - }; - - public: - StreamEndPointData() = delete; - StreamEndPointData(const StreamEndPointData&) = delete; - StreamEndPointData& operator=(const StreamEndPointData&) = delete; - virtual ~StreamEndPointData() = default; - - StreamEndPointData(const uint8_t id, const septype service, const mediatype media, - const std::function& fillerCb = nullptr) - : _id(id) - , _remoteId(0) - , _state(IDLE) - , _type(service) - , _mediaType(media) - , _capabilities() - , _configuration() - { - ASSERT(id != 0); - - if (fillerCb != nullptr) { - fillerCb(*this); - } - } - StreamEndPointData(StreamEndPointData&& other) - : _id(other._id) - , _remoteId(other._remoteId) - , _state(other._state) - , _type(other._type) - , _mediaType(other._mediaType) - , _capabilities(std::move(other._capabilities)) - , _configuration(std::move(other._configuration)) - { - } - StreamEndPointData(const uint8_t data[2]) - : _id(0) - , _remoteId(0) - , _state(IDLE) - , _type() - , _mediaType() - , _capabilities() - , _configuration() - { - Deserialize(data); - } - - public: - using ServiceMap = std::map; - - public: - uint32_t Id() const { - return (_id); - } - uint32_t RemoteId() const { - return (_remoteId); - } - septype Type() const { - return (_type); - } - mediatype MediaType() const { - return (_mediaType); - } - bool IsFree() const { - return (_state == IDLE); - } - statetype State() const { - return (_state); - } - const ServiceMap& Capabilities() const { - return (_capabilities); - } - ServiceMap& Capabilities() { - return (_capabilities); - } - const ServiceMap& Configuration() const { - return (_configuration); - } - ServiceMap& Configuration() { - return (_configuration); - } - - public: - struct capability_t { explicit capability_t() = default; }; - static constexpr capability_t capability = capability_t{}; // tag for selecting a proper overload - - void Add(capability_t, const Service::categorytype category) - { - _capabilities.emplace(std::piecewise_construct, - std::forward_as_tuple(category), - std::forward_as_tuple(category, Buffer())); - } - void Add(const Service::categorytype category) - { - _configuration.emplace(std::piecewise_construct, - std::forward_as_tuple(category), - std::forward_as_tuple(category, Buffer())); - } - - template - void Add(capability_t, const Service::categorytype category, T&& buffer) - { - _capabilities.emplace(std::piecewise_construct, - std::forward_as_tuple(category), - std::forward_as_tuple(category, std::forward(buffer))); - } - template - void Add(const Service::categorytype category, T&& buffer) - { - _configuration.emplace(std::piecewise_construct, - std::forward_as_tuple(category), - std::forward_as_tuple(category, std::forward(buffer))); - } - void RemoteId(const uint8_t id) - { - _remoteId = id; - } - - public: - void Serialize(Payload& payload) const - { - uint8_t octet; - octet = ((Id() << 2) | ((!IsFree()) << 1)); - payload.Push(octet); - - octet = ((_mediaType << 4) | (_type << 3)); - payload.Push(octet); - } - -#ifdef __DEBUG__ - string AsString() const - { - static const char *sepTypeLabel[] = { - "Source", "Sink" - }; - - static const char *mediaTypeLabel[] = { - "Audio", "Video", "Multimedia" - }; - - ASSERT(_type <= 1); - ASSERT(_mediaType <= 2); - - return (Core::Format(_T("Stream Endpoint SEID %02x; '%s %s' (%s)"), - Id(), mediaTypeLabel[MediaType()], sepTypeLabel[Type()], (IsFree()? "free" : "in-use"))); - } -#endif // __DEBUG__ - - protected: - statetype State(const statetype newState) - { - const statetype old = _state; - - _state = newState; - - return (old); - } - - private: - void Deserialize(const uint8_t data[2]) - { - _id = (data[0] >> 2); - _mediaType = static_cast(data[1] >> 4); - _type = static_cast(!!(data[1] & 0x08)); - _state = ((data[0] & 0x02) != 0? OPENED : IDLE); - _capabilities.clear(); - _configuration.clear(); - } - - private: - uint8_t _id; - uint8_t _remoteId; - statetype _state; - septype _type; - mediatype _mediaType; - ServiceMap _capabilities; - ServiceMap _configuration; - }; // class StreamEndPointData - - struct EXTERNAL IStreamEndPointControl { - virtual ~IStreamEndPointControl() { } - - virtual uint32_t OnSetConfiguration(uint8_t& outFailedCategory, Socket* channel) = 0; - virtual uint32_t OnReconfigure(uint8_t& outFailedCategory) = 0; - virtual uint32_t OnStart() = 0; - virtual uint32_t OnSuspend() = 0; - virtual uint32_t OnOpen() = 0; - virtual uint32_t OnClose() = 0; - virtual uint32_t OnAbort() = 0; - virtual uint32_t OnSecurityControl() = 0; - }; - - class EXTERNAL StreamEndPoint : public StreamEndPointData, - public IStreamEndPointControl { - public: - StreamEndPoint() = delete; - StreamEndPoint(const StreamEndPoint&) = delete; - StreamEndPoint& operator=(const StreamEndPoint&) = delete; - ~StreamEndPoint() override = default; - - StreamEndPoint(const uint8_t id, const septype service, const mediatype media, - const std::function& fillerCb = nullptr) - : StreamEndPointData(id, service, media, fillerCb) - { - } - }; - - class EXTERNAL Client { - public: - Client(const Client&) = delete; - Client& operator=(const Client&) = delete; - ~Client() = default; - - explicit Client(Socket* socket) - : _socket(socket) - , _command(*this) - { - } - - public: - Socket* Channel() { - return (_socket); - } - const Socket* Channel() const { - return (_socket); - } - - public: - void Channel(Socket* socket) - { - _socket = socket; - } - - public: - uint32_t Discover(const std::function& reportCb) const; - - uint32_t SetConfiguration(StreamEndPoint& ep, const uint8_t remoteId); - - uint32_t GetConfiguration(const uint8_t remoteId, const std::function& reportCb) const; - - uint32_t Start(StreamEndPoint& ep) - { - ASSERT(ep.RemoteId() != 0); - - _command.Set(Signal::AVDTP_START, ep.RemoteId()); - - return (Execute(_command)); - } - uint32_t Suspend(StreamEndPoint& ep) - { - ASSERT(ep.RemoteId() != 0); - - _command.Set(Signal::AVDTP_SUSPEND, ep.RemoteId()); - - return (Execute(_command)); - } - uint32_t Open(StreamEndPoint& ep) - { - ASSERT(ep.RemoteId() != 0); - - _command.Set(Signal::AVDTP_OPEN, ep.RemoteId()); - - return (Execute(_command)); - } - uint32_t Close(StreamEndPoint& ep) - { - ASSERT(ep.RemoteId() != 0); - - _command.Set(Signal::AVDTP_CLOSE, ep.RemoteId()); - - const uint32_t result = Execute(_command); - - return (result); - } - uint32_t Abort(StreamEndPoint& ep) - { - ASSERT(ep.RemoteId() != 0); - - _command.Set(Signal::AVDTP_ABORT, ep.RemoteId()); - - const uint32_t result = Execute(_command); - - return (result); - } - - private: - uint32_t Execute(Socket::CommandType& cmd, const Payload::Inspector& inspectorCb = nullptr) const; - - private: - Socket* _socket; - mutable AVDTP::Socket::CommandType _command; - }; // class Client - - class EXTERNAL Server { - using Handler = Socket::ResponseHandler; - - public: - Server() = default; - Server(const Server&) = delete; - Server& operator=(const Server&) = delete; - virtual ~Server() = default; - - public: - virtual bool Visit(const uint8_t id, const std::function& inspectCb) = 0; - - public: - void OnSignal(const Signal& signal, const Handler& handler) - { - switch (signal.Id()) { - case Signal::AVDTP_DISCOVER: - OnDiscover(handler); - break; - case Signal::AVDTP_GET_CAPABILITIES: - OnGetCapabilities(SEID(signal), handler); - break; - break; - case Signal::AVDTP_GET_ALL_CAPABILITIES: - OnGetAllCapabilities(SEID(signal), handler); - break; - case Signal::AVDTP_SET_CONFIGURATION: - OnSetConfiguration(signal, handler); - break; - case Signal::AVDTP_OPEN: - OnOpen(SEID(signal), handler); - break; - case Signal::AVDTP_CLOSE: - OnClose(SEID(signal), handler); - break; - case Signal::AVDTP_START: - OnStart(SEID(signal), handler); - break; - case Signal::AVDTP_SUSPEND: - OnSuspend(SEID(signal), handler); - break; - case Signal::AVDTP_ABORT: - OnAbort(SEID(signal), handler); - break; - default: - TRACE_L1("Usupported signal %d", signal.Id()); - handler(Signal::errorcode::NOT_SUPPORTED_COMMAND); - break; - } - } - - private: - void OnDiscover(const Handler&); - void OnGetCapabilities(const uint8_t seid, const Handler& handler); - void OnGetAllCapabilities(const uint8_t seid, const Handler& handler); - void OnSetConfiguration(const Signal& signal, const Handler& handler); - void OnReconfigure(const Signal& signal, const Handler& handler); - void OnOpen(const uint8_t seid, const Handler& handler); - void OnClose(const uint8_t seid, const Handler& handler); - void OnStart(const uint8_t seid, const Handler& handler); - void OnSuspend(const uint8_t seid, const Handler& handler); - void OnAbort(const uint8_t seid, const Handler& handler); - - private: - uint8_t SEID(const Signal& signal) const - { - uint8_t seid = 0; - - signal.InspectPayload([&seid](const Payload& payload) { - if (payload.Available() >= 1) { - payload.Pop(seid); - seid >>= 2; - } - }); - - return (seid); - } - Signal::errorcode ToSignalCode(const uint32_t result) - { - switch (result) - { - case Core::ERROR_NONE: - return (Signal::errorcode::SUCCESS); - case Core::ERROR_UNAVAILABLE: - return (Signal::errorcode::NOT_SUPPORTED_COMMAND); - case Core::ERROR_ALREADY_CONNECTED: - return (Signal::errorcode::SEP_IN_USE); - case Core::ERROR_ALREADY_RELEASED: - return (Signal::errorcode::SEP_NOT_IN_USE); - case Core::ERROR_BAD_REQUEST: - return (Signal::errorcode::UNSUPPORTED_CONFIGURATION); - case Core::ERROR_ILLEGAL_STATE: - return (Signal::errorcode::BAD_STATE); - default: - ASSERT(!"Undefined error"); - return (Signal::errorcode::BAD_STATE); - } - } - - private: - Signal::errorcode DeserializeConfig(const Payload& config, StreamEndPoint& ep, uint8_t& invalidCategory, - const std::function& verifyFn); - - }; // class Server - -} // namespace AVDTP - -} // namespace Bluetooth - -} \ No newline at end of file diff --git a/Source/bluetooth/audio/AVDTPSocket.cpp b/Source/bluetooth/audio/AVDTPSocket.cpp deleted file mode 100644 index 2335b93..0000000 --- a/Source/bluetooth/audio/AVDTPSocket.cpp +++ /dev/null @@ -1,195 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2021 Metrological - * - * 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. - */ - -#include "Module.h" -#include "AVDTPSocket.h" - -namespace Thunder { - -namespace Bluetooth { - -namespace AVDTP { - - uint16_t Signal::Serialize(uint8_t stream[], const uint16_t length) const - { - ASSERT(stream != nullptr); - - constexpr uint8_t HeaderSizeSingle = 2; - constexpr uint8_t HeaderSizeStart = 3; - constexpr uint8_t HeaderSizeContinue = 1; - - DataRecord msg(stream, length, 0); - packettype pktType{}; - - if (_payload.Length() + HeaderSizeSingle <= length) { - - if (_processedPackets == 0) { - ASSERT(_expectedPackets == 0); - - pktType = packettype::SINGLE; - _expectedPackets = 1; - } - } - else { - // Have to fragment the signal... - if (_processedPackets == 0) { - ASSERT(_expectedPackets == 0); - - _expectedPackets = ((_payload.Length() + HeaderSizeStart + (length - HeaderSizeContinue) - 1) / (length - HeaderSizeContinue)); - pktType = packettype::START; - } - else if (_processedPackets == (_expectedPackets - 1)) { - pktType = packettype::END; - } - else { - pktType = packettype::CONTINUE; - } - } - - if (_processedPackets != _expectedPackets) { - - if (_processedPackets == 0) { - TRACE_L1("AVDTP: sending %s", AsString().c_str()); - } - - msg.Push(static_cast((_label << 4) | (static_cast(pktType) << 2) | static_cast(_type))); - - if (pktType == packettype::START) { - msg.Push(_expectedPackets); - } - - if ((pktType == packettype::START) || (pktType == packettype::SINGLE)) { - msg.Push(static_cast(_id & 0x3F)); - } - - const uint16_t payloadSize = std::min((length - msg.Length()), (_payload.Length() - _offset)); - - if (payloadSize != 0) { - Payload payload((_payload.Data() + _offset), payloadSize); - msg.Push(payload); - } - - _processedPackets++; - } - - return (msg.Length()); - } - - uint16_t Signal::Deserialize(const uint8_t stream[], const uint16_t length) - { - ASSERT(stream != nullptr); - - bool truncated = false; - packettype pktType{}; - DataRecord msg(stream, length); - - if (msg.Available() >= 1) { - uint8_t octet; - msg.Pop(octet); - - pktType = static_cast((octet >> 2) & 0x3); - - if ((pktType == packettype::START) || (pktType == packettype::SINGLE)) { - _expectedPackets = 1; - _label = (octet >> 4); - _type = static_cast(octet & 0x3); - } - } - else { - truncated = true; - } - - if ((truncated == false) && (pktType == packettype::START)) { - if (msg.Available() >= 1) { - msg.Pop(_expectedPackets); - } - else { - truncated = true; - } - } - - if ((truncated == false) && ((pktType == packettype::START) || (pktType == packettype::SINGLE))) { - if (msg.Available() >= 1) { - - uint8_t octet; - msg.Pop(octet); - - _id = static_cast(octet & 0x3F); - } - else { - truncated = true; - } - } - - if (truncated == false) { - if ((_type == messagetype::RESPONSE_ACCEPT) || (_type == messagetype::COMMAND)) { - msg.Pop(_payload, msg.Available()); - _errorCode = errorcode::IN_PROGRESS; - } - } - else { - TRACE_L1("AVDTP: truncated signal data"); - _errorCode = errorcode::GENERAL_ERROR; - } - - _processedPackets++; - - if (IsComplete() == true) { - - if (IsValid() == false) { - TRACE_L1("Broken frame received"); - _errorCode = errorcode::GENERAL_ERROR; - } - else if (_type == messagetype::RESPONSE_ACCEPT) { - _errorCode = errorcode::SUCCESS; - } - else if (_type == messagetype::RESPONSE_REJECT) { - - if ((_id == AVDTP_SET_CONFIGURATION) || (_id == AVDTP_RECONFIGURE) - || (_id == AVDTP_START) || (_id == AVDTP_SUSPEND)) { - - // These signal responses also include the endpoint id that failed - uint8_t octet{}; - msg.Pop(octet); - } - - if (msg.Available() >= sizeof(_errorCode)) { - msg.Pop(_errorCode); - } - else { - TRACE_L1("AVDTP: truncated signal data"); - _errorCode = errorcode::GENERAL_ERROR; - } - } - else { - // GENERIC_REJECT or anything else unexpected - _errorCode = errorcode::GENERAL_ERROR; - } - - TRACE_L1("AVDTP: received %s; result: %d", AsString().c_str(), _errorCode); - } - - return (length); - } - -} // namespace AVDTP - -} // namespace Bluetooth - -} diff --git a/Source/bluetooth/audio/AVDTPSocket.h b/Source/bluetooth/audio/AVDTPSocket.h deleted file mode 100644 index 922c1b6..0000000 --- a/Source/bluetooth/audio/AVDTPSocket.h +++ /dev/null @@ -1,693 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2021 Metrological - * - * 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. - */ - -#pragma once - -#include "Module.h" -#include "DataRecord.h" - -namespace Thunder { - -namespace Bluetooth { - -namespace AVDTP { - - static constexpr uint8_t PSM = 25; - - class EXTERNAL Payload : public DataRecordBE { - public: - using Builder = std::function; - using Inspector = std::function; - - public: - // AVDTP is big-endiand oriented - using DataRecordBE::DataRecordBE; - ~Payload() = default; - }; // class Payload - - class EXTERNAL Signal { - public: - enum signalidentifier : uint8_t { - INVALID = 0x00, - AVDTP_DISCOVER = 0x01, - AVDTP_GET_CAPABILITIES = 0x02, - AVDTP_SET_CONFIGURATION = 0x03, - AVDTP_GET_CONFIGURATION = 0x04, - AVDTP_RECONFIGURE = 0x05, - AVDTP_OPEN = 0x06, - AVDTP_START = 0x07, - AVDTP_CLOSE = 0x08, - AVDTP_SUSPEND = 0x09, - AVDTP_ABORT = 0x0A, - AVDTP_SECURITY_CONTROL = 0x0B, - AVDTP_GET_ALL_CAPABILITIES = 0x0C, - AVDTP_DELAY_REPORT = 0x0D, - END - }; - - enum class errorcode : uint8_t { - SUCCESS = 0x00, - - // Header errors - BAD_HEADER_FORMAT = 0x01, - - // Payload format errors - BAD_LENGTH = 0x11, - BAD_ACP_SEID = 0x12, - SEP_IN_USE = 0x13, - SEP_NOT_IN_USE = 0x14, - BAD_SERV_CATEGORY = 0x17, - BAD_PAYLOAD_FORMAT = 0x18, - NOT_SUPPORTED_COMMAND = 0x19, - INVALID_CAPABILITIES = 0x1A, - - // Transport service errors - BAD_RECOVERY_TYPE = 0x22, - BAD_MEDIA_TRANSPORT_FORMAT = 0x23, - BAD_RECOVERY_FORMAT = 0x25, - BAD_ROHC_FORMAT = 0x26, - BAD_CP_FORMAT = 0x27, - BAD_MULTIPLEXING_FORMAT = 0x28, - UNSUPPORTED_CONFIGURATION = 0x29, - - // Procedure errors - BAD_STATE = 0x31, - - // In-house errors - IN_PROGRESS = 0xFE, - GENERAL_ERROR = 0xFF - }; - - protected: - static constexpr uint8_t INVALID_LABEL = 0xFF; - - enum class messagetype : uint8_t { - COMMAND = 0x00, - GENERAL_REJECT = 0x01, - RESPONSE_ACCEPT = 0x02, - RESPONSE_REJECT = 0x03, - END - }; - - enum class packettype : uint8_t { - SINGLE = 0x00, - START = 0x01, - CONTINUE = 0x02, - END - }; - - public: - Signal(const Signal&) = delete; - Signal& operator=(const Signal&) = delete; - - explicit Signal(const uint16_t bufferSize = 64) - : _buffer(new uint8_t[bufferSize]) - , _payload(_buffer.get(), bufferSize, 0) - , _label(INVALID_LABEL) - , _id(INVALID) - , _type(messagetype::COMMAND) - , _errorCode(errorcode::GENERAL_ERROR) - , _expectedPackets(0) - , _processedPackets(0) - , _offset(0) - { - ASSERT(bufferSize >= 2); - ASSERT(_buffer.get() != nullptr); - } - ~Signal() = default; - - public: - uint8_t Label() const { - return (_label); - } - signalidentifier Id() const { - return (_id); - } - messagetype Type() const { - return (_type); - } - errorcode Error() const { - return (_errorCode); - } - bool IsValid() const { - return ((_label != INVALID_LABEL) && (_id != INVALID) && (_id < signalidentifier::END)); - } - bool IsComplete() const { - return (_expectedPackets == _processedPackets); - } - - public: - void InspectPayload(const Payload::Inspector& inspectCb) const - { - ASSERT(inspectCb != nullptr); - - _payload.Rewind(); - inspectCb(_payload); - } - - public: - void Clear() - { - _label = INVALID_LABEL; - _id = INVALID; - _errorCode = errorcode::GENERAL_ERROR; - _expectedPackets = 0; - _processedPackets = 0; - _payload.Clear(); - } - void Reload() const - { - _expectedPackets = 0; - _processedPackets = 0; - _payload.Rewind(); - } - - uint16_t Serialize(uint8_t stream[], const uint16_t length) const; - uint16_t Deserialize(const uint8_t stream[], const uint16_t length); - - public: - string AsString() const - { -#ifdef __DEBUG__ - // Plain lookup, these tables are unlikely to ever change... - static const char *idLabels[] = { - "INVALID", "AVDTP_DISCOVER", "AVDTP_GET_CAPABILITIES", "AVDTP_SET_CONFIGURATION", - "AVDTP_GET_CONFIGURATION", "AVDTP_RECONFIGURE", "AVDTP_OPEN", "AVDTP_START", - "AVDTP_CLOSE", "AVDTP_SUSPEND", "AVDTP_ABORT", "AVDTP_SECURITY_CONTROL", - "AVDTP_GET_ALL_CAPABILITIES", "AVDTP_DELAY_REPORT" - }; - - static const char *messageTypeLabels[] = { - "COMMAND", "GENERAL_REJECT", "RESPONSE_ACCEPT", "RESPONSE_REJECT" - }; - - ASSERT(_id < signalidentifier::END); - ASSERT(_type <= messagetype::END); - - return Core::Format("signal #%d %s '%s' (%d bytes, %d packets)", - _label, messageTypeLabels[static_cast(_type)], - idLabels[static_cast(_id)], - _payload.Length(), _expectedPackets); -#else - return (Core::Format("signal #%d type %d id %d", _label, static_cast(_type), static_cast(_id))); -#endif - } - - protected: - void Set(const uint8_t label, const signalidentifier identifier, const messagetype type) - { - _label = label; - _id = identifier; - _type = type; - _offset = 0; - _expectedPackets = 0; - _processedPackets = 0; - _errorCode = errorcode::IN_PROGRESS; - _payload.Clear(); - } - void Set(const uint8_t label, const signalidentifier identifier, const messagetype type, const Payload::Builder& buildCb) - { - Set(label, identifier, type); - - if (buildCb != nullptr) { - buildCb(_payload); - } - } - - private: - std::unique_ptr _buffer; - Payload _payload; - uint8_t _label; - signalidentifier _id; - messagetype _type; - errorcode _errorCode; - mutable uint8_t _expectedPackets; - mutable uint8_t _processedPackets; - uint16_t _offset; - }; // class Signal - - class EXTERNAL Socket : public Core::SynchronousChannelType - , private Core::IOutbound::ICallback - , private Core::WorkerPool::JobType { - - friend class Core::ThreadPool::JobType; - - public: - static constexpr uint32_t CommunicationTimeout = 1000; /* ms */ - - public: - enum channeltype { - SIGNALLING, - TRANSPORT, - REPORTING, - RECOVERY, - }; - - public: - class EXTERNAL ResponseHandler { - public: - ResponseHandler(const ResponseHandler&) = default; - ResponseHandler& operator=(const ResponseHandler&) = default; - ~ResponseHandler() = default; - - ResponseHandler(Socket& channel, - const std::function& acceptor, - const std::function& rejector) - : _channel(channel) - , _acceptor(acceptor) - , _rejector(rejector) - { - } - - public: - void operator ()(const Payload::Builder& buildCb = nullptr) const - { - _acceptor(buildCb); - } - void operator ()(const Signal::errorcode result = Signal::errorcode::SUCCESS, const uint8_t data = 0) const - { - if (result == Signal::errorcode::SUCCESS) { - _acceptor(nullptr); - } - else { - _rejector(result, data); - } - } - - public: - Socket& Channel() const { - return (_channel); - } - - private: - Socket& _channel; - std::function _acceptor; - std::function _rejector; - }; // class ResponseHandler - - public: - template - class EXTERNAL CommandType : public Core::IOutbound, public Core::IInbound { - public: - class EXTERNAL Request : public Signal { - public: - Request(const Request&) = delete; - Request& operator=(const Request&) = delete; - Request() - : Signal() - , _counter(0xF) - { - } - ~Request() = default; - - public: - using Signal::Set; - - void Set(const signalidentifier signal) - { - Set(Counter(), signal, messagetype::COMMAND); - } - void Set(const signalidentifier signal, const uint8_t acpSeid) - { - ASSERT((acpSeid > 0) && (acpSeid < 0x3F)); - - Set(Counter(), signal, messagetype::COMMAND, [&](Payload& payload) { - - payload.Push(static_cast(acpSeid << 2)); - }); - } - void Set(const signalidentifier signal, const uint8_t acpSeid, const Payload::Builder& buildCb) - { - ASSERT((acpSeid > 0) && (acpSeid < 0x3F)); - - Set(Counter(), signal, messagetype::COMMAND, [&](Payload& payload) { - - payload.Push(static_cast(acpSeid << 2)); - - buildCb(payload); - }); - } - void Set(const signalidentifier signal, const uint8_t acpSeid, const uint8_t intSeid, const Payload::Builder& buildCb) - { - ASSERT((acpSeid > 0) && (acpSeid < 0x3F)); - ASSERT((intSeid > 0) && (intSeid < 0x3F)); - - Set(Counter(), signal, messagetype::COMMAND, [&](Payload& payload) { - - payload.Push(static_cast(acpSeid << 2)); - payload.Push(static_cast(intSeid << 2)); - - buildCb(payload); - }); - } - - private: - uint8_t Counter() const - { - _counter = ((_counter + 1) & 0xF); - return (_counter); - } - - private: - mutable uint8_t _counter; - }; // class Request - - public: - class EXTERNAL Response : public Signal { - public: - Response(const Response&) = delete; - Response& operator=(const Response&) = delete; - Response() - : Signal() - { - } - ~Response() = default; - }; // class Response - - public: - CommandType(const CommandType&) = delete; - CommandType& operator=(const CommandType&) = delete; - CommandType(ADMIN& admin) - : _admin(admin) - , _request() - , _response() - { - } - ~CommandType() = default; - - public: - template - void Set(const Signal::signalidentifier signal, Args&&... args) - { - _status = ~0; - _response.Clear(); - _request.Set(signal, std::forward(args)...); - } - - public: - Request& Call() { - return (_request); - } - const Request& Call() const { - return (_request); - } - Response& Result() { - return (_response); - } - const Response& Result() const { - return (_response); - } - bool IsAccepted() const { - return (Result().Error() == Signal::errorcode::SUCCESS); - } - bool IsValid() const { - return (_request.IsValid()); - } - - private: - void Reload() const override - { - _request.Reload(); - } - uint16_t Serialize(uint8_t stream[], const uint16_t length) const override - { - Socket* channel = _admin.Channel(); - ASSERT(channel != nullptr); - - const uint16_t result = _request.Serialize(stream, std::min(channel->OutputMTU(), length)); - - CMD_DUMP("AVTDP client sent", stream, result); - - return (result); - } - uint16_t Deserialize(const uint8_t stream[], const uint16_t length) override - { - CMD_DUMP("AVTDP client received", stream, length); - - return (_response.Deserialize(stream, length)); - } - Core::IInbound::state IsCompleted() const override - { - return (_response.IsComplete() == true? Core::IInbound::COMPLETED : Core::IInbound::INPROGRESS); - } - - private: - ADMIN& _admin; - uint32_t _status; - Request _request; - Response _response; - }; // class Command - - public: - Socket(const Socket&) = delete; - Socket& operator=(const Socket&) = delete; - - Socket(const Core::NodeId& localNode, const Core::NodeId& remoteNode) - : Core::SynchronousChannelType(SocketPort::SEQUENCED, localNode, remoteNode, 2048, 2048) - , Core::IOutbound::ICallback() - , Core::WorkerPool::JobType(*this) - , _adminLock() - , _request() - , _response(*this) - , _omtu(0) - , _type(SIGNALLING) - , _sync(true, true) - { - } - Socket(const SOCKET& connector, const Core::NodeId& remoteNode) - : Core::SynchronousChannelType(SocketPort::SEQUENCED, connector, remoteNode, 2048, 2048) - , Core::IOutbound::ICallback() - , Core::WorkerPool::JobType(*this) - , _adminLock() - , _request() - , _response(*this) - , _omtu(0) - , _type(SIGNALLING) - , _sync(true, true) - { - } - ~Socket() = default; - - public: - uint16_t OutputMTU() const { - return (_omtu); - } - channeltype Type() const { - return (_type); - } - - public: - void Type(const channeltype type) - { - _type = type; - -#ifdef __DEBUG__ - VARIABLE_IS_NOT_USED static const char* labels[] = { "signalling", "transport", "reporting", "recovery" }; - ASSERT(type < RECOVERY); - TRACE_L1("AVDTP: Changed channel type to: %s", labels[type]); -#endif - } - - protected: - virtual void OnSignal(const Signal& request VARIABLE_IS_NOT_USED, const ResponseHandler& handler VARIABLE_IS_NOT_USED) - { - TRACE_L1("AVDTP: Unhandled incoming signal %d", request.Id()); - } - virtual void OnPacket(const uint8_t stream[] VARIABLE_IS_NOT_USED, const uint16_t length VARIABLE_IS_NOT_USED) - { - TRACE_L1("AVDTP:: Unhandled incoming audio packet (%d bytes)", length); - } - - private: - class EXTERNAL Request : public Signal { - public: - Request(const Request&) = delete; - Request& operator=(const Request&) = delete; - Request() - : Signal() - { - } - ~Request() = default; - }; - - private: - class EXTERNAL Response : public Signal, public Core::IOutbound { - public: - Response(const Response&) = delete; - Response& operator=(const Response&) = delete; - Response(Socket& socket) - : Signal() - , _socket(socket) - { - } - ~Response() = default; - - public: - void Reload() const override - { - Signal::Reload(); - } - uint16_t Serialize(uint8_t stream[], const uint16_t length) const override - { - const uint16_t result = Signal::Serialize(stream, std::min(_socket.OutputMTU(), length)); - - CMD_DUMP("AVTDP server sent", stream, result); - - return (result); - } - - public: - void Accept(const uint8_t label, const signalidentifier identifier, const Payload::Builder& buildCb = nullptr) - { - Set(label, identifier, messagetype::RESPONSE_ACCEPT, buildCb); - } - - public: - void Reject(const uint8_t label, const signalidentifier identifier) - { - Set(label, identifier, messagetype::GENERAL_REJECT); - } - void Reject(const uint8_t label, const signalidentifier identifier, const errorcode code, const uint8_t data = 0) - { - ASSERT(code != Signal::errorcode::SUCCESS); - - if ((identifier == AVDTP_SET_CONFIGURATION) || (identifier == AVDTP_RECONFIGURE) - || (identifier == AVDTP_START) || (identifier == AVDTP_SUSPEND)) { - - Set(label, identifier, messagetype::RESPONSE_REJECT, [&](Payload& buffer) { - // Data may be zero if it doesn't fit the error code. - buffer.Push(data); - buffer.Push(code); - }); - } - else { - Set(label, identifier, messagetype::RESPONSE_REJECT, [&](Payload& buffer) { - buffer.Push(code); - }); - } - } - - private: - Socket& _socket; - }; - - private: - virtual void Operational(const bool upAndRunning) = 0; - - void StateChange() override - { - Core::SynchronousChannelType::StateChange(); - - if (IsOpen() == true) { - struct l2cap_options options{}; - socklen_t len = sizeof(options); - - ::getsockopt(Handle(), SOL_L2CAP, L2CAP_OPTIONS, &options, &len); - - ASSERT(options.omtu <= SendBufferSize()); - ASSERT(options.imtu <= ReceiveBufferSize()); - - _omtu = options.omtu; - - TRACE(Trace::Information, (_T("AVDTP channel input MTU: %d, output MTU: %d"), options.imtu, options.omtu)); - - Operational(true); - } - else { - Operational(false); - } - } - - private: - uint16_t Deserialize(const uint8_t stream[], const uint16_t length) override - { - uint16_t result = 0; - - if (_type == SIGNALLING) { - // This is an AVDTP request from a client. - CMD_DUMP("AVDTP server received", stream, length); - - _sync.Lock(); - _sync.ResetEvent(); - - result = _request.Deserialize(stream, length); - - if (_request.IsComplete() == true) { - JobType::Submit(); - } - } - else if (_type == TRANSPORT) { - OnPacket(stream, length); - result = length; - } - else { - ASSERT(!"Invalid socket type"); - } - - return (result); - } - - private: - void Dispatch() - { - if (_request.IsValid() == true) { - OnSignal(_request, ResponseHandler(*this, - [&](const Payload::Builder& buildCb) { - TRACE_L1("AVDTP: accepting %s", _request.AsString().c_str()); - _response.Accept(_request.Label(), _request.Id(), buildCb); - }, - [&](const Signal::errorcode result, const uint8_t data) { - TRACE_L1("AVDTP: rejecting %s, reason: %d, data 0x%02x", _request.AsString().c_str(), result, data); - _response.Reject(_request.Label(), _request.Id(), result, data); - })); - } - else { - // Totally no clue what this signal is, reply with general reject. - TRACE_L1("AVDTP: unknown signal received [%02x]", _request.Id()); - _response.Reject(_request.Label(), _request.Id()); - } - - // Clear for next request. - _request.Clear(); - - Send(CommunicationTimeout, _response, this, nullptr); - } - - private: - // IOutbound::ICallback overrides - void Updated(const Core::IOutbound& data VARIABLE_IS_NOT_USED, const uint32_t error_code VARIABLE_IS_NOT_USED) override - { - _sync.SetEvent(); - } - - private: - Core::CriticalSection _adminLock; - Request _request; - Response _response; - uint16_t _omtu; - channeltype _type; - Core::Event _sync; - }; // class Socket - -} // namespace AVDTP - -} // namespace Bluetooth - -} - diff --git a/Source/bluetooth/audio/CMakeLists.txt b/Source/bluetooth/audio/CMakeLists.txt deleted file mode 100644 index d948d64..0000000 --- a/Source/bluetooth/audio/CMakeLists.txt +++ /dev/null @@ -1,128 +0,0 @@ -# If not stated otherwise in this file or this component's license file the -# following copyright and licenses apply: -# -# Copyright 2023 Metrological -# -# 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. - -cmake_minimum_required(VERSION 3.15) - -find_package(Thunder) -find_package(${NAMESPACE}Core REQUIRED) -find_package(${NAMESPACE}Messaging REQUIRED) -find_package(CompileSettingsDebug CONFIG REQUIRED) - -project(${NAMESPACE}BluetoothAudio - VERSION 1.0.0 - DESCRIPTION "Bluetooth audio library" - LANGUAGES CXX) - -set(TARGET ${PROJECT_NAME}) -message("Setup ${TARGET} v${PROJECT_VERSION}") - -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") - -find_package(SBC REQUIRED) - -file(GLOB CODEC_HEADERS codecs/*.h) - -set(PUBLIC_HEADERS - IAudioCodec.h - IAudioContentProtection.h - SDPSocket.h - SDPProfile.h - AVDTPSocket.h - AVDTPProfile.h - RTPSocket.h - DataRecord.h - Module.h - bluetooth_audio.h -) - -add_library(${TARGET} - SDPSocket.cpp - SDPProfile.cpp - AVDTPSocket.cpp - AVDTPProfile.cpp - codecs/SBC.cpp - Module.cpp -) - -target_link_libraries(${TARGET} - PRIVATE - CompileSettingsDebug::CompileSettingsDebug - ${NAMESPACE}Core::${NAMESPACE}Core - ${NAMESPACE}Messaging::${NAMESPACE}Messaging - SBC::SBC -) - -set_target_properties(${TARGET} - PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES - FRAMEWORK FALSE - PUBLIC_HEADER "${PUBLIC_HEADERS}" # specify the public headers - VERSION ${PROJECT_VERSION} - SOVERSION ${PROJECT_VERSION_MAJOR} -) - -target_include_directories(${TARGET} - PUBLIC - $ - $ - $ - PRIVATE - "${CMAKE_CURRENT_SOURCE_DIR}/drivers" -) - -target_compile_options(${TARGET} - PRIVATE - -Wno-psabi - -fdiagnostics-color=always -) - -# -# From Bluez >= v5.64 the mgmt_ltk_info struct is changed due to inclusive language changes. -# https://github.com/bluez/bluez/commit/b7d6a7d25628e9b521a29a5c133fcadcedeb2102 -# -include(CheckStructHasMember) -check_struct_has_member("struct mgmt_ltk_info" central "../include/bluetooth/bluetooth.h;../include/bluetooth/mgmt.h" NO_INCLUSIVE_LANGUAGE LANGUAGE C) - -if(${NO_INCLUSIVE_LANGUAGE}) - message(VERBOSE "Your version of bluez don't uses inclusive language anymore") - target_compile_definitions(${TARGET} PUBLIC NO_INCLUSIVE_LANGUAGE) -endif() - -install( - TARGETS ${TARGET} EXPORT ${TARGET}Targets - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT ${NAMESPACE}_Development - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT ${NAMESPACE}_Runtime NAMELINK_COMPONENT ${NAMESPACE}_Development - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${NAMESPACE}_Runtime - FRAMEWORK DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${NAMESPACE}_Runtime - PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${NAMESPACE}/bluetooth/audio COMPONENT ${NAMESPACE}_Development - INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${NAMESPACE} -) - -install( - FILES ${CODEC_HEADERS} - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${NAMESPACE}/bluetooth/audio/codecs -) - -InstallPackageConfig( - TARGETS ${TARGET} - DESCRIPTION "${PROJECT_DESCRIPTION}" -) - -InstallCMakeConfig( - TARGETS ${TARGET} -) diff --git a/Source/bluetooth/audio/DataRecord.h b/Source/bluetooth/audio/DataRecord.h deleted file mode 100644 index f1b7434..0000000 --- a/Source/bluetooth/audio/DataRecord.h +++ /dev/null @@ -1,502 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2021 Metrological - * - * 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. - */ - -#pragma once - -#include "Module.h" -#include -#include - - -namespace Thunder { - -namespace Bluetooth { - - class Buffer : public std::basic_string { - public: - using basic_string::basic_string; - - Buffer(const uint16_t size) - : basic_string() - { - resize(size); - } - ~Buffer() = default; - - public: - const string ToString() const - { - string val; - Core::ToHexString(data(), size(), val); - return (val.empty() == true? string(_T("")) : val); - } - }; - - // Byteorder neutral version - class EXTERNAL DataRecord { - public: - DataRecord(const DataRecord& buffer) = delete; - DataRecord& operator=(const DataRecord&) = delete; - - DataRecord() - : _buffer(nullptr) - , _bufferSize(0) - , _filledSize(0) - , _readerOffset(0) - , _writerOffset(0) - { - } - DataRecord(const uint8_t buffer[], const uint16_t bufferSize) - // It is ensured that the buffer will never be written. - : _buffer(const_cast(buffer)) - , _bufferSize(bufferSize) - , _filledSize(bufferSize) - , _readerOffset(0) - , _writerOffset(bufferSize) - { - ASSERT(_buffer != nullptr); - ASSERT(_bufferSize != 0); - ASSERT(_bufferSize >= _filledSize); - } - DataRecord(uint8_t scratchPad[], const uint16_t scratchPadSize, const uint16_t filledSize) - : _buffer(scratchPad) - , _bufferSize(scratchPadSize) - , _filledSize(filledSize) - , _readerOffset(0) - , _writerOffset(filledSize) - { - ASSERT(_buffer != nullptr); - ASSERT(_bufferSize != 0); - ASSERT(_bufferSize >= _filledSize); - } - DataRecord(const Buffer& buffer) - // It is ensured that the buffer will never be written. - : _buffer(const_cast(buffer.data())) - , _bufferSize(buffer.size()) - , _filledSize(buffer.size()) - , _readerOffset(0) - , _writerOffset(buffer.size()) - { - ASSERT(buffer.size() < 0x10000); - ASSERT(_buffer != nullptr); - ASSERT(_bufferSize >= _filledSize); - } - DataRecord(Buffer& scratchPad, const uint16_t filledSize) - : _buffer(const_cast(scratchPad.data())) - , _bufferSize(scratchPad.size()) - , _filledSize(filledSize) - , _readerOffset(0) - , _writerOffset(filledSize) - { - ASSERT(_buffer != nullptr); - ASSERT(_bufferSize != 0); - ASSERT(_bufferSize >= _filledSize); - } - ~DataRecord() = default; - - public: - bool IsEmpty() const { - return (Available() == 0); - } - uint16_t Length() const { - return (_writerOffset); - } - uint16_t Capacity() const { - return (_bufferSize); - } - uint16_t Free() const { - return ((_bufferSize > _writerOffset) && (_buffer != nullptr)? (_bufferSize - _writerOffset) : 0); - } - uint16_t Available() const { - return ((_writerOffset > _readerOffset) && (_buffer != nullptr)? (_writerOffset - _readerOffset) : 0); - } - uint16_t Position() const { - return (_readerOffset); - } - const uint8_t* Data() const { - return (_buffer); - } - - public: - void Assign(uint8_t buffer[], const uint16_t bufferSize) - { - _buffer = buffer; - _bufferSize = bufferSize; - _filledSize = bufferSize; - _writerOffset = bufferSize; - _readerOffset = 0; - } - void Assign(uint8_t scratchPad[], const uint16_t scratchPadSize, const uint16_t filledSize) - { - _buffer = scratchPad; - _bufferSize = scratchPadSize; - _filledSize = filledSize; - _writerOffset = filledSize; - _readerOffset = 0; - } - void Clear() - { - _writerOffset = 0; - _filledSize = 0; - _readerOffset = 0; - } - void Seek(const uint16_t offset = 0) - { - ASSERT(offset < _bufferSize); - _writerOffset = offset; - } - void Advance(const uint16_t length) - { - ASSERT(_writerOffset + length < _bufferSize); - _writerOffset += length; - } - void Rewind(const uint16_t offset = 0) const - { - ASSERT(offset < _bufferSize); - _readerOffset = offset; - } - void Skip(const uint16_t length) const - { - ASSERT(_readerOffset + length < _bufferSize); - _readerOffset += length; - } - const string ToString() const - { - string val; - Core::ToHexString(Data(), Length(), val); - return (val.empty() == true? string(_T("")) : val); - } - void Export(Buffer& output) const - { - output.assign(Data(), Length()); - } - operator Buffer() const - { - if (IsEmpty() == true) { - return (Buffer()); - } else { - return (Buffer(Data(), Length())); - } - } - - public: - void Fill(const uint16_t size, uint8_t value = 0) - { - ::memset(WritePtr(), value, size); - _writerOffset += size; - } - void Push(const bool value) - { - ASSERT(Free() > sizeof(uint8_t)); - Push(static_cast(value)); - } - void Push(const string& value) - { - ASSERT(value.size() < 0x10000); - ASSERT(Free() >= value.size()); - Push(reinterpret_cast(value.data()), static_cast(value.length())); - } - void Push(const Buffer& value) - { - ASSERT(value.size() < 0x10000); - ASSERT(Free() >= value.size()); - Push(value.data(), static_cast(value.length())); - } - void Push(const uint8_t value[], const uint16_t size) - { - ASSERT(Free() >= size); - ::memcpy(WritePtr(), value, size); - _writerOffset += size; - } - void Push(const DataRecord& element) - { - ASSERT(Free() >= element.Length()); - ::memcpy(WritePtr(), element.Data(), element.Length()); - _writerOffset += element.Length(); - } - - public: - template::value, int>::type = 0> - void Push(const TYPE value) - { - static_assert(sizeof(TYPE) == 1, "Only 8-bit integers push supported in DataRecord, choose endian-aware version"); - PushIntegerValue(static_cast::type>(value)); - } - template::value, int>::type = 0> - void Push(const TYPE value) - { - static_assert(sizeof(TYPE) == 1, "Only 8-bit integers push supported in DataRecord, choose endian-aware version"); - Push(static_cast::type>(value)); - } - - public: - void Pop(string& value, const uint16_t length) const - { - if (Available() >= length) { - value.assign(reinterpret_cast(ReadPtr()), length); - _readerOffset += length; - } else { - TRACE_L1("DataRecord: Truncated payload"); - _readerOffset = _writerOffset; - value.clear(); - } - } - void Pop(Buffer& value, const uint16_t length) const - { - if (Available() >= length) { - value.assign(ReadPtr(), length); - _readerOffset += length; - } else { - TRACE_L1("DataRecord: Truncated payload"); - _readerOffset = _writerOffset; - value.clear(); - } - } - void Pop(DataRecord& element, const uint16_t size) const - { - if (Available() >= size) { - element.Push(ReadPtr(), size); - _readerOffset += size; - } else { - TRACE_L1("DataRecord: Truncated payload"); - _readerOffset = _writerOffset; - element.Clear(); - } - } - void PopAssign(DataRecord& element, const uint16_t size) const - { - if (Available() >= size) { - element.Assign(const_cast(ReadPtr()), size); - _readerOffset += size; - } else { - TRACE_L1("DataRecord: Truncated payload"); - _readerOffset = _writerOffset; - element.Clear(); - } - } - - public: - template::value, int>::type = 0> - void Pop(TYPE& value) const - { - static_assert(sizeof(TYPE) == 1, "Only 8-bit integers pop supported in DataRecord, choose endian-aware version"); - typename std::underlying_type::type temp{}; - PopIntegerValue(temp); - value = static_cast(temp); - } - template::value, int>::type = 0> - void Pop(TYPE& value) const - { - static_assert(sizeof(TYPE) == 1, "Only 8-bit integers pop supported in DataRecord, choose endian-aware version"); - PopIntegerValue(value); - } - - protected: - const uint8_t* ReadPtr() const { - return (&_buffer[_readerOffset]); - } - uint8_t* WritePtr() { - return (&_buffer[_writerOffset]); - } - - protected: - void PushIntegerValue(const uint8_t value) - { - ASSERT(Free() >= 1); - _buffer[_writerOffset++] = value; - } - void PopIntegerValue(uint8_t& value) const - { - if (Available() >= 1) { - value = _buffer[_readerOffset++]; - } else { - TRACE_L1("DataRecord: Truncated payload"); - value = 0; - } - } - - protected: - uint8_t* _buffer; - uint16_t _bufferSize; - uint16_t _filledSize; - mutable uint16_t _readerOffset; - uint16_t _writerOffset; - }; // class DataRecord - - // Big-Endian version - class EXTERNAL DataRecordBE : public DataRecord { - public: - using DataRecord::DataRecord; - ~DataRecordBE() = default; - - using DataRecord::Pop; - using DataRecord::Push; - using DataRecord::PopIntegerValue; - using DataRecord::PushIntegerValue; - - public: - template::value, int>::type = 0> - void Push(const TYPE value) - { - static_assert(sizeof(TYPE) <= 4 , "Up to 32-bit integers supported in DataRecordBE"); - PushIntegerValue(static_cast::type>(value)); - } - template::value, int>::type = 0> - void Push(const TYPE value) - { - static_assert(sizeof(TYPE) <= 4, "Up to 32-bit enum push supported in DataRecordBE"); - Push(static_cast::type>(value)); - } - template::value, int>::type = 0> - void Pop(TYPE& value) const - { - static_assert(sizeof(TYPE) <= 4 , "Up to 32-bit integers supported in DataRecordBE"); - PopIntegerValue(value); - } - template::value, int>::type = 0> - void Pop(TYPE& value) const - { - static_assert(sizeof(TYPE) <= 4, "Up to 32-bit enum pop supported in DataRecordBE"); - typename std::underlying_type::type temp{}; - PopIntegerValue(temp); - value = static_cast(temp); - } - - protected: - void PushIntegerValue(const uint16_t value) - { - ASSERT(Free() >= 2); - _buffer[_writerOffset++] = (value >> 8); - _buffer[_writerOffset++] = value; - } - void PushIntegerValue(const uint32_t value) - { - ASSERT(Free() >= 4); - _buffer[_writerOffset++] = (value >> 24); - _buffer[_writerOffset++] = (value >> 16); - _buffer[_writerOffset++] = (value >> 8); - _buffer[_writerOffset++] = value; - } - void PopIntegerValue(uint16_t& value) const - { - if (Available() >= 2) { - value = ((_buffer[_readerOffset] << 8) | _buffer[_readerOffset + 1]); - _readerOffset += 2; - } else { - TRACE_L1("DataRecord: Truncated payload"); - _readerOffset = _writerOffset; - value = 0; - } - } - void PopIntegerValue(uint32_t& value) const - { - if (Available() >= 4) { - value = ((_buffer[_readerOffset] << 24) | (_buffer[_readerOffset + 1] << 16) - | (_buffer[_readerOffset + 2] << 8) | _buffer[_readerOffset + 3]); - _readerOffset += 4; - } else { - TRACE_L1("DataRecord: Truncated payload"); - _readerOffset = _writerOffset; - value = 0; - } - } - }; // class DataRecordLE - - // Little-Endian version - class EXTERNAL DataRecordLE : public DataRecord { - public: - using DataRecord::DataRecord; - ~DataRecordLE() = default; - - using DataRecord::Pop; - using DataRecord::Push; - using DataRecord::PopIntegerValue; - using DataRecord::PushIntegerValue; - - public: - template::value, int>::type = 0> - void Push(const TYPE value) - { - static_assert(sizeof(TYPE) <= 4 , "Up to 32-bit integers supported in DataRecordLE"); - PushIntegerValue(static_cast::type>(value)); - } - template::value, int>::type = 0> - void Push(const TYPE value) - { - static_assert(sizeof(TYPE) <= 4, "Up to 32-bit enum push supported in DataRecordLE"); - Push(static_cast::type>(value)); - } - template::value, int>::type = 0> - void Pop(TYPE& value) const - { - static_assert(sizeof(TYPE) <= 4 , "Up to 32-bit integers supported in DataRecordLE"); - PopIntegerValue(value); - } - template::value, int>::type = 0> - void Pop(TYPE& value) const - { - static_assert(sizeof(TYPE) <= 4, "Up to 32-bit enum pop supported in DataRecordLE"); - typename std::underlying_type::type temp{}; - PopIntegerValue(temp); - value = static_cast(temp); - } - - protected: - void PushIntegerValue(const uint16_t value) - { - ASSERT(Free() >= 2); - _buffer[_writerOffset++] = value; - _buffer[_writerOffset++] = (value >> 8); - } - void PushIntegerValue(const uint32_t value) - { - ASSERT(Free() >= 4); - _buffer[_writerOffset++] = value; - _buffer[_writerOffset++] = (value >> 8); - _buffer[_writerOffset++] = (value >> 16); - _buffer[_writerOffset++] = (value >> 24); - } - void PopIntegerValue(uint16_t& value) const - { - if (Available() >= 2) { - value = ((_buffer[_readerOffset + 1] << 8) | _buffer[_readerOffset]); - _readerOffset += 2; - } else { - TRACE_L1("DataRecordLE: Truncated payload"); - _readerOffset = _writerOffset; - value = 0; - } - } - void PopIntegerValue(uint32_t& value) const - { - if (Available() >= 4) { - value = ((_buffer[_readerOffset + 3] << 24) | (_buffer[_readerOffset + 2] << 16) - | (_buffer[_readerOffset + 1] << 8) | _buffer[_readerOffset]); - _readerOffset += 4; - } else { - TRACE_L1("DataRecordLE: Truncated payload"); - _readerOffset = _writerOffset; - value = 0; - } - } - }; // class DataRecordLE - -} // namespace Bluetooth - -} diff --git a/Source/bluetooth/audio/IAudioCodec.h b/Source/bluetooth/audio/IAudioCodec.h deleted file mode 100644 index 804dcdc..0000000 --- a/Source/bluetooth/audio/IAudioCodec.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2021 Metrological - * - * 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. - */ - -#pragma once - -#include "Module.h" - -namespace Thunder { - -namespace Bluetooth { - -namespace A2DP { - - struct IAudioCodec { - - static constexpr uint8_t MEDIA_TYPE = 0x00; // audio - - enum codectype : uint8_t { - LC_SBC = 0 - }; - - struct StreamFormat { - uint32_t SampleRate; - uint16_t FrameRate; - uint8_t Resolution; - uint8_t Channels; - }; - - virtual ~IAudioCodec() = default; - - virtual codectype Type() const = 0; - - virtual uint32_t BitRate() const = 0; // bits per second - - virtual uint16_t RawFrameSize() const = 0; - virtual uint16_t EncodedFrameSize() const = 0; - - virtual uint32_t QOS(const int8_t policy) = 0; - - virtual uint32_t Configure(const StreamFormat& format, const string& settings) = 0; - virtual uint32_t Configure(const uint8_t stream[], const uint16_t length) = 0; - - virtual void Configuration(StreamFormat& format, string& settings) const = 0; - - virtual uint16_t Encode(const uint16_t inBufferSize, const uint8_t inBuffer[], - uint16_t& outBufferSize, uint8_t outBuffer[]) const = 0; - - virtual uint16_t Decode(const uint16_t inBufferSize, const uint8_t inBuffer[], - uint16_t& outBufferSize, uint8_t outBuffer[]) const = 0; - - virtual uint16_t Serialize(const bool capabilities, uint8_t stream[], const uint16_t length) const = 0; - }; - -} // namespace A2DP - -} // namespace Bluetooth - -} diff --git a/Source/bluetooth/audio/IAudioContentProtection.h b/Source/bluetooth/audio/IAudioContentProtection.h deleted file mode 100644 index 43456c8..0000000 --- a/Source/bluetooth/audio/IAudioContentProtection.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2021 Metrological - * - * 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. - */ - -#pragma once - -#include "Module.h" - -namespace Thunder { - -namespace Bluetooth { - -namespace A2DP { - - struct IAudioContentProtection { - - enum protectiontype { - SCMS_T - }; - - virtual ~IAudioContentProtection() = default; - - virtual protectiontype Type() const = 0; - - virtual uint32_t Configure(const string& format) = 0; - virtual void Configuration(string& format) const = 0; - - virtual uint32_t Protect(const uint16_t inBufferSize, const uint8_t inBuffer[], - const uint16_t maxOutBufferSize, uint8_t outBuffer) const = 0; - - virtual uint32_t Unprotect(const uint16_t inBufferSize, const uint8_t inBuffer[], - const uint16_t maxOutBufferSize, uint8_t outBuffer) const = 0; - - virtual uint32_t Serialize(const bool capabilities, uint8_t buffer[], const uint16_t length ) const = 0; - }; - -} // namespace A2DP - -} // namespace Bluetooth - -} diff --git a/Source/bluetooth/audio/Module.cpp b/Source/bluetooth/audio/Module.cpp deleted file mode 100644 index b734eff..0000000 --- a/Source/bluetooth/audio/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2023 Metrological - * - * 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. - */ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) diff --git a/Source/bluetooth/audio/Module.h b/Source/bluetooth/audio/Module.h deleted file mode 100644 index 9cb529d..0000000 --- a/Source/bluetooth/audio/Module.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2023 Metrological - * - * 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. - */ - -#pragma once - -#ifndef MODULE_NAME -#define MODULE_NAME Bluetooth_Audio -#endif - -#include -#include - -#include <../include/bluetooth/bluetooth.h> -#include <../include/bluetooth/l2cap.h> - -#include "../Debug.h" -#include "../UUID.h" - -#if defined(__WINDOWS__) && defined(BLUETOOTH_EXPORTS) -#undef EXTERNAL -#define EXTERNAL EXTERNAL_EXPORT -#endif - diff --git a/Source/bluetooth/audio/RTPSocket.h b/Source/bluetooth/audio/RTPSocket.h deleted file mode 100644 index c57b384..0000000 --- a/Source/bluetooth/audio/RTPSocket.h +++ /dev/null @@ -1,308 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2021 Metrological - * - * 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. - */ - -#pragma once - -#include "Module.h" -#include "IAudioCodec.h" - -namespace Thunder { - -namespace Bluetooth { - -namespace RTP { - - class EXTERNAL MediaPacket { - public: - MediaPacket(const uint8_t payloadType, const uint32_t synchronisationSource, - const uint16_t sequence, const uint32_t timestamp) - : _packet(nullptr) - , _packetLength(0) - , _sequence(sequence) - , _timestamp(timestamp) - , _synchronisationSource(synchronisationSource) - , _payload(nullptr) - , _payloadLength(0) - , _payloadType(payloadType) - { - } - MediaPacket(const uint8_t packet[], const uint16_t packetLength) - : _packet(packet) - , _packetLength(packetLength) - , _sequence(0) - , _timestamp(0) - , _synchronisationSource(0) - , _payload(nullptr) - , _payloadLength(0) - , _payloadType(0) - { - ASSERT(packet != nullptr); - - if (packetLength >= 12) { - DataRecordBE pkt(packet, packetLength); - - uint8_t octet; - pkt.Pop(octet); - - uint8_t csrcCount = (octet & 0x1F); - const bool extension = (octet & 16); - const bool padding = (octet & 32); - const uint8_t version = (octet >> 6); - - if (version == 2) { - pkt.Pop(octet); - _payloadType = (octet & 0x7F); - _marker = !!(octet & 0x80); - - pkt.Pop(_sequence); - pkt.Pop(_timestamp); - pkt.Pop(_synchronisationSource); // ssrc - - // Ignore contributing source IDs... - while (csrcCount--) { - pkt.Skip(sizeof(uint32_t)); // csrc - } - - // Ignore the application-specific extension. - if (extension == true) { - TRACE_L1("Have extension in RTP packet!"); - pkt.Skip(sizeof(uint32_t)); // extension id - - uint32_t extensionLength; - pkt.Pop(extensionLength); - pkt.Skip(extensionLength); - } - - // Any padding to remove? - const uint8_t paddingLength = (padding? _packet[_packetLength - 1] : 0); - - // Isolate the payload data - _payload = (_packet + pkt.Position()); - _payloadLength = (_packetLength - pkt.Position() - paddingLength); - } - else { - TRACE_L1("Unsupported RTP packet version!"); - } - } - else { - TRACE_L1("Invalid RTP packet!"); - } - } - - public: - uint16_t Pack(const A2DP::IAudioCodec& codec, const uint8_t payload[], const uint16_t payloadLength, - uint8_t buffer[], const uint16_t bufferLength) - { - ASSERT(bufferLength >= 12); - ASSERT(buffer != nullptr); - - DataRecordBE pkt(buffer, bufferLength, 0); - - pkt.Push(static_cast(2 << 6)); - pkt.Push(_payloadType); - pkt.Push(_sequence); - pkt.Push(_timestamp); - pkt.Push(_synchronisationSource); - - const uint16_t headerLength = pkt.Length(); - ASSERT(headerLength == 12); - - uint16_t length = (bufferLength - headerLength); - const uint16_t consumed = codec.Encode(payloadLength, payload, length, (buffer + headerLength)); - - _packet = buffer; - _payload = (_packet + headerLength); - _packetLength = (headerLength + length); - _payloadLength = length; - - return (consumed); - } - uint16_t Unpack(const A2DP::IAudioCodec& codec, uint8_t buffer[], uint16_t& length) - { - ASSERT(buffer != nullptr); - ASSERT(Payload() != nullptr); - ASSERT(length != 0); - - return (codec.Decode(PayloadLength(), Payload(), length, buffer)); - } - - public: - bool IsValid() const { - return ((_payloadType != 0) && (_payloadLength != 0)); - } - uint16_t Sequence() const { - return (_sequence); - } - uint32_t Timestamp() const { - return (_timestamp); - } - uint8_t Type() const { - return (_payloadType); - } - uint32_t SyncSource() const { - return (_synchronisationSource); - } - const uint8_t* Data() const { - return (_packet); - } - const uint16_t Length() const { - return (_packetLength); - } - const uint8_t* Payload() const { - return (_payload); - } - const uint16_t PayloadLength() const { - return (_payloadLength); - } - - private: - const uint8_t* _packet; - uint16_t _packetLength; - uint16_t _sequence; - uint32_t _timestamp; - uint32_t _synchronisationSource; - const uint8_t* _payload; - uint16_t _payloadLength; - uint8_t _payloadType; - bool _marker; - }; - - template - class EXTERNAL OutboundMediaPacketType : public MediaPacket, public Core::IOutbound { - public: - static_assert(SIZE >= 48, "Too small packet buffer"); - - OutboundMediaPacketType(const OutboundMediaPacketType&) = delete; - OutboundMediaPacketType& operator=(const OutboundMediaPacketType&) = delete; - ~OutboundMediaPacketType() = default; - - OutboundMediaPacketType(const uint16_t MTU, const uint32_t synchronisationSource, uint16_t sequence, const uint32_t timestamp) - : MediaPacket(TYPE, synchronisationSource, sequence, timestamp) - , _buffer() - , _offset(0) - , _mtu(MTU) - { - ASSERT(MTU <= sizeof(_buffer)); - } - - public: - uint16_t Ingest(const A2DP::IAudioCodec& codec, const uint8_t data[], const uint16_t dataLength) - { - ASSERT(data != nullptr); - - return (Pack(codec, data, dataLength, _buffer, _mtu)); - } - - private: - void Reload() const override - { - _offset = 0; - } - uint16_t Serialize(uint8_t stream[], const uint16_t length) const override - { - ASSERT(stream != nullptr); - - uint16_t result = std::min((Length() - _offset), length); - if (result > 0) { - ::memcpy(stream, (Data() + _offset), result); - _offset += result; - - // CMD_DUMP("RTP send", stream, result); - } - - return (result); - } - - private: - uint8_t _buffer[SIZE]; - mutable uint16_t _offset; - uint16_t _mtu; - }; // class OutboundMediaPacketType - - class EXTERNAL ClientSocket : public Core::SynchronousChannelType { - public: - static constexpr uint32_t CommunicationTimeout = 500; - - public: - ClientSocket(const ClientSocket&) = delete; - ClientSocket& operator=(const ClientSocket&) = delete; - ~ClientSocket() = default; - - ClientSocket(const Core::NodeId& localNode, const Core::NodeId& remoteNode) - : Core::SynchronousChannelType(SocketPort::SEQUENCED, localNode, remoteNode, 2048, 2048) - , _outputMTU(0) - { - } - - uint16_t OutputMTU() const { - return (_outputMTU); - } - - public: - virtual void Operational(const bool upAndRunning) = 0; - - private: - void StateChange() override - { - Core::SynchronousChannelType::StateChange(); - - if (IsOpen() == true) { - struct l2cap_options options{}; - socklen_t len = sizeof(options); - - ::getsockopt(Handle(), SOL_L2CAP, L2CAP_OPTIONS, &options, &len); - - ASSERT(options.omtu <= SendBufferSize()); - ASSERT(options.imtu <= ReceiveBufferSize()); - - _outputMTU = options.omtu; - - TRACE(Trace::Information, (_T("Transport channel input MTU: %d, output MTU: %d"), options.imtu, options.omtu)); - - Operational(true); - } else { - Operational(false); - } - } - - private: - uint16_t Deserialize(const uint8_t dataFrame[], const uint16_t availableData) override - { - // Do not expect anything inbound on this channel... - - uint32_t result = 0; - - if (availableData != 0) { - TRACE_L1("Unexpected RTP data received [%d bytes]", availableData); - - CMD_DUMP("RTP received unexpected", dataFrame, availableData); - } - - return (result); - } - - private: - uint16_t _outputMTU; - }; // class ClientSocket - -} // namespace RTP - -} // namespace Bluetooth - -} diff --git a/Source/bluetooth/audio/SDPProfile.cpp b/Source/bluetooth/audio/SDPProfile.cpp deleted file mode 100644 index 99a4368..0000000 --- a/Source/bluetooth/audio/SDPProfile.cpp +++ /dev/null @@ -1,927 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2021 Metrological - * - * 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. - */ - -#include "Module.h" - -#include "SDPSocket.h" -#include "SDPProfile.h" - -namespace Thunder { - -ENUM_CONVERSION_BEGIN(Bluetooth::SDP::ClassID::id) - { Bluetooth::SDP::ClassID::Undefined, _TXT("(undefined)") }, - - // Protocols - { Bluetooth::SDP::ClassID::SDP, _TXT("SDP") }, - { Bluetooth::SDP::ClassID::UDP, _TXT("UDP") }, - { Bluetooth::SDP::ClassID::RFCOMM, _TXT("RFCOMM") }, - { Bluetooth::SDP::ClassID::TCP, _TXT("TCP") }, - { Bluetooth::SDP::ClassID::TCS_BIN, _TXT("TCS-Binary") }, - { Bluetooth::SDP::ClassID::TCS_AT, _TXT("TCS-AT") }, - { Bluetooth::SDP::ClassID::ATT, _TXT("ATT") }, - { Bluetooth::SDP::ClassID::OBEX, _TXT("OBEX") }, - { Bluetooth::SDP::ClassID::IP, _TXT("IP") }, - { Bluetooth::SDP::ClassID::FTP, _TXT("FTP") }, - { Bluetooth::SDP::ClassID::HTTP, _TXT("HTTP") }, - { Bluetooth::SDP::ClassID::WSP, _TXT("WSP") }, - { Bluetooth::SDP::ClassID::BNEP, _TXT("BNEP") }, - { Bluetooth::SDP::ClassID::UPNP, _TXT("UPNP/ESDP") }, - { Bluetooth::SDP::ClassID::HIDP, _TXT("HIDP") }, - { Bluetooth::SDP::ClassID::HCRP_CTRL, _TXT("HCRP-ControlChannel") }, - { Bluetooth::SDP::ClassID::HCRP_DATA, _TXT("HCRP-DataChannel") }, - { Bluetooth::SDP::ClassID::HCRP_NOTE, _TXT("HCRP-Notification") }, - { Bluetooth::SDP::ClassID::AVCTP, _TXT("AVCTP") }, - { Bluetooth::SDP::ClassID::AVDTP, _TXT("AVDTP") }, - { Bluetooth::SDP::ClassID::CMTP, _TXT("CMTP") }, - { Bluetooth::SDP::ClassID::UDI, _TXT("UDI") }, - { Bluetooth::SDP::ClassID::MCAP_CTRL, _TXT("MCAP-ControlChannel") }, - { Bluetooth::SDP::ClassID::MCAP_DATA, _TXT("MCAP-DataChannel") }, - { Bluetooth::SDP::ClassID::L2CAP, _TXT("L2CAP") }, - - // SDP services - { Bluetooth::SDP::ClassID::ServiceDiscoveryServer, _TXT("Service Discovery Server") }, - { Bluetooth::SDP::ClassID::BrowseGroupDescriptor, _TXT("Browse Group Descriptor") }, - { Bluetooth::SDP::ClassID::PublicBrowseRoot, _TXT("Public Browse Root") }, - - // Services and Profiles - { Bluetooth::SDP::ClassID::SerialPort, _TXT("Serial Port (SPP)") }, - { Bluetooth::SDP::ClassID::LANAccessUsingPPP, _TXT("LAN Access Using PPP (LAP)") }, - { Bluetooth::SDP::ClassID::DialupNetworking, _TXT("Dial-Up Networking (DUN)") }, - { Bluetooth::SDP::ClassID::IrMCSync, _TXT("IrMC Sync (SYNCH)") }, - { Bluetooth::SDP::ClassID::OBEXObjectPush, _TXT("OBEX Obect Push (OPP)") }, - { Bluetooth::SDP::ClassID::OBEXFileTransfer, _TXT("OBEX File Transfer (FTP)") }, - { Bluetooth::SDP::ClassID::IrMCSyncCommand, _TXT("IrMC Sync Command (SYNCH)") }, - { Bluetooth::SDP::ClassID::HeadsetHSP, _TXT("Headset (HSP)") }, - { Bluetooth::SDP::ClassID::CordlessTelephony, _TXT("Cordless Telephony (CTP)") }, - { Bluetooth::SDP::ClassID::AudioSource, _TXT("Audio Source (A2DP)") }, - { Bluetooth::SDP::ClassID::AudioSink, _TXT("Audio Sink (A2DP)") }, - { Bluetooth::SDP::ClassID::AVRemoteControlTarget, _TXT("A/V Remote Control Target (AVRCP)") }, - { Bluetooth::SDP::ClassID::AdvancedAudioDistribution, _TXT("Advanced Audio Distribution (A2DP)") }, - { Bluetooth::SDP::ClassID::AVRemoteControl, _TXT("A/V Remote Control (AVRCP)") }, - { Bluetooth::SDP::ClassID::AVRemoteControlController, _TXT("A/V Remote Control Controller (AVRCP)") }, - { Bluetooth::SDP::ClassID::Intercom, _TXT("Intercom (ICP)") }, - { Bluetooth::SDP::ClassID::Fax, _TXT("Fax (FAX)") }, - { Bluetooth::SDP::ClassID::HeadsetAudioGateway, _TXT("Headset Audio Gateway (HSP)") }, - { Bluetooth::SDP::ClassID::WAP, _TXT("WAP (WAPB)") }, - { Bluetooth::SDP::ClassID::WAPClient, _TXT("WAP Client (WAPB)") }, - { Bluetooth::SDP::ClassID::PANU, _TXT("PAN User (PAN)") }, - { Bluetooth::SDP::ClassID::NAP, _TXT("Network Access Point (PAN)") }, - { Bluetooth::SDP::ClassID::GN, _TXT("Group Ad-hoc Network (PAN)") }, - { Bluetooth::SDP::ClassID::DirectPrinting, _TXT("Direct Printing (BPP)") }, - { Bluetooth::SDP::ClassID::ReferencePrinting, _TXT("Reference Printing (BPP)") }, - { Bluetooth::SDP::ClassID::BasicImagingProfile, _TXT("Basic Imaging (BIP)") }, - { Bluetooth::SDP::ClassID::ImagingResponder, _TXT("Imaging Responder (BIP)") }, - { Bluetooth::SDP::ClassID::ImagingAutomaticArchive, _TXT("Imaging Automatic Archive (BIP)") }, - { Bluetooth::SDP::ClassID::ImagingReferencedObjects, _TXT("Imaging Referenced Objects (BIP)") }, - { Bluetooth::SDP::ClassID::Handsfree, _TXT("Hands-Free (HFP)") }, - { Bluetooth::SDP::ClassID::HandsfreeAudioGateway, _TXT("Hands-Free Audio Gateway (HFP)") }, - { Bluetooth::SDP::ClassID::DirectPrintingReferenceObjects, _TXT("Direct Printing Reference Objects (BPP)") }, - { Bluetooth::SDP::ClassID::ReflectedUI, _TXT("Reflected UI (BPP)") }, - { Bluetooth::SDP::ClassID::BasicPrinting, _TXT("Basic Printing (BPP)") }, - { Bluetooth::SDP::ClassID::PrintingStatus, _TXT("Printing Status (BPP)") }, - { Bluetooth::SDP::ClassID::HumanInterfaceDeviceService, _TXT("Human Interface Device (HID)") }, - { Bluetooth::SDP::ClassID::HardcopyCableReplacement, _TXT("Hardcopy Cable Replacement (HCRP)") }, - { Bluetooth::SDP::ClassID::HCRPrint, _TXT("HCRP Print (HCRP) ") }, - { Bluetooth::SDP::ClassID::HCRScan, _TXT("HCRP Scan (HCRP)") }, - { Bluetooth::SDP::ClassID::CommonISDNAccess, _TXT("Common ISDN Access (CIP)") }, - { Bluetooth::SDP::ClassID::SIMAccess, _TXT("SIM Access (SAP)") }, - { Bluetooth::SDP::ClassID::PhonebookAccessPCE, _TXT("Phonebook Client Equipment (PBAP)") }, - { Bluetooth::SDP::ClassID::PhonebookAccessPSE, _TXT("Phonebook Server Equipment (PBAP)") }, - { Bluetooth::SDP::ClassID::PhonebookAccess, _TXT("Phonebook Access (PBAP)") }, - { Bluetooth::SDP::ClassID::HeadsetHS, _TXT("Headset v1.2 (HSP)") }, - { Bluetooth::SDP::ClassID::MessageAccessServer, _TXT("Message Access Server (MAP)") }, - { Bluetooth::SDP::ClassID::MessageNotificationServer, _TXT("Message Notification Server (MAP)") }, - { Bluetooth::SDP::ClassID::MessageAccess, _TXT("Message Access(MAP)") }, - { Bluetooth::SDP::ClassID::GNSS, _TXT("Global Navigation Satellite System (GNSS)") }, - { Bluetooth::SDP::ClassID::GNSSServer, _TXT("GNSS Server (GNSS)") }, - { Bluetooth::SDP::ClassID::ThreeDDisplay, _TXT("3D Display (3DSP)") }, - { Bluetooth::SDP::ClassID::ThreeDGlasses, _TXT("3D Glasses (3DSP)") }, - { Bluetooth::SDP::ClassID::ThreeDSynchronisation, _TXT("3D Synchronisation (3DSP)") }, - { Bluetooth::SDP::ClassID::MPS, _TXT("Multi-Profile Specification (MPS)") }, - { Bluetooth::SDP::ClassID::MPSSC, _TXT("MPS SC (MPS)") }, - { Bluetooth::SDP::ClassID::CTNAccessService, _TXT("CTN Access (CTN)") }, - { Bluetooth::SDP::ClassID::CTNNotificationService, _TXT("CTN Notification (CTN)") }, - { Bluetooth::SDP::ClassID::CTN, _TXT("Calendar Tasks and Notes (CTN)") }, - { Bluetooth::SDP::ClassID::PnPInformation, _TXT("PnP Information (DID") }, - { Bluetooth::SDP::ClassID::GenericNetworking, _TXT("Generic Networking") }, - { Bluetooth::SDP::ClassID::GenericFileTransfer, _TXT("Generic File Transfer") }, - { Bluetooth::SDP::ClassID::GenericAudio, _TXT("Generic Audio") }, - { Bluetooth::SDP::ClassID::GenericTelephony, _TXT("Generic Telephony") }, - { Bluetooth::SDP::ClassID::UPNPService, _TXT("UPNP (ESDP)") }, - { Bluetooth::SDP::ClassID::UPNPIPService, _TXT("UPNP IP (ESDP)") }, - { Bluetooth::SDP::ClassID::ESDPUPNPIPPAN, _TXT("UPNP IP PAN (ESDP)") }, - { Bluetooth::SDP::ClassID::ESDPUPNPIPLAP, _TXT("UPNP IP LAP (ESDP)") }, - { Bluetooth::SDP::ClassID::ESDPUPNPL2CAP, _TXT("UPNP L2CAP (ESDP)") }, - { Bluetooth::SDP::ClassID::VideoSource, _TXT("Video Source (VDP)") }, - { Bluetooth::SDP::ClassID::VideoSink, _TXT("Video Sink (VDP)") }, - { Bluetooth::SDP::ClassID::VideoDistribution, _TXT("Video Distribution Profile (VDP)") }, - { Bluetooth::SDP::ClassID::HDP, _TXT("Health Device (HDP)") }, - { Bluetooth::SDP::ClassID::HDPSource, _TXT("HDP Source (HDP)") }, - { Bluetooth::SDP::ClassID::HDPSink, _TXT("HDP Sink (HDP)") }, -ENUM_CONVERSION_END(Bluetooth::SDP::ClassID::id) - -ENUM_CONVERSION_BEGIN(Bluetooth::SDP::Service::AttributeDescriptor::id) - { Bluetooth::SDP::Service::AttributeDescriptor::ServiceRecordHandle, _TXT("ServiceRecordHandle") }, - { Bluetooth::SDP::Service::AttributeDescriptor::ServiceClassIDList, _TXT("ServiceClassIDList") }, - { Bluetooth::SDP::Service::AttributeDescriptor::ServiceRecordState, _TXT("ServiceRecordState") }, - { Bluetooth::SDP::Service::AttributeDescriptor::ServiceID, _TXT("ServiceID") }, - { Bluetooth::SDP::Service::AttributeDescriptor::ProtocolDescriptorList, _TXT("ProtocolDescriptorList") }, - { Bluetooth::SDP::Service::AttributeDescriptor::BrowseGroupList, _TXT("BrowseGroupList") }, - { Bluetooth::SDP::Service::AttributeDescriptor::LanguageBaseAttributeIDList, _TXT("LanguageBaseAttributeIDList") }, - { Bluetooth::SDP::Service::AttributeDescriptor::ServiceInfoTimeToLive, _TXT("ServiceInfoTimeToLive") }, - { Bluetooth::SDP::Service::AttributeDescriptor::ServiceAvailability, _TXT("ServiceAvailability") }, - { Bluetooth::SDP::Service::AttributeDescriptor::ProfileDescriptorList, _TXT("BluetoothProfileDescriptorList") }, - { Bluetooth::SDP::Service::AttributeDescriptor::DocumentationURL, _TXT("DocumentationURL") }, - { Bluetooth::SDP::Service::AttributeDescriptor::ClientExecutableURL, _TXT("ClientExecutableURL") }, - { Bluetooth::SDP::Service::AttributeDescriptor::IconURL, _TXT("IconURL") }, -ENUM_CONVERSION_END(Bluetooth::SDP::Service::AttributeDescriptor::id) - -namespace Bluetooth { - -namespace SDP { - - // CLIENT --- - - uint32_t Client::Discover(const std::list& services, Tree& tree) const - { - // Convenience method to discover and add services and their attributes to a service tree. - - uint32_t result = Core::ERROR_NONE; - - std::vector handles; - - // First find all the requested services... - - if ((result = ServiceSearch(services, handles)) == Core::ERROR_NONE) { - - for (uint32_t& h : handles) { - std::list> attributes; - - // Then retrieve their attributes... - - if ((result = ServiceAttribute(h, std::list{ 0x0000FFFF } /* all of them */, attributes)) == Core::ERROR_NONE) { - - Service& service(tree.Add(h)); - - for (auto const& attr : attributes) { - service.Deserialize(attr.first, attr.second); - } - } else { - break; - } - } - } - - if (result != Core::ERROR_NONE) { - TRACE(Trace::Error, (_T("Failed to retrieve Bluetooth services via SDP protocol"))); - } - - return (result); - } - - uint32_t Client::ServiceSearch(const std::list& services, std::vector& outHandles) const - { - ASSERT((services.size() > 0) && (services.size() <= 12)); // As per spec - - ClientSocket::Command command(_socket); - - const uint16_t maxResults = ((Capacity(command.Result()) - (2 * sizeof(uint32_t))) / sizeof(uint32_t)); - TRACE_L5("capacity=%d handles", maxResults); - - uint32_t result = Core::ERROR_NONE; - Buffer continuationData; - - outHandles.clear(); - - do { - // Handle fragmented packets by repeating the request until the continuation state is 0. - - command.Set(PDU::ServiceSearchRequest, [&](Payload& payload) { - - // ServiceSearchRequest frame format: - // - ServiceSearchPattern (sequence of UUIDs) - // - MaximumServiceRecordCount (word) - // - ContinuationState - - payload.Push(use_descriptor, services); - payload.Push(maxResults - outHandles.size()); - - ASSERT(continuationData.size() <= 16); - payload.Push(continuationData.size()); - - if (continuationData.empty() == false) { - payload.Push(continuationData); - } - }); - - result = Execute(command, [&](const Payload& payload) { - - // ServiceSearchResponse frame format: - // - TotalServiceRecordCount (long) - // - CurrentServiceRecordCount (long) - // - ServiceRecordHandleList (list of longs, not a sequence!) - // - ContinuationState - - if (payload.Available() < (2 * sizeof(uint16_t))) { - TRACE_L1("SDP: Truncated payload in ServiceSearchResponse!"); - result = Core::ERROR_BAD_REQUEST; - } - else { - uint16_t totalCount{}; - payload.Pop(totalCount); - - uint16_t currentCount{}; - payload.Pop(currentCount); - - TRACE_L5("TotalServiceRecordCount=%d", totalCount); - TRACE_L5("CurrentServiceRecordCount=%d", currentCount); - - // Clip this in case of a phony value. - totalCount = std::min(32, totalCount); - currentCount = std::min(32, currentCount); - - outHandles.reserve(totalCount); - - if (payload.Available() >= (currentCount * sizeof(uint32_t))) { - - payload.Pop(outHandles, currentCount); - - for (uint16_t i=0; i < outHandles.size(); i++) { - TRACE_L5("ServiceRecordHandleList[%d]=0x%08x", i, outHandles[i]); - } - - if (payload.Available() >= sizeof(uint8_t)) { - uint8_t continuationDataLength{}; - payload.Pop(continuationDataLength); - - if ((continuationDataLength > 16) || (payload.Available() < continuationDataLength)) { - TRACE_L1("SDP: Invalid continuation data in ServiceSearchResponse!"); - result = Core::ERROR_BAD_REQUEST; - } - else if (continuationDataLength > 0) { - payload.Pop(continuationData, continuationDataLength); - } - } - else { - TRACE_L1("SDP: Truncated payload in ServiceSearchResponse!"); - result = Core::ERROR_BAD_REQUEST; - } - - if (payload.Available() != 0) { - TRACE_L1("SDP: Unexpected data in ServiceSearchResponse payload!"); - } - } else { - TRACE_L1("SDP: Truncated payload in ServiceSearchResponse!"); - result = Core::ERROR_BAD_REQUEST; - } - } - }); - - } while ((continuationData.size() != 0) && (result == Core::ERROR_NONE)); - - TRACE_L1("SDP: ServiceSearch found %d matching service(s)", outHandles.size()); - - return (result); - } - - /* private */ - uint32_t Client::InternalServiceAttribute(const PDU::pduid id, - const std::function& buildCb, - const std::list& attributeIdRanges, - std::list>& outAttributes) const - { - ASSERT(buildCb != 0); - ASSERT((attributeIdRanges.size() > 0) && (attributeIdRanges.size() <= 256)); - - ClientSocket::Command command(_socket); - - const uint16_t maxByteCount = (Capacity(command.Result()) - sizeof(uint16_t)); - TRACE_L5("capacity=%d bytes", maxByteCount); - - // From client perspective ServiceAttribute and ServiceSearchAttribute are very similar, - // hence use one method to handle both. - - uint32_t result = Core::ERROR_NONE; - Buffer continuationData; - - do { - // Handle fragmented packets by repeating the request until the continuation state is 0. - - command.Set(id, [&](Payload& payload) { - - // Here's the difference between ServiceAttribute and ServiceSearchAttribute handled - // First sends a service handle, the second a list of UUIDs to scan for. - buildCb(payload); - - payload.Push(maxByteCount); - payload.Push(use_descriptor, attributeIdRanges); - - ASSERT(continuationData.size() <= 16); - payload.Push(continuationData.size()); - - if (continuationData.empty() == false) { - payload.Push(continuationData); - } - }); - - result = Execute(command, [&](const Payload& payload) { - - // ServiceAttributeResponse/ServiceSearchAttributeResponse frame format: - // - AttributeListByteCount (word) - // - AttributeList (sequence of long:data pairs, where data size is dependant on the attribute and may be a sequence) - // - ContinuationState - - if (payload.Available() < 2) { - TRACE_L1("SDP: Truncated Service(Search)AttributeResponse payload!"); - result = Core::ERROR_BAD_REQUEST; - } - else { - payload.Pop(use_length, [&](const Payload& buffer) { - buffer.Pop(use_descriptor, [&](const Payload& sequence) { - while (sequence.Available() >= 2) { - uint16_t attribute{}; - Buffer value; - - sequence.Pop(use_descriptor, attribute); - sequence.Pop(use_descriptor, value); - - TRACE_L5("attribute %d=[%s]", attribute, value.ToString().c_str()); - - outAttributes.emplace_back(attribute, std::move(value)); - } - - if (sequence.Available() != 0) { - TRACE_L1("SDP: Unexpected data in Service(Search)AttributeResponse!"); - } - }); - - if (buffer.Available() != 0) { - TRACE_L1("SDP: Unexpected data in Service(Search)AttributeResponse!"); - } - }); - - if (payload.Available() >= 1) { - uint8_t continuationDataLength{}; - payload.Pop(continuationDataLength); - - if ((continuationDataLength > 16) || (payload.Available() < continuationDataLength)) { - TRACE_L1("SDP: Invalid continuation data in Service(Search)AttributeResponse!"); - result = Core::ERROR_BAD_REQUEST; - } - else { - payload.Pop(continuationData, continuationDataLength); - } - } - else { - TRACE_L1("SDP: Truncated payload in Service(Search)AttributeResponse!"); - result = Core::ERROR_BAD_REQUEST; - } - - if (payload.Available() != 0) { - TRACE_L1("SDP: Unexpected data in ServiceSearchAttributeResponse!"); - } - } - }); - } while ((continuationData.size() != 0) && (result == Core::ERROR_NONE)); - - TRACE_L1("SDP: Service(Search)Attribute found %d matching attribute(s)", outAttributes.size()); - - return (result); - } - - uint32_t Client::ServiceAttribute(const uint32_t serviceHandle, const std::list& attributeIdRanges, - std::list>& outAttributes) const - { - ASSERT(serviceHandle != 0); - - return (InternalServiceAttribute(PDU::ServiceAttributeRequest, [&](Payload& payload) { - - // ServiceAttributeRequest frame format: - // - ServiceRecordHandle (long) - // - MaximumAttributeByteCount (word) - // - AttributeIDList (sequence of UUID ranges or UUIDs) [only ranges supported in this client-side implementation] - // - ContinuationState - - payload.Push(serviceHandle); - - // MaximumAttributeByteCount, AttributeIDList and ContinuationState is handled by InternalServiceAttribute(). - - }, attributeIdRanges, outAttributes)); - } - - uint32_t Client::ServiceSearchAttribute(const std::list& services, const std::list& attributeIdRanges, - std::list>& outAttributes) const - { - ASSERT((services.size() > 0) && (services.size() <= 12)); - - return (InternalServiceAttribute(PDU::ServiceSearchAttributeRequest, [&](Payload& payload) { - - // ServiceSearchAttributeRequest frame format: - // - ServiceSearchPattern (sequence of UUIDs) - // - MaximumAttributeByteCount (word) - // - AttributeIDList (sequence of UUID ranges or UUIDs) [only ranges supported in this client-side implementation] - // - ContinuationState - - payload.Push(use_descriptor, services); - - // MaximumAttributeByteCount, AttributeIDList and ContinuationState is handled by InternalServiceAttribute(). - - }, attributeIdRanges, outAttributes)); - } - - /* private */ - uint32_t Client::Execute(ClientSocket::Command& command, const Payload::Inspector& inspectorCb) const - { - uint32_t result = Core::ERROR_ASYNC_FAILED; - - if (_socket.Exchange(ClientSocket::CommunicationTimeout, command, command) == Core::ERROR_NONE) { - - if (command.Result().Error() != PDU::Success) { - TRACE_L1("SDP server: Message %d failed! [%d]", command.Call().Type(), command.Result().Error()); - } - else if (command.Result().TransactionId() != command.Call().TransactionId()) { - TRACE_L1("SDP server: Mismatched message transaction ID!"); - } - else { - result = Core::ERROR_NONE; - - if (inspectorCb != nullptr) { - command.Result().InspectPayload(inspectorCb); - } - } - } - - return (result); - } - - // SERVER --- - - void Server::OnServiceSearchRequest(const ServerSocket& socket, const PDU& request, const Handler& handlerCb) - { - PDU::errorid result = PDU::Success; - std::list uuids; - uint16_t maxCount{}; - uint16_t offset = 0; - - request.InspectPayload([&](const Payload& payload) { - - // ServiceSearchRequest frame format: - // - ServiceSearchPattern (sequence of UUIDs) - // - MaximumServiceRecordCount (word) - // - ContinuationState - - // In this server implementation the continuation state is a word - // value containing the index of last service sent in the previous - // call. - - payload.Pop(use_descriptor, [&](const Payload& sequence) { - - // No count stored, need to read until end of the sequence... - - while (sequence.Available() >= 2 /* min UUID size */) { - UUID uuid; - - sequence.Pop(use_descriptor, uuid); - - TRACE_L5("ServiceSearchPattern[%d]=%s ('%s')", uuids.size(), uuid.ToString().c_str(), ClassID(uuid).Name().c_str()); - - if (uuid.IsValid() == true) { - uuids.push_back(uuid); - } - else { - TRACE_L1("SDP server: invalid UUID!"); - uuids.clear(); - break; - } - } - - if (sequence.Available() != 0) { - TRACE_L1("SDP server: Unexpected data ServiceSearchRequest payload!"); - // Let's continue anyway... - } - }); - - payload.Pop(maxCount); // 0 if truncated, 0 is error - - TRACE_L5("MaximumServiceRecordCount=%d", maxCount); - - if ((uuids.empty() == true) || (maxCount == 0)) { - TRACE_L1("SDP server: Invalid ServiceSearchRequest parameters!"); - result = PDU::InvalidRequestSyntax; - } - else if (payload.Available() >= sizeof(uint8_t)) { - uint8_t continuationSize; - payload.Pop(continuationSize); - - if (continuationSize == sizeof(uint16_t)) { - payload.Pop(offset); - - if (offset == 0) { - TRACE_L1("SDP server: Invalid ServiceSearchRequest continuation state (zero)!"); - result = PDU::InvalidContinuationState; - } - } - else if (continuationSize != 0) { - TRACE_L1("SDP server: Invalid ServiceSearchRequest continuation size!"); - result = PDU::InvalidContinuationState; - } - } - else { - TRACE_L1("SDP server: Truncated ServiceSearchRequest payload!"); - result = PDU::InvalidPduSize; - } - }); - - uint16_t count = 0; - std::list handles; - - if (result == PDU::Success) { - - // Sca all matching handles, even if can't fit them all in response, - // because the total number of matches needs to be returned. - - WithServiceTree([&](const Tree& tree) { - for (auto const& service : tree.Services()) { - for (auto const& uuid : uuids) { - - if (service.Search(uuid) == true) { - if ((count >= offset) && (handles.size() < maxCount)) { - handles.push_back(service.Handle()); - } - - count++; - } - } - } - }); - - if (offset > count) { - TRACE_L1("SDP server: Invalid ServiceSearchRequest continuation state!"); - result = PDU::InvalidContinuationState; - } - } - - if (result == PDU::Success) { - - // Cap the max count to the actual possible capacity. - maxCount = std::min(maxCount, (Capacity(socket, request) - (2 * sizeof(uint32_t)) / sizeof(uint32_t))); - TRACE_L5("capacity=%d handles", maxCount); - - handlerCb(PDU::ServiceSearchResponse, [&](Payload& payload) { - - // ServiceSearchResponse frame format: - // - TotalServiceRecordCount (word) - // - CurrentServiceRecordCount (word) - // - ServiceRecordHandleList (list of longs, not sequence) - // - ContinuationState - - payload.Push(count); - payload.Push(handles.size()); - payload.Push(handles); - - if ((offset + handles.size()) < count) { - // Not all sent yet! Store offset for continuation. - payload.Push(sizeof(uint16_t)); - payload.Push(offset + handles.size()); - } - else { - // All sent! - payload.Push(0); - } - - TRACE_L1("SDP server: ServiceSearch found %d matching service(s) and will reply with %d service(s)", count, handles.size()); - }); - } - else { - TRACE_L1("SDP server: ServiceSearchRequest failed!"); - handlerCb(result); - } - } - - /* private */ - void Server::InternalOnServiceSearchAttributeRequest(const PDU::pduid id, - const std::function&)>& inspectCb, - const ServerSocket& socket, - const PDU& request, - const Handler& handlerCb) - { - // Again, ServiceAttribute and ServiceSearchAttribute are very similar, - // so use one method to handle both. - - PDU::errorid result = PDU::Success; - - uint16_t maxByteCount{}; - std::list attributeRanges; - std::list handles; - uint16_t offset = 0; - - request.InspectPayload([&](const Payload& payload) { - - // ServiceAttributeRequest/ServiceSearch frame format: - // - ServiceRecordHandle (long) OR ServiceSearchPattern (sequence of UUIDs) - // - MaximumAttributeByteCount (word) - // - AttributeIDList (sequence of UUID ranges or UUIDs) - // - ContinuationState - - // In this server implementation the continuation state is a word - // value containing the index of last attribute sent in the previous - // call. - - if (inspectCb(payload, handles) == PDU::Success) { - - payload.Pop(maxByteCount); - TRACE_L5("MaximumAttributeByteCount=%d", maxByteCount); - - if (maxByteCount > 9 /* i.e. descriptors and one result entry */) { - payload.Pop(use_descriptor, [&](const Payload& sequence) { - while (sequence.Available() >= (sizeof(uint16_t) + 1)) { - uint32_t range{}; - uint32_t size{}; - - sequence.Pop(use_descriptor, range, &size); - - if (size == sizeof(uint32_t)) { - // A range indeed. - TRACE_L5("AttributeIDList[%d]=%04x..%04x", attributeRanges.size(), (range >> 16), (range & 0xFFFF)); - - attributeRanges.push_back(range); - } - else if (size == sizeof(uint16_t)) { - // Not a range, but single 16-bit UUID. - TRACE_L5("AttributeIDList[%d]=%04x ('%s')", attributeRanges.size(), range, ClassID(UUID(range)).Name().c_str()); - - attributeRanges.push_back((static_cast(range) << 16) | static_cast(range)); - } - else { - TRACE_L1("SDP server: Invalid UUID list!"); - result = PDU::InvalidRequestSyntax; - } - } - - if (sequence.Available() != 0) { - TRACE_L1("SDP server: Unexpected data in Service(Search)AttributeRequest payload!"); - } - }); - } - - if ((maxByteCount < 9) || (attributeRanges.empty() == true)) { - TRACE_L1("SDP server: Invalid Service(Search)AttributeRequest parameters!"); - result = PDU::InvalidRequestSyntax; - } - else if (payload.Available() >= sizeof(uint8_t)) { - uint8_t continuationSize; - payload.Pop(continuationSize); - - if (continuationSize == sizeof(uint16_t)) { - payload.Pop(offset); - - if (offset == 0) { - TRACE_L1("SDP server: Invalid Service(Search)AttributeRequest continuation state (zero)!"); - result = PDU::InvalidContinuationState; - } - } - else if (continuationSize != 0) { - TRACE_L1("SDP server: Invalid Service(Search)AttributeRequest continuation size!"); - result = PDU::InvalidContinuationState; - } - } - else { - TRACE_L1("SDP server: Truncated Service(Search)AttributeRequest payload!"); - result = PDU::InvalidPduSize; - } - } - }); - - std::list> attributes; - uint16_t totalAttributes = 0; - - if (result == PDU::Success) { - - WithServiceTree([&](const Tree& tree) { - - for (auto const& handle : handles) { - const Service* service = tree.Find(handle); - - if (service != nullptr) { - attributes.emplace_back(SerializeAttributesByRange(*service, attributeRanges, offset, totalAttributes)); - } - } - }); - - if (result == PDU::Success) { - - // Cap the max count to the actual possible capacity. - maxByteCount = std::min(maxByteCount, (Capacity(socket, request) - sizeof(uint16_t))); - TRACE_L5("capacity=%d bytes", maxByteCount); - - handlerCb(id, [&](Payload& payload) { - - // ServiceAttributeResponse/ServiceSearchAttribute frame format: - // - AttributeListByteCount (word) - // - AttributeList (sequence of long:data pairs, where data size is dependant on the attribute and may be a sequence) - // - ContinuationState - - bool allDone = true; - uint16_t attributesWritten = 0; - - auto PushLists = [&](Payload& buffer) { - for (auto const& service : attributes) { - buffer.Push(use_descriptor, [&](Payload& sequence) { - for (auto const& attr : service) { - if ((sequence.Position() + attr.second.size() + sizeof(uint16_t)) < maxByteCount) { - - if (attr.second.size() != 0) { - sequence.Push([&](Payload& record) { - record.Push(use_descriptor, attr.first); - record.Push(attr.second); // Already packed as necessary, thus no use_descriptor here. - }); - - attributesWritten++; - } - } - else { - allDone = false; - break; - } - } - }); - - if (allDone == false) { - break; - } - } - }; - - payload.Push(use_length, [&](Payload& buffer) { - if (id == PDU::ServiceAttributeResponse) { - ASSERT(handles.size() == 1); - PushLists(buffer); - } - else { - // In case of ServiceSearchAtributes this is a list of lists. - buffer.Push(use_descriptor, [&](Payload& listBuffer) { - PushLists(listBuffer); - }); - } - }); - - if (allDone == false) { - payload.Push(sizeof(uint16_t)); - payload.Push(offset + attributesWritten); - } - else { - payload.Push(0); - } - - TRACE_L1("SDP server: Service(Search)Attribute found %d attribute(s) and will reply with %d attribute(s)", totalAttributes, attributesWritten); - }); - } - } - else { - TRACE_L1("SDP server: Service(Search)Attribute failed!"); - handlerCb(result); - } - } - - void Server::OnServiceAttributeRequest(const ServerSocket& socket, const PDU& request, const Handler& handlerCb) - { - InternalOnServiceSearchAttributeRequest(PDU::ServiceAttributeResponse, - [&](const Payload& payload, std::list& handles) -> PDU::errorid { - - // ServiceAttributeRequest frame format: - // - ServiceRecordHandle (long) - // - MaximumAttributeByteCount (word) - // - AttributeIDList (sequence of UUID ranges or UUIDs) - // - ContinuationState - - uint32_t handle{}; - payload.Pop(handle); // 0 if truncated - - TRACE_L1("ServiceRecordHandle=0x%08x", handle); - - if (handle != 0) { - // Easy, one handle is given, directly. - handles.push_back(handle); - } - - // MaximumAttributeByteCount, AttributeIDList and ContinuationState is handled by InternalOnServiceSearchAttributeRequest(). - - return (PDU::Success); - - }, socket, request, handlerCb); - } - - void Server::OnServiceSearchAttributeRequest(const ServerSocket& socket, const PDU& request, const Handler& handlerCb) - { - InternalOnServiceSearchAttributeRequest(PDU::ServiceSearchAttributeResponse, - [&](const Payload& payload, std::list& handles) -> PDU::errorid { - - // ServiceSearchAttribute frame format: - // - ServiceSearchPattern (sequence of UUIDs) - // - MaximumAttributeByteCount (word) - // - AttributeIDList (sequence of UUID ranges or UUIDs) - // - ContinuationState - - std::list uuids; - - // Pick up UUIDs of interest... - payload.Pop(use_descriptor, [&](const Payload& sequence) { - while (sequence.Available() >= 2 /* min UUID size */) { - UUID uuid; - - sequence.Pop(use_descriptor, uuid); - - TRACE_L1("ServiceSearchPattern[%d]=%s '%s'", uuids.size(), uuid.ToString().c_str(), ClassID(uuid).Name().c_str()); - - if (uuid.IsValid() == true) { - uuids.push_back(uuid); - } - else { - TRACE_L1("SDP server: Invalid UUID in ServiceSearchRequest payload!"); - } - } - - if (sequence.Available() != 0) { - TRACE_L1("SDP server: Unexpected data ServiceSearchRequest payload!"); - } - }); - - if (uuids.empty() == false) { - // Now have to find the handles that have anything to do with the UUIDs recieved. - - WithServiceTree([&](const Tree& tree) { - for (auto const& service : tree.Services()) { - for (auto const& uuid : uuids) { - if (service.Search(uuid) == true) { - handles.push_back(service.Handle()); - } - } - } - }); - } - - TRACE_L1("SDP server: Found %d service(s) matching the search patterns", handles.size()); - - return (uuids.empty() == true? PDU::InvalidRequestSyntax : PDU::Success); - - }, socket, request, handlerCb); - } - - /* private */ - std::map Server::SerializeAttributesByRange(const Service& service, const std::list& attributeRanges, const uint16_t offset, uint16_t& count) const - { - std::map attributes; - - for (uint32_t range : attributeRanges) { - const uint16_t standardLeft = std::max(Service::AttributeDescriptor::ServiceRecordHandle, (range >> 16)); - const uint16_t standardRight = std::min(Service::AttributeDescriptor::IconURL, (range & 0xFFFF)); - - // Universal attributes. - for (uint16_t id = standardLeft; id <= standardRight; id++) { - Buffer buffer = service.Serialize(id); - - if (buffer.empty() == false) { - if (count >= offset) { - attributes.emplace(id, std::move(buffer)); - } - - count++; - } - } - - // custom attributes - for (auto const& attr : service.Attributes()) { - if ((attr.Id() >= std::max(0x100, (range >> 16))) && (attr.Id() <= (range & 0xFFFF))) { - if (count >= offset) { - attributes.emplace(attr.Id(), attr.Value()); - } - - count++; - } - } - } - - return (attributes); - } - -} // namespace SDP - -} // namespace Bluetooth - -} \ No newline at end of file diff --git a/Source/bluetooth/audio/SDPProfile.h b/Source/bluetooth/audio/SDPProfile.h deleted file mode 100644 index 55065c3..0000000 --- a/Source/bluetooth/audio/SDPProfile.h +++ /dev/null @@ -1,1278 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2021 Metrological - * - * 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. - */ - -#pragma once - -#include "Module.h" -#include "SDPSocket.h" - -#include - - -namespace Thunder { - -namespace Bluetooth { - -namespace SDP { - - static constexpr uint16_t CHARSET_US_ASCII = 3; - static constexpr uint16_t CHARSET_UTF8 = 106; - - class EXTERNAL ClassID { - public: - enum id : uint16_t { - Undefined = 0x0000, - - // Protocols - SDP = 0x0001, - UDP = 0x0002, - RFCOMM = 0x0003, - TCP = 0x0004, - TCS_BIN = 0x0005, - TCS_AT = 0x0006, - ATT = 0x0007, - OBEX = 0x0008, - IP = 0x0009, - FTP = 0x000a, - HTTP = 0x000c, - WSP = 0x000e, - BNEP = 0x000f, - UPNP = 0x0010, - HIDP = 0x0011, - HCRP_CTRL = 0x0012, - HCRP_DATA = 0x0014, - HCRP_NOTE = 0x0016, - AVCTP = 0x0017, - AVDTP = 0x0019, - CMTP = 0x001b, - UDI = 0x001d, - MCAP_CTRL = 0x001e, - MCAP_DATA = 0x001f, - L2CAP = 0x0100, - - // SDP itself - ServiceDiscoveryServer = 0x1000, // Service - BrowseGroupDescriptor = 0x1001, - PublicBrowseRoot = 0x1002, - - // Services and Profiles - SerialPort = 0x1101, // Service + Profile - LANAccessUsingPPP = 0x1102, // Service + Profile - DialupNetworking = 0x1103, // Service + Profile - IrMCSync = 0x1104, // Service + Profile - OBEXObjectPush = 0x1105, // Service + Profile - OBEXFileTransfer = 0x1106, // Service + Profile - IrMCSyncCommand = 0x1107, // Service - HeadsetHSP = 0x1108, // Service + Profile - CordlessTelephony = 0x1109, // Service + Profile - AudioSource = 0x110A, // Service - AudioSink = 0x110B, // Service - AVRemoteControlTarget = 0x110C, // Service - AdvancedAudioDistribution = 0x110D, // Profile - AVRemoteControl = 0x110E, // Service + Profile - AVRemoteControlController = 0x110F, // Service - Intercom = 0x1110, // Service + Profile - Fax = 0x1111, // Service + Profile - HeadsetAudioGateway = 0x1112, // Service - WAP = 0x1113, // Service - WAPClient = 0x1114, // Service - PANU = 0x1115, // Service + Profile - NAP = 0x1116, // Service + Profile - GN = 0x1117, // Service + Profile - DirectPrinting = 0x1118, // Service - ReferencePrinting = 0x1119, // Service - BasicImagingProfile = 0x111A, // Profile - ImagingResponder = 0x111B, // Service - ImagingAutomaticArchive = 0x111C, // Service - ImagingReferencedObjects = 0x111D, // Service - Handsfree = 0x111E, // Service + Profile - HandsfreeAudioGateway = 0x111F, // Service - DirectPrintingReferenceObjects = 0x1120, // Service - ReflectedUI = 0x1121, // Service - BasicPrinting = 0x1122, // Profile - PrintingStatus = 0x1123, // Service - HumanInterfaceDeviceService = 0x1124, // Service + Profile - HardcopyCableReplacement = 0x1125, // Profile - HCRPrint = 0x1126, // Service - HCRScan = 0x1127, // Service - CommonISDNAccess = 0x1128, // Service + Profile - SIMAccess = 0x112D, // Service + Profile - PhonebookAccessPCE = 0x112E, // Service - PhonebookAccessPSE = 0x112F, // Service - PhonebookAccess = 0x1130, // Profile - HeadsetHS = 0x1131, // Service - MessageAccessServer = 0x1132, // Service - MessageNotificationServer = 0x1133, // Service - MessageAccess = 0x1134, // Profile - GNSS = 0x1135, // Profile - GNSSServer = 0x1136, // Service - ThreeDDisplay = 0x1137, // Service - ThreeDGlasses = 0x1138, // Service - ThreeDSynchronisation = 0x1339, // Profile - MPS = 0x113A, // Profile - MPSSC = 0x113B, // Service - CTNAccessService = 0x113C, // Service - CTNNotificationService = 0x113D, // Service - CTN = 0x113E, // Profile - PnPInformation = 0x1200, // Service - GenericNetworking = 0x1201, // Service - GenericFileTransfer = 0x1202, // Service - GenericAudio = 0x1203, // Service - GenericTelephony = 0x1204, // Service - UPNPService = 0x1205, // Service - UPNPIPService = 0x1206, // Service - ESDPUPNPIPPAN = 0x1300, // Service - ESDPUPNPIPLAP = 0x1301, // Service - ESDPUPNPL2CAP = 0x1302, // Service - VideoSource = 0x1303, // Service - VideoSink = 0x1304, // Service - VideoDistribution = 0x1305, // Profile - HDP = 0x1400, // Profile - HDPSource = 0x1401, // Service - HDPSink = 0x1402 // Service - }; - - public: - ClassID() - : _id() - { - } - ClassID(const ClassID& other) - : _id(other._id) - { - } - ClassID(const id& classId) - : _id(UUID(classId)) - { - } - ClassID(const UUID& uuid) - : _id(uuid) - { - } - ~ClassID() = default; - - public: - ClassID& operator=(const ClassID& rhs) - { - _id = rhs._id; - return (*this); - } - bool operator==(const ClassID& rhs) const - { - return (_id == rhs._id); - } - bool operator!=(const ClassID& rhs) const - { - return !(*this == rhs); - } - bool operator<(const ClassID& rhs) const - { - return (_id < rhs._id); - } - - public: - const UUID& Type() const - { - return (_id); - } - const string Name() const - { - string name; - if (_id.HasShort() == true) { - id input = static_cast(_id.Short()); - Core::EnumerateType value(input); - name = (value.IsSet() == true? string(value.Data()) : _id.ToString(false)); - } - if (name.empty() == true) { - name = _id.ToString(); - } - return (name); - } - - private: - UUID _id; - }; // class ClassID - - class EXTERNAL Service { - public: - class EXTERNAL AttributeDescriptor { - public: - // universal attributes - enum id : uint16_t { - // required - ServiceRecordHandle = 0x0000, - ServiceClassIDList = 0x0001, - // optional - ServiceRecordState = 0x0002, - ServiceID = 0x0003, - ProtocolDescriptorList = 0x0004, - BrowseGroupList = 0x0005, - LanguageBaseAttributeIDList = 0x0006, - ServiceInfoTimeToLive = 0x0007, - ServiceAvailability = 0x0008, - ProfileDescriptorList = 0x0009, - DocumentationURL = 0x000a, - ClientExecutableURL = 0x000b, - IconURL = 0x000c, - }; - - static constexpr uint16_t ServiceNameOffset = 0; - static constexpr uint16_t ServiceDescriptionOffset = 1; - static constexpr uint16_t ProviderNameOffset = 2; - - // specific to Advanced Audio Distribution - enum class a2dp : uint16_t { - SupportedFeatures = 0x0311 - }; - - // specfic to AVRemoteControl profile - enum class avcrp : uint16_t { - SupportedFeatures = 0x0311 - }; - - // specific to Basic Imaging profile - enum class bip : uint16_t { - GoepL2capPsm = 0x0200, - SupportedCapabilities = 0x0300, - SupportedFeatures = 0x0311, - SupportedFunctions = 0x0312, - TotalImagingDataCapacity = 0x0313 - }; - - // specific to PnPInformation profile - enum class did : uint16_t { - SpecificationID = 0x0200, - VendorID = 0x0201, - ProductID = 0x0202, - Version = 0x0203, - PrimaryRecord = 0x0204, - VendorIDSource = 0x0205 - }; - - public: - AttributeDescriptor() = delete; - AttributeDescriptor(const AttributeDescriptor&) = delete; - AttributeDescriptor& operator=(const AttributeDescriptor&) = delete; - - template - AttributeDescriptor(const uint16_t id, T&& value) - : _id(id) - , _value(std::forward(value)) - { - TRACE_L5("AttributeDescriptor: adding raw attribute 0x%04x", id); - } - - ~AttributeDescriptor() = default; - - public: - bool operator==(const AttributeDescriptor& rhs) const - { - return (_id == rhs._id); - } - bool operator!=(const AttributeDescriptor& rhs) const - { - return !(*this == rhs); - } - bool operator<(const AttributeDescriptor& rhs) const - { - return (_id < rhs._id); - } - - public: - uint32_t Id() const - { - return (_id); - } - const Buffer& Value() const - { - return (_value); - } - string Name() const - { - Core::EnumerateType value(_id); - string name = (value.IsSet() == true? string(value.Data()) : _T("")); - return (name); - } - - private: - uint16_t _id; - Buffer _value; - }; // class AttributeDescriptor - - struct Data { - template - class EXTERNAL Element { - public: - Element() = delete; - Element(const Element&) = default; - Element& operator=(const Element&) = default; - - Element(T&& data) - : _data(std::move(data)) - { - } - Element(const T& data) - : _data(data) - { - } - Element(const Buffer& buffer) - : _data() - { - const Payload payload(buffer); - if (payload.Available() > 0) { - payload.Pop(use_descriptor, _data); - } - } - ~Element() = default; - - public: - const T& Value() const - { - return (_data); - } - - public: - operator Buffer() const - { - uint8_t scratchpad[256]; - Payload payload(scratchpad, sizeof(scratchpad), 0); - payload.Push(use_descriptor, _data); - return (payload); - } - - private: - T _data; - }; // class Element - }; // struct Data - - struct Protocol { - public: - class EXTERNAL L2CAP : public Data::Element { - public: - using Element::Element; - L2CAP(const L2CAP&) = default; - L2CAP& operator=(const L2CAP&) = default; - ~L2CAP() = default; - - public: - uint16_t PSM() const - { - return (Value()); - } - }; // class L2CAP - - class EXTERNAL AVDTP : public Data::Element { - public: - using Element::Element; - AVDTP(const AVDTP&) = default; - AVDTP& operator=(const AVDTP&) = default; - ~AVDTP() = default; - - public: - uint16_t Version() const - { - return (Value()); - } - }; // class AVDTP - }; // struct Protocol - - struct Attribute { - class EXTERNAL ServiceRecordHandle { - public: - static constexpr auto type = AttributeDescriptor::ServiceRecordHandle; - - public: - ServiceRecordHandle() - : _handle(0) - { - } - ServiceRecordHandle(const uint32_t handle) - : _handle(handle) - { - } - ServiceRecordHandle(const uint8_t buffer[], const uint16_t size) - { - uint32_t handle{}; - const Payload payload(buffer, size); - payload.Pop(use_descriptor, handle); - Handle(handle); - } - ServiceRecordHandle(const ServiceRecordHandle&) = delete; - ServiceRecordHandle& operator=(const ServiceRecordHandle&) = delete; - ~ServiceRecordHandle() = default; - - public: - operator Buffer() const - { - uint8_t scratchPad[8]; - Payload payload(scratchPad, sizeof(scratchPad), 0); - payload.Push(use_descriptor, _handle); - return (payload); - } - - public: - void Handle(const uint32_t handle) - { - TRACE_L5("ServiceRecordHandle: handle 0x%08x", handle); - _handle = handle; - } - uint32_t Handle() const - { - return (_handle); - } - - private: - uint32_t _handle; - }; // class ServiceRecordHandle - - class EXTERNAL ServiceClassIDList { - public: - static constexpr auto type = AttributeDescriptor::ServiceClassIDList; - - public: - ServiceClassIDList() - : _classes() - { - } - ServiceClassIDList(const uint8_t buffer[], const uint16_t size) - { - const Payload payload(buffer, size); - payload.Pop(use_descriptor, [&](const Payload& sequence) { - while (sequence.Available() > 0) { - UUID uuid; - sequence.Pop(use_descriptor, uuid); - Add(uuid); - } - }); - } - ServiceClassIDList(const ServiceRecordHandle&) = delete; - ServiceClassIDList& operator=(const ServiceRecordHandle&) = delete; - ~ServiceClassIDList() = default; - - public: - operator Buffer() const - { - uint8_t scratchPad[256]; - Payload payload(scratchPad, sizeof(scratchPad), 0); - payload.Push(use_descriptor, [this](Payload& sequence) { - for (auto const& classId : Classes()) { - sequence.Push(use_descriptor, classId.Type()); - } - }); - - return (payload); - } - - public: - void Add(const ClassID& classId) - { - TRACE_L5("ServiceClassIDList: Added class %s '%s'", classId.Type().ToString().c_str(), classId.Name().c_str()); - _classes.emplace(classId); - } - const std::set& Classes() const - { - return (_classes); - } - bool HasID(const UUID& id) const - { - return (_classes.find(id) != _classes.cend()); - } - - private: - std::set _classes; - }; // class ServiceClassIDList - - class EXTERNAL ProtocolDescriptorList { - public: - static constexpr auto type = AttributeDescriptor::ProtocolDescriptorList; - - public: - ProtocolDescriptorList() - : _protocols() - { - } - ProtocolDescriptorList(const uint8_t buffer[], const uint16_t size) - { - const Payload payload(buffer, size); - payload.Pop(use_descriptor, [&](const Payload& sequence) { - while (sequence.Available() > 0) { - sequence.Pop(use_descriptor, [&](const Payload& record) { - UUID uuid; - Buffer params; - record.Pop(use_descriptor, uuid); - record.Pop(params, record.Available()); // No descriptor! Just take everything what's left in this record. - Add(uuid, params); - }); - } - }); - } - ProtocolDescriptorList(const ProtocolDescriptorList&) = delete; - ProtocolDescriptorList& operator=(const ProtocolDescriptorList&) = delete; - ~ProtocolDescriptorList() = default; - - public: - operator Buffer() const - { - uint8_t scratchPad[256]; - Payload payload(scratchPad, sizeof(scratchPad), 0); - payload.Push(use_descriptor, [this](Payload& sequence) { - for (auto const& kv : Protocols()) { - sequence.Push(use_descriptor, [&kv](Payload& record) { - record.Push(use_descriptor, kv.first.Type()); - record.Push(kv.second); // no descriptor here! - }); - } - }); - - return (payload); - } - - public: - template - void Add(const ClassID& id, T&& data) - { - TRACE_L5("ProtocolDescriptorList: added %s '%s'", id.Type().ToString().c_str(), id.Name().c_str()); - _protocols.emplace(id, std::forward(data)); - } - const std::map& Protocols() const - { - return (_protocols); - } - const Buffer* Protocol(const UUID& id) const - { - auto const& it = _protocols.find(id); - if (it != _protocols.cend()) { - return (&(*it).second); - } else { - return (nullptr); - } - } - - private: - std::map _protocols; - }; // class ProtocolDescriptorList - - class EXTERNAL BrowseGroupList : public ServiceClassIDList { - public: - static constexpr auto type = AttributeDescriptor::BrowseGroupList; - - public: - using ServiceClassIDList::ServiceClassIDList; - BrowseGroupList(const BrowseGroupList&) = delete; - BrowseGroupList& operator=(const BrowseGroupList&) = delete; - ~BrowseGroupList() = default; - }; // class BrowseGroupList - - class LanguageBaseAttributeIDList { - public: - static constexpr auto type = AttributeDescriptor::LanguageBaseAttributeIDList; - - public: - class Triplet { - public: - Triplet() = delete; - Triplet(const Triplet&) = default; - Triplet& operator=(const Triplet&) = default; - - Triplet(const uint16_t language, const uint16_t charset, const uint16_t base) - : _language(language) - , _charset(charset) - , _base(base) - { - } - - ~Triplet() = default; - - public: - uint16_t Language() const - { - return (_language); - } - uint16_t Charset() const - { - return (_charset); - } - uint16_t Base() const - { - return (_base); - } - - private: - uint16_t _language; - uint16_t _charset; - uint16_t _base; - }; - - public: - LanguageBaseAttributeIDList() - : _languageBases() - , _freeBase(0x100) - { - } - LanguageBaseAttributeIDList(const uint8_t buffer[], const uint16_t size) - { - const Payload payload(buffer, size); - payload.Pop(use_descriptor, [&](const Payload& sequence) { - while (sequence.Available() > 0) { - uint16_t lang = 0; - uint16_t charset = 0; - uint16_t base = 0; - - sequence.Pop(use_descriptor, lang); - sequence.Pop(use_descriptor, charset); - sequence.Pop(use_descriptor, base); - - Add(lang, charset, base); - } - }); - } - LanguageBaseAttributeIDList(const LanguageBaseAttributeIDList&) = delete; - LanguageBaseAttributeIDList& operator=(const LanguageBaseAttributeIDList&) = delete; - ~LanguageBaseAttributeIDList() = default; - - public: - operator Buffer() const - { - uint8_t scratchPad[256]; - Payload payload(scratchPad, sizeof(scratchPad), 0); - payload.Push(use_descriptor, [this](Payload& sequence) { - for (auto const& entry : LanguageBases()) { - sequence.Push(use_descriptor, entry.Language()); - sequence.Push(use_descriptor, entry.Charset()); - sequence.Push(use_descriptor, entry.Base()); - } - }); - - return (payload); - } - - public: - void Add(const uint16_t language, const uint16_t charset, const uint16_t base) - { - TRACE_L5("LanguageBaseAttributeIDList: added 0x%04x 0x%04x 0x%04x", language, charset, base); - _languageBases.emplace_back(language, charset, base); - _freeBase = base + 3; - } - void Add(const string& language, const uint16_t charset, const uint16_t base) - { - ASSERT(language.size() == 2); - Add(ToCode(language), charset, base); - } - uint16_t Add(const string& language = _T("en"), const uint16_t charset = CHARSET_US_ASCII) - { - const uint16_t base = _freeBase; - Add(language, charset, base); - return (base); - } - - public: - const std::list& LanguageBases() const - { - return (_languageBases); - } - uint16_t LanguageBase(const uint16_t language, const uint16_t charset) const - { - auto const& it = std::find_if(_languageBases.cbegin(), _languageBases.cend(), - [&](const Triplet& entry) { return ((entry.Language() == language) && (entry.Charset() == charset)); }); - - if (it != _languageBases.cend()) { - return ((*it).Base()); - } else { - return (0); - } - } - uint16_t LanguageBase(const uint16_t language) const - { - auto const& it = std::find_if(_languageBases.cbegin(), _languageBases.cend(), - [&](const Triplet& entry) { return (entry.Language() == language); }); - - if (it != _languageBases.cend()) { - return ((*it).Base()); - } else { - return (0); - } - } - uint16_t LanguageBase(const string& language, const uint16_t charset) const - { - return (LanguageBase(ToCode(language), charset)); - } - uint16_t LanguageBase(const string& language) const - { - return (LanguageBase(ToCode(language))); - } - - private: - static uint16_t ToCode(const string& language) - { - return ((static_cast(language[0]) << 8) | language[1]); - } - - private: - std::list _languageBases; - uint16_t _freeBase; - }; // class LanguageBaseAttributeIDList - - class EXTERNAL ProfileDescriptorList { - public: - static constexpr auto type = AttributeDescriptor::ProfileDescriptorList; - - public: - class Data { - public: - Data() = delete; - Data(const Data&) = delete; - Data& operator=(const Data&) = delete; - - Data(const uint16_t version) - : _version(version) - { - } - - ~Data() = default; - - public: - uint16_t Version() const - { - return (_version); - } - - private: - uint16_t _version; - }; // class Data - - public: - ProfileDescriptorList() - : _profiles() - { - } - ProfileDescriptorList(const uint8_t buffer[], const uint16_t size) - { - const Payload payload(buffer, size); - payload.Pop(use_descriptor, [&](const Payload& sequence) { - while (sequence.Available() > 0) { - sequence.Pop(use_descriptor, [&](const Payload& record) { - UUID uuid; - uint16_t version{}; - record.Pop(use_descriptor, uuid); - record.Pop(use_descriptor, version); - Add(uuid, version); - }); - } - }); - } - ProfileDescriptorList(const ProfileDescriptorList&) = delete; - ProfileDescriptorList& operator=(const ProfileDescriptorList&) = delete; - ~ProfileDescriptorList() = default; - - public: - operator Buffer() const - { - uint8_t scratchPad[256]; - Payload payload(scratchPad, sizeof(scratchPad), 0); - payload.Push(use_descriptor, [this](Payload& sequence) { - for (auto const& kv : Profiles()) { - sequence.Push(use_descriptor, [&kv](Payload& record) { - record.Push(use_descriptor, kv.first.Type()); - record.Push(use_descriptor, kv.second.Version()); - }); - } - }); - - return (payload); - } - - public: - void Add(const ClassID& id, const uint16_t version) - { - TRACE_L5("ProfileDescriptorList: added %s '%s'", id.Type().ToString().c_str(), id.Name().c_str()); - _profiles.emplace(id, version); - } - const std::map& Profiles() const - { - return (_profiles); - } - const Data* Profile(const UUID& id) const - { - auto const& it = _profiles.find(id); - if (it != _profiles.cend()) { - return (&(*it).second); - } else { - return (nullptr); - } - } - - private: - std::map _profiles; - }; // class ProfileDescriptorList - }; // struct Attribute - - public: - Service() = delete; - Service(const Service&) = delete; - Service& operator=(const Service&) = delete; - - Service(const uint32_t handle) - : _enabled(false) - , _serviceRecordHandle(nullptr) - , _serviceClassIDList(nullptr) - , _protocolDescriptorList(nullptr) - , _browseGroupList(nullptr) - , _languageBaseAttributeIDList(nullptr) - , _profileDescriptorList(nullptr) - { - if (handle != 0) { - ServiceRecordHandle()->Handle(handle); - } - } - - ~Service() - { - delete _serviceRecordHandle; - delete _serviceClassIDList; - delete _protocolDescriptorList; - delete _browseGroupList; - delete _languageBaseAttributeIDList; - delete _profileDescriptorList; - } - public: - void Deserialize(const uint16_t id, const Buffer& buffer) - { - Add(id, buffer, _serviceRecordHandle, - _serviceClassIDList, - _protocolDescriptorList, - _browseGroupList, - _languageBaseAttributeIDList, - _profileDescriptorList); - } - Buffer Serialize(const uint16_t id) const - { - return (Descriptor(id, _serviceRecordHandle, - _serviceClassIDList, - _protocolDescriptorList, - _browseGroupList, - _languageBaseAttributeIDList, - _profileDescriptorList)); - } - - public: - uint32_t Handle() const - { - return (ServiceRecordHandle() == nullptr? 0 : ServiceRecordHandle()->Handle()); - } - bool HasClassID(const UUID& id) const - { - return (ServiceClassIDList() == nullptr? false : ServiceClassIDList()->HasID(id)); - } - bool IsInBrowseGroup(const UUID& id) const - { - return (BrowseGroupList() == nullptr? false : BrowseGroupList()->HasID(id)); - } - const Buffer* Protocol(const UUID& id) const - { - return (ProtocolDescriptorList() == nullptr? nullptr : ProtocolDescriptorList()->Protocol(id)); - } - const Attribute::ProfileDescriptorList::Data* Profile(const UUID& id) const - { - return (ProfileDescriptorList() == nullptr? 0 : ProfileDescriptorList()->Profile(id)); - } - template::value, int>::type = 0> - const Buffer* Attribute(const TYPE id) const - { - // enum class is not implicitly convertible to its underlying type - return (Attribute(static_cast(id))); - } - const Buffer* Attribute(const uint16_t id) const - { - auto const& it = std::find_if(_attributes.cbegin(), _attributes.cend(), [&](const AttributeDescriptor& attr) { return (attr.Id() == id); }); - return (it == _attributes.cend()? nullptr : &(*it).Value()); - } - bool Search(const UUID& id) const - { - return ((IsEnabled() == true) && ((HasClassID(id) == true) || (IsInBrowseGroup(id) == true) || (Protocol(id) != nullptr) || (Profile(id) != 0))); - } - string Name() const - { - string name{}; - - if (LanguageBaseAttributeIDList() != nullptr) { - uint16_t lb = LanguageBaseAttributeIDList()->LanguageBase("en", CHARSET_US_ASCII); - if (lb == 0) { - lb = LanguageBaseAttributeIDList()->LanguageBase("en", CHARSET_UTF8); - } - - if (lb != 0) { - const Buffer* buffer = Attribute(lb + AttributeDescriptor::ServiceNameOffset); - if (buffer != nullptr) { - name = Data::Element(*buffer).Value(); - } - } - } - - return (name); - } - bool Metadata(string& name, string& description, string& provider, const string& language = _T("en"), const uint16_t charset = CHARSET_US_ASCII) const - { - bool result = false; - - if (LanguageBaseAttributeIDList() != nullptr) { - uint16_t lb = LanguageBaseAttributeIDList()->LanguageBase(language, charset); - if (lb != 0) { - const Buffer* buffer = Attribute(lb + AttributeDescriptor::ServiceNameOffset); - if (buffer != nullptr) { - name = Data::Element(*buffer).Value(); - } - - buffer = Attribute(lb + AttributeDescriptor::ServiceDescriptionOffset); - if (buffer != nullptr) { - description = Data::Element(*buffer).Value(); - } - - buffer = Attribute(lb + AttributeDescriptor::ProviderNameOffset); - if (buffer != nullptr) { - provider = Data::Element(*buffer).Value(); - } - - result = true; - } - } - - return (result); - } - - public: - void Enable(const bool enable) - { - _enabled = enable; - } - bool IsEnabled() const - { - return (_enabled); - } - Attribute::ServiceRecordHandle* ServiceRecordHandle() - { - if (_serviceRecordHandle == nullptr) { - _serviceRecordHandle = new Attribute::ServiceRecordHandle(); - ASSERT(_serviceRecordHandle != nullptr); - } - return (_serviceRecordHandle); - } - const Attribute::ServiceRecordHandle* ServiceRecordHandle() const - { - return (_serviceRecordHandle); - } - Attribute::ServiceClassIDList* ServiceClassIDList() - { - if (_serviceClassIDList == nullptr) { - _serviceClassIDList = new Attribute::ServiceClassIDList(); - ASSERT(_serviceClassIDList != nullptr); - } - return (_serviceClassIDList); - } - const Attribute::ServiceClassIDList* ServiceClassIDList() const - { - return (_serviceClassIDList); - } - Attribute::ProtocolDescriptorList* ProtocolDescriptorList() - { - if (_protocolDescriptorList == nullptr) { - _protocolDescriptorList = new Attribute::ProtocolDescriptorList(); - ASSERT(_protocolDescriptorList != nullptr); - } - return (_protocolDescriptorList); - } - const Attribute::ProtocolDescriptorList* ProtocolDescriptorList() const - { - return (_protocolDescriptorList); - } - Attribute::BrowseGroupList* BrowseGroupList() - { - if (_browseGroupList == nullptr) { - _browseGroupList = new Attribute::BrowseGroupList(); - ASSERT(_browseGroupList != nullptr); - } - return (_browseGroupList); - } - const Attribute::BrowseGroupList* BrowseGroupList() const - { - return (_browseGroupList); - } - Attribute::LanguageBaseAttributeIDList* LanguageBaseAttributeIDList() - { - if (_languageBaseAttributeIDList == nullptr) { - _languageBaseAttributeIDList = new Attribute::LanguageBaseAttributeIDList(); - ASSERT(_languageBaseAttributeIDList != nullptr); - } - return (_languageBaseAttributeIDList); - } - const Attribute::LanguageBaseAttributeIDList* LanguageBaseAttributeIDList() const - { - return (_languageBaseAttributeIDList); - } - Attribute::ProfileDescriptorList* ProfileDescriptorList() - { - if (_profileDescriptorList == nullptr) { - _profileDescriptorList = new Attribute::ProfileDescriptorList(); - ASSERT(_profileDescriptorList != nullptr); - } - return (_profileDescriptorList); - } - const Attribute::ProfileDescriptorList* ProfileDescriptorList() const - { - return (_profileDescriptorList); - } - - public: - std::set& Attributes() - { - return (_attributes); - } - const std::set& Attributes() const - { - return (_attributes); - } - - public: - void Add(const uint16_t id, const Buffer& buffer) - { - if (buffer.empty() == false) { - _attributes.emplace(id, buffer); - } - } - template::value, int>::type = 0> - void Add(const TYPE id, const Buffer& buffer) - { - // enum class is not implicitly convertible to its underlying type - Add(static_cast(id), buffer); - } - template - void Description(const std::string& name, const std::string& description = {}, const std::string& provider = {}, Args... args) - { - uint16_t id = LanguageBaseAttributeIDList()->Add(args...); - - if (name.empty() == false) { - Add(id + AttributeDescriptor::ServiceNameOffset, Data::Element(name)); - } - - if (description.empty() == false) { - Add(id + AttributeDescriptor::ServiceDescriptionOffset, Data::Element(description)); - } - - if (provider.empty() == false) { - Add(id + AttributeDescriptor::ProviderNameOffset, Data::Element(provider)); - } - } - - private: - template - void Add(const uint16_t id, const Buffer& buffer, T& attribute, Ts&... attributes) - { - if (buffer.size() != 0) { - using Attribute = typename std::remove_pointer::type; - - if (id == Attribute::type) { - if (attribute == nullptr) { - attribute = new Attribute(buffer.data(), buffer.size()); - ASSERT(attribute != nullptr); - -#ifdef __DEBUG__ - // In debug, store all the attributes in raw form for inspection. - Add(id, buffer); -#endif - } - } else { - Add(id, buffer, attributes...); - // Once the attribute list for deserialisation is recursively exhausted - // this will fall back to storing raw attributes. - } - } - } - - private: - template - Buffer Descriptor(const uint16_t id, const T attribute, const Ts... attributes) const - { - using Attribute = typename std::remove_pointer::type; - - if (id == Attribute::type) { - return (attribute != nullptr? *attribute : Buffer{}); - } else { - return Descriptor(id, attributes...); - } - } - Buffer Descriptor(const uint16_t) const - { - // Just to stop the recursive attribute serialisation. - return {}; - } - - private: - bool _enabled; - Attribute::ServiceRecordHandle* _serviceRecordHandle; - Attribute::ServiceClassIDList* _serviceClassIDList; - Attribute::ProtocolDescriptorList* _protocolDescriptorList; - Attribute::BrowseGroupList* _browseGroupList; - Attribute::LanguageBaseAttributeIDList* _languageBaseAttributeIDList; - Attribute::ProfileDescriptorList* _profileDescriptorList; - std::set _attributes; - }; // class Service - - class EXTERNAL Tree { - public: - Tree(const Tree&) = delete; - Tree& operator=(const Tree&) = delete; - ~Tree() = default; - - Tree() - : _services() - { - } - - public: - const std::list& Services() const - { - return (_services); - } - const SDP::Service* Find(const uint32_t handle) const - { - auto const& it = std::find_if(_services.cbegin(), _services.cend(), [&](const Service& s) { return (s.Handle() == handle); }); - return (it == _services.cend()? nullptr : &(*it)); - } - Service& Add(const uint32_t handle = 0) - { - _services.emplace_back(handle == 0? (0x10000 + _services.size()) : handle); - Service& added = _services.back(); - return (added); - } - - protected: - std::list _services; - }; // class Tree - - class EXTERNAL Client { - public: - Client() = delete; - Client(const Client&) = delete; - Client& operator=(const Client&) = delete; - ~Client() = default; - - Client(ClientSocket& socket) - : _socket(socket) - { - } - - public: - uint32_t Discover(const std::list& services, Tree& tree) const; - - public: - uint32_t ServiceSearch(const std::list& services, std::vector& outHandles) const; - - uint32_t ServiceAttribute(const uint32_t serviceHandle, - const std::list& attributeIdRanges, - std::list>& outAttributes) const; - - uint32_t ServiceSearchAttribute(const std::list& services, - const std::list& attributeIdRanges, - std::list>& outAttributes) const; - - private: - uint32_t InternalServiceAttribute(const PDU::pduid id, - const std::function& buildCb, - const std::list& attributeIdRanges, - std::list>& outAttributes) const; - - private: - uint32_t Execute(ClientSocket::Command& cmd, const Payload::Inspector& inspectorCb = nullptr) const; - - private: - uint16_t Capacity(const PDU& pdu) const - { - const uint16_t bufferSize = std::min(pdu.Capacity(), (_socket.InputMTU() - PDU::HeaderSize)); - ASSERT(bufferSize >= (1 + PDU::MaxContinuationSize)); - - return (bufferSize - (1 + PDU::MaxContinuationSize)); - } - - private: - ClientSocket& _socket; - }; // class Client - - class EXTERNAL Server { - using Handler = ServerSocket::ResponseHandler; - - public: - Server() = default; - Server(const Server&) = delete; - Server& operator=(const Server&) = delete; - virtual ~Server() = default; - - public: - virtual void WithServiceTree(const std::function& inspectCb) = 0; - - public: - void OnPDU(const ServerSocket& socket, const PDU& pdu, const Handler& handler) - { - switch (pdu.Type()) { - case PDU::ServiceSearchRequest: - OnServiceSearchRequest(socket, pdu, handler); - break; - case PDU::ServiceAttributeRequest: - OnServiceAttributeRequest(socket, pdu, handler); - break; - case PDU::ServiceSearchAttributeRequest: - OnServiceSearchAttributeRequest(socket, pdu, handler); - break; - default: - TRACE_L1("SDP server: Usupported PDU %d", pdu.Type()); - handler(PDU::InvalidRequestSyntax); - break; - } - } - - private: - void OnServiceSearchRequest(const ServerSocket& socket, const PDU& pdu, const Handler& handler); - void OnServiceAttributeRequest(const ServerSocket& socket, const PDU& pdu, const Handler& handler); - void OnServiceSearchAttributeRequest(const ServerSocket& socket, const PDU& pdu, const Handler& handler); - - private: - void InternalOnServiceSearchAttributeRequest(const PDU::pduid id, - const std::function&)>& inspectCb, - const ServerSocket& socket, - const PDU& request, - const Handler& handlerCb); - - std::map SerializeAttributesByRange(const Service& service, const std::list& attributeRanges, - const uint16_t offset, uint16_t& count) const; - - - private: - uint16_t Capacity(const ServerSocket& socket, const PDU& pdu) const - { - const uint16_t bufferSize = std::min(pdu.Capacity(), (socket.OutputMTU() - PDU::HeaderSize)); - ASSERT(bufferSize >= (1 + PDU::MaxContinuationSize)); - - return (bufferSize - (1 + PDU::MaxContinuationSize)); - } - - }; // class Server - -} // namespace SDP - -} // namespace Bluetooth - -} \ No newline at end of file diff --git a/Source/bluetooth/audio/SDPSocket.cpp b/Source/bluetooth/audio/SDPSocket.cpp deleted file mode 100644 index da353b9..0000000 --- a/Source/bluetooth/audio/SDPSocket.cpp +++ /dev/null @@ -1,232 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2021 Metrological - * - * 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. - */ - -#include "Module.h" -#include "SDPSocket.h" - -namespace Thunder { - -namespace Bluetooth { - -namespace SDP { - - void Payload::PushDescriptor(const elementtype type, const uint32_t size) - { - ASSERT(_buffer != nullptr); - ASSERT(Free() >= 1); - - uint8_t* buffer = &_buffer[_writerOffset]; - uint32_t offset = 0; - - buffer[offset++] = (type | SIZE_8); - - switch (type) { - case NIL: - ASSERT(size == 0); - // Exception: even if size descriptor says BYTE, for NIL type there's no data following. - break; - case BOOL: - ASSERT(size == 1); - break; - case INT: - case UINT: - if (size == 1) { - // already set - } else if (size == 2) { - buffer[0] |= SIZE_16; - } else if (size == 4) { - buffer[0] |= SIZE_32; - } else if (size == 8) { - buffer[0] |= SIZE_64; - } else { - ASSERT(false && "Invalid INT size"); - } - break; - case UUID: - if (size == 2) { - buffer[0] |= SIZE_16; - } else if (size == 4) { - buffer[0] |= SIZE_32; - } else if (size == 16) { - buffer[0] |= SIZE_128; - } else { - ASSERT(false && "Invalid UUID size"); - } - break; - case TEXT: - case SEQ: - case ALT: - case URL: - if (size <= 0xFF) { - ASSERT(Free() >= 1); - buffer[0] |= SIZE_U8_FOLLOWS; - } else if (size <= 0xFFFF) { - ASSERT(Free() >= 2); - buffer[0] |= SIZE_U16_FOLLOWS; - buffer[offset++] = (size >> 8); - } else { - ASSERT(Free() >= 4); - buffer[0] |= SIZE_U32_FOLLOWS; - buffer[offset++] = (size >> 24); - buffer[offset++] = (size >> 16); - buffer[offset++] = (size >> 8); - } - buffer[offset++] = size; - break; - } - - _writerOffset += offset; - } - - uint8_t Payload::ReadDescriptor(elementtype& type, uint32_t& size) const - { - uint8_t offset = 0; - uint8_t t = _buffer[_readerOffset + offset++]; - - switch (t & 7) { - case SIZE_8: - size = 1; - break; - case SIZE_16: - size = 2; - break; - case SIZE_32: - size = 4; - break; - case SIZE_64: - size = 8; - break; - case SIZE_128: - size = 16; - break; - case SIZE_U8_FOLLOWS: - size = _buffer[_readerOffset + offset++]; - break; - case SIZE_U16_FOLLOWS: - size = (_buffer[_readerOffset + offset++] << 8); - size |= _buffer[_readerOffset + offset++]; - break; - case SIZE_U32_FOLLOWS: - size = (_buffer[_readerOffset + offset++] << 24); - size |= (_buffer[_readerOffset + offset++] << 16); - size |= (_buffer[_readerOffset + offset++] << 8); - size |= _buffer[_readerOffset + offset++]; - break; - default: - TRACE_L1("SDP: Unexpected descriptor size [0x%01x]", (t & 7)); - size = 0; - break; - } - - type = static_cast(t & 0xF8); - if (type == NIL) { - size = 0; - } - - return (offset); - } - - uint16_t PDU::Serialize(uint8_t stream[], const uint16_t length) const - { - ASSERT(stream != nullptr); - - // The request must always fit into MTU! - ASSERT((HeaderSize + _payload.Length()) <= length); - - DataRecordBE msg(stream, length, 0); - - if (_errorCode != InProgress) { - msg.Push(_type); - msg.Push(_transactionId); - - if (Type() == PDU::ErrorResponse) { - msg.Push(2); - msg.Push(_errorCode); - } else { - msg.Push(_payload.Length()); - msg.Push(_payload); - } - - _errorCode = InProgress; - } - - if (msg.Length() != 0) { - TRACE_L1("SDP: sent %s; result: %d", AsString().c_str(), _errorCode); - } - - return (msg.Length()); - } - - uint16_t PDU::Deserialize(const uint8_t stream[], const uint16_t length) - { - ASSERT(stream != nullptr); - - DataRecordBE msg(stream, length); - bool truncated = false; - - _errorCode = Success; - - if (msg.Available() >= sizeof(_type)) { - msg.Pop(_type); - } else { - truncated = true; - } - - if (truncated == false) { - if (msg.Available() >= (sizeof(_transactionId) + sizeof(uint16_t))) { - msg.Pop(_transactionId); - - uint16_t payloadLength{}; - msg.Pop(payloadLength); - - if (payloadLength > 0) { - if (msg.Available() >= payloadLength) { - if (Type() == PDU::ErrorResponse) { - if (payloadLength >= 2) { - msg.Pop(_errorCode); - } else { - truncated = true; - } - } else { - msg.Pop(_payload, payloadLength); - } - } else { - truncated = true; - } - } - } else { - truncated = true; - } - } - - if (truncated == true) { - TRACE_L1("SDP: Message was truncated"); - _errorCode = DeserializationFailed; - } - - TRACE_L1("SDP: received %s; result: %d", AsString().c_str(), _errorCode); - - return (length); - } - -} // namespace SDP - -} // namespace Bluetooth - -} diff --git a/Source/bluetooth/audio/SDPSocket.h b/Source/bluetooth/audio/SDPSocket.h deleted file mode 100644 index 1b2c4a6..0000000 --- a/Source/bluetooth/audio/SDPSocket.h +++ /dev/null @@ -1,913 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2021 Metrological - * - * 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. - */ - -#pragma once - -#include "Module.h" -#include "DataRecord.h" - -namespace Thunder { - -namespace Bluetooth { - -namespace SDP { - - static constexpr uint8_t PSM = 1; - static constexpr uint16_t SocketBufferSize = 2048; - - struct EXTERNAL use_descriptor_t { explicit use_descriptor_t() = default; }; - constexpr use_descriptor_t use_descriptor = use_descriptor_t{}; // tag for selecting a proper overload - - struct EXTERNAL use_length_t { explicit use_length_t() = default; }; - constexpr use_length_t use_length = use_length_t{}; - - class EXTERNAL Payload : public DataRecordBE { - public: - enum elementtype : uint8_t { - NIL = 0x00, - UINT = 0x08, - INT = 0x10, - UUID = 0x18, - TEXT = 0x20, - BOOL = 0x28, - SEQ = 0x30, - ALT = 0x38, - URL = 0x40, - }; - - enum sizetype { - SIZE_8 = 0, - SIZE_16 = 1, - SIZE_32 = 2, - SIZE_64 = 3, - SIZE_128 = 4, - SIZE_U8_FOLLOWS = 5, - SIZE_U16_FOLLOWS = 6, - SIZE_U32_FOLLOWS = 7 - }; - - public: - using Builder = std::function; - using Inspector = std::function; - - enum class Continuation : uint8_t { - ABSENT = 0, - FOLLOWS - }; - - public: - using DataRecordBE::DataRecordBE; - using DataRecordBE::Pop; - using DataRecordBE::Push; - using DataRecordBE::PopAssign; - - ~Payload() = default; - - public: - void Push(use_descriptor_t) - { - PushDescriptor(NIL); - } - void Push(const Bluetooth::UUID& value) - { - ASSERT(Free() >= value.Length()); - uint8_t size = value.Length(); - while (size-- > 0) { - _buffer[_writerOffset++] = value.Data()[size]; // reverse! - } - } - void Push(use_descriptor_t, const Bluetooth::UUID& value) - { - PushDescriptor(UUID, value.Length()); - Push(value); - } - void Push(use_descriptor_t, const string& value, bool url = false) - { - PushDescriptor((url? URL : TEXT), value.length()); - Push(value); - } - void Push(use_descriptor_t, const bool value) - { - PushDescriptor(BOOL, 1); - Push(value); - } - template::value, int>::type = 0> - void Push(use_descriptor_t, const TYPE value) - { - PushDescriptor((std::numeric_limits::is_signed? INT : UINT), sizeof(TYPE)); - Push(value); - } - template::value, int>::type = 0> - void Push(use_descriptor_t, const TYPE value) - { - PushDescriptor(UINT, sizeof(TYPE)); - Push(value); - } - void Push(use_descriptor_t, const Payload& sequence, const bool alternative = false) - { - PushDescriptor((alternative? ALT : SEQ), sequence.Length()); - if (sequence.Length() != 0) { - Push(sequence); - } - } - void Push(use_length_t, const Payload& sequence, const bool = false) - { - Push(sequence.Length()); - if (sequence.Length() != 0) { - Push(sequence); - } - } - void Push(use_descriptor_t, const Buffer& sequence, const bool alternative = false) - { - PushDescriptor((alternative? ALT : SEQ), sequence.size()); - if (sequence.size() != 0) { - Push(sequence); - } - } - void Push(use_length_t, const Buffer& sequence, const bool = false) - { - ASSERT(sequence.size() < 0x10000); - Push(sequence.size()); - if (sequence.size() != 0) { - Push(sequence); - } - } - void Push(use_descriptor_t, const uint8_t sequence[], const uint16_t length, const bool alternative = false) - { - if (length != 0) { - PushDescriptor((alternative? ALT : SEQ), length); - Push(sequence, length); - } - } - void Push(use_length_t, const uint8_t sequence[], const uint16_t length) - { - Push(length); - if (length != 0) { - Push(sequence, length); - } - } - void Push(const Builder& Build, const uint16_t scratchPadSize = 2048) - { - uint8_t* scratchPad = static_cast(ALLOCA(scratchPadSize)); - Payload sequence(scratchPad, scratchPadSize, 0); - Build(sequence); - Push(sequence); - } - template - void Push(TAG tag, const Builder& Build, const bool alternative = false, const uint16_t scratchPadSize = 2048) - { - uint8_t* scratchPad = static_cast(ALLOCA(scratchPadSize)); - Payload sequence(scratchPad, scratchPadSize, 0); - Build(sequence); - Push(tag, sequence, alternative); - } - template - void Push(const std::list& list, const uint16_t scratchPadSize = 2048) - { - if (list.size() != 0) { - ASSERT(Free() >= (list.size() * sizeof(TYPE))); - Push([&](Payload& sequence){ - for (const auto& item : list) { - sequence.Push(item); - } - }, scratchPadSize); - } - } - template - void Push(use_descriptor_t, const std::list& list, const bool alternative = false, const uint16_t scratchPadSize = 2048) - { - if (list.size() != 0) { - Push(use_descriptor, [&](Payload& sequence){ - for (const auto& item : list) { - sequence.Push(use_descriptor, item); - } - }, alternative, scratchPadSize); - } - } - - public: - void Pop(use_descriptor_t, string& value) const - { - elementtype type; - uint32_t size = 0; - _readerOffset += ReadDescriptor(type, size); - if ((type == TEXT) || (type == URL)) { - Pop(value, size); - } else { - TRACE_L1("SDP: Unexpected descriptor in payload [0x%02x], expected TEXT or URL", type); - _readerOffset += size; - } - } - template::value, int>::type = 0> - void Pop(use_descriptor_t, TYPE& value) - { - elementtype type; - uint32_t size = 0; - _readerOffset += ReadDescriptor(type, size); - if (type == UINT) { - typename std::underlying_type::type temp; - if (size != sizeof(temp)) { - TRACE_L1("SDP: Warning: enum underlying type size does not match!"); - } - Pop(temp); - value = static_cast(temp); - } else { - TRACE_L1("SDP: Unexpected descriptor in payload [0x%02x], expected a UINT for enum", type); - _readerOffset += size; - } - } - template::value, int>::type = 0> - void Pop(use_descriptor_t, TYPE& value, uint32_t* outSize = nullptr) const - { - elementtype type; - uint32_t size = 0; - _readerOffset += ReadDescriptor(type, size); - if (type == (std::numeric_limits::is_signed? INT : UINT)) { - if (size > sizeof(TYPE)) { - TRACE_L1("SDP: Warning: integer value possibly truncated!"); - } - if (size == 1) { - uint8_t val{}; - DataRecord::PopIntegerValue(val); - value = val; - } else if (size == 2) { - uint16_t val{}; - PopIntegerValue(val); - value = val; - } else if (size == 4) { - uint32_t val{}; - PopIntegerValue(val); - value = val; - } else { - TRACE_L1("SDP: Unexpected integer size"); - _readerOffset += size; - } - if (outSize != nullptr) { - (*outSize) = size; - } - } else { - TRACE_L1("SDP: Unexpected descriptor in payload [0x%02x], expected %s", type, (std::numeric_limits::is_signed? "an INT" : "a UINT")); - _readerOffset += size; - } - } - template - void Pop(std::vector& vect, const uint16_t count) const - { - if (Available() >= (count * sizeof(TYPE))) { - vect.reserve(count); - - uint16_t i = count; - while (i-- > 0) { - TYPE item; - Pop(item); - vect.push_back(item); - } - } else { - TRACE_L1("SDP: Truncated payload while reading a vector"); - _readerOffset = _writerOffset; - } - } - template - void Pop(std::list& list, const uint16_t count) const - { - if (Available() >= (count * sizeof(TYPE))) { - uint16_t i = count; - while (i-- > 0) { - TYPE item; - Pop(item); - list.push_back(item); - } - } else { - TRACE_L1("SDP: Truncated payload while reading a list"); - _readerOffset = _writerOffset; - } - } - template - void Pop(use_descriptor_t, std::list& list, const uint16_t count) const - { - if (Available() >= (count * sizeof(TYPE))) { - uint16_t i = count; - while (i-- > 0) { - TYPE item; - Pop(use_descriptor, item); - list.push_back(item); - } -} else { - TRACE_L1("SDP: Truncated payload while reading a list"); - _readerOffset = _writerOffset; - } - } - void Pop(use_descriptor_t, Bluetooth::UUID& uuid) const - { - uint32_t size = 0; - elementtype type; - _readerOffset += ReadDescriptor(type, size); - if (type == UUID) { - if (Available() >= size) { - if (size == 2) { - uuid = Bluetooth::UUID((_buffer[_readerOffset] << 8) | _buffer[_readerOffset + 1]); - } else if (size == 4) { - uuid = Bluetooth::UUID((_buffer[_readerOffset] << 24) | (_buffer[_readerOffset + 1] << 16) - | (_buffer[_readerOffset + 2] << 8) | _buffer[_readerOffset + 3]); - } else { - uint8_t* buffer = static_cast(ALLOCA(size)); - uint8_t i = size; - while (i-- > 0) { - buffer[i] = _buffer[_readerOffset++]; - } - uuid = Bluetooth::UUID(buffer); - } - _readerOffset += size; - } else { - TRACE_L1("SDP: Truncated payload while reading UUID"); - _readerOffset = _writerOffset; - } - } else { - TRACE_L1("SDP: Unexpected descriptor in payload [0x%02x], expected a UUID", type); - _readerOffset += size; - } - } - void Pop(use_descriptor_t, const Inspector& inspector) const - { - uint32_t size = 0; - elementtype type; - _readerOffset += ReadDescriptor(type, size); - if (type == SEQ) { - if (Available() >= size) { - Payload sequence(&_buffer[_readerOffset], size, size); - inspector(sequence); - _readerOffset += size; - } else { - TRACE_L1("SDP: Truncated payload while reading a sequence"); - _readerOffset = _writerOffset; - } - } else { - TRACE_L1("SDP: Unexpected descriptor in payload [0x%02x], expected a SEQ", type); - _readerOffset += size; - } - } - void Pop(use_descriptor_t, Buffer& element) const - { - elementtype elemType; - uint32_t elemSize; - uint8_t descriptorSize = ReadDescriptor(elemType, elemSize); - // Don't assume any type of data here. - if (Available() >= (descriptorSize + elemSize)) { - element.assign(&_buffer[_readerOffset], (descriptorSize + elemSize)); - _readerOffset += (descriptorSize + elemSize); - } else { - TRACE_L1("SDP: Truncated payload while reading a sequence"); - _readerOffset = _writerOffset; - } - } - void Pop(use_descriptor_t, Buffer& element, const uint16_t size) const - { - // Don't assume any type of data here. - if (Available() >= size) { - element.assign(&_buffer[_readerOffset], size); - _readerOffset += size; - } else { - TRACE_L1("SDP: Truncated payload while reading a buffer"); - _readerOffset = _writerOffset; - } - } - void Pop(use_length_t, const Inspector& inspector) const - { - uint16_t size{}; - Pop(size); - if (Available() >= size) { - Payload sequence(&_buffer[_readerOffset], size); - inspector(sequence); - _readerOffset += size; - } else { - TRACE_L1("SDP: Truncated payload while reading a buffer"); - _readerOffset = _writerOffset; - } - } - void Pop(use_length_t, Buffer& element) const - { - uint16_t size{}; - Pop(size); - if (Available() >= size) { - element.assign(&_buffer[_readerOffset], size); - _readerOffset += size; - } else { - TRACE_L1("SDP: Truncated payload while reading a buffer"); - _readerOffset = _writerOffset; - } - } - - public: - void PopAssign(use_descriptor_t, Payload& element) const - { - elementtype elemType; - uint32_t elemSize; - uint8_t descriptorSize = ReadDescriptor(elemType, elemSize); - if (Available() >= (descriptorSize + elemSize)) { - element.Assign(&_buffer[_readerOffset], (descriptorSize + elemSize)); - _readerOffset += (descriptorSize + elemSize); - } else { - TRACE_L1("SDP: Truncated payload"); - _readerOffset = _writerOffset; - } - } - - private: - void PushDescriptor(const elementtype type, const uint32_t size = 0); - uint8_t ReadDescriptor(elementtype& type, uint32_t& size) const; - }; // class Payload - - class EXTERNAL PDU { - public: - static constexpr uint8_t HeaderSize = 5; - static constexpr uint8_t MaxContinuationSize = 16; - - public: - enum pduid : uint8_t { - Invalid = 0, - ErrorResponse = 1, - ServiceSearchRequest = 2, - ServiceSearchResponse = 3, - ServiceAttributeRequest = 4, - ServiceAttributeResponse = 5, - ServiceSearchAttributeRequest = 6, - ServiceSearchAttributeResponse = 7, - }; - - enum errorid : uint16_t { - Success = 0, - UnsupportedSdpVersion = 1, - InvalidServiceRecordHandle = 2, - InvalidRequestSyntax = 3, - InvalidPduSize = 4, - InvalidContinuationState = 5, - InsufficientResources = 6, - Reserved = 255, - InProgress, - SerializationFailed, - DeserializationFailed, - }; - - public: - PDU(const PDU&) = delete; - PDU& operator=(const PDU&) = delete; - ~PDU() = default; - - explicit PDU(const uint16_t bufferSize = SocketBufferSize) - : _buffer(new uint8_t[bufferSize]) - , _payload(_buffer.get(), bufferSize, 0) - , _type(Invalid) - , _transactionId(~0) - , _errorCode(Reserved) - { - ASSERT(bufferSize > (HeaderSize + (1 /* continuation length */) + MaxContinuationSize)); - ASSERT(_buffer.get() != nullptr); - } - - public: - string AsString() const - { -#ifdef __DEBUG__ - const char* labels[] = { "Invalid", "ErrorResponse", "ServiceSearchRequest", "ServiceSearchResponse", "ServiceAttributeRequest", - "ServiceAttributeResponse", "ServiceSearchAttributeRequest", "ServiceSearchAttributeResponse" }; - - ASSERT(Type() <= ServiceSearchAttributeResponse); - return (Core::Format("PDU #%d '%s'", _transactionId, labels[_type])); -#else - return (Core::Format("PDU #%d type %d", _transactionId, _type)); -#endif - } - - public: - bool IsValid() const { - return ((Type() != Invalid) && (TransactionId() != static_cast(~0))); - } - pduid Type() const { - return (_type); - } - uint16_t TransactionId() const { - return (_transactionId); - } - errorid Error() const { - return (_errorCode); - } - uint16_t Capacity() const { - return (_payload.Capacity()); - } - - public: - void InspectPayload(const Payload::Inspector& inspectorCb) const - { - ASSERT(inspectorCb != nullptr); - - _payload.Rewind(); - inspectorCb(_payload); - } - - public: - void Reload() const - { - _payload.Rewind(); - } - void Clear() - { - _payload.Clear(); - _type = Invalid; - _transactionId = -1; - _errorCode = Reserved; - } - void Set(const uint16_t transactionId, const pduid type, const Payload::Builder& buildCb) - { - _errorCode = SerializationFailed; - _transactionId = transactionId; - _type = type; - _payload.Clear(); - - if (buildCb != nullptr) { - buildCb(_payload); - } - } - - public: - uint16_t Serialize(uint8_t stream[], const uint16_t length) const; - uint16_t Deserialize(const uint8_t stream[], const uint16_t length); - - private: - std::unique_ptr _buffer; - Payload _payload; - pduid _type; - uint16_t _transactionId; - mutable errorid _errorCode; - }; // class PDU - - class EXTERNAL ClientSocket : public Core::SynchronousChannelType { - public: - static constexpr uint32_t CommunicationTimeout = 2000; /* 2 seconds. */ - - class EXTERNAL Command : public Core::IOutbound, public Core::IInbound { - public: - class EXTERNAL Request : public PDU { - public: - Request(const Request&) = delete; - Request& operator=(const Request&) = delete; - ~Request() = default; - - Request() - : PDU() - , _counter(~0) - { - } - - public: - using PDU::Set; - - void Set(const PDU::pduid type, const Payload::Builder& buildCb = nullptr) - { - Set(Counter(), type, buildCb); - } - - private: - uint16_t Counter() const { - return (++_counter); - } - - private: - mutable uint16_t _counter; - }; // class Request - - public: - class EXTERNAL Response : public PDU { - public: - Response(const Response&) = delete; - Response& operator=(const Response&) = delete; - ~Response() = default; - - Response() - : PDU() - { - } - }; // class Response - - public: - Command(const Command&) = delete; - Command& operator=(const Command&) = delete; - - Command(ClientSocket& socket) - : _request() - , _response() - , _socket(socket) - { - } - ~Command() = default; - - public: - template - void Set(Args&&... args) - { - _response.Clear(); - _request.Set(std::forward(args)...); - } - - public: - Response& Result() { - return (_response); - } - const Response& Result() const - { - return (_response); - } - const Request& Call() const - { - return (_request); - } - bool IsValid() const - { - return (_request.IsValid()); - } - - private: - void Reload() const override - { - _request.Reload(); - } - uint16_t Serialize(uint8_t stream[], const uint16_t length) const override - { - ASSERT(stream != nullptr); - - const uint16_t result = _request.Serialize(stream, std::min(_socket.OutputMTU(), length)); - - if (result != 0) { - CMD_DUMP("SDP client send", stream, result); - } - - return (result); - } - uint16_t Deserialize(const uint8_t stream[], const uint16_t length) override - { - ASSERT(stream != nullptr); - - CMD_DUMP("SDP client received", stream, length); - - return (_response.Deserialize(stream, length)); - } - Core::IInbound::state IsCompleted() const override - { - return (Core::IInbound::COMPLETED); - } - - private: - Request _request; - Response _response; - ClientSocket& _socket; - }; // class Command - - public: - ClientSocket(const ClientSocket&) = delete; - ClientSocket& operator=(const ClientSocket&) = delete; - ~ClientSocket() = default; - - ClientSocket(const Core::NodeId& localNode, const Core::NodeId& remoteNode) - : Core::SynchronousChannelType(SocketPort::SEQUENCED, - localNode, remoteNode, SocketBufferSize, SocketBufferSize) - , _adminLock() - , _omtu(0) - { - } - ClientSocket(const SOCKET& connector, const Core::NodeId& remoteNode) - : Core::SynchronousChannelType(SocketPort::SEQUENCED, - connector, remoteNode, SocketBufferSize, SocketBufferSize) - , _adminLock() - , _imtu(0) - , _omtu(0) - { - } - - public: - uint16_t InputMTU() const { - return (_omtu); - } - uint16_t OutputMTU() const { - return (_omtu); - } - - private: - virtual void Operational(const bool upAndRunning) = 0; - - void StateChange() override - { - Core::SynchronousChannelType::StateChange(); - - if (IsOpen() == true) { - struct l2cap_options options{}; - socklen_t len = sizeof(options); - - ::getsockopt(Handle(), SOL_L2CAP, L2CAP_OPTIONS, &options, &len); - - ASSERT(options.omtu <= SendBufferSize()); - ASSERT(options.imtu <= ReceiveBufferSize()); - - TRACE(Trace::Information, (_T("SDP channel input MTU: %d, output MTU: %d"), options.imtu, options.omtu)); - - _omtu = options.omtu; - _imtu = options.imtu; - - Operational(true); - - } else { - Operational(false); - - _omtu = 0; - _imtu = 0; - } - } - - uint16_t Deserialize(const uint8_t stream[] VARIABLE_IS_NOT_USED, const uint16_t length) override - { - if (length != 0) { - TRACE_L1("SDP: Unexpected data for deserialization [%d bytes]", length); - CMD_DUMP("SDP client received unexpected", stream, length); - } - - return (length); - } - - private: - Core::CriticalSection _adminLock; - uint16_t _imtu; - uint16_t _omtu; - }; // class ClientSocket - - class EXTERNAL ServerSocket : public ClientSocket { - public: - class EXTERNAL ResponseHandler { - public: - ResponseHandler(const ResponseHandler&) = default; - ResponseHandler& operator=(const ResponseHandler&) = default; - ~ResponseHandler() = default; - - ResponseHandler(const std::function& acceptor, - const std::function& rejector) - : _acceptor(acceptor) - , _rejector(rejector) - { - } - - public: - void operator ()(const PDU::pduid newId, const Payload::Builder& buildCb = nullptr) const - { - _acceptor(newId, buildCb); - } - void operator ()(const PDU::errorid result) const - { - _rejector(result); - } - - private: - std::function _acceptor; - std::function _rejector; - }; // class ResponseHandler - - private: - class EXTERNAL Request : public PDU { - public: - Request(const Request&) = delete; - Request& operator=(const Request&) = delete; - ~Request() = default; - - Request() - : PDU() - { - } - }; // class Request - - class EXTERNAL Response : public PDU, public Core::IOutbound { - public: - Response(const Response&) = delete; - Response& operator=(const Response&) = delete; - Response(ServerSocket& socket) - : PDU() - , _socket(socket) - { - } - ~Response() = default; - - public: - using PDU::Set; - - void Set(const uint16_t transactionId, PDU::errorid code) - { - Set(transactionId, PDU::ErrorResponse, [code](Payload& payload) { - payload.Push(code); - }); - } - - public: - const ServerSocket& Socket() const { - return (_socket); - } - - public: - void Reload() const override - { - PDU::Reload(); - } - uint16_t Serialize(uint8_t stream[], const uint16_t length) const override - { - const uint16_t result = PDU::Serialize(stream, std::min(_socket.OutputMTU(), length)); - - if (result != 0) { - CMD_DUMP("SDP server sent", stream, result); - } - - return (result); - } - - private: - ServerSocket& _socket; - }; // class Response - - public: - ServerSocket(const ServerSocket&) = delete; - ServerSocket& operator=(const ServerSocket&) = delete; - - ServerSocket(const Core::NodeId& localNode, const Core::NodeId& remoteNode) - : ClientSocket(localNode, remoteNode) - , _request() - , _response(*this) - { - } - ServerSocket(const SOCKET& connector, const Core::NodeId& remoteNode) - : ClientSocket(connector, remoteNode) - , _request() - , _response(*this) - { - } - ~ServerSocket() = default; - - public: - uint16_t Deserialize(const uint8_t stream[], const uint16_t length) override - { - uint16_t result = 0; - - CMD_DUMP("SDP server received", stream, length); - - result = _request.Deserialize(stream, length); - - if (result != 0) { - Received(_request, _response); - _request.Clear(); - } - - return (result); - } - - private: - void Received(const Request& request, Response& response) - { - if (request.IsValid() == true) { - OnPDU(*this, request, ResponseHandler( - [&](const PDU::pduid newId, const Payload::Builder& buildCb) { - TRACE_L1("SDP server: accepting %s", request.AsString().c_str()); - response.Set(request.TransactionId(), newId, buildCb); - }, - [&](const PDU::errorid result) { - TRACE_L1("SDP server: rejecting %s, reason: %d", request.AsString().c_str(), result); - response.Set(request.TransactionId(), result); - })); - } else { - TRACE_L1("SDP server: Invalid request!"); - response.Set(request.TransactionId(), PDU::InvalidRequestSyntax); - } - - Send(CommunicationTimeout, response, nullptr, nullptr); - } - - protected: - virtual void OnPDU(const ServerSocket& socket, const PDU& request, const ResponseHandler& handler) = 0; - - private: - Request _request; - Response _response; - }; - -} // namespace SDP - -} // namespace Bluetooth - -} // namespace Thunder diff --git a/Source/bluetooth/audio/bluetooth_audio.h b/Source/bluetooth/audio/bluetooth_audio.h deleted file mode 100644 index 7bdfe9f..0000000 --- a/Source/bluetooth/audio/bluetooth_audio.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2023 Metrological - * - * 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. - */ - -#pragma once - -#ifndef MODULE_NAME -#error "Please define a MODULE_NAME that describes the binary/library you are building." -#endif - -#include -#include "SDPSocket.h" -#include "SDPProfile.h" -#include "AVDTPSocket.h" -#include "AVDTPProfile.h" -#include "RTPSocket.h" -#include "DataRecord.h" - -#include "IAudioCodec.h" -#include "IAudioContentProtection.h" - -#ifdef __WINDOWS__ -#pragma comment(lib, "bluetoothaudio.lib") -#endif \ No newline at end of file diff --git a/Source/bluetooth/audio/cmake/FindSBC.cmake b/Source/bluetooth/audio/cmake/FindSBC.cmake deleted file mode 100644 index ef43283..0000000 --- a/Source/bluetooth/audio/cmake/FindSBC.cmake +++ /dev/null @@ -1,34 +0,0 @@ -# If not stated otherwise in this file or this component's LICENSE file the -# following copyright and licenses apply: -# -# Copyright 2021 Metrological -# -# 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. - -# - Try to find sbc -# Once done this will define -# SBC_FOUND - System has libsbc -# SBC_INCLUDE_DIRS - The libsbc include directories -# SBC_LIBRARIES - The libraries needed to use libsbc - -find_package(PkgConfig) -pkg_check_modules(SBC REQUIRED sbc IMPORTED_TARGET) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(SBC DEFAULT_MSG SBC_LIBRARIES SBC_INCLUDE_DIRS) - -mark_as_advanced(SBC_FOUND SBC_LIBRARIES SBC_INCLUDE_DIRS) - -if(SBC_FOUND) - add_library(SBC::SBC ALIAS PkgConfig::SBC) -endif() \ No newline at end of file diff --git a/Source/bluetooth/audio/codecs/SBC.cpp b/Source/bluetooth/audio/codecs/SBC.cpp deleted file mode 100644 index a40b17e..0000000 --- a/Source/bluetooth/audio/codecs/SBC.cpp +++ /dev/null @@ -1,654 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2021 Metrological - * - * 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. - */ - -#include "../Module.h" - -#include "SBC.h" - -#include - -namespace Thunder { - -ENUM_CONVERSION_BEGIN(Bluetooth::A2DP::SBC::preset) - { Bluetooth::A2DP::SBC::COMPATIBLE, _TXT("Compatible") }, - { Bluetooth::A2DP::SBC::LQ, _TXT("LQ") }, - { Bluetooth::A2DP::SBC::MQ, _TXT("MQ") }, - { Bluetooth::A2DP::SBC::HQ, _TXT("HQ") }, - { Bluetooth::A2DP::SBC::XQ, _TXT("XQ") }, -ENUM_CONVERSION_END(Bluetooth::A2DP::SBC::preset) - -ENUM_CONVERSION_BEGIN(Bluetooth::A2DP::SBC::Config::channelmode) - { Bluetooth::A2DP::SBC::Config::MONO, _TXT("Mono") }, - { Bluetooth::A2DP::SBC::Config::STEREO, _TXT("Stereo") }, - { Bluetooth::A2DP::SBC::Config::JOINT_STEREO, _TXT("JointSstereo") }, - { Bluetooth::A2DP::SBC::Config::DUAL_CHANNEL, _TXT("DualChannel") }, -ENUM_CONVERSION_END(Bluetooth::A2DP::SBC::Config::channelmode) - -namespace Bluetooth { - -namespace A2DP { - - /* virtual */ uint32_t SBC::Configure(const StreamFormat& format, const string& settings) - { - uint32_t result = Core::ERROR_NONE; - - Core::JSON::String Data; - Core::JSON::Container container; - container.Add("LC-SBC", &Data); - container.FromString(settings); - - Config config; - config.FromString(Data.Value()); - - _lock.Lock(); - - preset preferredPreset = HQ; - Format::samplingfrequency frequency = Format::SF_INVALID; - Format::channelmode channelMode = Format::CM_INVALID; - uint8_t maxBitpool = _supported.MinBitpool(); - - if (config.Preset.IsSet() == true) { - // Preset requested in config, this will now be the target quality. - if (config.Preset.Value() != COMPATIBLE) { - preferredPreset = config.Preset.Value(); - } - else { - preferredPreset = LQ; - } - } - - switch (format.SampleRate) { - case 16000: - frequency = Format::SF_16000_HZ; - break; - case 32000: - frequency = Format::SF_32000_HZ; - break; - case 44100: - frequency = Format::SF_44100_HZ; - break; - case 48000: - frequency = Format::SF_48000_HZ; - break; - default: - break; - } - - frequency = static_cast(frequency & _supported.SamplingFrequency()); - - switch (format.Channels) { - case 1: - channelMode = Format::CM_MONO; - break; - case 2: - if (config.ChannelMode.IsSet() == true) { - - switch (config.ChannelMode) { - case Config::STEREO: - channelMode = Format::CM_STEREO; - break; - case Config::DUAL_CHANNEL: - channelMode = Format::CM_DUAL_CHANNEL; - break; - default: - break; - } - } - - if (channelMode == Format::CM_INVALID) { - // Joint-Stereo compresses better than regular stereo when the signal is concentrated - // in the middle of the stereo image, what is quite typical. - channelMode = Format::CM_JOINT_STEREO; - } - - break; - } - - channelMode = static_cast(channelMode & _supported.ChannelMode()); - - if ((channelMode != Format::CM_INVALID) && (frequency != Format::SF_INVALID) && (format.Resolution == 16)) { - bool stereo = (channelMode != Format::CM_MONO); - - // Select bitpool and channel mode based on preferred format... - // (Note that bitpools for sample rates of 16 and 32 kHz are not specified, hence will receive same values as 44,1 kHz.) - if (preferredPreset == XQ) { - if (_supported.MaxBitpool() >= 38) { - maxBitpool = 38; - - if (stereo == true) { - if (_supported.MaxBitpool() >= 76) { - maxBitpool = 76; - } - else { - // Max supported bitpool is too low for XQ joint-stereo, so try 38 on dual channel instead - // - that should give similar quality/bitrate. - channelMode = Format::CM_DUAL_CHANNEL; - } - } - } - else { - // XQ not supported, drop to the next best one... - preferredPreset = HQ; - } - } - - if (preferredPreset == HQ) { - if (frequency == Format::SF_48000_HZ) { - maxBitpool = (stereo? 51 : 29); - } - else { - maxBitpool = (stereo? 53 : 31); - } - - if (maxBitpool > _supported.MaxBitpool()) { - preferredPreset = MQ; - } - } - - if (preferredPreset == MQ) { - if (frequency == Format::SF_48000_HZ) { - maxBitpool = (stereo? 33 : 18); - } - else { - maxBitpool = (stereo? 35 : 19); - } - - if (maxBitpool > _supported.MaxBitpool()) { - preferredPreset = LQ; - } - } - - if (preferredPreset == LQ) { - maxBitpool = (stereo? 29 : 15); - - if (maxBitpool > _supported.MaxBitpool()) { - preferredPreset = COMPATIBLE; - } - } - - if (preferredPreset == COMPATIBLE) { - // Use whatever is the maximum supported bitpool. - maxBitpool = _supported.MaxBitpool(); - } - - ASSERT(maxBitpool <= MAX_BITPOOL); - - _actuals.SamplingFrequency(frequency); - _actuals.ChannelMode(channelMode); - _actuals.MinBitpool(_supported.MinBitpool()); - _actuals.MaxBitpool(maxBitpool); - _preferredBitpool = maxBitpool; - _preset = preferredPreset; - -#ifdef __DEBUG__ - DumpConfiguration(); -#endif - - Bitpool(maxBitpool); - } - else { - result = Core::ERROR_NOT_SUPPORTED; - TRACE(Trace::Error, (_T("Unsuppored SBC paramters requested"))); - } - - _lock.Unlock(); - - return (result); - } - - /* virtual */ uint32_t SBC::Configure(const uint8_t stream[], const uint16_t length) - { - uint32_t result = Core::ERROR_NONE; - - _lock.Lock(); - - _actuals.Deserialize(stream, length); - - _preset = COMPATIBLE; - - _preferredBitpool = _actuals.MaxBitpool(); - - Bitpool(_actuals.MaxBitpool()); - - _lock.Unlock(); - - return (result); - } - - /* virtual */ void SBC::Configuration(StreamFormat& format, string& settings) const - { - Config config; - - _lock.Lock(); - - format.FrameRate = 0; - - format.Resolution = 16; // Always 16-bit samples - - switch (_actuals.SamplingFrequency()) { - case Format::SF_48000_HZ: - format.SampleRate = 48000; - break; - case Format::SF_44100_HZ: - format.SampleRate = 44100; - break; - case Format::SF_32000_HZ: - format.SampleRate = 32000; - break; - case Format::SF_16000_HZ: - format.SampleRate = 16000; - break; - default: - ASSERT(false && "Invalid sampling frequency configured"); - break; - } - - switch (_actuals.ChannelMode()) { - case Format::CM_MONO: - config.ChannelMode = Config::MONO; - format.Channels = 1; - break; - case Format::CM_DUAL_CHANNEL: - config.ChannelMode = Config::DUAL_CHANNEL; - format.Channels = 2; - break; - case Format::CM_STEREO: - config.ChannelMode = Config::STEREO; - format.Channels = 2; - break; - case Format::CM_JOINT_STEREO: - config.ChannelMode = Config::JOINT_STEREO; - format.Channels = 2; - break; - default: - ASSERT(false && "Invalid channel mode configured"); - break; - } - - config.Preset = _preset; - config.Bitpool = _bitpool; - - _lock.Unlock(); - - config.ToString(settings); - } - - /* virtual */ uint16_t SBC::Serialize(const bool capabilities, uint8_t stream[], const uint16_t length) const - { - _lock.Lock(); - - const uint16_t result = (capabilities? _supported.Serialize(stream, length) : _actuals.Serialize(stream, length)); - - _lock.Unlock(); - - return (result); - } - - /* virtual */ uint16_t SBC::Encode(const uint16_t inBufferSize, const uint8_t inBuffer[], - uint16_t& outSize, uint8_t outBuffer[]) const - { - ASSERT(_rawFrameSize != 0); - ASSERT(_encodedFrameSize != 0); - - ASSERT(inBuffer != nullptr); - ASSERT(outBuffer != nullptr); - - uint16_t consumed = 0; - uint16_t produced = sizeof(SBCHeader); - uint16_t count = 0; - - _lock.Lock(); - - if ((_rawFrameSize != 0) && (_encodedFrameSize != 0)) { - - const uint8_t MAX_FRAMES = 15; // only a four bit number holds the number of frames in a packet - - uint16_t frames = (inBufferSize / _rawFrameSize); - uint16_t available = (outSize - produced); - - ASSERT(outSize >= sizeof(SBCHeader)); - - if (frames > MAX_FRAMES) { - frames = MAX_FRAMES; - } - - while ((frames-- > 0) - && (inBufferSize >= (consumed + _rawFrameSize)) - && (available >= _encodedFrameSize)) { - - ssize_t written = 0; - ssize_t read = ::sbc_encode(static_cast<::sbc_t*>(_sbcHandle), - (inBuffer + consumed), _rawFrameSize, - (outBuffer + produced), available, - &written); - - if (read < 0) { - TRACE_L1("Failed to encode an SBC frame!"); - break; - } - else { - consumed += read; - available -= written; - produced += written; - count++; - } - } - } - - _lock.Unlock(); - - if (count > 0) { - SBCHeader* header = reinterpret_cast(outBuffer); - header->frameCount = (count & 0xF); - outSize = produced; - } - else { - outSize = 0; - } - - return (consumed); - } - - /* virtual */ uint16_t SBC::Decode(const uint16_t inBufferSize, const uint8_t inBuffer[], - uint16_t& outSize, uint8_t outBuffer[]) const - { - ASSERT(_rawFrameSize != 0); - ASSERT(_encodedFrameSize != 0); - - ASSERT(inBuffer != nullptr); - ASSERT(outBuffer != nullptr); - - uint16_t consumed = 0; - uint16_t produced = 0; - uint16_t available = outSize; - - _lock.Lock(); - - if ((_rawFrameSize != 0) && (_encodedFrameSize != 0)) { - - ASSERT(outSize >= sizeof(SBCHeader)); - const SBCHeader* header = reinterpret_cast(inBuffer); - - uint8_t frames = header->frameCount; - consumed = sizeof(SBCHeader); - - while ((frames != 0) - && (inBufferSize >= (consumed + _encodedFrameSize)) - && (available >= _rawFrameSize)) { - - size_t written = 0; - ssize_t read = ::sbc_decode(static_cast<::sbc_t*>(_sbcHandle), - (inBuffer + consumed), _encodedFrameSize, - (outBuffer + produced), available, - &written); - - - if (read < 0) { - TRACE_L1("Failed to decode an SBC frame!"); - break; - } - else { - available -= written; - produced += written; - consumed += read; - } - - frames--; - } - - ASSERT(frames == 0); - } - - _lock.Unlock(); - - outSize = produced; - - return (consumed); - } - - /* virtual */ uint32_t SBC::QOS(const int8_t policy) - { - uint32_t result = Core::ERROR_NONE; - - ASSERT(_preferredBitpool != 0); - - const uint8_t STEP = (_preferredBitpool / 10); - - _lock.Lock(); - - uint8_t newBitpool = _bitpool; - - if (policy == 0) { - // reset quality - newBitpool = _preferredBitpool; - } - else if (policy < 0) { - // decrease quality - if (newBitpool == _supported.MinBitpool()) { - result = Core::ERROR_UNAVAILABLE; - } - else if ((newBitpool - STEP) < _supported.MinBitpool()) { - newBitpool = _supported.MinBitpool(); - } - else { - newBitpool -= STEP; - } - } - else { - // increase quality - if (_bitpool == _preferredBitpool) { - newBitpool = Core::ERROR_UNAVAILABLE; - } - else if ((_bitpool + STEP) >= _preferredBitpool) { - newBitpool = _preferredBitpool; - } - else { - newBitpool += STEP; - } - } - - if (result == Core::ERROR_NONE) { - Bitpool(newBitpool); - } - - _lock.Unlock(); - - return (result); - } - - void SBC::Bitpool(uint8_t value) - { - ASSERT(value <= MAX_BITPOOL); - ASSERT(value >= MIN_BITPOOL); - - _bitpool = value; - - TRACE(Trace::Information, (_T("New bitpool value for SBC: %d"), _bitpool)); - - SBCConfigure(); - #ifdef __DEBUG__ - DumpBitrateConfiguration(); - #endif - } - - void SBC::SBCInitialize() - { - _lock.Lock(); - - ASSERT(_sbcHandle == nullptr); - - _sbcHandle = static_cast(new ::sbc_t); - ASSERT(_sbcHandle != nullptr); - - ::sbc_init(static_cast<::sbc_t*>(_sbcHandle), 0L); - - _lock.Unlock(); - } - - void SBC::SBCDeinitialize() - { - _lock.Lock(); - - if (_sbcHandle != nullptr) { - ::sbc_finish(static_cast<::sbc_t*>(_sbcHandle)); - - delete static_cast<::sbc_t*>(_sbcHandle); - - _sbcHandle = nullptr; - } - - _lock.Unlock(); - } - - void SBC::SBCConfigure() - { - _lock.Lock(); - - ASSERT(_sbcHandle != nullptr); - ::sbc_reinit(static_cast<::sbc_t*>(_sbcHandle), 0L); - - uint32_t rate; - uint32_t blocks; - uint32_t bands; - - ::sbc_t* sbc = static_cast<::sbc_t*>(_sbcHandle); - - sbc->bitpool = _bitpool; - sbc->allocation = (_actuals.AllocationMethod() == Format::AM_LOUDNESS? SBC_AM_LOUDNESS : SBC_AM_SNR); - - switch (_actuals.SubBands()) { - default: - case Format::SB_8: - sbc->subbands = SBC_SB_8; - bands = 8; - break; - case Format::SB_4: - sbc->subbands = SBC_SB_4; - bands = 4; - break; - } - - switch (_actuals.SamplingFrequency()) { - case Format::SF_48000_HZ: - sbc->frequency = SBC_FREQ_48000; - rate = 48000; - break; - default: - case Format::SF_44100_HZ: - sbc->frequency = SBC_FREQ_44100; - rate = 44100; - break; - case Format::SF_32000_HZ: - sbc->frequency = SBC_FREQ_32000; - rate = 32000; - break; - case Format::SF_16000_HZ: - sbc->frequency = SBC_FREQ_16000; - rate = 16000; - break; - } - - switch (_actuals.BlockLength()) { - default: - case Format::BL_16: - sbc->blocks = SBC_BLK_16; - blocks = 16; - break; - case Format::BL_12: - sbc->blocks = SBC_BLK_12; - blocks = 12; - break; - case Format::BL_8: - sbc->blocks = SBC_BLK_8; - blocks = 8; - break; - case Format::BL_4: - sbc->blocks = SBC_BLK_4; - blocks = 4; - break; - } - - switch (_actuals.ChannelMode()) { - default: - case Format::CM_JOINT_STEREO: - sbc->mode = SBC_MODE_JOINT_STEREO; - break; - case Format::CM_STEREO: - sbc->mode = SBC_MODE_STEREO; - break; - case Format::CM_DUAL_CHANNEL: - sbc->mode = SBC_MODE_DUAL_CHANNEL; - break; - case Format::CM_MONO: - sbc->mode = SBC_MODE_MONO; - break; - } - - _frameDuration = ::sbc_get_frame_duration(sbc); /* microseconds */ - _rawFrameSize = ::sbc_get_codesize(sbc); /* bytes */ - _encodedFrameSize = ::sbc_get_frame_length(sbc); /* bytes */ - - _bitRate = ((8L * _encodedFrameSize * rate) / (bands * blocks)); /* bits per second */ - _channels = (sbc->mode == SBC_MODE_MONO? 1 : 2); - _sampleRate = rate; - - _lock.Unlock(); - } - -#ifdef __DEBUG__ - void SBC::DumpConfiguration() const - { - #define ELEM(name, val, prop) (_T(" [ %d] " name " [ %d]"), !!(_supported.val() & Format::prop), !!(_actuals.val() & Format::prop)) - TRACE(Trace::Information, (_T("SBC configuration:"))); - TRACE(Trace::Information, ELEM("Sampling frequency - 16 kHz ", SamplingFrequency, SF_16000_HZ)); - TRACE(Trace::Information, ELEM("Sampling frequency - 32 kHz ", SamplingFrequency, SF_32000_HZ)); - TRACE(Trace::Information, ELEM("Sampling frequency - 44.1 kHz ", SamplingFrequency, SF_44100_HZ)); - TRACE(Trace::Information, ELEM("Sampling frequency - 48 kHz ", SamplingFrequency, SF_48000_HZ)); - TRACE(Trace::Information, ELEM("Channel mode - Mono ", ChannelMode, CM_MONO)); - TRACE(Trace::Information, ELEM("Channel mode - Stereo ", ChannelMode, CM_STEREO)); - TRACE(Trace::Information, ELEM("Channel mode - Dual Channel ", ChannelMode, CM_DUAL_CHANNEL)); - TRACE(Trace::Information, ELEM("Channel mode - Joint Stereo ", ChannelMode, CM_JOINT_STEREO)); - TRACE(Trace::Information, ELEM("Block length - 4 ", BlockLength, BL_4)); - TRACE(Trace::Information, ELEM("Block length - 8 ", BlockLength, BL_8)); - TRACE(Trace::Information, ELEM("Block length - 12 ", BlockLength, BL_12)); - TRACE(Trace::Information, ELEM("Block length - 16 ", BlockLength, BL_16)); - TRACE(Trace::Information, ELEM("Frequency sub-bands - 4 ", SubBands, SB_4)); - TRACE(Trace::Information, ELEM("Frequency sub-bands - 8 ", SubBands, SB_8)); - TRACE(Trace::Information, ELEM("Bit allocation method - SNR ", AllocationMethod, AM_SNR)); - TRACE(Trace::Information, ELEM("Bit allocation method - Loudness", AllocationMethod, AM_LOUDNESS)); - TRACE(Trace::Information, (_T(" [%3d] Minimal bitpool value [%3d]"), _supported.MinBitpool(), _actuals.MinBitpool())); - TRACE(Trace::Information, (_T(" [%3d] Maximal bitpool value [%3d]"), _supported.MaxBitpool(), _actuals.MaxBitpool())); - #undef ELEM - } - - void SBC::DumpBitrateConfiguration() const - { - Core::EnumerateType preset(_preset); - TRACE(Trace::Information, (_T("Quality preset: %s"), (preset.IsSet() == true? preset.Data() : "(custom)"))); - TRACE(Trace::Information, (_T("Bitpool value: %d"), _bitpool)); - TRACE(Trace::Information, (_T("Bitrate: %d bps"), _bitRate)); - TRACE(Trace::Information, (_T("Frame size: raw %d bytes, encoded %d bytes (%d us)"), _rawFrameSize, _encodedFrameSize, _frameDuration)); - } -#endif // __DEBUG__ - -} // namespace A2DP - -} // namespace Bluetooth - -} diff --git a/Source/bluetooth/audio/codecs/SBC.h b/Source/bluetooth/audio/codecs/SBC.h deleted file mode 100644 index e480361..0000000 --- a/Source/bluetooth/audio/codecs/SBC.h +++ /dev/null @@ -1,375 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2021 Metrological - * - * 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. - */ - -#pragma once - -#include "../Module.h" -#include "../IAudioCodec.h" -#include "../DataRecord.h" - -namespace Thunder { - -namespace Bluetooth { - -namespace A2DP { - - class EXTERNAL SBC : public IAudioCodec { - public: - static constexpr uint8_t CODEC_TYPE = 0x00; // SBC - - static constexpr uint8_t MIN_BITPOOL = 2; - static constexpr uint8_t MAX_BITPOOL = 250; - - public: - enum preset { - COMPATIBLE, - LQ, - MQ, - HQ, - XQ - }; - - class Config : public Core::JSON::Container { - public: - enum channelmode { - MONO, - STEREO, - JOINT_STEREO, - DUAL_CHANNEL - }; - - public: - Config(const Config&) = delete; - Config& operator=(const Config&) = delete; - Config() - : Core::JSON::Container() - , Preset(COMPATIBLE) - , ChannelMode(JOINT_STEREO) - , Bitpool(MIN_BITPOOL) - { - Add(_T("preset"), &Preset); - Add(_T("channelmode"), &ChannelMode); - Add(_T("bitpool"), &Bitpool); - } - ~Config() = default; - - public: - Core::JSON::EnumType Preset; - Core::JSON::EnumType ChannelMode; - Core::JSON::DecUInt32 Bitpool; - }; // class Config - - class Format { - public: - enum samplingfrequency : uint8_t { - SF_INVALID = 0, - SF_48000_HZ = 1, // mandatory for sink - SF_44100_HZ = 2, // mandatory for sink - SF_32000_HZ = 4, - SF_16000_HZ = 8 - }; - - enum channelmode : uint8_t { - CM_INVALID = 0, - CM_JOINT_STEREO = 1, // all mandatory for sink - CM_STEREO = 2, - CM_DUAL_CHANNEL = 4, - CM_MONO = 8 - }; - - enum blocklength : uint8_t { - BL_INVALID = 0, - BL_16 = 1, // all mandatory for sink - BL_12 = 2, - BL_8 = 4, - BL_4 = 8, - }; - - enum subbands : uint8_t { - SB_INVALID = 0, - SB_8 = 1, // all mandatory for sink - SB_4 = 2, - }; - - enum allocationmethod : uint8_t { - AM_INVALID = 0, - AM_LOUDNESS = 1, // all mandatory for sink - AM_SNR = 2, - }; - - public: - Format() - : _samplingFrequency(SF_44100_HZ) - , _channelMode(CM_JOINT_STEREO) - , _blockLength(BL_16) - , _subBands(SB_8) - , _allocationMethod(AM_LOUDNESS) - , _minBitpool(MIN_BITPOOL) - , _maxBitpool(MIN_BITPOOL) // not an error - { - } - Format(const uint8_t stream[], const uint16_t length) - : _samplingFrequency(SF_44100_HZ) - , _channelMode(CM_JOINT_STEREO) - , _blockLength(BL_16) - , _subBands(SB_8) - , _allocationMethod(AM_LOUDNESS) - , _minBitpool(MIN_BITPOOL) - , _maxBitpool(MIN_BITPOOL) // not an error - { - Deserialize(stream, length); - } - Format(const uint16_t maxBitpool, const uint16_t minBitpool) - : _samplingFrequency(SF_16000_HZ | SF_32000_HZ | SF_44100_HZ | SF_48000_HZ) - , _channelMode(CM_MONO | CM_DUAL_CHANNEL | CM_STEREO | CM_JOINT_STEREO) - , _blockLength(BL_4 | BL_8 | BL_12 | BL_16) - , _subBands(SB_4 | SB_8) - , _allocationMethod(AM_LOUDNESS | AM_SNR) - , _minBitpool(minBitpool) - , _maxBitpool(maxBitpool) - { - } - ~Format() = default; - Format(const Format&) = default; - Format& operator=(const Format&) = default; - - public: - uint16_t Serialize(uint8_t stream[], const uint16_t length) const - { - ASSERT(length >= 6); - - uint8_t octet; - Bluetooth::DataRecord data(stream, length, 0); - - data.Push(IAudioCodec::MEDIA_TYPE); - data.Push(CODEC_TYPE); - - octet = ((static_cast(_samplingFrequency) << 4) | static_cast(_channelMode)); - data.Push(octet); - - octet = ((static_cast(_blockLength) << 4) | (static_cast(_subBands) << 2) | static_cast(_allocationMethod)); - data.Push(octet); - - data.Push(_minBitpool); - data.Push(_maxBitpool); - - return (data.Length()); - } - uint16_t Deserialize(const uint8_t stream[], const uint16_t length) - { - ASSERT(length >= 6); - - Bluetooth::DataRecord data(stream, length); - - uint8_t octet{}; - - data.Pop(octet); - ASSERT(octet == IAudioCodec::MEDIA_TYPE); - - data.Pop(octet); - ASSERT(octet == CODEC_TYPE); - - data.Pop(octet); - _samplingFrequency = (octet >> 4); - _channelMode = (octet & 0xF); - - data.Pop(octet); - _blockLength = (octet >> 4); - _subBands = ((octet >> 2) & 0x3); - _allocationMethod = (octet & 0x3); - - data.Pop(_minBitpool); - data.Pop(_maxBitpool); - - return (6); - } - - public: - uint8_t SamplingFrequency() const { - return (_samplingFrequency); - } - uint8_t ChannelMode() const { - return (_channelMode); - } - uint8_t BlockLength() const { - return (_blockLength); - } - uint8_t SubBands() const { - return (_subBands); - } - uint8_t AllocationMethod() const { - return (_allocationMethod); - } - uint8_t MinBitpool() const { - return (_minBitpool); - } - uint8_t MaxBitpool() const { - return (_maxBitpool); - } - - public: - void SamplingFrequency(const samplingfrequency sf) - { - _samplingFrequency = sf; - } - void ChannelMode(const channelmode cm) - { - _channelMode = cm; - } - void BlockLength(const blocklength bl) - { - _blockLength = bl; - } - void SubBands(const subbands sb) - { - _subBands = sb; - } - void AllocationMethod(const allocationmethod am) - { - _allocationMethod = am; - } - void MinBitpool(const uint8_t value) - { - _minBitpool = (value < MIN_BITPOOL? MIN_BITPOOL : value); - } - void MaxBitpool(const uint8_t value) - { - _maxBitpool = (value > MAX_BITPOOL? MAX_BITPOOL : value); - } - - private: - uint8_t _samplingFrequency; - uint8_t _channelMode; - uint8_t _blockLength; - uint8_t _subBands; - uint8_t _allocationMethod; - uint8_t _minBitpool; - uint8_t _maxBitpool; - }; // class Format - - public: - SBC(const uint8_t maxBitpool, const uint8_t minBitpool = 2) - : _lock() - , _supported(maxBitpool, minBitpool) - , _actuals() - , _preset(COMPATIBLE) - , _sbcHandle(nullptr) - , _preferredBitpool(0) - , _bitpool(0) - , _bitRate(0) - , _sampleRate(0) - , _channels(0) - , _rawFrameSize(0) - , _encodedFrameSize(0) - , _frameDuration(0) - { - SBCInitialize(); - } - SBC(const Bluetooth::Buffer& config) - : _lock() - , _supported(config.data(), config.length()) - , _actuals() - , _preset(COMPATIBLE) - , _sbcHandle(nullptr) - , _preferredBitpool(0) - , _bitpool(0) - , _bitRate(0) - , _sampleRate(0) - , _channels(0) - , _rawFrameSize(0) - , _encodedFrameSize(0) - , _frameDuration(0) - { - SBCInitialize(); - } - ~SBC() override - { - SBCDeinitialize(); - } - - public: - IAudioCodec::codectype Type() const override { - return (IAudioCodec::codectype::LC_SBC); - } - uint32_t BitRate() const override { - return (_bitRate); - } - uint16_t RawFrameSize() const override { - return (_rawFrameSize); - } - uint16_t EncodedFrameSize() const override { - return (_encodedFrameSize); - } - - uint32_t Configure(const uint8_t stream[], const uint16_t length) override; - uint32_t Configure(const StreamFormat& format, const string& settings) override; - - void Configuration(StreamFormat& format, string& settings) const override; - - uint32_t QOS(const int8_t policy); - - uint16_t Encode(const uint16_t inBufferSize, const uint8_t inBuffer[], - uint16_t& outBufferSize, uint8_t outBuffer[]) const override; - - uint16_t Decode(const uint16_t inBufferSize, const uint8_t inBuffer[], - uint16_t& outBufferSize, uint8_t outBuffer[]) const override; - - uint16_t Serialize(const bool capabilities, uint8_t stream[], const uint16_t length) const override; - - private: - void Bitpool(uint8_t value); - - private: -#ifdef __DEBUG__ - void DumpConfiguration() const; - void DumpBitrateConfiguration() const; -#endif - - private: - void SBCInitialize(); - void SBCDeinitialize(); - void SBCConfigure(); - - private: - mutable Core::CriticalSection _lock; - Format _supported; - Format _actuals; - preset _preset; - void* _sbcHandle; - uint8_t _preferredBitpool; - uint8_t _bitpool; - uint32_t _bitRate; - uint32_t _sampleRate; - uint8_t _channels; - uint16_t _rawFrameSize; - uint16_t _encodedFrameSize; - uint32_t _frameDuration; - - private: - struct SBCHeader { - uint8_t frameCount; - } __attribute__((packed)); - - }; // class SBC - -} // namespace A2DP - -} // namespace Bluetooth - -} diff --git a/Source/bluetooth/bluetooth.h b/Source/bluetooth/bluetooth.h deleted file mode 100644 index 51a0093..0000000 --- a/Source/bluetooth/bluetooth.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#pragma once - -#ifndef MODULE_NAME -#error "Please define a MODULE_NAME that describes the binary/library you are building." -#endif - -#include "IDriver.h" -#include "HCISocket.h" -#include "UUID.h" -#include "Debug.h" - -#ifdef __WINDOWS__ -#pragma comment(lib, "bluetooth.lib") -#endif diff --git a/Source/bluetooth/cmake/FindBluez5UtilHeaders.cmake b/Source/bluetooth/cmake/FindBluez5UtilHeaders.cmake deleted file mode 100644 index 3856c0f..0000000 --- a/Source/bluetooth/cmake/FindBluez5UtilHeaders.cmake +++ /dev/null @@ -1,66 +0,0 @@ -# - Try to find Bluez Utils Headers -# Once done this will define -# Bluez5UtilHeaders::Bluez5UtilHeaders - The bluez include directories -# -# Copyright (C) 2022 Metrological. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS CONTRIBUTORS ``AS -# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ITS -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE - -if(Bluez5UtilHeaders_FIND_QUIETLY) - set(_FIND_MODE QUIET) -elseif(Bluez5UtilHeaders_FIND_REQUIRED) - set(_FIND_MODE REQUIRED) -endif() - -set(NEEDED_BLUEZ_HEADERS - bluetooth.h - hci.h - mgmt.h - l2cap.h -) - -set(BLUEZ_INCLUDE_DIRS) - -foreach(_header ${NEEDED_BLUEZ_HEADERS}) - find_path(_header_path bluetooth/${_header}) - if(_header_path) - message(VERBOSE "Found ${_header} in ${_header_path}") - list(APPEND BLUEZ_INCLUDE_DIRS ${_header_path}) - endif() -endforeach() - -list(REMOVE_DUPLICATES BLUEZ_INCLUDE_DIRS) - -add_library(Bluez5UtilHeaders INTERFACE) - -target_include_directories(Bluez5UtilHeaders - INTERFACE - INTERFACE_INCLUDE_DIRECTORIES ${BLUEZ_INCLUDE_DIRS} -) - -add_library(Bluez5UtilHeaders::Bluez5UtilHeaders ALIAS Bluez5UtilHeaders) - -message(TRACE "BLUEZ_INCLUDE_DIRS ${BLUEZ_INCLUDE_DIRS}") - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(Bluez5UtilHeaders DEFAULT_MSG BLUEZ_INCLUDE_DIRS) -mark_as_advanced(BLUEZ_INCLUDE_DIRS) diff --git a/Source/bluetooth/drivers/BCM43XX.cpp b/Source/bluetooth/drivers/BCM43XX.cpp deleted file mode 100644 index 437cbe2..0000000 --- a/Source/bluetooth/drivers/BCM43XX.cpp +++ /dev/null @@ -1,417 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#include "SerialDriver.h" -#include -#include - -namespace Thunder { - -namespace Bluetooth { - - class Broadcom43XX : public SerialDriver { - private: - Broadcom43XX() = delete; - Broadcom43XX(const Broadcom43XX&) = delete; - Broadcom43XX& operator=(const Broadcom43XX&) = delete; - - // Vendor-specyfic HCI commands - static constexpr uint16_t BCM43XX_WRITE_LOCAL_CLOCK = 0x0045; - static constexpr uint16_t BCM43XX_WRITE_LOCAL_SPEED = 0x0018; - static constexpr uint16_t BCM43XX_WRITE_LOCAL_ADDRESS = 0x0001; - static constexpr uint16_t BCM43XX_WRITE_LOCAL_FIRMWARE = 0x002e; - - static constexpr uint8_t BCM43XX_CLOCK_48 = 1; - static constexpr uint8_t BCM43XX_CLOCK_24 = 2; - static constexpr uint8_t CMD_SUCCESS = 0; - - public: - class Config : public Core::JSON::Container { - private: - Config(const Config&); - Config& operator=(const Config&); - - public: - Config() - : Core::JSON::Container() - , Port(_T("/dev/ttyAMA0")) - , Firmware(_T("/etc/firmware/")) - , SetupRate(115200) - , BaudRate(921600) - , MACAddress() - , Break(false) - , SerialAsMAC(false) - { - Add(_T("port"), &Port); - Add(_T("firmware"), &Firmware); - Add(_T("baudrate"), &BaudRate); - Add(_T("setup"), &SetupRate); - Add(_T("address"), &MACAddress); - Add(_T("break"), &Break); - Add(_T("serialmac"), &SerialAsMAC); - } - ~Config() - { - } - - public: - Core::JSON::String Port; - Core::JSON::String Firmware; - Core::JSON::DecUInt32 SetupRate; - Core::JSON::DecUInt32 BaudRate; - Core::JSON::String MACAddress; - Core::JSON::Boolean Break; - Core::JSON::Boolean SerialAsMAC; - }; - - public: - Broadcom43XX(const Config& config) - : SerialDriver(config.Port.Value(), config.SetupRate.Value(), Core::SerialPort::OFF, config.Break.Value()) - , _directory(config.Firmware.Value()) - , _name() - , _MACLength(0) - , _setupRate(config.SetupRate.Value()) - , _baudRate(config.BaudRate.Value()) - { - uint8_t max = 0; - - if (config.MACAddress.IsSet() == true) { - Bluetooth::Address address (config.MACAddress.Value().c_str()); - - if (address.IsValid() == true) { - max = std::min(address.Length(), static_cast(sizeof(_MACAddress))); - ::memcpy (_MACAddress, address.Data(), max); - } - } - else if (config.SerialAsMAC.Value() == true) { - const uint8_t* mac = GetDeviceMAC(); - max = std::min(mac[0], static_cast(sizeof(_MACAddress))); - for (uint8_t index = 1; index <= max; index++) { - _MACAddress[max - index] = mac[index]; - } - } - - if (max > 0) { - if (max < sizeof(_MACAddress)) { - ::memset(&(_MACAddress[max]), 0, sizeof(_MACAddress) - max); - } - _MACLength = sizeof(_MACAddress); - } - } - virtual ~Broadcom43XX() - { - } - - public: - const char* Initialize() - { - const char* result = nullptr; - - if (Reset() != Core::ERROR_NONE) { - ::SleepMs(500); - SetBaudRate(_baudRate); - result = "Initial reset failed!!!"; - } - - if ((result != nullptr) && (Reset() != Core::ERROR_NONE)) { - result = "Could not reset the chip to a defined state"; - } - else if (LoadName() != Core::ERROR_NONE) { - result = "Could not load the drivers name."; - } - else if (SetSpeed(_baudRate) != Core::ERROR_NONE) { - result = "Could not set the BaudRate (first time)"; - } - else { - uint16_t index = 0; - while (isalnum(_name[index++])) /* INTENTIONALLY LEFT EMPTY */ ; - uint32_t loaded = Firmware(_directory, _name.substr(0, index - 1)); - - result = nullptr; - - // It has been observed that once the firmware is loaded the name of - // the device changes from BCM43430A1 to BCM43438A1, this is due to - // a previous load, that is not nessecarely an issue :-) - if (loaded == Core::ERROR_NONE) { - // Controller speed has been reset to default speed!!! - SetBaudRate(_setupRate); - - if (Reset() != Core::ERROR_NONE) { - result = "Could not reset the device after the firmware upload"; - } - else if (SetSpeed(_baudRate) != Core::ERROR_NONE) { - result = "Could not set the BaudRate (second time)"; - } - } else if (loaded != Core::ERROR_ALREADY_CONNECTED) { - result = "Could not upload firmware."; - } - - if ((result == nullptr) && (_MACLength > 0)) { - if (MACAddress(_MACLength, _MACAddress) != Core::ERROR_NONE) { - result = "Could not set the MAC Address specified."; - } - } - - if ( (result == nullptr) && (SerialDriver::Setup(0, HCI_UART_H4) != Core::ERROR_NONE) ) { - result = "Could not set up the driver in H4 mode."; - } - } - - return (result); - } - uint32_t Reset() - { - const uint16_t command = cmd_opcode_pack(OGF_HOST_CTL, OCF_RESET); - Exchange::Response response(Exchange::COMMAND_PKT, command); - uint32_t result = Exchange(Exchange::Request(Exchange::COMMAND_PKT, command, 0, nullptr), response, 1000); - - if ((result == Core::ERROR_NONE) && (response[3] != CMD_SUCCESS)) { - TRACE_L1("Failed to reset chip, command failure\n"); - result = Core::ERROR_GENERAL; - } - - return result; - } - - private: - string FindFirmware(const string& directory, const string& chipName) - { - string result; - Core::Directory index(directory.c_str(), "*.hcd"); - - while ((result.empty() == true) && (index.Next() == true)) { - - if (index.Name() == chipName) { - result = index.Current(); - } else if ((index.IsDirectory() == true) && (index.Name() != _T(".")) && (index.Name() != _T(".."))) { - - result = FindFirmware(index.Current(), chipName); - } - } - - return (result); - } - uint32_t LoadName() - { - const uint16_t command = cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_LOCAL_NAME); - Exchange::Response response(Exchange::COMMAND_PKT, command); - uint32_t result = Exchange(Exchange::Request(Exchange::COMMAND_PKT, command, 0, nullptr), response, 500); - - if ((result == Core::ERROR_NONE) && (response[3] != CMD_SUCCESS)) { - TRACE_L1("Failed to read local name, command failure\n"); - result = Core::ERROR_GENERAL; - } - if (result == Core::ERROR_NONE) { - _name = string(reinterpret_cast(&(response[4]))); - } - return (result); - } - uint32_t SetClock(const uint8_t clock) - { - const uint16_t command = cmd_opcode_pack(OGF_VENDOR_CMD, BCM43XX_WRITE_LOCAL_CLOCK); - Exchange::Response response(Exchange::COMMAND_PKT, command); - uint32_t result = Exchange(Exchange::Request(Exchange::COMMAND_PKT, command, 1, &clock), response, 500); - - if ((result == Core::ERROR_NONE) && (response[3] != CMD_SUCCESS)) { - TRACE_L1("Failed to read local name, command failure\n"); - result = Core::ERROR_GENERAL; - } - - return (result); - } - uint32_t SetSpeed(const uint32_t baudrate) - { - uint32_t result = Core::ERROR_NONE; - const uint16_t command = cmd_opcode_pack(OGF_VENDOR_CMD, BCM43XX_WRITE_LOCAL_SPEED); - - if (baudrate > 3000000) { - result = SetClock(BCM43XX_CLOCK_48); - Flush(); - } - - if (result == Core::ERROR_NONE) { - uint8_t data[6]; - - data[0] = 0x00; - data[1] = 0x00; - data[2] = static_cast(baudrate & 0xFF); - data[3] = static_cast((baudrate >> 8) & 0xFF); - data[4] = static_cast((baudrate >> 16) & 0xFF); - data[5] = static_cast((baudrate >> 24) & 0xFF); - - Exchange::Response response(Exchange::COMMAND_PKT, command); - uint32_t result = Exchange(Exchange::Request(Exchange::COMMAND_PKT, command, sizeof(data), data), response, 500); - - if ((result == Core::ERROR_NONE) && (response[3] != CMD_SUCCESS)) { - TRACE_L1("Failed to read local name, command failure\n"); - result = Core::ERROR_GENERAL; - } else { - SetBaudRate(baudrate); - } - } - - return (result); - } - uint32_t MACAddress(const uint8_t length, const uint8_t address[]) - { - uint8_t data[6]; - ::memset(data, 0, sizeof(data)); - ::memcpy(data, address, std::min(length, static_cast(sizeof(data)))); - const uint16_t command = cmd_opcode_pack(OGF_VENDOR_CMD, BCM43XX_WRITE_LOCAL_ADDRESS); - - Exchange::Response response(Exchange::COMMAND_PKT, command); - uint32_t result = Exchange(Exchange::Request(Exchange::COMMAND_PKT, command, sizeof(data), data), response, 500); - - if ((result == Core::ERROR_NONE) && (response[3] != CMD_SUCCESS)) { - TRACE_L1("Failed to set the MAC address\n"); - result = Core::ERROR_GENERAL; - } - - return (result); - } - uint32_t Firmware(const string& directory, const string& name) - { - uint32_t result = Core::ERROR_UNAVAILABLE; - string searchPath = Core::Directory::Normalize(directory); - string firmwareName = FindFirmware(searchPath, name + ".hcd"); - const uint16_t command = cmd_opcode_pack(OGF_VENDOR_CMD, BCM43XX_WRITE_LOCAL_FIRMWARE); - - if (firmwareName.empty() == true) { - // It has been observed that once the firmware is loaded the name of - // the device changes from BCM43430A1 to BCM43438A1, this is due to - // a previous load, that is not nessecarely an issue :-) - result = Core::ERROR_ALREADY_CONNECTED; - } else { - int fd = open(firmwareName.c_str(), O_RDONLY); - - if (fd >= 0) { - Exchange::Response response(Exchange::COMMAND_PKT, command); - result = Exchange(Exchange::Request(Exchange::COMMAND_PKT, command, 0, nullptr), response, 500); - - Flush(); - - if ((result == Core::ERROR_NONE) && (response[3] != CMD_SUCCESS)) { - TRACE_L1("Failed to set chip to download firmware, code: %d", response[3]); - result = Core::ERROR_GENERAL; - } - - if (result == Core::ERROR_NONE) { - int loaded = 0; - uint8_t tx_buf[255]; - - /* Wait 50ms to let the firmware placed in download mode */ - SleepMs(50); - Flush(); - - while ((result == Core::ERROR_NONE) && ((loaded = read(fd, tx_buf, 3)) > 0)) { - uint16_t code = tx_buf[0] | (tx_buf[1] << 8); - uint8_t len = tx_buf[2]; - - if (read(fd, tx_buf, len) < 0) { - result = Core::ERROR_READ_ERROR; - } else { - Exchange::Response response(Exchange::COMMAND_PKT, code); - result = Exchange(Exchange::Request(Exchange::COMMAND_PKT, code, len, tx_buf), response, 500); - Flush(); - } - } - - if ((loaded != 0) && (result == Core::ERROR_NONE)) { - result = Core::ERROR_NEGATIVE_ACKNOWLEDGE; - } - - /* Wait for firmware ready */ - SleepMs(2000); - } - - close(fd); - } - } - - return (result); - } - const uint8_t* GetDeviceMAC() const - { - static uint8_t MACAddressBuffer[Core::AdapterIterator::MacSize]; - - memset(MACAddressBuffer, 0, Core::AdapterIterator::MacSize); - - Core::AdapterIterator adapters; - while ((adapters.Next() == true)) { - if (adapters.HasMAC() == true) { - adapters.MACAddress(MACAddressBuffer, Core::AdapterIterator::MacSize); - break; - } - } - - return MACAddressBuffer; - } - - private: - const string _directory; - string _name; - uint8_t _MACLength; - uint8_t _MACAddress[Core::AdapterIterator::MacSize]; - uint32_t _setupRate; - uint32_t _baudRate; - }; -} -} // namespace Thunder::Bluetooth - - -#ifdef __cplusplus -extern "C" { -#endif - -Thunder::Bluetooth::Broadcom43XX* g_driver = nullptr; - -const char* construct_bluetooth_driver(const char* input) { - const char* result = "Driver already loaded."; - - if (g_driver == nullptr) { - Thunder::Bluetooth::Broadcom43XX::Config config; - config.FromString(input); - Thunder::Bluetooth::Broadcom43XX* driver = new Thunder::Bluetooth::Broadcom43XX(config); - - - result = driver->Initialize(); - - if (result == nullptr) { - g_driver = driver; - } - else { - delete driver; - } - } - return (result); -} - -void destruct_bluetooth_driver() { - if (g_driver != nullptr) { - delete g_driver; - g_driver = nullptr; - } -} - - -#ifdef __cplusplus -} -#endif - - diff --git a/Source/bluetooth/drivers/Basic.cpp b/Source/bluetooth/drivers/Basic.cpp deleted file mode 100644 index 20aecaa..0000000 --- a/Source/bluetooth/drivers/Basic.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -const char* construct_bluetooth_driver(const char* /* config */) { - return (nullptr); -} - -void destruct_bluetooth_driver() { -} - - -#ifdef __cplusplus -} -#endif - diff --git a/Source/bluetooth/drivers/SerialDriver.h b/Source/bluetooth/drivers/SerialDriver.h deleted file mode 100644 index 30561a5..0000000 --- a/Source/bluetooth/drivers/SerialDriver.h +++ /dev/null @@ -1,476 +0,0 @@ - /* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#include "../Module.h" - -namespace Thunder { - -namespace Bluetooth { - -// #define DUMP_FRAMES 1 - -#define HCIUARTSETPROTO _IOW('U', 200, int) -#define HCIUARTGETPROTO _IOR('U', 201, int) -#define HCIUARTGETDEVICE _IOR('U', 202, int) -#define HCIUARTSETFLAGS _IOW('U', 203, int) -#define HCIUARTGETFLAGS _IOR('U', 204, int) - -#define HCI_UART_H4 0 -#define HCI_UART_BCSP 1 -#define HCI_UART_3WIRE 2 -#define HCI_UART_H4DS 3 -#define HCI_UART_LL 4 -#define HCI_UART_ATH3K 5 -#define HCI_UART_INTEL 6 -#define HCI_UART_BCM 7 -#define HCI_UART_QCA 8 -#define HCI_UART_AG6XX 9 -#define HCI_UART_NOKIA 10 -#define HCI_UART_MRVL 11 - - class EXTERNAL SerialDriver { - private: - SerialDriver() = delete; - SerialDriver(const SerialDriver&) = delete; - SerialDriver& operator=(const SerialDriver&) = delete; - - public: - // - // Exchange holds a definitions of a request and a response for the communication with the - // HCI. See Thunder/Source/core/StreamTypeKeyValue.h for more details. - // - struct Exchange { - - enum command : uint8_t { - COMMAND_PKT = 0x01, - EVENT_PKT = 0x04 - }; - - static constexpr uint32_t BUFFERSIZE = 255; - -#ifdef DUMP_FRAMES - static void DumpFrame(const char header[], const uint8_t length, const uint8_t stream[]) - { - printf("%s ", header); - for (uint8_t index = 0; index < length; index++) { - if (index != 0) { - printf(":"); - } - printf("%02X", stream[index]); - } - printf("\n"); - } -#else -#define DumpFrame(X, Y, Z) -#endif - - class Request { - private: - Request() = delete; - Request(const Request& copy) = delete; - Request& operator=(const Request& copy) = delete; - - protected: - inline Request(const uint8_t* value) - : _command(EVENT_PKT) - , _sequence(0) - , _length(0) - , _offset(0) - , _value(value) - { - ASSERT(value != nullptr); - } - inline Request(const command& cmd, const uint16_t sequence, const uint8_t* value) - : _command(cmd) - , _sequence(sequence) - , _length(0) - , _offset(0) - , _value(value) - { - ASSERT(value != nullptr); - } - - public: - inline Request(const command& cmd, const uint16_t sequence, const uint8_t length, const uint8_t* value) - : _command(cmd) - , _sequence(sequence) - , _length(length) - , _offset(0) - , _value(value) - { - ASSERT((value != nullptr) || (length == 0)); - } - inline ~Request() - { - } - - public: - inline void Reset() - { - Request::Offset(0); - } - inline command Command() const - { - return (_command); - } - inline uint16_t Sequence() const - { - return (_sequence); - } - inline uint8_t Length() const - { - return (_length); - } - inline const uint8_t* Value() const - { - return (_value); - } - inline uint16_t Acknowledge() const - { - return (_command != EVENT_PKT ? _sequence : (_length > 2 ? (_value[1] | (_value[2] << 8)) : ~0)); - } - inline command Response() const - { - return (_command != EVENT_PKT ? _command : static_cast(_length > 0 ? _value[0] : ~0)); - } - inline uint8_t DataLength() const - { - return (_length - EventOffset()); - } - inline const uint8_t& operator[](const uint8_t index) const - { - ASSERT(index < (_length - EventOffset())); - return (_value[index - EventOffset()]); - } - inline uint16_t Serialize(uint8_t stream[], const uint16_t length) const - { - uint16_t result = 0; - - if (_offset == 0) { - _offset++; - stream[result++] = _command; - } - if ((_offset == 1) && ((length - result) > 0)) { - _offset++; - stream[result++] = static_cast((_sequence) & 0xFF); - } - if ((_offset == 2) && ((length - result) > 0)) { - _offset++; - if (_command != EVENT_PKT) { - stream[result++] = static_cast((_sequence >> 8) & 0xFF); - } - } - if ((_offset == 3) && ((length - result) > 0)) { - _offset++; - stream[result++] = _length; - } - if ((length - result) > 0) { - uint16_t copyLength = ((_length - (_offset - 4)) > (length - result) ? (length - result) : (_length - (_offset - 4))); - if (copyLength > 0) { - ::memcpy(&(stream[result]), &(_value[_offset - 4]), copyLength); - _offset += copyLength; - result += copyLength; - } - } - - DumpFrame("OUT:", result, stream); - - return (result); - } - - protected: - inline uint8_t EventOffset() const - { - return (_command != EVENT_PKT ? 0 : (_length > 2 ? 3 : _length)); - } - inline void Command(const command cmd) - { - _command = cmd; - } - inline void Sequence(const uint16_t sequence) - { - _sequence = sequence; - } - inline void Length(const uint8_t length) - { - _length = length; - } - inline void Offset(const uint16_t offset) - { - _offset = offset; - } - inline uint16_t Offset() const - { - return (_offset); - } - - private: - command _command; - uint16_t _sequence; - uint8_t _length; - mutable uint16_t _offset; - const uint8_t* _value; - }; - class Response : public Request { - private: - Response() = delete; - Response(const Response& copy) = delete; - Response& operator=(const Response& copy) = delete; - - public: -PUSH_WARNING(DISABLE_WARNING_MAYBE_UNINITIALIZED) - inline Response(const command cmd, const uint16_t sequence) - : Request(cmd, sequence, _value) - { - } -POP_WARNING() - inline ~Response() - { - } - - public: - bool Copy(const Request& buffer) - { - bool result = false; - - if ((buffer.Response() == Command()) && (buffer.Acknowledge() == Sequence())) { - uint8_t copyLength = static_cast(buffer.Length() < BUFFERSIZE ? buffer.Length() : BUFFERSIZE); - ::memcpy(_value, buffer.Value(), copyLength); - Length(copyLength); - result = true; - } - - return (result); - } - - private: - uint8_t _value[BUFFERSIZE]; - }; - class Buffer : public Request { - private: - Buffer(const Buffer& copy) = delete; - Buffer& operator=(const Buffer& copy) = delete; - - public: - inline Buffer() - : Request(_value) - , _used(0) - { - } - inline ~Buffer() - { - } - - public: - inline void Flush() { - _used = 0; - Length(0); - Offset(0); - } - inline bool Next() - { - bool result = false; - - // Clear the current selected block, move on to the nex block, return true, if - // we have a next block.. - if ((Request::Offset() > 4) && ((Request::Offset() - 4) == Request::Length())) { - Request::Offset(0); - if (_used > 0) { - uint8_t length = _used; - _used = 0; - ::memcpy(&_value[0], &(_value[Request::Length()]), length); - result = Deserialize(_value, length); - } - } - return (result); - } - inline bool Deserialize(const uint8_t stream[], const uint16_t length) - { - uint16_t result = 0; - if (Offset() < 1) { - Command(static_cast(stream[result++])); - Offset(1); - } - if ((Offset() < 2) && ((length - result) > 0)) { - Sequence(stream[result++]); - Offset(2); - } - if ((Offset() < 3) && ((length - result) > 0)) { - if (Command() != EVENT_PKT) { - uint16_t sequence = (stream[result++] << 8) | Sequence(); - Sequence(sequence); - } - Offset(3); - } - if ((Offset() < 4) && ((length - result) > 0)) { - Length(stream[result++]); - Offset(4); - } - if ((length - result) > 0) { - uint16_t copyLength = std::min(Length() - (Offset() - 4), length - result); - if (copyLength > 0) { - ::memcpy(&(_value[Offset() - 4]), &(stream[result]), copyLength); - Offset(Offset() + copyLength); - result += copyLength; - } - } - DumpFrame("IN: ", result, stream); - if (result < length) { - // TODO: This needs furhter investigation in case of failures ...... - uint16_t copyLength = std::min(static_cast((2 * BUFFERSIZE) - (Offset() - 4) - _used), static_cast(length - result)); - ::memcpy(&(_value[Offset() - 4 + _used]), &stream[result], copyLength); - _used += copyLength; - printf("Bytes in store: %d\n", _used); - } - - return ((Offset() >= 4) && ((Offset() - 4) == Length())); - } - - private: - uint16_t _used; - uint8_t _value[2 * BUFFERSIZE]; - }; - }; - - private: - class Channel : public Core::MessageExchangeType { - private: - Channel() = delete; - Channel(const Channel&) = delete; - Channel& operator=(const Channel&) = delete; - - typedef MessageExchangeType BaseClass; - - public: - Channel(SerialDriver& parent, const string& name) - : BaseClass(name) - , _parent(parent) - { - } - virtual ~Channel() - { - } - - private: - virtual void Received(const Exchange::Request& element) override - { - _parent.Received(element); - } - - private: - SerialDriver& _parent; - }; - - protected: - SerialDriver(const string& port, const uint32_t baudRate, const Core::SerialPort::FlowControl flowControl, const bool sendBreak) - : _port(*this, port) - , _flowControl(flowControl) - { - if (_port.Open(100) == Core::ERROR_NONE) { - - ToTerminal(); - _port.Link().Configuration(Core::SerialPort::Convert(baudRate), flowControl); - _port.Flush(); - - if (sendBreak == true) { - _port.Link().SendBreak(); - SleepMs(500); - } - } - else { - printf("Could not open serialport.\n"); - } - } - - public: - virtual ~SerialDriver() - { - if (_port.IsOpen() == true) { - ToTerminal(); - _port.Close(Core::infinite); - } - } - - public: - uint32_t Setup(const unsigned long flags, const int protocol) - { - _port.Flush(); - - int ttyValue = N_HCI; - if (::ioctl(static_cast(_port.Link()).Descriptor(), TIOCSETD, &ttyValue) < 0) { - TRACE_L1("Failed direct IOCTL to TIOCSETD, %d", errno); - } else if (::ioctl(static_cast(_port.Link()).Descriptor(), HCIUARTSETFLAGS, flags) < 0) { - TRACE_L1("Failed HCIUARTSETFLAGS. [flags:%lu]", flags); - } else if (::ioctl(static_cast(_port.Link()).Descriptor(), HCIUARTSETPROTO, protocol) < 0) { - TRACE_L1("Failed HCIUARTSETPROTO. [protocol:%d]", protocol); - } else { - return (Core::ERROR_NONE); - } - - return (Core::ERROR_GENERAL); - } - uint32_t Exchange(const Exchange::Request& request, Exchange::Response& response, const uint32_t allowedTime) - { - return (_port.Exchange(request, response, allowedTime)); - } - void Reconfigure(const uint32_t baudRate) - { - if (_port.IsOpen() == true) { - ToTerminal(); - _port.Close(Core::infinite); - } - if (_port.Open(100) == Core::ERROR_NONE) { - - ToTerminal(); - _port.Link().Configuration(Core::SerialPort::Convert(baudRate), _flowControl); - _port.Flush(); - } - else { - printf("Could not open serialport.\n"); - } - } - void SetBaudRate(const uint32_t baudRate) - { - _port.Link().SetBaudRate(Core::SerialPort::Convert(baudRate)); - _port.Flush(); - } - void Flush() - { - _port.Flush(); - } - virtual void Received(const Exchange::Request& element VARIABLE_IS_NOT_USED) - { - } - - private: - inline void ToTerminal() - { - int ttyValue = N_TTY; - _port.Link().Flush(); - if (::ioctl(static_cast(_port.Link()).Descriptor(), TIOCSETD, &ttyValue) < 0) { - printf("Failed direct IOCTL to TIOCSETD, %d\n", errno); - } - } - - private: - Channel _port; - Core::SerialPort::FlowControl _flowControl; - }; -} -} // namespace Thunder::Bluetooth diff --git a/Source/bluetooth/gatt/CMakeLists.txt b/Source/bluetooth/gatt/CMakeLists.txt deleted file mode 100644 index cf99854..0000000 --- a/Source/bluetooth/gatt/CMakeLists.txt +++ /dev/null @@ -1,107 +0,0 @@ -# If not stated otherwise in this file or this component's license file the -# following copyright and licenses apply: -# -# Copyright 2020 Metrological -# -# 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. - -cmake_minimum_required(VERSION 3.15) - -find_package(Thunder) -find_package(${NAMESPACE}Core REQUIRED) -find_package(${NAMESPACE}Messaging REQUIRED) -find_package(CompileSettingsDebug CONFIG REQUIRED) - -project(${NAMESPACE}BluetoothGATT - VERSION 1.0.0 - DESCRIPTION "Bluetooth GATT library" - LANGUAGES CXX) - -set(TARGET ${PROJECT_NAME}) -message("Setup ${TARGET} v${PROJECT_VERSION}") - -set(PUBLIC_HEADERS - GATTSocket.h - GATTProfile.h - Module.h - bluetooth_gatt.h -) - -add_library(${TARGET} - GATTSocket.cpp - GATTProfile.cpp - Module.cpp -) - -target_link_libraries(${TARGET} - PRIVATE - CompileSettingsDebug::CompileSettingsDebug - ${NAMESPACE}Core::${NAMESPACE}Core - ${NAMESPACE}Messaging::${NAMESPACE}Messaging -) - -set_target_properties(${TARGET} - PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES - FRAMEWORK FALSE - PUBLIC_HEADER "${PUBLIC_HEADERS}" # specify the public headers - VERSION ${PROJECT_VERSION} - SOVERSION ${PROJECT_VERSION_MAJOR} -) - -target_include_directories(${TARGET} - PUBLIC - $ - $ - $ - PRIVATE - "${CMAKE_CURRENT_SOURCE_DIR}/drivers" -) - -target_compile_options(${TARGET} - PRIVATE - -Wno-psabi - -fdiagnostics-color=always -) - -# -# From Bluez >= v5.64 the mgmt_ltk_info struct is changed due to inclusive language changes. -# https://github.com/bluez/bluez/commit/b7d6a7d25628e9b521a29a5c133fcadcedeb2102 -# -include(CheckStructHasMember) -check_struct_has_member("struct mgmt_ltk_info" central "../include/bluetooth/bluetooth.h;../include/bluetooth/mgmt.h" NO_INCLUSIVE_LANGUAGE LANGUAGE C) - -if(${NO_INCLUSIVE_LANGUAGE}) - message(VERBOSE "Your version of bluez don't uses inclusive language anymore") - target_compile_definitions(${TARGET} PUBLIC NO_INCLUSIVE_LANGUAGE) -endif() - -install( - TARGETS ${TARGET} EXPORT ${TARGET}Targets - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT ${NAMESPACE}_Development - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT ${NAMESPACE}_Runtime NAMELINK_COMPONENT ${NAMESPACE}_Development - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${NAMESPACE}_Runtime - FRAMEWORK DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${NAMESPACE}_Runtime - PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${NAMESPACE}/bluetooth/gatt COMPONENT ${NAMESPACE}_Development - INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${NAMESPACE} -) - -InstallPackageConfig( - TARGETS ${TARGET} - DESCRIPTION "${PROJECT_DESCRIPTION}" -) - -InstallCMakeConfig( - TARGETS ${TARGET} -) diff --git a/Source/bluetooth/gatt/GATTProfile.cpp b/Source/bluetooth/gatt/GATTProfile.cpp deleted file mode 100644 index 385c1a2..0000000 --- a/Source/bluetooth/gatt/GATTProfile.cpp +++ /dev/null @@ -1,326 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#include "GATTProfile.h" - -namespace Thunder { - -ENUM_CONVERSION_BEGIN(Bluetooth::GATTProfile::Service::Characteristic::Descriptor::type) - - { Bluetooth::GATTProfile::Service::Characteristic::Descriptor::CharacteristicAggregateFormat, _TXT("CharacteristicAggregateFormat") }, - { Bluetooth::GATTProfile::Service::Characteristic::Descriptor::CharacteristicExtendedPropertie, _TXT("CharacteristicExtendedPropertie") }, - { Bluetooth::GATTProfile::Service::Characteristic::Descriptor::CharacteristicPresentationFormat, _TXT("CharacteristicPresentationFormat") }, - { Bluetooth::GATTProfile::Service::Characteristic::Descriptor::CharacteristicUserDescription, _TXT("CharacteristicUserDescription") }, - { Bluetooth::GATTProfile::Service::Characteristic::Descriptor::ClientCharacteristicConfiguration, _TXT("ClientCharacteristicConfiguration") }, - { Bluetooth::GATTProfile::Service::Characteristic::Descriptor::EnvironmentalSensingConfiguration, _TXT("EnvironmentalSensingConfiguration") }, - { Bluetooth::GATTProfile::Service::Characteristic::Descriptor::EnvironmentalSensingMeasurement, _TXT("EnvironmentalSensingMeasurement") }, - { Bluetooth::GATTProfile::Service::Characteristic::Descriptor::EnvironmentalSensingTriggerSetting, _TXT("EnvironmentalSensingTriggerSetting") }, - { Bluetooth::GATTProfile::Service::Characteristic::Descriptor::ExternalReportReference, _TXT("ExternalReportReference") }, - { Bluetooth::GATTProfile::Service::Characteristic::Descriptor::NumberOfDigital, _TXT("NumberOfDigital") }, - { Bluetooth::GATTProfile::Service::Characteristic::Descriptor::ReportReference, _TXT("ReportReference") }, - { Bluetooth::GATTProfile::Service::Characteristic::Descriptor::ServerCharacteristicConfiguration, _TXT("ServerCharacteristicConfiguration") }, - { Bluetooth::GATTProfile::Service::Characteristic::Descriptor::TimeTriggerSetting, _TXT("TimeTriggerSetting") }, - { Bluetooth::GATTProfile::Service::Characteristic::Descriptor::ValidRange, _TXT("ValidRange") }, - { Bluetooth::GATTProfile::Service::Characteristic::Descriptor::ValueTriggerSetting, _TXT("ValueTriggerSetting") }, - -ENUM_CONVERSION_END(Bluetooth::GATTProfile::Service::Characteristic::Descriptor::type) - -ENUM_CONVERSION_BEGIN(Bluetooth::GATTProfile::Service::Characteristic::type) - - { Bluetooth::GATTProfile::Service::Characteristic::AerobicHeartRateLowerLimit, _TXT("AerobicHeartRateLowerLimit") }, - { Bluetooth::GATTProfile::Service::Characteristic::AerobicHeartRateUpperLimit, _TXT("AerobicHeartRateUpperLimit") }, - { Bluetooth::GATTProfile::Service::Characteristic::AerobicThreshold, _TXT("AerobicThreshold") }, - { Bluetooth::GATTProfile::Service::Characteristic::Age, _TXT("Age") }, - { Bluetooth::GATTProfile::Service::Characteristic::Aggregate, _TXT("Aggregate") }, - { Bluetooth::GATTProfile::Service::Characteristic::AlertCategoryID, _TXT("AlertCategoryID") }, - { Bluetooth::GATTProfile::Service::Characteristic::AlertCategoryIDBitMask, _TXT("AlertCategoryIDBitMask") }, - { Bluetooth::GATTProfile::Service::Characteristic::AlertLevel, _TXT("AlertLevel") }, - { Bluetooth::GATTProfile::Service::Characteristic::AlertNotificationControlPoint, _TXT("AlertNotificationControlPoint") }, - { Bluetooth::GATTProfile::Service::Characteristic::AlertStatus, _TXT("AlertStatus") }, - { Bluetooth::GATTProfile::Service::Characteristic::Altitude, _TXT("Altitude") }, - { Bluetooth::GATTProfile::Service::Characteristic::AnaerobicHeartRateLowerLimit, _TXT("AnaerobicHeartRateLowerLimit") }, - { Bluetooth::GATTProfile::Service::Characteristic::AnaerobicHeartRateUpperLimit, _TXT("AnaerobicHeartRateUpperLimit") }, - { Bluetooth::GATTProfile::Service::Characteristic::AnaerobicThreshold, _TXT("AnaerobicThreshold") }, - { Bluetooth::GATTProfile::Service::Characteristic::Analog, _TXT("Analog") }, - { Bluetooth::GATTProfile::Service::Characteristic::AnalogOutput, _TXT("AnalogOutput") }, - { Bluetooth::GATTProfile::Service::Characteristic::ApparentWindDirection, _TXT("ApparentWindDirection") }, - { Bluetooth::GATTProfile::Service::Characteristic::ApparentWindSpeed, _TXT("ApparentWindSpeed") }, - { Bluetooth::GATTProfile::Service::Characteristic::Appearance, _TXT("Appearance") }, - { Bluetooth::GATTProfile::Service::Characteristic::BarometricPressureTrend, _TXT("BarometricPressureTrend") }, - { Bluetooth::GATTProfile::Service::Characteristic::BatteryLevel, _TXT("BatteryLevel") }, - { Bluetooth::GATTProfile::Service::Characteristic::BatteryLevelState, _TXT("BatteryLevelState") }, - { Bluetooth::GATTProfile::Service::Characteristic::BatteryPowerState, _TXT("BatteryPowerState") }, - { Bluetooth::GATTProfile::Service::Characteristic::BloodPressureFeature, _TXT("BloodPressureFeature") }, - { Bluetooth::GATTProfile::Service::Characteristic::BloodPressureMeasurement, _TXT("BloodPressureMeasurement") }, - { Bluetooth::GATTProfile::Service::Characteristic::BodyCompositionFeature, _TXT("BodyCompositionFeature") }, - { Bluetooth::GATTProfile::Service::Characteristic::BodyCompositionMeasurement, _TXT("BodyCompositionMeasurement") }, - { Bluetooth::GATTProfile::Service::Characteristic::BodySensorLocation, _TXT("BodySensorLocation") }, - { Bluetooth::GATTProfile::Service::Characteristic::BondManagementControlPoint, _TXT("BondManagementControlPoint") }, - { Bluetooth::GATTProfile::Service::Characteristic::BondManagementFeatures, _TXT("BondManagementFeatures") }, - { Bluetooth::GATTProfile::Service::Characteristic::BootKeyboardInputReport, _TXT("BootKeyboardInputReport") }, - { Bluetooth::GATTProfile::Service::Characteristic::BootKeyboardOutputReport, _TXT("BootKeyboardOutputReport") }, - { Bluetooth::GATTProfile::Service::Characteristic::BootMouseInputReport, _TXT("BootMouseInputReport") }, - { Bluetooth::GATTProfile::Service::Characteristic::BSSControlPoint, _TXT("BSSControlPoint") }, - { Bluetooth::GATTProfile::Service::Characteristic::BSSResponse, _TXT("BSSResponse") }, - { Bluetooth::GATTProfile::Service::Characteristic::CGMFeature, _TXT("CGMFeature") }, - { Bluetooth::GATTProfile::Service::Characteristic::CGMMeasurement, _TXT("CGMMeasurement") }, - { Bluetooth::GATTProfile::Service::Characteristic::CGMSessionRunTime, _TXT("CGMSessionRunTime") }, - { Bluetooth::GATTProfile::Service::Characteristic::CGMSessionStartTime, _TXT("CGMSessionStartTime") }, - { Bluetooth::GATTProfile::Service::Characteristic::CGMSpecificOpsControlPoint, _TXT("CGMSpecificOpsControlPoint") }, - { Bluetooth::GATTProfile::Service::Characteristic::CGMStatus, _TXT("CGMStatus") }, - { Bluetooth::GATTProfile::Service::Characteristic::CrossTrainerData, _TXT("CrossTrainerData") }, - { Bluetooth::GATTProfile::Service::Characteristic::CSCFeature, _TXT("CSCFeature") }, - { Bluetooth::GATTProfile::Service::Characteristic::CSCMeasurement, _TXT("CSCMeasurement") }, - { Bluetooth::GATTProfile::Service::Characteristic::CurrentTime, _TXT("CurrentTime") }, - { Bluetooth::GATTProfile::Service::Characteristic::CyclingPowerControlPoint, _TXT("CyclingPowerControlPoint") }, - { Bluetooth::GATTProfile::Service::Characteristic::CyclingPowerFeature, _TXT("CyclingPowerFeature") }, - { Bluetooth::GATTProfile::Service::Characteristic::CyclingPowerMeasurement, _TXT("CyclingPowerMeasurement") }, - { Bluetooth::GATTProfile::Service::Characteristic::CyclingPowerVector, _TXT("CyclingPowerVector") }, - { Bluetooth::GATTProfile::Service::Characteristic::DatabaseChangeIncrement, _TXT("DatabaseChangeIncrement") }, - { Bluetooth::GATTProfile::Service::Characteristic::DateofBirth, _TXT("DateofBirth") }, - { Bluetooth::GATTProfile::Service::Characteristic::DateofThresholdAssessment, _TXT("DateofThresholdAssessment") }, - { Bluetooth::GATTProfile::Service::Characteristic::DateTime, _TXT("DateTime") }, - { Bluetooth::GATTProfile::Service::Characteristic::DateUTC, _TXT("DateUTC") }, - { Bluetooth::GATTProfile::Service::Characteristic::DayDateTime, _TXT("DayDateTime") }, - { Bluetooth::GATTProfile::Service::Characteristic::DayofWeek, _TXT("DayofWeek") }, - { Bluetooth::GATTProfile::Service::Characteristic::DescriptorValueChanged, _TXT("DescriptorValueChanged") }, - { Bluetooth::GATTProfile::Service::Characteristic::DewPoint, _TXT("DewPoint") }, - { Bluetooth::GATTProfile::Service::Characteristic::Digital, _TXT("Digital") }, - { Bluetooth::GATTProfile::Service::Characteristic::DigitalOutput, _TXT("DigitalOutput") }, - { Bluetooth::GATTProfile::Service::Characteristic::DSTOffset, _TXT("DSTOffset") }, - { Bluetooth::GATTProfile::Service::Characteristic::Elevation, _TXT("Elevation") }, - { Bluetooth::GATTProfile::Service::Characteristic::EmailAddress, _TXT("EmailAddress") }, - { Bluetooth::GATTProfile::Service::Characteristic::EmergencyID, _TXT("EmergencyID") }, - { Bluetooth::GATTProfile::Service::Characteristic::EmergencyText, _TXT("EmergencyText") }, - { Bluetooth::GATTProfile::Service::Characteristic::ExactTime100, _TXT("ExactTime100") }, - { Bluetooth::GATTProfile::Service::Characteristic::ExactTime256, _TXT("ExactTime256") }, - { Bluetooth::GATTProfile::Service::Characteristic::FatBurnHeartRateLowerLimit, _TXT("FatBurnHeartRateLowerLimit") }, - { Bluetooth::GATTProfile::Service::Characteristic::FatBurnHeartRateUpperLimit, _TXT("FatBurnHeartRateUpperLimit") }, - { Bluetooth::GATTProfile::Service::Characteristic::FirmwareRevisionString, _TXT("FirmwareRevisionString") }, - { Bluetooth::GATTProfile::Service::Characteristic::FirstName, _TXT("FirstName") }, - { Bluetooth::GATTProfile::Service::Characteristic::FitnessMachineControlPoint, _TXT("FitnessMachineControlPoint") }, - { Bluetooth::GATTProfile::Service::Characteristic::FitnessMachineFeature, _TXT("FitnessMachineFeature") }, - { Bluetooth::GATTProfile::Service::Characteristic::FitnessMachineStatus, _TXT("FitnessMachineStatus") }, - { Bluetooth::GATTProfile::Service::Characteristic::FiveZoneHeartRateLimits, _TXT("FiveZoneHeartRateLimits") }, - { Bluetooth::GATTProfile::Service::Characteristic::FloorNumber, _TXT("FloorNumber") }, - { Bluetooth::GATTProfile::Service::Characteristic::CentralAddressResolution, _TXT("CentralAddressResolution") }, - { Bluetooth::GATTProfile::Service::Characteristic::DeviceName, _TXT("DeviceName") }, - { Bluetooth::GATTProfile::Service::Characteristic::PeripheralPreferredConnectionParameters, _TXT("PeripheralPreferredConnectionParameters") }, - { Bluetooth::GATTProfile::Service::Characteristic::PeripheralPrivacyFlag, _TXT("PeripheralPrivacyFlag") }, - { Bluetooth::GATTProfile::Service::Characteristic::ReconnectionAddress, _TXT("ReconnectionAddress") }, - { Bluetooth::GATTProfile::Service::Characteristic::ServiceChanged, _TXT("ServiceChanged") }, - { Bluetooth::GATTProfile::Service::Characteristic::Gender, _TXT("Gender") }, - { Bluetooth::GATTProfile::Service::Characteristic::GlucoseFeature, _TXT("GlucoseFeature") }, - { Bluetooth::GATTProfile::Service::Characteristic::GlucoseMeasurement, _TXT("GlucoseMeasurement") }, - { Bluetooth::GATTProfile::Service::Characteristic::GlucoseMeasurementContext, _TXT("GlucoseMeasurementContext") }, - { Bluetooth::GATTProfile::Service::Characteristic::GustFactor, _TXT("GustFactor") }, - { Bluetooth::GATTProfile::Service::Characteristic::HardwareRevisionString, _TXT("HardwareRevisionString") }, - { Bluetooth::GATTProfile::Service::Characteristic::HeartRateControlPoint, _TXT("HeartRateControlPoint") }, - { Bluetooth::GATTProfile::Service::Characteristic::HeartRateMax, _TXT("HeartRateMax") }, - { Bluetooth::GATTProfile::Service::Characteristic::HeartRateMeasurement, _TXT("HeartRateMeasurement") }, - { Bluetooth::GATTProfile::Service::Characteristic::HeatIndex, _TXT("HeatIndex") }, - { Bluetooth::GATTProfile::Service::Characteristic::Height, _TXT("Height") }, - { Bluetooth::GATTProfile::Service::Characteristic::HIDControlPoint, _TXT("HIDControlPoint") }, - { Bluetooth::GATTProfile::Service::Characteristic::HIDInformation, _TXT("HIDInformation") }, - { Bluetooth::GATTProfile::Service::Characteristic::HipCircumference, _TXT("HipCircumference") }, - { Bluetooth::GATTProfile::Service::Characteristic::HTTPControlPoint, _TXT("HTTPControlPoint") }, - { Bluetooth::GATTProfile::Service::Characteristic::HTTPEntityBody, _TXT("HTTPEntityBody") }, - { Bluetooth::GATTProfile::Service::Characteristic::HTTPHeaders, _TXT("HTTPHeaders") }, - { Bluetooth::GATTProfile::Service::Characteristic::HTTPStatusCode, _TXT("HTTPStatusCode") }, - { Bluetooth::GATTProfile::Service::Characteristic::HTTPSSecurity, _TXT("HTTPSSecurity") }, - { Bluetooth::GATTProfile::Service::Characteristic::Humidity, _TXT("Humidity") }, - { Bluetooth::GATTProfile::Service::Characteristic::IDDAnnunciationStatus, _TXT("IDDAnnunciationStatus") }, - { Bluetooth::GATTProfile::Service::Characteristic::IDDCommandControlPoint, _TXT("IDDCommandControlPoint") }, - { Bluetooth::GATTProfile::Service::Characteristic::IDDCommandData, _TXT("IDDCommandData") }, - { Bluetooth::GATTProfile::Service::Characteristic::IDDFeatures, _TXT("IDDFeatures") }, - { Bluetooth::GATTProfile::Service::Characteristic::IDDHistoryData, _TXT("IDDHistoryData") }, - { Bluetooth::GATTProfile::Service::Characteristic::IDDRecordAccessControlPoint, _TXT("IDDRecordAccessControlPoint") }, - { Bluetooth::GATTProfile::Service::Characteristic::IDDStatus, _TXT("IDDStatus") }, - { Bluetooth::GATTProfile::Service::Characteristic::IDDStatusChanged, _TXT("IDDStatusChanged") }, - { Bluetooth::GATTProfile::Service::Characteristic::IDDStatusReaderControlPoint, _TXT("IDDStatusReaderControlPoint") }, - { Bluetooth::GATTProfile::Service::Characteristic::IndoorBikeData, _TXT("IndoorBikeData") }, - { Bluetooth::GATTProfile::Service::Characteristic::IndoorPositioningConfiguration, _TXT("IndoorPositioningConfiguration") }, - { Bluetooth::GATTProfile::Service::Characteristic::IntermediateCuffPressure, _TXT("IntermediateCuffPressure") }, - { Bluetooth::GATTProfile::Service::Characteristic::IntermediateTemperature, _TXT("IntermediateTemperature") }, - { Bluetooth::GATTProfile::Service::Characteristic::Irradiance, _TXT("Irradiance") }, - { Bluetooth::GATTProfile::Service::Characteristic::Language, _TXT("Language") }, - { Bluetooth::GATTProfile::Service::Characteristic::LastName, _TXT("LastName") }, - { Bluetooth::GATTProfile::Service::Characteristic::Latitude, _TXT("Latitude") }, - { Bluetooth::GATTProfile::Service::Characteristic::LNControlPoint, _TXT("LNControlPoint") }, - { Bluetooth::GATTProfile::Service::Characteristic::LNFeature, _TXT("LNFeature") }, - { Bluetooth::GATTProfile::Service::Characteristic::LocalEastCoordinate, _TXT("LocalEastCoordinate") }, - { Bluetooth::GATTProfile::Service::Characteristic::LocalNorthCoordinate, _TXT("LocalNorthCoordinate") }, - { Bluetooth::GATTProfile::Service::Characteristic::LocalTimeInformation, _TXT("LocalTimeInformation") }, - { Bluetooth::GATTProfile::Service::Characteristic::LocationandSpeedCharacteristic, _TXT("LocationandSpeedCharacteristic") }, - { Bluetooth::GATTProfile::Service::Characteristic::LocationName, _TXT("LocationName") }, - { Bluetooth::GATTProfile::Service::Characteristic::Longitude, _TXT("Longitude") }, - { Bluetooth::GATTProfile::Service::Characteristic::MagneticDeclination, _TXT("MagneticDeclination") }, - { Bluetooth::GATTProfile::Service::Characteristic::MagneticFluxDensity_2D, _TXT("MagneticFluxDensity_2D") }, - { Bluetooth::GATTProfile::Service::Characteristic::MagneticFluxDensity_3D, _TXT("MagneticFluxDensity_3D") }, - { Bluetooth::GATTProfile::Service::Characteristic::ManufacturerNameString, _TXT("ManufacturerNameString") }, - { Bluetooth::GATTProfile::Service::Characteristic::MaximumRecommendedHeartRate, _TXT("MaximumRecommendedHeartRate") }, - { Bluetooth::GATTProfile::Service::Characteristic::MeasurementInterval, _TXT("MeasurementInterval") }, - { Bluetooth::GATTProfile::Service::Characteristic::ModelNumberString, _TXT("ModelNumberString") }, - { Bluetooth::GATTProfile::Service::Characteristic::Navigation, _TXT("Navigation") }, - { Bluetooth::GATTProfile::Service::Characteristic::NetworkAvailability, _TXT("NetworkAvailability") }, - { Bluetooth::GATTProfile::Service::Characteristic::NewAlert, _TXT("NewAlert") }, - { Bluetooth::GATTProfile::Service::Characteristic::ObjectActionControlPoint, _TXT("ObjectActionControlPoint") }, - { Bluetooth::GATTProfile::Service::Characteristic::ObjectChanged, _TXT("ObjectChanged") }, - { Bluetooth::GATTProfile::Service::Characteristic::ObjectFirst_Created, _TXT("ObjectFirst_Created") }, - { Bluetooth::GATTProfile::Service::Characteristic::ObjectID, _TXT("ObjectID") }, - { Bluetooth::GATTProfile::Service::Characteristic::ObjectLast_Modified, _TXT("ObjectLast_Modified") }, - { Bluetooth::GATTProfile::Service::Characteristic::ObjectListControlPoint, _TXT("ObjectListControlPoint") }, - { Bluetooth::GATTProfile::Service::Characteristic::ObjectListFilter, _TXT("ObjectListFilter") }, - { Bluetooth::GATTProfile::Service::Characteristic::ObjectName, _TXT("ObjectName") }, - { Bluetooth::GATTProfile::Service::Characteristic::ObjectProperties, _TXT("ObjectProperties") }, - { Bluetooth::GATTProfile::Service::Characteristic::ObjectSize, _TXT("ObjectSize") }, - { Bluetooth::GATTProfile::Service::Characteristic::ObjectType, _TXT("ObjectType") }, - { Bluetooth::GATTProfile::Service::Characteristic::OTSFeature, _TXT("OTSFeature") }, - { Bluetooth::GATTProfile::Service::Characteristic::PLXContinuousMeasurementCharacteristic, _TXT("PLXContinuousMeasurementCharacteristic") }, - { Bluetooth::GATTProfile::Service::Characteristic::PLXFeatures, _TXT("PLXFeatures") }, - { Bluetooth::GATTProfile::Service::Characteristic::PLXSpot_CheckMeasurement, _TXT("PLXSpot_CheckMeasurement") }, - { Bluetooth::GATTProfile::Service::Characteristic::PnPID, _TXT("PnPID") }, - { Bluetooth::GATTProfile::Service::Characteristic::PollenConcentration, _TXT("PollenConcentration") }, - { Bluetooth::GATTProfile::Service::Characteristic::Position2D, _TXT("Position2D") }, - { Bluetooth::GATTProfile::Service::Characteristic::Position3D, _TXT("Position3D") }, - { Bluetooth::GATTProfile::Service::Characteristic::PositionQuality, _TXT("PositionQuality") }, - { Bluetooth::GATTProfile::Service::Characteristic::Pressure, _TXT("Pressure") }, - { Bluetooth::GATTProfile::Service::Characteristic::ProtocolMode, _TXT("ProtocolMode") }, - { Bluetooth::GATTProfile::Service::Characteristic::PulseOximetryControlPoint, _TXT("PulseOximetryControlPoint") }, - { Bluetooth::GATTProfile::Service::Characteristic::Rainfall, _TXT("Rainfall") }, - { Bluetooth::GATTProfile::Service::Characteristic::RCFeature, _TXT("RCFeature") }, - { Bluetooth::GATTProfile::Service::Characteristic::RCSettings, _TXT("RCSettings") }, - { Bluetooth::GATTProfile::Service::Characteristic::ReconnectionConfigurationControlPoint, _TXT("ReconnectionConfigurationControlPoint") }, - { Bluetooth::GATTProfile::Service::Characteristic::RecordAccessControlPoint, _TXT("RecordAccessControlPoint") }, - { Bluetooth::GATTProfile::Service::Characteristic::RegulatoryCertificationDataList, _TXT("RegulatoryCertificationDataList") }, - { Bluetooth::GATTProfile::Service::Characteristic::ReferenceTimeInformation, _TXT("ReferenceTimeInformation") }, - { Bluetooth::GATTProfile::Service::Characteristic::Removable, _TXT("Removable") }, - { Bluetooth::GATTProfile::Service::Characteristic::Report, _TXT("Report") }, - { Bluetooth::GATTProfile::Service::Characteristic::ReportMap, _TXT("ReportMap") }, - { Bluetooth::GATTProfile::Service::Characteristic::ResolvablePrivateAddressOnly, _TXT("ResolvablePrivateAddressOnly") }, - { Bluetooth::GATTProfile::Service::Characteristic::RestingHeartRate, _TXT("RestingHeartRate") }, - { Bluetooth::GATTProfile::Service::Characteristic::RingerControlpoint, _TXT("RingerControlpoint") }, - { Bluetooth::GATTProfile::Service::Characteristic::RingerSetting, _TXT("RingerSetting") }, - { Bluetooth::GATTProfile::Service::Characteristic::RowerData, _TXT("RowerData") }, - { Bluetooth::GATTProfile::Service::Characteristic::RSCFeature, _TXT("RSCFeature") }, - { Bluetooth::GATTProfile::Service::Characteristic::RSCMeasurement, _TXT("RSCMeasurement") }, - { Bluetooth::GATTProfile::Service::Characteristic::SCControlPoint, _TXT("SCControlPoint") }, - { Bluetooth::GATTProfile::Service::Characteristic::ScanIntervalWindow, _TXT("ScanIntervalWindow") }, - { Bluetooth::GATTProfile::Service::Characteristic::ScanRefresh, _TXT("ScanRefresh") }, - { Bluetooth::GATTProfile::Service::Characteristic::ScientificTemperatureCelsius, _TXT("ScientificTemperatureCelsius") }, - { Bluetooth::GATTProfile::Service::Characteristic::SecondaryTimeZone, _TXT("SecondaryTimeZone") }, - { Bluetooth::GATTProfile::Service::Characteristic::SensorLocation, _TXT("SensorLocation") }, - { Bluetooth::GATTProfile::Service::Characteristic::SerialNumberString, _TXT("SerialNumberString") }, - { Bluetooth::GATTProfile::Service::Characteristic::ServiceRequired, _TXT("ServiceRequired") }, - { Bluetooth::GATTProfile::Service::Characteristic::SoftwareRevisionString, _TXT("SoftwareRevisionString") }, - { Bluetooth::GATTProfile::Service::Characteristic::SportTypeforAerobicandAnaerobicThresholds, _TXT("SportTypeforAerobicandAnaerobicThresholds") }, - { Bluetooth::GATTProfile::Service::Characteristic::StairClimberData, _TXT("StairClimberData") }, - { Bluetooth::GATTProfile::Service::Characteristic::StepClimberData, _TXT("StepClimberData") }, - { Bluetooth::GATTProfile::Service::Characteristic::String, _TXT("String") }, - { Bluetooth::GATTProfile::Service::Characteristic::SupportedHeartRateRange, _TXT("SupportedHeartRateRange") }, - { Bluetooth::GATTProfile::Service::Characteristic::SupportedInclinationRange, _TXT("SupportedInclinationRange") }, - { Bluetooth::GATTProfile::Service::Characteristic::SupportedNewAlertCategory, _TXT("SupportedNewAlertCategory") }, - { Bluetooth::GATTProfile::Service::Characteristic::SupportedPowerRange, _TXT("SupportedPowerRange") }, - { Bluetooth::GATTProfile::Service::Characteristic::SupportedResistanceLevelRange, _TXT("SupportedResistanceLevelRange") }, - { Bluetooth::GATTProfile::Service::Characteristic::SupportedSpeedRange, _TXT("SupportedSpeedRange") }, - { Bluetooth::GATTProfile::Service::Characteristic::SupportedUnreadAlertCategory, _TXT("SupportedUnreadAlertCategory") }, - { Bluetooth::GATTProfile::Service::Characteristic::SystemID, _TXT("SystemID") }, - { Bluetooth::GATTProfile::Service::Characteristic::TDSControlPoint, _TXT("TDSControlPoint") }, - { Bluetooth::GATTProfile::Service::Characteristic::Temperature, _TXT("Temperature") }, - { Bluetooth::GATTProfile::Service::Characteristic::TemperatureCelsius, _TXT("TemperatureCelsius") }, - { Bluetooth::GATTProfile::Service::Characteristic::TemperatureFahrenheit, _TXT("TemperatureFahrenheit") }, - { Bluetooth::GATTProfile::Service::Characteristic::TemperatureMeasurement, _TXT("TemperatureMeasurement") }, - { Bluetooth::GATTProfile::Service::Characteristic::TemperatureType, _TXT("TemperatureType") }, - { Bluetooth::GATTProfile::Service::Characteristic::ThreeZoneHeartRateLimits, _TXT("ThreeZoneHeartRateLimits") }, - { Bluetooth::GATTProfile::Service::Characteristic::TimeAccuracy, _TXT("TimeAccuracy") }, - { Bluetooth::GATTProfile::Service::Characteristic::TimeBroadcast, _TXT("TimeBroadcast") }, - { Bluetooth::GATTProfile::Service::Characteristic::TimeSource, _TXT("TimeSource") }, - { Bluetooth::GATTProfile::Service::Characteristic::TimeUpdateControlPoint, _TXT("TimeUpdateControlPoint") }, - { Bluetooth::GATTProfile::Service::Characteristic::TimeUpdateState, _TXT("TimeUpdateState") }, - { Bluetooth::GATTProfile::Service::Characteristic::TimewithDST, _TXT("TimewithDST") }, - { Bluetooth::GATTProfile::Service::Characteristic::TimeZone, _TXT("TimeZone") }, - { Bluetooth::GATTProfile::Service::Characteristic::TrainingStatus, _TXT("TrainingStatus") }, - { Bluetooth::GATTProfile::Service::Characteristic::TreadmillData, _TXT("TreadmillData") }, - { Bluetooth::GATTProfile::Service::Characteristic::TrueWindDirection, _TXT("TrueWindDirection") }, - { Bluetooth::GATTProfile::Service::Characteristic::TrueWindSpeed, _TXT("TrueWindSpeed") }, - { Bluetooth::GATTProfile::Service::Characteristic::TwoZoneHeartRateLimit, _TXT("TwoZoneHeartRateLimit") }, - { Bluetooth::GATTProfile::Service::Characteristic::TxPowerLevel, _TXT("TxPowerLevel") }, - { Bluetooth::GATTProfile::Service::Characteristic::Uncertainty, _TXT("Uncertainty") }, - { Bluetooth::GATTProfile::Service::Characteristic::UnreadAlertStatus, _TXT("UnreadAlertStatus") }, - { Bluetooth::GATTProfile::Service::Characteristic::URI, _TXT("URI") }, - { Bluetooth::GATTProfile::Service::Characteristic::UserControlPoint, _TXT("UserControlPoint") }, - { Bluetooth::GATTProfile::Service::Characteristic::UserIndex, _TXT("UserIndex") }, - { Bluetooth::GATTProfile::Service::Characteristic::UVIndex, _TXT("UVIndex") }, - { Bluetooth::GATTProfile::Service::Characteristic::VO2Max, _TXT("VO2Max") }, - { Bluetooth::GATTProfile::Service::Characteristic::WaistCircumference, _TXT("WaistCircumference") }, - { Bluetooth::GATTProfile::Service::Characteristic::Weight, _TXT("Weight") }, - { Bluetooth::GATTProfile::Service::Characteristic::WeightMeasurement, _TXT("WeightMeasurement") }, - { Bluetooth::GATTProfile::Service::Characteristic::WeightScaleFeature, _TXT("WeightScaleFeature") }, - { Bluetooth::GATTProfile::Service::Characteristic::WindChill, _TXT("WindChill") }, -ENUM_CONVERSION_END(Bluetooth::GATTProfile::Service::Characteristic::type) - -ENUM_CONVERSION_BEGIN(Bluetooth::GATTProfile::Service::type) - - { Bluetooth::GATTProfile::Service::GenericAccess, _TXT("Generic Access") }, - { Bluetooth::GATTProfile::Service::AlertNotificationService, _TXT("Alert Notification Service") }, - { Bluetooth::GATTProfile::Service::AutomationIO, _TXT("Automation IO") }, - { Bluetooth::GATTProfile::Service::BatteryService, _TXT("Battery Service") }, - { Bluetooth::GATTProfile::Service::BinarySensor, _TXT("Binary Sensor") }, - { Bluetooth::GATTProfile::Service::BloodPressure, _TXT("Blood Pressure") }, - { Bluetooth::GATTProfile::Service::BodyComposition, _TXT("Body Composition") }, - { Bluetooth::GATTProfile::Service::BondManagementService, _TXT("Bond Management Service") }, - { Bluetooth::GATTProfile::Service::ContinuousGlucoseMonitoring, _TXT("Continuous Glucose Monitoring") }, - { Bluetooth::GATTProfile::Service::CurrentTimeService, _TXT("Current Time Service") }, - { Bluetooth::GATTProfile::Service::CyclingPower, _TXT("Cycling Power") }, - { Bluetooth::GATTProfile::Service::CyclingSpeedAndCadence, _TXT("Cycling Speed and Cadence") }, - { Bluetooth::GATTProfile::Service::DeviceInformation, _TXT("Device Information") }, - { Bluetooth::GATTProfile::Service::EmergencyConfiguration, _TXT("Emergency Configuration") }, - { Bluetooth::GATTProfile::Service::EnvironmentalSensing, _TXT("Environmental Sensing") }, - { Bluetooth::GATTProfile::Service::FitnessMachine, _TXT("Fitness Machine") }, - { Bluetooth::GATTProfile::Service::GenericAttribute, _TXT("Generic Attribute") }, - { Bluetooth::GATTProfile::Service::Glucose, _TXT("Glucose") }, - { Bluetooth::GATTProfile::Service::HealthThermometer, _TXT("Health Thermometer") }, - { Bluetooth::GATTProfile::Service::HeartRate, _TXT("Heart Rate") }, - { Bluetooth::GATTProfile::Service::HTTPProxy, _TXT("HTTP Proxy") }, - { Bluetooth::GATTProfile::Service::HumanInterfaceDevice, _TXT("Human Interface Device") }, - { Bluetooth::GATTProfile::Service::ImmediateAlert, _TXT("Immediate Alert") }, - { Bluetooth::GATTProfile::Service::IndoorPositioning, _TXT("Indoor Positioning") }, - { Bluetooth::GATTProfile::Service::InsulinDelivery, _TXT("Insulin Delivery") }, - { Bluetooth::GATTProfile::Service::InternetProtocolSupport, _TXT("Internet Protocol Support") }, - { Bluetooth::GATTProfile::Service::LinkLoss, _TXT("Link Loss") }, - { Bluetooth::GATTProfile::Service::LocationAndNavigation, _TXT("Location and Navigation") }, - { Bluetooth::GATTProfile::Service::MeshProvisioningService, _TXT("Mesh Provisioning Service") }, - { Bluetooth::GATTProfile::Service::MeshProxyService, _TXT("Mesh Proxy Service") }, - { Bluetooth::GATTProfile::Service::NextDSTChangeService, _TXT("Next DST Change Service") }, - { Bluetooth::GATTProfile::Service::ObjectTransferService, _TXT("ObjectTransferService") }, - { Bluetooth::GATTProfile::Service::PhoneAlertStatusService, _TXT("Phone Alert Status Service") }, - { Bluetooth::GATTProfile::Service::PulseOximeterService, _TXT("Pulse Oximeter Service") }, - { Bluetooth::GATTProfile::Service::ReconnectionConfiguration, _TXT("Reconnection Configuration") }, - { Bluetooth::GATTProfile::Service::ReferenceTimeUpdateService, _TXT("Reference Time Update Service") }, - { Bluetooth::GATTProfile::Service::RunningSpeedAndCadence, _TXT("Running Speed and Cadence") }, - { Bluetooth::GATTProfile::Service::ScanParameters, _TXT("Scan Parameters") }, - { Bluetooth::GATTProfile::Service::TransportDiscovery, _TXT("Transport Discovery") }, - { Bluetooth::GATTProfile::Service::TxPower, _TXT("Tx Power") }, - { Bluetooth::GATTProfile::Service::UserData, _TXT("User Data") }, - { Bluetooth::GATTProfile::Service::WeightScale, _TXT("Weight Scale") }, - -ENUM_CONVERSION_END(Bluetooth::GATTProfile::Service::type) - -} // namespace Thunder - diff --git a/Source/bluetooth/gatt/GATTProfile.h b/Source/bluetooth/gatt/GATTProfile.h deleted file mode 100644 index d014ac9..0000000 --- a/Source/bluetooth/gatt/GATTProfile.h +++ /dev/null @@ -1,883 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#pragma once - -#include "Module.h" -#include "GATTSocket.h" - -namespace Thunder { - -namespace Bluetooth { - - class EXTERNAL GATTProfile { - private: - static constexpr uint16_t PRIMARY_SERVICE_UUID = 0x2800; - static constexpr uint16_t CHARACTERISTICS_UUID = 0x2803; - - public: - class EXTERNAL Service { - public: - enum type : uint16_t { - GenericAccess = 0x1800, - AlertNotificationService = 0x1811, - AutomationIO = 0x1815, - BatteryService = 0x180F, - BinarySensor = 0x183B, - BloodPressure = 0x1810, - BodyComposition = 0x181B, - BondManagementService = 0x181E, - ContinuousGlucoseMonitoring = 0x181F, - CurrentTimeService = 0x1805, - CyclingPower = 0x1818, - CyclingSpeedAndCadence = 0x1816, - DeviceInformation = 0x180A, - EmergencyConfiguration = 0x183C, - EnvironmentalSensing = 0x181A, - FitnessMachine = 0x1826, - GenericAttribute = 0x1801, - Glucose = 0x1808, - HealthThermometer = 0x1809, - HeartRate = 0x180D, - HTTPProxy = 0x1823, - HumanInterfaceDevice = 0x1812, - ImmediateAlert = 0x1802, - IndoorPositioning = 0x1821, - InsulinDelivery = 0x183A, - InternetProtocolSupport = 0x1820, - LinkLoss = 0x1803, - LocationAndNavigation = 0x1819, - MeshProvisioningService = 0x1827, - MeshProxyService = 0x1828, - NextDSTChangeService = 0x1807, - ObjectTransferService = 0x1825, - PhoneAlertStatusService = 0x180E, - PulseOximeterService = 0x1822, - ReconnectionConfiguration = 0x1829, - ReferenceTimeUpdateService = 0x1806, - RunningSpeedAndCadence = 0x1814, - ScanParameters = 0x1813, - TransportDiscovery = 0x1824, - TxPower = 0x1804, - UserData = 0x181C, - WeightScale = 0x181D, - }; - - class EXTERNAL Characteristic { - public: - enum type : uint16_t { - - AerobicHeartRateLowerLimit = 0x2A7E, - AerobicHeartRateUpperLimit = 0x2A84, - AerobicThreshold = 0x2A7F, - Age = 0x2A80, - Aggregate = 0x2A5A, - AlertCategoryID = 0x2A43, - AlertCategoryIDBitMask = 0x2A42, - AlertLevel = 0x2A06, - AlertNotificationControlPoint = 0x2A44, - AlertStatus = 0x2A3F, - Altitude = 0x2AB3, - AnaerobicHeartRateLowerLimit = 0x2A81, - AnaerobicHeartRateUpperLimit = 0x2A82, - AnaerobicThreshold = 0x2A83, - Analog = 0x2A58, - AnalogOutput = 0x2A59, - ApparentWindDirection = 0x2A73, - ApparentWindSpeed = 0x2A72, - Appearance = 0x2A01, - BarometricPressureTrend = 0x2AA3, - BatteryLevel = 0x2A19, - BatteryLevelState = 0x2A1B, - BatteryPowerState = 0x2A1A, - BloodPressureFeature = 0x2A49, - BloodPressureMeasurement = 0x2A35, - BodyCompositionFeature = 0x2A9B, - BodyCompositionMeasurement = 0x2A9C, - BodySensorLocation = 0x2A38, - BondManagementControlPoint = 0x2AA4, - BondManagementFeatures = 0x2AA5, - BootKeyboardInputReport = 0x2A22, - BootKeyboardOutputReport = 0x2A32, - BootMouseInputReport = 0x2A33, - BSSControlPoint = 0x2B2B, - BSSResponse = 0x2B2C, - CGMFeature = 0x2AA8, - CGMMeasurement = 0x2AA7, - CGMSessionRunTime = 0x2AAB, - CGMSessionStartTime = 0x2AAA, - CGMSpecificOpsControlPoint = 0x2AAC, - CGMStatus = 0x2AA9, - CrossTrainerData = 0x2ACE, - CSCFeature = 0x2A5C, - CSCMeasurement = 0x2A5B, - CurrentTime = 0x2A2B, - CyclingPowerControlPoint = 0x2A66, - CyclingPowerFeature = 0x2A65, - CyclingPowerMeasurement = 0x2A63, - CyclingPowerVector = 0x2A64, - DatabaseChangeIncrement = 0x2A99, - DateofBirth = 0x2A85, - DateofThresholdAssessment = 0x2A86, - DateTime = 0x2A08, - DateUTC = 0x2AED, - DayDateTime = 0x2A0A, - DayofWeek = 0x2A09, - DescriptorValueChanged = 0x2A7D, - DewPoint = 0x2A7B, - Digital = 0x2A56, - DigitalOutput = 0x2A57, - DSTOffset = 0x2A0D, - Elevation = 0x2A6C, - EmailAddress = 0x2A87, - EmergencyID = 0x2B2D, - EmergencyText = 0x2B2E, - ExactTime100 = 0x2A0B, - ExactTime256 = 0x2A0C, - FatBurnHeartRateLowerLimit = 0x2A88, - FatBurnHeartRateUpperLimit = 0x2A89, - FirmwareRevisionString = 0x2A26, - FirstName = 0x2A8A, - FitnessMachineControlPoint = 0x2AD9, - FitnessMachineFeature = 0x2ACC, - FitnessMachineStatus = 0x2ADA, - FiveZoneHeartRateLimits = 0x2A8B, - FloorNumber = 0x2AB2, - CentralAddressResolution = 0x2AA6, - DeviceName = 0x2A00, - PeripheralPreferredConnectionParameters = 0x2A04, - PeripheralPrivacyFlag = 0x2A02, - ReconnectionAddress = 0x2A03, - ServiceChanged = 0x2A05, - Gender = 0x2A8C, - GlucoseFeature = 0x2A51, - GlucoseMeasurement = 0x2A18, - GlucoseMeasurementContext = 0x2A34, - GustFactor = 0x2A74, - HardwareRevisionString = 0x2A27, - HeartRateControlPoint = 0x2A39, - HeartRateMax = 0x2A8D, - HeartRateMeasurement = 0x2A37, - HeatIndex = 0x2A7A, - Height = 0x2A8E, - HIDControlPoint = 0x2A4C, - HIDInformation = 0x2A4A, - HipCircumference = 0x2A8F, - HTTPControlPoint = 0x2ABA, - HTTPEntityBody = 0x2AB9, - HTTPHeaders = 0x2AB7, - HTTPStatusCode = 0x2AB8, - HTTPSSecurity = 0x2ABB, - Humidity = 0x2A6F, - IDDAnnunciationStatus = 0x2B22, - IDDCommandControlPoint = 0x2B25, - IDDCommandData = 0x2B26, - IDDFeatures = 0x2B23, - IDDHistoryData = 0x2B28, - IDDRecordAccessControlPoint = 0x2B27, - IDDStatus = 0x2B21, - IDDStatusChanged = 0x2B20, - IDDStatusReaderControlPoint = 0x2B24, - IndoorBikeData = 0x2AD2, - IndoorPositioningConfiguration = 0x2AAD, - IntermediateCuffPressure = 0x2A36, - IntermediateTemperature = 0x2A1E, - Irradiance = 0x2A77, - Language = 0x2AA2, - LastName = 0x2A90, - Latitude = 0x2AAE, - LNControlPoint = 0x2A6B, - LNFeature = 0x2A6A, - LocalEastCoordinate = 0x2AB1, - LocalNorthCoordinate = 0x2AB0, - LocalTimeInformation = 0x2A0F, - LocationandSpeedCharacteristic = 0x2A67, - LocationName = 0x2AB5, - Longitude = 0x2AAF, - MagneticDeclination = 0x2A2C, - MagneticFluxDensity_2D = 0x2AA0, - MagneticFluxDensity_3D = 0x2AA1, - ManufacturerNameString = 0x2A29, - MaximumRecommendedHeartRate = 0x2A91, - MeasurementInterval = 0x2A21, - ModelNumberString = 0x2A24, - Navigation = 0x2A68, - NetworkAvailability = 0x2A3E, - NewAlert = 0x2A46, - ObjectActionControlPoint = 0x2AC5, - ObjectChanged = 0x2AC8, - ObjectFirst_Created = 0x2AC1, - ObjectID = 0x2AC3, - ObjectLast_Modified = 0x2AC2, - ObjectListControlPoint = 0x2AC6, - ObjectListFilter = 0x2AC7, - ObjectName = 0x2ABE, - ObjectProperties = 0x2AC4, - ObjectSize = 0x2AC0, - ObjectType = 0x2ABF, - OTSFeature = 0x2ABD, - PLXContinuousMeasurementCharacteristic = 0x2A5F, - PLXFeatures = 0x2A60, - PLXSpot_CheckMeasurement = 0x2A5E, - PnPID = 0x2A50, - PollenConcentration = 0x2A75, - Position2D = 0x2A2F, - Position3D = 0x2A30, - PositionQuality = 0x2A69, - Pressure = 0x2A6D, - ProtocolMode = 0x2A4E, - PulseOximetryControlPoint = 0x2A62, - Rainfall = 0x2A78, - RCFeature = 0x2B1D, - RCSettings = 0x2B1E, - ReconnectionConfigurationControlPoint = 0x2B1F, - RecordAccessControlPoint = 0x2A52, - RegulatoryCertificationDataList = 0x2A2A, - ReferenceTimeInformation = 0x2A14, - Removable = 0x2A3A, - Report = 0x2A4D, - ReportMap = 0x2A4B, - ResolvablePrivateAddressOnly = 0x2AC9, - RestingHeartRate = 0x2A92, - RingerControlpoint = 0x2A40, - RingerSetting = 0x2A41, - RowerData = 0x2AD1, - RSCFeature = 0x2A54, - RSCMeasurement = 0x2A53, - SCControlPoint = 0x2A55, - ScanIntervalWindow = 0x2A4F, - ScanRefresh = 0x2A31, - ScientificTemperatureCelsius = 0x2A3C, - SecondaryTimeZone = 0x2A10, - SensorLocation = 0x2A5D, - SerialNumberString = 0x2A25, - ServiceRequired = 0x2A3B, - SoftwareRevisionString = 0x2A28, - SportTypeforAerobicandAnaerobicThresholds = 0x2A93, - StairClimberData = 0x2AD0, - StepClimberData = 0x2ACF, - String = 0x2A3D, - SupportedHeartRateRange = 0x2AD7, - SupportedInclinationRange = 0x2AD5, - SupportedNewAlertCategory = 0x2A47, - SupportedPowerRange = 0x2AD8, - SupportedResistanceLevelRange = 0x2AD6, - SupportedSpeedRange = 0x2AD4, - SupportedUnreadAlertCategory = 0x2A48, - SystemID = 0x2A23, - TDSControlPoint = 0x2ABC, - Temperature = 0x2A6E, - TemperatureCelsius = 0x2A1F, - TemperatureFahrenheit = 0x2A20, - TemperatureMeasurement = 0x2A1C, - TemperatureType = 0x2A1D, - ThreeZoneHeartRateLimits = 0x2A94, - TimeAccuracy = 0x2A12, - TimeBroadcast = 0x2A15, - TimeSource = 0x2A13, - TimeUpdateControlPoint = 0x2A16, - TimeUpdateState = 0x2A17, - TimewithDST = 0x2A11, - TimeZone = 0x2A0E, - TrainingStatus = 0x2AD3, - TreadmillData = 0x2ACD, - TrueWindDirection = 0x2A71, - TrueWindSpeed = 0x2A70, - TwoZoneHeartRateLimit = 0x2A95, - TxPowerLevel = 0x2A07, - Uncertainty = 0x2AB4, - UnreadAlertStatus = 0x2A45, - URI = 0x2AB6, - UserControlPoint = 0x2A9F, - UserIndex = 0x2A9A, - UVIndex = 0x2A76, - VO2Max = 0x2A96, - WaistCircumference = 0x2A97, - Weight = 0x2A98, - WeightMeasurement = 0x2A9D, - WeightScaleFeature = 0x2A9E, - WindChill = 0x2A79 - }; - - class EXTERNAL Descriptor { - public: - enum type : uint16_t { - CharacteristicAggregateFormat = 0x2905, - CharacteristicExtendedPropertie = 0x2900, - CharacteristicPresentationFormat = 0x2904, - CharacteristicUserDescription = 0x2901, - ClientCharacteristicConfiguration = 0x2902, - EnvironmentalSensingConfiguration = 0x290B, - EnvironmentalSensingMeasurement = 0x290C, - EnvironmentalSensingTriggerSetting = 0x290D, - ExternalReportReference = 0x2907, - NumberOfDigital = 0x2909, - ReportReference = 0x2908, - ServerCharacteristicConfiguration = 0x2903, - TimeTriggerSetting = 0x290E, - ValidRange = 0x2906, - ValueTriggerSetting = 0x290A - }; - - public: - Descriptor(const Descriptor&) = delete; - Descriptor& operator= (const Descriptor&) = delete; - - Descriptor(const uint16_t handle, const UUID& uuid) - : _handle(handle) - , _uuid(uuid) { - } - ~Descriptor() { - } - - public: - bool operator== (const UUID& id) const { - return (id == _uuid); - } - bool operator!= (const UUID& id) const { - return (!operator== (id)); - } - const UUID& Type() const { - return (_uuid); - } - string Name() const { - string result; - if (_uuid.HasShort() == false) { - result = _uuid.ToString(); - } - else { - type input = static_cast(_uuid.Short()); - Core::EnumerateType value (input); - result = (value.IsSet() == true ? string(value.Data()) : _uuid.ToString(false)); - } - return (result); - } - uint16_t Handle() const { - return (_handle); - } - - private: - uint16_t _handle; - UUID _uuid; - }; - - public: - typedef Core::IteratorType< const std::list, const Descriptor&, std::list::const_iterator> Iterator; - - Characteristic(const Characteristic&) = delete; - Characteristic& operator= (const Characteristic&) = delete; - - Characteristic(const uint16_t end, const uint8_t rights, const uint16_t value, const UUID& attribute) - : _handle(value) - , _rights(rights) - , _end(end) - , _type(attribute) - , _error(0) - , _value() { - } - ~Characteristic() { - } - - public: - bool operator== (const UUID& id) const { - return (id == _type); - } - bool operator!= (const UUID& id) const { - return (!operator== (id)); - } - uint8_t Error() const { - return (_error); - } - string ToString() const { - string result; - result.reserve(_value.length() + 1); - for (const char& c : _value) { - if (::isprint(c)) { - result = result + c; - } - else { - result = result + '.'; - } - } - return (result); - } - const UUID& Type() const { - return (_type); - } - uint8_t Rights() const { - return (_rights); - } - string Name() const { - string result; - if (_type.HasShort() == false) { - result = _type.ToString(); - } - else { - type input = static_cast(_type.Short()); - Core::EnumerateType value (input); - result = (value.IsSet() == true ? string(value.Data()) : _type.ToString(false)); - } - return (result); - } - Iterator Descriptors() const { - return (Iterator(_descriptors)); - } - const Descriptor* operator[] (const UUID& id) const { - std::list::const_iterator index (_descriptors.begin()); - - while ((index != _descriptors.end()) && (*index != id)) { index++; } - - return (index != _descriptors.end() ? &(*index) : nullptr); - } - uint16_t Handle() const { - return (_handle); - } - uint16_t Max() const { - return (_end); - } - - private: - friend class GATTProfile; - void Descriptors (GATTSocket::Command::Response& response) { - while (response.Next() == true) { - UUID descriptor(response.Attribute()); - _descriptors.emplace_back(response.Handle(), descriptor); - } - } - uint16_t Value(GATTSocket::Command::Response& response) { - _error = response.Error(); - if ( (_error != 0) || (response.Data() == nullptr)) { - _value.clear(); - } - else { - _value = std::string(reinterpret_cast(response.Data()), response.Length()); - } - return(0); - } - - private: - uint16_t _handle; - uint8_t _rights; - uint16_t _end; - UUID _type; - std::list _descriptors; - uint8_t _error; - std::string _value; - }; - - public: - typedef Core::IteratorType< const std::list, const Characteristic&, std::list::const_iterator> Iterator; - typedef Core::IteratorType< std::list, Characteristic&> Index; - - Service(const Service&) = delete; - Service& operator= (const Service&) = delete; - - Service(const UUID& serviceId, const uint16_t handle, const uint16_t group) - : _handle(handle) - , _group(group) - , _serviceId(serviceId) - , _characteristics() { - } - ~Service() { - } - - public: - bool operator== (const UUID& id) const { - return (id == _serviceId); - } - bool operator!= (const UUID& id) const { - return (!operator== (id)); - } - const UUID& Type() const { - return (_serviceId); - } - string Name() const { - string result; - if (_serviceId.HasShort() == false) { - result = _serviceId.ToString(); - } - else { - Core::EnumerateType value(static_cast(_serviceId.Short())); - result = (value.IsSet() == true ? string(value.Data()) : _serviceId.ToString(false)); - } - return (result); - } - Iterator Characteristics() const { - return (Iterator(_characteristics)); - } - const Characteristic* operator[] (const UUID& id) const { - std::list::const_iterator index (_characteristics.begin()); - - while ((index != _characteristics.end()) && (*index != id)) { index++; } - - return (index != _characteristics.end() ? &(*index) : nullptr); - } - uint16_t Handle() const { - return (_handle); - } - uint16_t Max() const { - return (_group); - } - - private: - friend class GATTProfile; - void AddCharacteristics (GATTSocket::Command::Response& response) { - if (response.Next() == true) { - do { - uint16_t value (response.Group()); - uint8_t rights (response.Rights()); - UUID attribute (response.Attribute()); - - // Where does the next one start ? - uint16_t end = (response.Next() ? response.Handle() - 1 : Max()); - - _characteristics.emplace_back(end, rights, value, attribute); - - } while (response.IsValid() == true); - } - } - Index Filler() { - return (Index(_characteristics)); - } - - private: - uint16_t _handle; - uint16_t _group; - UUID _serviceId; - std::list _characteristics; - }; - - public: - typedef std::function Handler; - typedef Core::IteratorType< const std::list, const Service&, std::list::const_iterator> Iterator; - - GATTProfile (const GATTProfile&) = delete; - GATTProfile& operator= (const GATTProfile&) = delete; - - GATTProfile(const bool includeVendorCharacteristics) - : _adminLock() - , _services() - , _index() - , _custom(includeVendorCharacteristics) - , _socket(nullptr) - , _command() - , _handler() - , _expired(0) { - } - ~GATTProfile() { - } - - public: - uint32_t Discover(const uint32_t waitTime, GATTSocket& socket, const Handler& handler) { - uint32_t result = Core::ERROR_INPROGRESS; - - _adminLock.Lock(); - if (_socket == nullptr) { - result = Core::ERROR_NONE; - _socket = &socket; - _expired = Core::Time::Now().Add(waitTime).Ticks(); - _handler = handler; - _services.clear(); - _command.ReadByGroupType(0x0001, 0xFFFF, UUID(PRIMARY_SERVICE_UUID)); - _socket->Execute(waitTime, _command, [&](const GATTSocket::Command& cmd) { OnServices(cmd); }); - } - _adminLock.Unlock(); - - return(result); - } - void Abort () { - Report(Core::ERROR_ASYNC_ABORTED); - } - bool IsValid() const { - return ((_services.size() > 0) && (_expired == Core::ERROR_NONE)); - } - Iterator Services() const { - return (Iterator(_services)); - } - const Service* operator[] (const UUID& id) const { - std::list::const_iterator index (_services.begin()); - - while ((index != _services.end()) && (*index != id)) { index++; } - - return (index != _services.end() ? &(*index) : nullptr); - } - void Find(const UUID& serviceUuid, const UUID& charUuid, std::list& characteristics) const - { - const Service* service = (*this)[serviceUuid]; - if (service != nullptr) { - auto it = service->Characteristics(); - while (it.Next() == true) { - if (it.Current() == charUuid) { - characteristics.push_back(&it.Current()); - } - } - } - } - uint16_t FindHandle(const Service::Characteristic& characteristic, const UUID& descUuid) const - { - uint16_t handle = 0; - const Service::Characteristic::Descriptor* descriptor = characteristic[descUuid]; - if (descriptor != nullptr) { - handle = descriptor->Handle(); - } - return (handle); - } - uint16_t FindHandle(const UUID& serviceUuid, const UUID& charUuid) const - { - const Service::Characteristic* characteristic = FindCharacteristic(serviceUuid, charUuid); - return (characteristic == nullptr ? 0 : characteristic->Handle()); - } - uint16_t FindHandle(const UUID& serviceUuid, const UUID& charUuid, const UUID& descUuid) const - { - uint16_t handle = 0; - const Service::Characteristic* characteristic = FindCharacteristic(serviceUuid, charUuid); - if (characteristic != nullptr) { - const Service::Characteristic::Descriptor* descriptor = (*characteristic)[descUuid]; - if (descriptor != nullptr) { - handle = descriptor->Handle(); - } - } - return (handle); - } - - private: - const Service::Characteristic* FindCharacteristic(const UUID& serviceUuid, const UUID& charUuid) const - { - const Service::Characteristic* result = nullptr; - const Service* service = (*this)[serviceUuid]; - if (service != nullptr) { - result = (*service)[charUuid]; - } - return (result); - } - std::list::iterator ValidService(const std::list::iterator& input) { - std::list::iterator index (input); - while ( (index != _services.end()) && - ( (index->Handle() >= index->Max()) || ((_custom == false) && (index->Type().HasShort() == false)) ) ) { - index++; - } - - return (index); - } - bool NextCharacteristic() { - do { - if ( _characteristics.Next() == false) { - _index = ValidService(++_index); - - if (_index != _services.end()) { - _characteristics = _index->Filler(); - } - } - - } while ((_index != _services.end()) && (_characteristics.IsValid() == false)); - - return (_characteristics.IsValid()); - } - void LoadCharacteristics(uint32_t waitTime) { - uint16_t begin = _characteristics.Current().Handle(); - uint16_t end = _characteristics.Current().Max(); - - _adminLock.Lock(); - - if (_socket != nullptr) { - if (begin < end){ - _command.FindInformation(begin + 1, end); - _socket->Execute(waitTime, _command, [&](const GATTSocket::Command& cmd) { OnDescriptors(cmd); }); - } - else { - _command.Read(_characteristics.Current().Handle()); - _socket->Execute(waitTime, _command, [&](const GATTSocket::Command& cmd) { OnAttribute(cmd); }); - } - } - _adminLock.Unlock(); - } - void OnServices(const GATTSocket::Command& cmd) { - ASSERT (&cmd == &_command); - - if ( (cmd.Error() != Core::ERROR_NONE) && (cmd.Result().Error() != 0) ) { - // Seems like the services could not be discovered, report it.. - Report(Core::ERROR_GENERAL); - } - else { - uint32_t waitTime = AvailableTime(); - - if (waitTime > 0) { - GATTSocket::Command::Response& response(_command.Result()); - - while (response.Next() == true) { - const uint8_t* service = response.Data(); - if (response.Length() == 2) { - _services.emplace_back( UUID(service[0] | (service[1] << 8)), response.Handle(), response.Group() ); - } - else if (response.Length() == 16) { - _services.emplace_back( UUID(service), response.Handle(), response.Group() ); - } - } - - if (_services.size() == 0) { - Report (Core::ERROR_UNAVAILABLE); - } - else { - _index = ValidService(_services.begin()); - - if (_index == _services.end()) { - Report (Core::ERROR_NONE); - } - else { - _adminLock.Lock(); - if (_socket != nullptr) { - _command.ReadByType(_index->Handle()+1, _index->Max(), UUID(CHARACTERISTICS_UUID)); - _socket->Execute(waitTime, _command, [&](const GATTSocket::Command& cmd) { OnCharacteristics(cmd); }); - } - _adminLock.Unlock(); - } - } - } - } - } - void OnCharacteristics(const GATTSocket::Command& cmd) { - ASSERT (&cmd == &_command); - - if ( (cmd.Error() != Core::ERROR_NONE) && (cmd.Result().Error() != 0) ) { - // Seems like the services could not be discovered, report it.. - Report(Core::ERROR_GENERAL); - } - else { - uint32_t waitTime = AvailableTime(); - - if (waitTime > 0) { - GATTSocket::Command::Response& response(_command.Result()); - - _index->AddCharacteristics(response); - _index = ValidService(++_index); - - if (_index != _services.end()) { - _adminLock.Lock(); - if (_socket != nullptr) { - _command.ReadByType(_index->Handle()+1, _index->Max(), UUID(CHARACTERISTICS_UUID)); - _socket->Execute(waitTime, _command, [&](const GATTSocket::Command& cmd) { OnCharacteristics(cmd); }); - } - _adminLock.Unlock(); - } - else { - - // Time to start reading the attributes on the services!! - _index = _services.begin(); - - // If we get here, there must be services, otherwise we would have bailed out on OnServices!! - ASSERT (_index != _services.end()); - - _characteristics = _index->Filler(); - - if (NextCharacteristic() == false) { - Report(Core::ERROR_NONE); - } - else { - LoadCharacteristics(waitTime); - } - } - } - } - } - void OnDescriptors(const GATTSocket::Command& cmd) { - ASSERT (&cmd == &_command); - - if ( (cmd.Error() != Core::ERROR_NONE) && (cmd.Result().Error() != 0) ) { - // Seems like the services could not be discovered, report it.. - Report(Core::ERROR_GENERAL); - } - else { - uint32_t waitTime = AvailableTime(); - - if (waitTime > 0) { - _characteristics.Current().Descriptors(_command.Result()); - - _adminLock.Lock(); - - if (_socket != nullptr) { - - _command.Read(_characteristics.Current().Handle()); - _socket->Execute(waitTime, _command, [&](const GATTSocket::Command& cmd) { OnAttribute(cmd); }); - } - - _adminLock.Unlock(); - } - } - } - void OnAttribute(const GATTSocket::Command& cmd) { - ASSERT (&cmd == &_command); - - if (cmd.Error() != Core::ERROR_NONE) { - // Seems like the services could not be discovered, report it.. - Report(Core::ERROR_GENERAL); - } - else { - uint32_t waitTime = AvailableTime(); - - if (waitTime > 0) { - - _characteristics.Current().Value(_command.Result()); - - if (NextCharacteristic() == false) { - Report(Core::ERROR_NONE); - } - else { - LoadCharacteristics(waitTime); - } - } - } - } - void Report(const uint32_t result) { - _adminLock.Lock(); - if (_socket != nullptr) { - Handler caller = _handler; - _socket = nullptr; - _handler = nullptr; - _expired = result; - - caller(result); - } - _adminLock.Unlock(); - } - uint32_t AvailableTime () { - uint64_t now = Core::Time::Now().Ticks(); - uint32_t result = (now >= _expired ? 0 : static_cast((_expired - now) / Core::Time::TicksPerMillisecond)); - - if (result == 0) { - Report(Core::ERROR_TIMEDOUT); - } - return (result); - } - - private: - Core::CriticalSection _adminLock; - std::list _services; - std::list::iterator _index; - Service::Index _characteristics; - bool _custom; - GATTSocket* _socket; - GATTSocket::Command _command; - Handler _handler; - uint64_t _expired; - }; - -} // namespace Bluetooth - -} // namespace Thunder - diff --git a/Source/bluetooth/gatt/GATTSocket.cpp b/Source/bluetooth/gatt/GATTSocket.cpp deleted file mode 100644 index b71ce74..0000000 --- a/Source/bluetooth/gatt/GATTSocket.cpp +++ /dev/null @@ -1,356 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#include "GATTSocket.h" - -namespace Thunder { - -namespace Bluetooth { - -uint16_t Attribute::Deserialize(const uint16_t size, const uint8_t stream[]) -{ - uint16_t result = 0; - - if (size > 0) { - if (_offset == 0) { - _type = stream[0]; - if ((_type & 0x7) <= 4) { - if (_type == 0) { - result = 1; - - // It's a nil, nothing more required - _offset = static_cast(~0); - _type = stream[0]; - } else { - uint8_t length = (1 << (_type & 0x07)); - uint8_t copyLength = std::min(length, static_cast(size - 1)); - ::memcpy(_buffer, &stream[1], copyLength); - result = 1 + copyLength; - _offset = (copyLength == length ? ~0 : copyLength); - } - } else { - uint8_t length = (1 << ((_type & 0x07) - 5)); - uint8_t copyLength = std::min(length, static_cast(size - 1)); - ::memcpy(_buffer, &stream[1], copyLength); - result = 1 + copyLength; - _offset = copyLength; - } - } - - if ((result < size) && (IsLoaded() == false)) { - // See if we need to set the length - if (((_type & 0x7) > 4) && (_length == static_cast(~0))) { - uint8_t length = (1 << ((_type & 0x07) - 5)); - uint8_t copyLength = std::min(static_cast(length - _offset), static_cast(size - result)); - if (copyLength > 0) { - ::memcpy(&(_buffer[_offset]), &stream[result], copyLength); - result += copyLength; - _offset += copyLength; - } - - if (_offset == length) { - _length = 0; - - for (uint8_t index = 0; index < length; index++) { - _length = (length << 8) | _buffer[index]; - } - _offset = (_length == 0 ? ~0 : 0); - } - } - - if (result < size) { - // Normal payload loading... - uint32_t copyLength = std::min(Length() - _offset, static_cast(size - result)); - // TODO: This one might potentially get very big. Check if the buffer still fits.. - ::memcpy(&(_buffer[_offset]), &stream[result], copyLength); - result += copyLength; - _offset = (_offset + copyLength == Length() ? ~0 : _offset + copyLength); - } - } - } - return (result); -} - -/* virtual */ uint16_t GATTSocket::Command::Deserialize(const uint8_t stream[], const uint16_t length) -{ - uint16_t result = 0; - - // See if we need to retrigger.. - if ((stream[0] != _id) && ((stream[0] != ATT_OP_ERROR) && (length >= 2) && (stream[1] == _id))) { - TRACE_L1(_T("Unexpected L2CapSocket message. Expected: %d, got %d [%d]"), _id, stream[0], stream[1]); - } else if (stream[0] != ATT_OP_HANDLE_NOTIFY) { - result = length; - - // TRACE_L1(_T("L2CapSocket Receive [%d], Type: %02X"), length, stream[0]); - // printf("L2CAP received [%d]: ", length); - // for (uint8_t index = 0; index < (length - 1); index++) { printf("%02X:", stream[index]); } printf("%02X\n", stream[length - 1]); - - // This is what we are expecting, so process it... - switch (stream[0]) { - case ATT_OP_ERROR: { - if ((stream[4] == ATT_ECODE_ATTR_NOT_FOUND) && (_frame.End() != 0) && (_response.Empty() == false)) { - _error = Core::ERROR_NONE; - } - else { - _response._min = stream[4]; - _response.Type(stream[0]); - _error = Core::ERROR_GENERAL; - } - break; - } - case ATT_OP_READ_BY_GROUP_RESP: { - /* PDU must contain at least: - * - Attribute length (1 octet) - * - Attribute Data List (at least one entry): - * - Attribute Handle (2 octets) - * - End Group Handle (2 octets) - * - Data (Attribute length - 4) */ - /* Minimum Attribute Data List size */ - if (stream[1] < 4) { - _error = Core::ERROR_BAD_REQUEST; - } - else { - uint16_t last = 0; - uint8_t entries = (length - 2) / stream[1]; - for (uint8_t index = 0; index < entries; index++) { - uint16_t offset = 2 + (index * stream[1]); - uint16_t foundHandle = (stream[offset + 1] << 8) | stream[offset + 0]; - uint16_t groupHandle = (stream[offset + 3] << 8) | stream[offset + 2]; - _response.Add(foundHandle, groupHandle, (stream[1] - 4), &(stream[offset+4])); - if (last < groupHandle) { - last = groupHandle; - } - } - - ASSERT(_frame.End() != 0); - - if (last >= _frame.End()) { - _error = Core::ERROR_NONE; - } - else { - _frame.ReadByGroupType(last + 1); - } - - _response.Type(stream[0]); - } - break; - } - case ATT_OP_FIND_BY_TYPE_RESP: { - /* PDU must contain at least: - * - Attribute Opcode (1 octet) - * - Length (1 octet) - * - Attribute Data List (at least one entry): - * - Attribute Handle (2 octets) - * - Attribute Value (at least 1 octet) */ - /* Minimum Attribute Data List size */ - if (length < 5) { - _error = Core::ERROR_BAD_REQUEST; - } - else { - uint16_t last = 0; - uint8_t entries = (length - 1) / 4; - for (uint8_t index = 0; index < entries; index++) { - uint16_t offset = 1 + (index * 4); - uint16_t foundHandle = (stream[offset + 1] << 8) | stream[offset + 0]; - uint16_t groupHandle = (stream[offset + 3] << 8) | stream[offset + 2]; - _response.Add(foundHandle, groupHandle); - - if (last < groupHandle) { - last = groupHandle; - } - } - - ASSERT(_frame.End() != 0); - - if (last >= _frame.End()) { - _error = Core::ERROR_NONE; - } - else { - _frame.FindByType(last + 1); - } - - _response.Type(stream[0]); - } - - break; - } - case ATT_OP_READ_BY_TYPE_RESP: { - /* PDU must contain at least: - * - Attribute Opcode (1 octet) - * - Length (1 octet) - * - Attribute Data List (at least one entry): - * - Attribute Handle (2 octets) - * - Attribute Value (at least 1 octet) */ - /* Minimum Attribute Data List size */ - if (stream[1] < 3) { - _error = Core::ERROR_BAD_REQUEST; - } - else { - uint16_t last = 0; - uint8_t entries = ((length - 2) / stream[1]); - for (uint8_t index = 0; index < entries; index++) { - uint16_t offset = 2 + (index * stream[1]); - uint16_t handle = (stream[offset + 1] << 8) | stream[offset + 0]; - - _response.Add(handle, stream[1] - 2, &(stream[offset + 2])); - if (last < handle) { - last = handle; - } - } - - ASSERT(_frame.End() != 0); - - if (last >= _frame.End()) { - _error = Core::ERROR_NONE; - } - else { - _frame.ReadByType(last + 1); - } - - _response.Type(stream[0]); - } - - break; - } - case ATT_OP_FIND_INFO_RESP: { - if ((stream[1] != 1) && (stream[1] != 2)) { - _error = Core::ERROR_BAD_REQUEST; - } - else { - uint16_t last = 0; - uint8_t step = (stream[1] == 1 ? 2 : 16); - uint8_t entries = ((length - 2) / (2 + step)); - - for (uint8_t index = 0; index < entries; index++) { - uint16_t offset = 2 + (index * (2 + step)); - uint16_t handle = (stream[offset + 1] << 8) | stream[offset + 0]; - - _response.Add(handle, step, &(stream[offset + 2])); - if (last < handle) { - last = handle; - } - } - - ASSERT(_frame.End() != 0); - - if (last >= _frame.End()) { - _error = Core::ERROR_NONE; - } - else { - _frame.FindInformation(last + 1); - } - - _response.Type(stream[0]); - } - - break; - } - case ATT_OP_WRITE_RESP: { - _error = Core::ERROR_NONE; - _response.Type(stream[0]); - break; - } - case ATT_OP_READ_RESP: { - _response.Add(_frame.Handle(), length - 1, &(stream[1])); - if (length == _mtu) { - _id = _frame.ReadBlob(_frame.Handle(), _response.Offset()); - _frame.Reload(); - } - else { - _error = Core::ERROR_NONE; - } - - _response.Type(stream[0]); - break; - } - case ATT_OP_READ_BLOB_RESP: { - if (_response.Offset() == 0) { - _response.Add(_frame.Handle(), length - 1, &(stream[1])); - } else { - _response.Extend(length - 1, &(stream[1])); - } - if (length == _mtu) { - _id = _frame.ReadBlob(_frame.Handle(), _response.Offset()); - _frame.Reload(); - } else { - _error = Core::ERROR_NONE; - } - _response.Type(ATT_OP_READ_RESP); - break; - } - default: - break; - } - } - return (result); -} - -bool GATTSocket::Security(const uint8_t level) -{ - bool result = true; - - int lm = 0; - switch (level) { - case BT_SECURITY_SDP: - break; - case BT_SECURITY_LOW: - lm = L2CAP_LM_AUTH; - break; - case BT_SECURITY_MEDIUM: - lm = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT; - break; - case BT_SECURITY_HIGH: - lm = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE; - break; - default: - TRACE_L1("Invalid security level"); - result = false; - } - - if (result == true) { - struct bt_security btSecurity; - btSecurity.level = level; - btSecurity.key_size = 0; - if (::setsockopt(Handle(), SOL_BLUETOOTH, BT_SECURITY, &btSecurity, sizeof(btSecurity)) != 0) { - TRACE_L1("Failed to set Bluetooth Security level for device [%s], error: %d, try L2CAP Security", RemoteId().c_str(), errno); - if (::setsockopt(Handle(), SOL_L2CAP, L2CAP_LM, &lm, sizeof(lm)) != 0) { - TRACE_L1("Error setting L2CAP Security for device [%s], error: %d", RemoteId().c_str(), errno); - result = false; - } - } - } - - return (result); -} - -/* virtual */ void GATTSocket::StateChange() -{ - Core::SynchronousChannelType::StateChange(); - - if (IsOpen() == true) { - socklen_t len = sizeof(_connectionInfo); - ::getsockopt(Handle(), SOL_L2CAP, L2CAP_CONNINFO, &_connectionInfo, &len); - - Send(CommunicationTimeOut, _sink, &_sink, &_sink); - } -} - -} // namespace Bluetooth - -} // namespace Thunder diff --git a/Source/bluetooth/gatt/GATTSocket.h b/Source/bluetooth/gatt/GATTSocket.h deleted file mode 100644 index 9cad937..0000000 --- a/Source/bluetooth/gatt/GATTSocket.h +++ /dev/null @@ -1,908 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#pragma once - -#include "Module.h" - -namespace Thunder { - -namespace Bluetooth { - - class EXTERNAL Attribute { - public: - enum type { - NIL = 0x00, - INTEGER_UNSIGNED = 0x08, - INTEGER_SIGNED = 0x10, - UUID = 0x18, - TEXT = 0x20, - BOOLEAN = 0x28, - SEQUENCE = 0x30, - ALTERNATIVE = 0x38, - URL = 0x40 - }; - - Attribute() - : _type(~0) - , _offset(0) - , _length(~0) - , _bufferSize(64) - , _buffer(reinterpret_cast(::malloc(_bufferSize))) - { - } - Attribute(const uint16_t size, const uint8_t stream[]) - : _type(~0) - , _offset(0) - , _length(~0) - , _bufferSize(size) - , _buffer(reinterpret_cast(::malloc(_bufferSize))) { - Deserialize(size, stream); - } - ~Attribute() - { - if (_buffer != nullptr) { - ::free(_buffer); - } - } - - public: - void Clear() - { - _type = ~0; - _offset = 0; - _length = ~0; - } - bool IsLoaded() const - { - return (_offset == static_cast(~0)); - } - type Type() const - { - return (static_cast(_type & 0xF8)); - } - uint32_t Length() const - { - return ((_type & 0x3) <= 4 ? (_type == 0 ? 0 : 1 << (_type & 0x03)) : _length); - } - template - void Load(TYPE& value) const - { - value = 0; - for (uint8_t index = 0; index < sizeof(TYPE); index++) { - value = (value << 8) | _buffer[index]; - } - } - void Load(bool& value) const - { - value = (_buffer[0] != 0); - } - void Load(string& value) const - { - value = string(reinterpret_cast(_buffer), _length); - } - - uint16_t Deserialize(const uint16_t size, const uint8_t stream[]); - - private: - uint8_t _type; - uint32_t _offset; - uint32_t _length; - uint32_t _bufferSize; - uint8_t* _buffer; - }; - - class EXTERNAL GATTSocket : public Core::SynchronousChannelType { - public: - static constexpr uint8_t LE_ATT_CID = 4; - - enum rights : uint8_t { - Broadcast = 0x01, - Read = 0x02, - Write = 0x04, - WriteResponse = 0x08, - Notify = 0x10, - Indicate = 0x20 - }; - - private: - GATTSocket(const GATTSocket&) = delete; - GATTSocket& operator=(const GATTSocket&) = delete; - - static constexpr uint8_t ATT_OP_ERROR = 0x01; - static constexpr uint8_t ATT_OP_MTU_REQ = 0x02; - static constexpr uint8_t ATT_OP_MTU_RESP = 0x03; - static constexpr uint8_t ATT_OP_FIND_INFO_REQ = 0x04; - static constexpr uint8_t ATT_OP_FIND_INFO_RESP = 0x05; - static constexpr uint8_t ATT_OP_FIND_BY_TYPE_REQ = 0x06; - static constexpr uint8_t ATT_OP_FIND_BY_TYPE_RESP = 0x07; - static constexpr uint8_t ATT_OP_READ_BY_TYPE_REQ = 0x08; - static constexpr uint8_t ATT_OP_READ_BY_TYPE_RESP = 0x09; - static constexpr uint8_t ATT_OP_READ_REQ = 0x0A; - static constexpr uint8_t ATT_OP_READ_RESP = 0x0B; - static constexpr uint8_t ATT_OP_READ_BLOB_REQ = 0x0C; - static constexpr uint8_t ATT_OP_READ_BLOB_RESP = 0x0D; - static constexpr uint8_t ATT_OP_READ_MULTI_REQ = 0x0E; - static constexpr uint8_t ATT_OP_READ_MULTI_RESP = 0x0F; - static constexpr uint8_t ATT_OP_READ_BY_GROUP_REQ = 0x10; - static constexpr uint8_t ATT_OP_READ_BY_GROUP_RESP = 0x11; - static constexpr uint8_t ATT_OP_WRITE_REQ = 0x12; - static constexpr uint8_t ATT_OP_WRITE_CMD = 0x52; - static constexpr uint8_t ATT_OP_WRITE_RESP = 0x13; - static constexpr uint8_t ATT_OP_HANDLE_NOTIFY = 0x1B; - - - static constexpr uint8_t ATT_ECODE_INVALID_HANDLE = 0x01; - static constexpr uint8_t ATT_ECODE_READ_NOT_PERM = 0x02; - static constexpr uint8_t ATT_ECODE_WRITE_NOT_PERM = 0x03; - static constexpr uint8_t ATT_ECODE_INVALID_PDU = 0x04; - static constexpr uint8_t ATT_ECODE_AUTHENTICATION = 0x05; - static constexpr uint8_t ATT_ECODE_REQ_NOT_SUPP = 0x06; - static constexpr uint8_t ATT_ECODE_INVALID_OFFSET = 0x07; - static constexpr uint8_t ATT_ECODE_AUTHORIZATION = 0x08; - static constexpr uint8_t ATT_ECODE_PREP_QUEUE_FULL = 0x09; - static constexpr uint8_t ATT_ECODE_ATTR_NOT_FOUND = 0x0A; - static constexpr uint8_t ATT_ECODE_ATTR_NOT_LONG = 0x0B; - static constexpr uint8_t ATT_ECODE_INSUFF_ENCR_KEY_SIZE = 0x0C; - static constexpr uint8_t ATT_ECODE_INVAL_ATTR_VALUE_LEN = 0x0D; - static constexpr uint8_t ATT_ECODE_UNLIKELY = 0x0E; - static constexpr uint8_t ATT_ECODE_INSUFF_ENC = 0x0F; - static constexpr uint8_t ATT_ECODE_UNSUPP_GRP_TYPE = 0x10; - static constexpr uint8_t ATT_ECODE_INSUFF_RESOURCES = 0x11; - - /* Application error */ - static constexpr uint8_t ATT_ECODE_IO = 0x80; - static constexpr uint8_t ATT_ECODE_TIMEOUT = 0x81; - static constexpr uint8_t ATT_ECODE_ABORTED = 0x82; - - class CommandSink : public Core::IOutbound::ICallback, public Core::IOutbound, public Core::IInbound - { - public: - CommandSink() = delete; - CommandSink(const CommandSink&) = delete; - CommandSink& operator= (const CommandSink&) = delete; - - CommandSink(GATTSocket& parent, const uint16_t preferredMTU) : _parent(parent), _mtu(preferredMTU) { - Reload(); - } - virtual ~CommandSink() { - } - - public: - inline uint16_t MTU () const { - return (_mtu & 0xFFFF); - } - inline bool HasMTU() const { - return (_mtu <= 0xFFFF); - } - virtual void Updated(const Core::IOutbound& data, const uint32_t error_code) override - { - _parent.Completed(data, error_code); - } - - virtual void Reload() const override - { - _mtu = ((_mtu & 0xFFFF) | 0xFF000000); - } - virtual uint16_t Serialize(uint8_t stream[], const uint16_t length VARIABLE_IS_NOT_USED) const override - { - uint16_t result = 0; - if ((_mtu >> 24) == 0xFF) { - ASSERT(length >= 3); - stream[0] = ATT_OP_MTU_REQ; - stream[1] = (_mtu & 0xFF); - stream[2] = ((_mtu >> 8) & 0xFF); - _mtu = ((_mtu & 0xFFFF) | 0xF0000000); - result = 3; - } - return (result); - } - virtual Core::IInbound::state IsCompleted() const override - { - return ((_mtu >> 24) == 0x00 ? Core::IInbound::COMPLETED : Core::IInbound::INPROGRESS); - } - virtual uint16_t Deserialize(const uint8_t stream[], const uint16_t length) override { - uint16_t result = 0; - - // See if we need to retrigger.. - if (stream[0] == ATT_OP_MTU_RESP) { - _mtu = ((stream[2] << 8) | stream[1]); - result = length; - } else if ((stream[0] == ATT_OP_ERROR) && (stream[1] == ATT_OP_MTU_RESP)) { - TRACE_L1("Error on receiving MTU: [%d]", stream[2]); - result = length; - } else { - TRACE_L1("Unexpected L2CapSocket message. Expected: %d, got %d [%d]", ATT_OP_MTU_RESP, stream[0], stream[1]); - result = 0; - } - return (result); - } - - private: - GATTSocket& _parent; - mutable uint32_t _mtu; - }; - - public: - static constexpr uint32_t CommunicationTimeOut = 2000; /* 2 seconds. */ - - class EXTERNAL Command : public Core::IOutbound, public Core::IInbound { - private: - Command(const Command&) = delete; - Command& operator=(const Command&) = delete; - - static constexpr uint16_t BLOCKSIZE = 64; - - class Exchange { - private: - Exchange(const Exchange&) = delete; - Exchange& operator=(const Exchange&) = delete; - - public: - Exchange() - : _offset(~0) - , _size(0) - { - } - ~Exchange() - { - } - - public: - bool IsSend() const - { - return (_offset >= _size); - } - void Reload() const - { - _offset = 0; - } - void ReadByGroupType(const uint16_t start) - { - _buffer[1] = (start & 0xFF); - _buffer[2] = (start >> 8) & 0xFF; - Reload(); - } - uint8_t ReadByGroupType(const uint16_t start, const uint16_t end, const UUID& id) - { - _buffer[0] = ATT_OP_READ_BY_GROUP_REQ; - _buffer[1] = (start & 0xFF); - _buffer[2] = (start >> 8) & 0xFF; - _buffer[3] = (end & 0xFF); - _buffer[4] = (end >> 8) & 0xFF; - ::memcpy(&(_buffer[5]), id.Data(), id.Length()); - _size = id.Length() + 5; - _end = end; - return (ATT_OP_READ_BY_GROUP_RESP); - } - void FindByType(const uint16_t start) - { - _buffer[1] = (start & 0xFF); - _buffer[2] = (start >> 8) & 0xFF; - Reload(); - } - uint8_t FindByType(const uint16_t start, const uint16_t end, const UUID& id, const uint8_t length, const uint8_t data[]) - { - _buffer[0] = ATT_OP_FIND_BY_TYPE_REQ; - _buffer[1] = (start & 0xFF); - _buffer[2] = (start >> 8) & 0xFF; - _buffer[3] = (end & 0xFF); - _buffer[4] = (end >> 8) & 0xFF; - _buffer[5] = (id.Short() & 0xFF); - _buffer[6] = (id.Short() >> 8) & 0xFF; - ::memcpy(&(_buffer[7]), data, length); - _size = 7 + length; - _end = end; - return (ATT_OP_FIND_BY_TYPE_RESP); - } - uint8_t FindByType(const uint16_t start, const uint16_t end, const UUID& id, const uint16_t handle) - { - _buffer[0] = ATT_OP_FIND_BY_TYPE_REQ; - _buffer[1] = (start & 0xFF); - _buffer[2] = (start >> 8) & 0xFF; - _buffer[3] = (end & 0xFF); - _buffer[4] = (end >> 8) & 0xFF; - _buffer[5] = (id.Short() & 0xFF); - _buffer[6] = (id.Short() >> 8) & 0xFF; - _buffer[7] = (handle & 0xFF); - _buffer[8] = (handle >> 8) & 0xFF; - _size = 9; - _end = end; - return (ATT_OP_FIND_BY_TYPE_RESP); - } - void ReadByType(const uint16_t start) - { - _buffer[1] = (start & 0xFF); - _buffer[2] = (start >> 8) & 0xFF; - Reload(); - } - uint8_t ReadByType(const uint16_t start, const uint16_t end, const UUID& id) - { - _buffer[0] = ATT_OP_READ_BY_TYPE_REQ; - _buffer[1] = (start & 0xFF); - _buffer[2] = (start >> 8) & 0xFF; - _buffer[3] = (end & 0xFF); - _buffer[4] = (end >> 8) & 0xFF; - ::memcpy(&(_buffer[5]), id.Data(), id.Length()); - _size = id.Length() + 5; - _end = end; - return (ATT_OP_READ_BY_TYPE_RESP); - } - void FindInformation(const uint16_t start) - { - _buffer[1] = (start & 0xFF); - _buffer[2] = (start >> 8) & 0xFF; - Reload(); - } - uint8_t FindInformation(const uint16_t start, const uint16_t end) - { - _buffer[0] = ATT_OP_FIND_INFO_REQ; - _buffer[1] = (start & 0xFF); - _buffer[2] = (start >> 8) & 0xFF; - _buffer[3] = (end & 0xFF); - _buffer[4] = (end >> 8) & 0xFF; - _size = 5; - _end = end; - return (ATT_OP_FIND_INFO_RESP); - } - uint8_t Read(const uint16_t handle) - { - _buffer[0] = ATT_OP_READ_REQ; - _buffer[1] = (handle & 0xFF); - _buffer[2] = (handle >> 8) & 0xFF; - _size = 3; - _end = 0; - return (ATT_OP_READ_RESP); - } - uint8_t ReadBlob(const uint16_t handle, const uint16_t offset) - { - _buffer[0] = ATT_OP_READ_BLOB_REQ; - _buffer[1] = (handle & 0xFF); - _buffer[2] = (handle >> 8) & 0xFF; - _buffer[3] = (offset & 0xFF); - _buffer[4] = (offset >> 8) & 0xFF; - _size = 5; - _end = 0; - return (ATT_OP_READ_BLOB_RESP); - } - void WriteCommand(const uint16_t handle, const uint8_t length, const uint8_t data[]) - { - _buffer[0] = ATT_OP_WRITE_CMD; - _buffer[1] = (handle & 0xFF); - _buffer[2] = (handle >> 8) & 0xFF; - ::memcpy(&(_buffer[3]), data, length); - _size = 3 + length; - _end = 0; - } - uint8_t Write(const uint16_t handle, const uint8_t length, const uint8_t data[]) - { - _buffer[0] = ATT_OP_WRITE_REQ; - _buffer[1] = (handle & 0xFF); - _buffer[2] = (handle >> 8) & 0xFF; - ::memcpy(&(_buffer[3]), data, length); - _size = 3 + length; - _end = 0; - return (ATT_OP_WRITE_RESP); - } - uint16_t Serialize(uint8_t stream[], const uint16_t length) const - { - uint16_t result = std::min(static_cast(_size - _offset), length); - if (result > 0) { - ::memcpy(stream, &(_buffer[_offset]), result); - _offset += result; - - // printf("L2CAP send [%d]: ", result); - // for (uint8_t index = 0; index < (result - 1); index++) { printf("%02X:", stream[index]); } printf("%02X\n", stream[result - 1]); - } - - return (result); - } - uint16_t Handle() const - { - return (((_buffer[0] == ATT_OP_READ_BLOB_REQ) || (_buffer[0] == ATT_OP_READ_REQ)) ? ((_buffer[2] << 8) | _buffer[1]) : 0); - } - uint16_t Offset() const - { - return ((_buffer[0] == ATT_OP_READ_BLOB_REQ) ? ((_buffer[4] << 8) | _buffer[3]) : 0); - } - uint16_t End() const { - return (_end); - } - - private: - mutable uint16_t _offset; - uint16_t _end; - uint8_t _size; - uint8_t _buffer[BLOCKSIZE]; - }; - - public: - class EXTERNAL Response { - private: - Response(const Response&) = delete; - Response& operator=(const Response&) = delete; - - typedef std::pair > Entry; - - public: - Response() - : _maxSize(BLOCKSIZE) - , _loaded(0) - , _result() - , _iterator() - , _storage(reinterpret_cast(::malloc(_maxSize))) - , _preHead(true) - , _min(0x0001) - , _max(0xFFFF) - , _type(ATT_OP_ERROR) - { - } - ~Response() - { - if (_storage != nullptr) { - ::free(_storage); - } - } - - public: - uint8_t Type() const { - return(_type); - } - void Dump () const { - if (_storage != nullptr) { - fprintf (stderr, "Loaded data [%d]:", _loaded); - for (uint16_t index = 0; index < _loaded; index++) { - if (index == 0) { - fprintf (stderr, " %02X", _storage[index]); - } - else { - fprintf (stderr, ":%02X", _storage[index]); - } - } - fprintf (stderr, "\n"); - } - else { - fprintf (stderr, "There is no data to print..\n"); - } - } - void Clear() - { - Reset(); - _result.clear(); - _loaded = 0; - _min = 0xFFFF; - _max = 0x0001; - _type = ATT_OP_ERROR; - } - uint8_t Error() const { - return (_type == ATT_OP_ERROR ? static_cast(_min) : 0); - } - void Reset() - { - _preHead = true; - } - bool IsValid() const - { - return ((_preHead == false) && (_iterator != _result.end())); - } - bool Next() - { - if (_preHead == true) { - _preHead = false; - _iterator = _result.begin(); - } else { - _iterator++; - } - return (_iterator != _result.end()); - } - uint16_t Count() const - { - return (_result.size()); - } - bool Empty() const - { - return (_result.empty()); - } - uint16_t Handle() const - { - return (IsValid() == true ? _iterator->first : (_result.size() == 1 ? _result.begin()->first : 0)); - } - uint16_t MTU() const - { - return ((_storage[0] << 8) | _storage[1]); - } - uint16_t Group() const - { - return (_type == ATT_OP_READ_BY_TYPE_RESP ? ((_storage[_iterator->second.second + 2] << 8) | (_storage[_iterator->second.second + 1])) : _iterator->second.first); - } - UUID Attribute() const { - uint8_t offset = (_type == ATT_OP_READ_BY_TYPE_RESP ? 3 : 0); - uint16_t length = Delta() - offset; - const uint8_t* data = &(_storage[_iterator->second.second + offset]); - - if ((length != 2) && (length != 16)) { - TRACE_L1("**** Unexpected Attribute length [%d] !!!!", length); - } - - return (length == 2 ? UUID(static_cast((data[1] << 8) | (*data))) : - length == 16 ? UUID(data) : - UUID()); - } - uint8_t Rights() const { - return (_storage[_iterator->second.second]); - } - uint16_t Length() const - { - uint16_t result = _loaded; - if (IsValid() == true) { - result = Delta(); - } - return (result); - } - const uint8_t* Data() const - { - return (IsValid() == true ? &(_storage[_iterator->second.second]) : (((_result.size() <= 1) && (_loaded > 0)) ? _storage : nullptr)); - } - uint16_t Min() const { - return(_min); - } - uint16_t Max() const { - return(_max); - } - - private: - friend class Command; - void Type(const uint8_t response) { - _type = response; - } - uint16_t Delta() const { - std::list::iterator next(_iterator); - return (++next == _result.end() ? (_loaded - _iterator->second.second) : (next->second.second - _iterator->second.second)); - } - void SetMTU(const uint16_t MTU) - { - _storage[0] = (MTU >> 8) & 0xFF; - _storage[1] = MTU & 0xFF; - } - void Add(const uint16_t handle, const uint16_t group) - { - if (_min > handle) - _min = handle; - if (_max < group) - _max = group; - _result.emplace_back(Entry(handle, std::pair(group,_loaded))); - } - void Add(const uint16_t handle, const uint8_t length, const uint8_t buffer[]) - { - if (_min > handle) - _min = handle; - if (_max < handle) - _max = handle; - - _result.emplace_back(Entry(handle, std::pair(0,_loaded))); - Extend(length, buffer); - } - void Add(const uint16_t handle, const uint16_t group, const uint8_t length, const uint8_t buffer[]) - { - if (_min > handle) - _min = handle; - if (_max < group) - _max = group; - _result.emplace_back(Entry(handle, std::pair(group,_loaded))); - Extend(length, buffer); - } - void Extend(const uint8_t length, const uint8_t buffer[]) - { - if (length > 0) { - if ((_loaded + length) > _maxSize) { - _maxSize = ((((_loaded + length) / BLOCKSIZE) + 1) * BLOCKSIZE); - _storage = reinterpret_cast(::realloc(_storage, _maxSize)); - } - - ::memcpy(&(_storage[_loaded]), buffer, length); - _loaded += length; - } - } - uint16_t Offset() const - { - return (_result.size() != 0 ? _loaded : _loaded - _result.back().second.second); - } - - private: - uint16_t _maxSize; - uint16_t _loaded; - std::list _result; - std::list::iterator _iterator; - uint8_t* _storage; - bool _preHead; - uint16_t _min; - uint16_t _max; - uint8_t _type; - }; - - public: - Command() - : _error(~0) - , _mtu(0) - , _id(0) - , _frame() - , _response() - { - } - virtual ~Command() - { - } - - public: - Response& Result() { - return (_response); - } - const Response& Result() const { - return (_response); - } - uint8_t Id() const { - return(_id); - } - uint16_t Error() const { - return(_error); - } - void FindInformation(const uint16_t min, const uint16_t max) - { - _response.Clear(); - _error = ~0; - _id = _frame.FindInformation(min, max); - } - void ReadByGroupType(const uint16_t min, const uint16_t max, const UUID& uuid) - { - _response.Clear(); - _error = ~0; - _id = _frame.ReadByGroupType(min, max, uuid); - } - void ReadByType(const uint16_t min, const uint16_t max, const UUID& uuid) - { - _response.Clear(); - _error = ~0; - _id = _frame.ReadByType(min, max, uuid); - } - void ReadBlob(const uint16_t handle) - { - _response.Clear(); - _error = ~0; - _id = _frame.ReadBlob(handle, 0); - } - void Read(const uint16_t handle) - { - _response.Clear(); - _error = ~0; - _id = _frame.Read(handle); - } - void WriteCommand(const uint16_t handle, const uint8_t length, const uint8_t data[]) - { - _response.Clear(); - _error = Core::ERROR_NONE; - _frame.WriteCommand(handle, length, data); - } - void Write(const uint16_t handle, const uint8_t length, const uint8_t data[]) - { - _response.Clear(); - _response.Extend(length, data); - _error = ~0; - _id = _frame.Write(handle, length, data); - } - void FindByType(const uint16_t min, const uint16_t max, const UUID& uuid, const uint8_t length, const uint8_t data[]) - { - ASSERT(uuid.HasShort() == true); - _response.Clear(); - _error = ~0; - _id = _frame.FindByType(min, max, uuid, length, data); - } - void FindByType(const uint16_t min, const uint16_t max, const UUID& uuid, const uint16_t handle) - { - ASSERT(uuid.HasShort() == true); - _response.Clear(); - _error = ~0; - _id = _frame.FindByType(min, max, uuid, handle); - } - - void Error(const uint32_t error_code) { - _error = error_code; - } - void MTU(const uint16_t mtu) { - _mtu = mtu; - } - - private: - virtual uint16_t Deserialize(const uint8_t stream[], const uint16_t length) override; - virtual void Reload() const override - { - _frame.Reload(); - } - virtual uint16_t Serialize(uint8_t stream[], const uint16_t length) const override - { - return (_frame.Serialize(stream, length)); - } - virtual Core::IInbound::state IsCompleted() const override - { - return (_error != static_cast(~0) ? Core::IInbound::COMPLETED : (_frame.IsSend() ? Core::IInbound::INPROGRESS : Core::IInbound::RESEND)); - } - - private: - uint16_t _error; - uint16_t _mtu; - uint8_t _id; - Exchange _frame; - Response _response; - }; - - private: - typedef std::function Handler; - - class Entry { - public: - Entry() = delete; - Entry(const Entry&) = delete; - Entry& operator= (const Entry&) = delete; - Entry(const uint32_t waitTime, Command& cmd, const Handler& handler) - : _waitTime(waitTime) - , _cmd(cmd) - , _handler(handler) { - } - ~Entry() { - } - - public: - Command& Cmd() { - return(_cmd); - } - uint32_t WaitTime() const { - return(_waitTime); - } - bool operator== (const Core::IOutbound* rhs) const { - return (rhs == &_cmd); - } - bool operator!= (const Core::IOutbound* rhs) const { - return(!operator==(rhs)); - } - void Completed(const uint32_t error_code) { - _cmd.Error(error_code); - _handler(_cmd); - } - - private: - uint32_t _waitTime; - Command& _cmd; - Handler _handler; - }; - - public: - GATTSocket(const Core::NodeId& localNode, const Core::NodeId& remoteNode, const uint16_t maxMTU) - : Core::SynchronousChannelType(SocketPort::SEQUENCED, localNode, remoteNode, static_cast(48*1024), static_cast(48*1024)) - , _adminLock() - , _sink(*this, maxMTU) - , _queue() - { - } - GATTSocket(const Core::NodeId& localNode, const Core::NodeId& remoteNode, const uint16_t maxMTU, const uint16_t sendBufferSize, const uint16_t recvBufferSize) - : Core::SynchronousChannelType(SocketPort::SEQUENCED, localNode, remoteNode, sendBufferSize, recvBufferSize) - , _adminLock() - , _sink(*this, maxMTU) - , _queue() - { - } - virtual ~GATTSocket() - { - } - - public: - bool Security(const uint8_t level); - - inline uint16_t MTU() const { - return (_sink.MTU()); - } - uint32_t Execute(const uint32_t waitTime, Command& cmd) - { - cmd.MTU(_sink.MTU()); - return (Exchange(waitTime, cmd, cmd)); - } - void Execute(const uint32_t waitTime, Command& cmd, const Handler& handler) - { - cmd.MTU(_sink.MTU()); - _adminLock.Lock(); - _queue.emplace_back(waitTime, cmd, handler); - if (_queue.size() == 1) { - Send(waitTime, cmd, &_sink, &cmd); - } - _adminLock.Unlock(); - } - void Execute(Command& cmd) - { - cmd.MTU(_sink.MTU()); - Exchange(CommunicationTimeOut, cmd); - } - void Revoke(const Command& cmd) - { - Revoke(cmd); - } - - private: - virtual void Notification(const uint16_t handle, const uint8_t[], const uint16_t) = 0; - virtual void Operational() = 0; - - void StateChange() override; - - uint16_t Deserialize(const uint8_t dataFrame[], const uint16_t availableData) override { - uint32_t result = 0; - - if (availableData >= 1) { - const uint8_t& opcode = dataFrame[0]; - - if ((opcode == ATT_OP_HANDLE_NOTIFY) && (availableData >= 3)) { - uint16_t handle = ((dataFrame[2] << 8) | dataFrame[1]); - Notification(handle, &dataFrame[3], (availableData - 3)); - result = availableData; - } - else { - TRACE_L1("**** Unexpected data, TYPE [%02X] !!!!\n", dataFrame[0]); - } - } - else { - TRACE_L1("**** Unexpected data for deserialization [%d] !!!!", availableData); - } - - return (result); - } - void Completed(const Core::IOutbound& data, const uint32_t error_code) - { - if ( (&data == &_sink) && (_sink.HasMTU() == true) ) { - Operational(); - } - else { - _adminLock.Lock(); - - if ((_queue.size() == 0) || (*(_queue.begin()) != &data)) { - ASSERT (false && _T("Always the first one should be the one to be handled!!")); - } - else { - // Command completion... - _queue.begin()->Completed(error_code); - _queue.erase(_queue.begin()); - - if (_queue.size() > 0) { - Entry& entry(*(_queue.begin())); - Command& cmd (entry.Cmd()); - - Send(entry.WaitTime(), cmd, &_sink, &cmd); - } - } - - _adminLock.Unlock(); - } - } - - private: - Core::CriticalSection _adminLock; - CommandSink _sink; - std::list _queue; - uint32_t _mtuSize; - struct l2cap_conninfo _connectionInfo; - }; - -} // namespace Bluetooth - -} // namespace Thunder diff --git a/Source/bluetooth/gatt/Module.cpp b/Source/bluetooth/gatt/Module.cpp deleted file mode 100644 index 393d6a2..0000000 --- a/Source/bluetooth/gatt/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) diff --git a/Source/bluetooth/gatt/Module.h b/Source/bluetooth/gatt/Module.h deleted file mode 100644 index a3168d4..0000000 --- a/Source/bluetooth/gatt/Module.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#pragma once - -#ifndef MODULE_NAME -#define MODULE_NAME Bluetooth_GATT -#endif - -#include -#include - -#include <../include/bluetooth/bluetooth.h> - -#include "../Debug.h" -#include "../UUID.h" - -#if defined(__WINDOWS__) && defined(BLUETOOTH_EXPORTS) -#undef EXTERNAL -#define EXTERNAL EXTERNAL_EXPORT -#endif diff --git a/Source/bluetooth/gatt/bluetooth_gatt.h b/Source/bluetooth/gatt/bluetooth_gatt.h deleted file mode 100644 index 629d375..0000000 --- a/Source/bluetooth/gatt/bluetooth_gatt.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#pragma once - -#ifndef MODULE_NAME -#error "Please define a MODULE_NAME that describes the binary/library you are building." -#endif - -#include -#include "GATTSocket.h" -#include "GATTProfile.h" - -#ifdef __WINDOWS__ -#pragma comment(lib, "bluetoothgatt.lib") -#endif \ No newline at end of file diff --git a/Source/broadcast/CMakeLists.txt b/Source/broadcast/CMakeLists.txt deleted file mode 100644 index d606f38..0000000 --- a/Source/broadcast/CMakeLists.txt +++ /dev/null @@ -1,133 +0,0 @@ -# If not stated otherwise in this file or this component's license file the -# following copyright and licenses apply: -# -# Copyright 2020 Metrological -# -# 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. - -cmake_minimum_required(VERSION 3.15) - -find_package(Thunder) -find_package(${NAMESPACE}Core REQUIRED) -find_package(CompileSettingsDebug CONFIG REQUIRED) - -project(${NAMESPACE}Broadcast - VERSION 1.0.0 - DESCRIPTION "Abstraction to parse DVB tables" - LANGUAGES CXX) - -set(TARGET ${PROJECT_NAME}) -message("Setup ${TARGET} v${PROJECT_VERSION}") -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") - -find_package(NXCLIENT QUIET) - -add_library(${TARGET} - ProgramTable.cpp - Definitions.cpp - TunerAdministrator.cpp - Module.cpp - ) - -set(PUBLIC_HEADERS - broadcast.h - Definitions.h - Descriptors.h - MPEGDescriptor.h - MPEGSection.h - MPEGTable.h - ProgramTable.h - TunerAdministrator.h - Services.h - Networks.h - TimeDate.h - Schedule.h - NIT.h - SDT.h - TDT.h - EIT.h - Module.h - ) - -target_link_libraries(${TARGET} - PRIVATE - CompileSettingsDebug::CompileSettingsDebug - ${NAMESPACE}Core::${NAMESPACE}Core - ) - -if(NXCLIENT_FOUND) - find_package(NEXUS REQUIRED) - - if (BROADCAST_IMPLEMENTATION_PATH) - target_sources(${TARGET} PRIVATE ${BROADCAST_IMPLEMENTATION_PATH}/Tuner.cpp) - else() - include(GetExternalCode) - set(BROADCAST_IMPLEMENTATION_VERSION "master" CACHE STRING "broadcast implementation version: commit_id_or_tag_or_branch_name") - set(BROADCAST_IMPLEMENTATION_REPOSITORY "https://code.rdkcentral.com/r/soc/broadcom/components/rdkcentral/thunder/broadcast" CACHE STRING "broadcast implementation repository") - GetExternalCode( - GIT_REPOSITORY ${BROADCAST_IMPLEMENTATION_REPOSITORY} - GIT_VERSION ${BROADCAST_IMPLEMENTATION_VERSION} - SOURCE_DIR "Implementation/Nexus" - ) - target_sources(${TARGET} PRIVATE Implementation/Nexus/Tuner.cpp) - endif() - - target_link_libraries(${TARGET} - PRIVATE - NEXUS::NEXUS - NXCLIENT::NXCLIENT - ) -else() - target_sources(${TARGET} PRIVATE Implementation/V4L/Tuner.cpp) -endif() - -set_target_properties(${TARGET} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES - FRAMEWORK FALSE - PUBLIC_HEADER "${PUBLIC_HEADERS}" # specify the public headers - VERSION ${PROJECT_VERSION} - SOVERSION ${PROJECT_VERSION_MAJOR} - ) - -target_include_directories( ${TARGET} - PUBLIC - $ - $ - $ - ) - -# =========================================================================================== -# Install ARTIFACTS: -# =========================================================================================== -install( - TARGETS ${TARGET} EXPORT ${TARGET}Targets - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT ${NAMESPACE}_Development - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT ${NAMESPACE}_Runtime NAMELINK_COMPONENT ${NAMESPACE}_Development - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${NAMESPACE}_Runtime - FRAMEWORK DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${NAMESPACE}_Runtime - PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${NAMESPACE}/broadcast COMPONENT ${NAMESPACE}_Development - INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${NAMESPACE}/broadcast # headers -) - -# =========================================================================================== -# Install METADATA: -# =========================================================================================== -InstallPackageConfig( - TARGETS ${TARGET} - DESCRIPTION "${PROJECT_DESCRIPTION}" ) - -InstallCMakeConfig( - TARGETS ${TARGET}) - -add_subdirectory(test) diff --git a/Source/broadcast/Definitions.cpp b/Source/broadcast/Definitions.cpp deleted file mode 100644 index 48e301e..0000000 --- a/Source/broadcast/Definitions.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#include "Definitions.h" - -namespace Thunder { - -ENUM_CONVERSION_BEGIN(Broadcast::ITuner::DTVStandard) - { Broadcast::ITuner::DVB, _TXT("DVB") }, - { Broadcast::ITuner::ATSC, _TXT("ATSC") }, - { Broadcast::ITuner::ISDB, _TXT("ISDB") }, - { Broadcast::ITuner::DAB, _TXT("DAB") }, -ENUM_CONVERSION_END(Broadcast::ITuner::DTVStandard) - -ENUM_CONVERSION_BEGIN(Broadcast::ITuner::annex) - { Broadcast::ITuner::NoAnnex, _TXT("None") }, - { Broadcast::ITuner::A, _TXT("A") }, - { Broadcast::ITuner::B, _TXT("B") }, - { Broadcast::ITuner::C, _TXT("C") }, -ENUM_CONVERSION_END(Broadcast::ITuner::annex) - -ENUM_CONVERSION_BEGIN(Broadcast::ITuner::modus) - { Broadcast::ITuner::Cable, _TXT("Cable") }, - { Broadcast::ITuner::Terrestrial, _TXT("Terrestrial") }, - { Broadcast::ITuner::Satellite, _TXT("Satellite") }, -ENUM_CONVERSION_END(Broadcast::ITuner::modus) - -ENUM_CONVERSION_BEGIN(Broadcast::SpectralInversion) - { Broadcast::Auto, _TXT("Auto") }, - { Broadcast::Normal, _TXT("Normal") }, - { Broadcast::Inverted, _TXT("Inverted") }, -ENUM_CONVERSION_END(Broadcast::SpectralInversion) - -ENUM_CONVERSION_BEGIN(Broadcast::Modulation) - { Broadcast::HORIZONTAL_QPSK, _TXT("QPSK_H") }, - { Broadcast::HORIZONTAL_8PSK, _TXT("8PSK_H") }, - { Broadcast::HORIZONTAL_QAM16, _TXT("QAM16_H") }, - { Broadcast::VERTICAL_QPSK, _TXT("QPSK_V") }, - { Broadcast::VERTICAL_8PSK, _TXT("8PSK_V") }, - { Broadcast::VERTICAL_QAM16, _TXT("QAM16_V") }, - { Broadcast::LEFT_QPSK, _TXT("QPSK_L") }, - { Broadcast::LEFT_8PSK, _TXT("8PSK_L") }, - { Broadcast::LEFT_QAM16, _TXT("QAM16_L") }, - { Broadcast::RIGHT_QPSK, _TXT("QPSK_R") }, - { Broadcast::RIGHT_8PSK, _TXT("8PSK_R") }, - { Broadcast::RIGHT_QAM16, _TXT("QAM16_R") }, - { Broadcast::QAM16, _TXT("QAM16") }, - { Broadcast::QAM32, _TXT("QAM32") }, - { Broadcast::QAM64, _TXT("QAM64") }, - { Broadcast::QAM128, _TXT("QAM128") }, - { Broadcast::QAM256, _TXT("QAM256") }, - { Broadcast::QAM512, _TXT("QAM512") }, - { Broadcast::QAM1024, _TXT("QAM1024") }, - { Broadcast::QAM2048, _TXT("QAM2048") }, - { Broadcast::QAM4096, _TXT("QAM4096") }, -ENUM_CONVERSION_END(Broadcast::Modulation) - -} // namespace Thunder diff --git a/Source/broadcast/Definitions.h b/Source/broadcast/Definitions.h deleted file mode 100644 index e7d2635..0000000 --- a/Source/broadcast/Definitions.h +++ /dev/null @@ -1,372 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#ifndef __BROADCAST_DEFINITIONS_H -#define __BROADCAST_DEFINITIONS_H - -#include "Module.h" - -namespace Thunder { - -namespace Broadcast { - - namespace MPEG { - - class Section; - } - - struct ISection { - virtual ~ISection() {} - virtual void Handle(const MPEG::Section& section) = 0; - }; - - struct IMonitor { - virtual ~IMonitor() {} - virtual void ChangePid(const uint16_t newpid, ISection* observer) = 0; - }; - - template - class IteratorType { - public: - IteratorType() - : _position(0) - , _index() - , _list() - { - } - IteratorType(const std::map& container) - : _position(0) - , _index() - , _list() - { - typename std::map::const_iterator index(container.begin()); - while (index != container.end()) { - _list.emplace_back(index->second); - index++; - } - } - IteratorType(const IteratorType& copy) - : _list() - { - operator=(copy); - } - ~IteratorType() - { - } - - IteratorType& operator=(const IteratorType& rhs) - { - _position = rhs._position; - _list.clear(); - typename std::list::const_iterator index(rhs._list.begin()); - - while (index != rhs._list.end()) { - _list.emplace_back(*index); - if (_list.size() == rhs._position) { - _index = --_list.end(); - } - index++; - } - return (*this); - } - - public: - bool IsValid() const - { - return ((_position != 0) && (_position <= _list.size())); - } - void Reset() - { - _position = 0; - } - bool Next() - { - if (_position == 0) { - _index = _list.begin(); - _position++; - } else if (_position <= _list.size()) { - _index++; - _position++; - } - - return (_position <= _list.size()); - } - const LISTOBJECT& Current() const - { - - ASSERT(IsValid() == true); - - return (*_index); - } - - private: - uint32_t _position; - typename std::list::const_iterator _index; - typename std::list _list; - }; - - template - TYPE ConvertBCD(const uint8_t buffer[], const uint8_t digits, const bool evenStart) - { - TYPE value = 0; - for (uint8_t index = 0; index < digits;) { - value *= 10; - if (evenStart == true) { - value += ((index & 0x01) ? (buffer[index / 2] & 0xF) : (buffer[index / 2] >> 4)); - index++; - } else { - index++; - value += ((index & 0x01) ? (buffer[index / 2] & 0xF) : (buffer[index / 2] >> 4)); - } - } - return (value); - } - - enum SpectralInversion { - Auto, - Normal, - Inverted - }; - - enum Modulation { - MODULATION_UNKNOWN = 0, - - // Satellite modulation types - HORIZONTAL_QPSK = 1, - HORIZONTAL_8PSK = 2, - HORIZONTAL_QAM16 = 3, - VERTICAL_QPSK = 5, - VERTICAL_8PSK = 6, - VERTICAL_QAM16 = 7, - LEFT_QPSK = 9, - LEFT_8PSK = 10, - LEFT_QAM16 = 11, - RIGHT_QPSK = 13, - RIGHT_8PSK = 14, - RIGHT_QAM16 = 15, - - // Cable/Terestrial modulation types - QAM16 = 16, - QAM32 = 32, - QAM64 = 64, - QAM128 = 128, - QAM256 = 256, - QAM512 = 512, - QAM1024 = 1024, - QAM2048 = 2048, - QAM4096 = 4096 - }; - - enum fec { - FEC_INNER_UNKNOWN = 0, - FEC_1_2 = 1, - FEC_2_3 = 2, - FEC_3_4 = 3, - FEC_5_6 = 4, - FEC_7_8 = 5, - FEC_8_9 = 6, - FEC_3_5 = 7, - FEC_4_5 = 8, - FEC_9_10 = 9, - FEC_2_5 = 10, - FEC_6_7 = 11, - FEC_INNER_NONE = 15 - }; - - enum fec_outer { - FEC_OUTER_UNKNOWN = 0, - FEC_OUTER_NONE = 1, - RS = 2 - }; - - enum transmission { - TRANSMISSION_AUTO, - TRANSMISSION_1K, - TRANSMISSION_2K, - TRANSMISSION_4K, - TRANSMISSION_8K, - TRANSMISSION_16K, - TRANSMISSION_32K, - TRANSMISSION_C3780, - TRANSMISSION_C1 - }; - - enum guard { - GUARD_AUTO, - GUARD_1_4, - GUARD_1_8, - GUARD_1_16, - GUARD_1_32, - GUARD_1_128, - GUARD_19_128, - GUARD_19_256, - }; - - enum hierarchy { - NoHierarchy, - AutoHierarchy, - Hierarchy1, - Hierarchy2, - Hierarchy4, - }; - - struct EXTERNAL ITuner { - - struct INotification { - virtual ~INotification() {} - - virtual void Activated(ITuner* tuner) = 0; - virtual void Deactivated(ITuner* tuner) = 0; - virtual void StateChange(ITuner* tuner) = 0; - }; - - struct ICallback { - virtual ~ICallback() {} - - virtual void StateChange() = 0; - }; - - ITuner() : _adminLock(), _callback(nullptr) {} - virtual ~ITuner() {} - - enum state { - IDLE = 0x01, - LOCKED = 0x02, - PREPARED = 0x04, - STREAMING = 0x08 - }; - - enum DTVStandard { - DVB = 0x1000, - ATSC = 0x2000, - ISDB = 0x3000, - DAB = 0x4000 - }; - - enum modus { - Satellite = 0x1, - Terrestrial = 0x2, - Cable = 0x3 - }; - - enum annex { - NoAnnex = 0x000, // NoAnnex -> S/T - A = 0x400, // A -> S2/T2 - B = 0x800, - C = 0xC00 - }; - - // The following methods will be called before any create is called. It allows for an initialization, - // if requires, and a deinitialization, if the Tuners will no longer be used. - static uint32_t Initialize(const string& configuration); - static uint32_t Deinitialize(); - - // See if the tuner supports the requested mode, or is configured for the requested mode. This method - // only returns proper values if the Initialize has been called before. - static bool IsSupported(const ITuner::modus mode); - - // Accessor to create a tuner. - static ITuner* Create(const string& info); - - // Accessor to metadata on the tuners. - static void Register(INotification* notify); - static void Unregister(INotification* notify); - - // Offer the ability to get the proper information (with respect to hardware properties) of this tuner instance. - virtual uint32_t Properties() const = 0; - - inline annex Annex() const { - return (static_cast(Properties() & 0x0F00)); - } - inline modus Modus() const { - return (static_cast(Properties() & 0xF)); - } - inline DTVStandard Standard() const { - return (static_cast(Properties() & 0xF000)); - } - - // Currently locked on ID - // This method return a unique number that will identify the locked on Transport stream. The ID will always - // identify the uniquely locked on to Tune request. ID => 0 is reserved and means not locked on to anything. - virtual uint16_t Id() const = 0; - - // Using these methods the state of the tuner can be viewed. - // IDLE: Means there is no request, or the frequency requested (with other parameters) can not be locked. - // LOCKED: The stream has been locked, frequency, modulation, symbolrate and spectral inversion seem to be fine. - // PREPARED: The program that was requetsed to prepare fore, has been found in PAT/PMT, the needed information, - // like PIDS is loaded. If Priming is available, this means that the priming has started! - // STREAMING: This means that the requested program is being streamed to decoder or file, depending on implementation/inpuy. - virtual state State() const = 0; - - // Using the next method, the allocated Frontend will try to lock the channel that is found at the given parameters. - // Frequency is always in MHz. - virtual uint32_t Tune(const uint16_t frequency, const Modulation, const uint32_t symbolRate, const uint16_t fec, const SpectralInversion) = 0; - - // In case the tuner needs to be tuned to s apecific programId, please list it here. Once the PID's associated to this - // programId have been found, and set, the Tuner will reach its PREPARED state. - virtual uint32_t Prepare(const uint16_t programId) = 0; - - // A Tuner can be used to filter PSI/SI. Using the next call a callback can be installed to receive sections associated - // with a table. Each valid section received will be offered as a single section on the ISection interface for the user - // to process. - virtual uint32_t Filter(const uint16_t pid, const uint8_t tableId, ISection* callback) = 0; - - // Using the next two methods, the frontends will be hooked up to decoders or file, and be removed from a decoder or file. - virtual uint32_t Attach(const uint8_t index) = 0; - virtual uint32_t Detach(const uint8_t index) = 0; - - - // If you have an ITuner interface, you can subscribe to state changes of this Tuner interface - // This will only be one instance, by design, to avoid the overhead of maintining a list and - // thus spending more resources. The idea is that the object holding the ITuner interface to - // do the actual tune can assign a callback and receive the actual state changes. If you "just" - // receive this interface on the INotification, you should *NOT* set a callback on this interface - void Callback(ICallback* callback) { - - _adminLock.Lock(); - - ASSERT ((_callback == nullptr) ^ (callback == nullptr)); - - _callback = callback; - - _adminLock.Unlock(); - } - void StateChange() { - _adminLock.Lock(); - if (_callback != nullptr) { - _callback->StateChange(); - } - _adminLock.Unlock(); - } - void Lock() const { - _adminLock.Lock(); - } - void Unlock() const { - _adminLock.Unlock(); - } - - private: - mutable Core::CriticalSection _adminLock; - ICallback* _callback; - }; - -} // namespace Broadcast -} // namespace Thunder - -#endif // __BROADCAST_DEFINITIONS_H diff --git a/Source/broadcast/Descriptors.h b/Source/broadcast/Descriptors.h deleted file mode 100644 index 8d8c066..0000000 --- a/Source/broadcast/Descriptors.h +++ /dev/null @@ -1,229 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#ifndef DESCRIPTORS_H -#define DESCRIPTORS_H - -#include "Definitions.h" -#include "MPEGDescriptor.h" - -namespace Thunder { -namespace Broadcast { - namespace DVB { - namespace Descriptors { - - class EXTERNAL NetworkName { - private: - NetworkName operator=(const NetworkName& rhs) = delete; - - public: - constexpr static uint8_t TAG = 0x40; - - public: - NetworkName() - : _data() - { - } - NetworkName(const NetworkName& copy) - : _data(copy._data) - { - } - NetworkName(const MPEG::Descriptor& copy) - : _data(copy) - { - } - ~NetworkName() - { - } - - public: - string Name() const - { - return (Core::ToString(reinterpret_cast(&(_data[1])), _data[0])); - } - - private: - MPEG::Descriptor _data; - }; - - class EXTERNAL SatelliteDeliverySystem { - private: - SatelliteDeliverySystem operator=(const SatelliteDeliverySystem& rhs) = delete; - - public: - constexpr static uint8_t TAG = 0x43; - - public: - SatelliteDeliverySystem() - : _data() - { - } - SatelliteDeliverySystem(const SatelliteDeliverySystem& copy) - : _data(copy._data) - { - } - SatelliteDeliverySystem(const MPEG::Descriptor& copy) - : _data(copy) - { - } - ~SatelliteDeliverySystem() - { - } - - public: - // Frequency in KHz - uint32_t Frequency() const - { - return (Broadcast::ConvertBCD(&(_data[0]), 8, true) * 10); - } - Broadcast::Modulation Modulation() const - { - return (static_cast(((_data[6] >> 3) & 0x0C) | (_data[6] & 0x03))); - } - uint32_t SymbolRate() const - { - return (Broadcast::ConvertBCD(&(_data[7]), 7, true)); - } - fec FECInner() const - { - return (static_cast(_data[5] & 0xF)); - } - - private: - MPEG::Descriptor _data; - }; - - class EXTERNAL CableDeliverySystem { - private: - CableDeliverySystem operator=(const CableDeliverySystem& rhs) = delete; - - public: - constexpr static uint8_t TAG = 0x44; - - public: - CableDeliverySystem() - : _data() - { - } - CableDeliverySystem(const CableDeliverySystem& copy) - : _data(copy._data) - { - } - CableDeliverySystem(const MPEG::Descriptor& copy) - : _data(copy) - { - } - ~CableDeliverySystem() - { - } - - public: - // Frequency in KHz - uint32_t Frequency() const - { - return (Broadcast::ConvertBCD(&(_data[0]), 8, true) / 10); - } - Broadcast::Modulation Modulation() const - { - uint8_t mod(_data[6]); - return (static_cast(((mod == 0) || (mod > 9)) ? 0 : (0x10 << (mod - 1)))); - } - uint32_t SymbolRate() const - { - return (Broadcast::ConvertBCD(&(_data[7]), 7, true)); - } - fec FECInner() const - { - return (static_cast(_data[5] & 0xF)); - } - fec_outer FECOuter() const - { - return (static_cast(_data[10] & 0x3)); - } - - private: - MPEG::Descriptor _data; - }; - - class EXTERNAL Service { - private: - Service operator=(const Service& rhs) = delete; - - public: - constexpr static uint8_t TAG = 0x48; - - enum type { - DIGITAL_TELEVISION = 0x01, - DIGITAL_RADIO = 0x02, - TELETEXT = 0x03, - NVOD_REFERENCE = 0x04, - NVOD_TIME_SHIFT = 0x05, - MOSAIC = 0x06, - ADVANCED_DIGITAL_RADIO = 0x0A, - ADVANCED_DIGITAL_MOSAIC = 0x0B, - DATA_BROADCAST_SERVICE = 0x0C, - ADVANCED_SD_TELEVISION = 0x16, - ADVANCED_SD_NVOD_TIME_SHIFT = 0x17, - ADVANCED_SD_NVOD_REFERENCE = 0x18, - ADVANCED_HD_TELEVISION = 0x19, - ADVANCED_HD_NVOD_TIME_SHIFT = 0x1A, - ADVANCED_HD_NVOD_REFERENCE = 0x1B - }; - - public: - Service() - : _data() - { - } - Service(const Service& copy) - : _data(copy._data) - { - } - Service(const MPEG::Descriptor& copy) - : _data(copy) - { - } - ~Service() - { - } - - public: - type Type() const - { - return (static_cast(_data[0])); - } - string Provider() const - { - return (Core::ToString(reinterpret_cast(&(_data[2])), _data[1])); - } - string Name() const - { - uint8_t offset = 1 /* service type */ + 1 /* length */ + _data[1]; - return (Core::ToString(reinterpret_cast(&(_data[offset + 1])), _data[offset])); - } - - private: - MPEG::Descriptor _data; - }; - } - } -} -} // namespace Thunder::Broadcast::DVB::Descriptors - -#endif // DESCRIPTORS_H diff --git a/Source/broadcast/EIT.h b/Source/broadcast/EIT.h deleted file mode 100644 index 4bdc331..0000000 --- a/Source/broadcast/EIT.h +++ /dev/null @@ -1,203 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#ifndef DVB_EIT_TABLE_H -#define DVB_EIT_TABLE_H - -// ---- Include system wide include files ---- - -// ---- Include local include files ---- -#include "MPEGDescriptor.h" -#include "MPEGSection.h" -#include "Module.h" - -// ---- Referenced classes and types ---- - -// ---- Helper types and constants ---- - -// ---- Helper functions ---- - -// ---- Class Definition ---- - -namespace Thunder { -namespace Broadcast { - namespace DVB { - - class EXTERNAL EIT { - public: - static const uint16_t ACTUAL = 0x42; - static const uint16_t OTHER = 0x46; - - public: - enum running { - Undefined = 0, - NotRunning = 1, - AboutToStart = 2, - Pausing = 3, - Running = 4 - }; - - public: - class ServiceIterator { - public: - ServiceIterator() - : _info() - , _offset(~0) - { - } - ServiceIterator(const Core::DataElement& data) - : _info(data) - , _offset(~0) - { - } - ServiceIterator(const ServiceIterator& copy) - : _info(copy._info) - , _offset(copy._offset) - { - } - ~ServiceIterator() {} - - ServiceIterator& operator=(const ServiceIterator& RHS) - { - _info = RHS._info; - _offset = RHS._offset; - - return (*this); - } - - public: - inline bool IsValid() const { return (_offset < _info.Size()); } - inline void Reset() { _offset = ~0; } - inline bool Next() - { - if (_offset == static_cast(~0)) { - _offset = 0; - } else if (_offset < _info.Size()) { - _offset += (DescriptorSize() + 5); - } - - return (IsValid()); - } - inline bool EIT_PF() const - { - return ((_info[_offset + 2] & 0x01) != 0); - } - inline bool EIT_Schedule() const - { - return ((_info[_offset + 2] & 0x02) != 0); - } - inline bool IsFreeToAir() const - { - return ((_info[_offset + 3] & 0x10) != 0); - } - inline running RunningMode() const - { - return (static_cast((_info[_offset + 3] & 0xE0) >> 5)); - } - inline uint16_t ServiceId() const - { - return ((_info[_offset + 0] << 8) | _info[_offset + 1]); - } - inline MPEG::DescriptorIterator Descriptors() const - { - return (MPEG::DescriptorIterator( - Core::DataElement(_info, _offset + 5, DescriptorSize()))); - } - inline uint8_t Services() const - { - uint8_t count = 0; - uint16_t offset = 0; - while (offset < _info.Size()) { - offset += (((_info[offset + 3] << 8) | _info[offset + 4]) & 0x0FFF) + 5; - count++; - } - return (count); - } - - private: - inline uint16_t DescriptorSize() const - { - return ((_info[_offset + 3] << 8) | _info[_offset + 4]) & 0x0FFF; - } - - private: - Core::DataElement _info; - uint16_t _offset; - }; - - public: - EIT() - : _data() - , _transportStreamId(~0) - { - } - EIT(const MPEG::Table& data) - : _data(data.Data()) - , _transportStreamId(data.Extension()) - { - } - EIT(const uint16_t transportStreamId, const Core::DataElement& data) - : _data(data) - , _transportStreamId(transportStreamId) - { - } - EIT(const EIT& copy) - : _data(copy._data) - , _transportStreamId(copy._transportStreamId) - { - } - ~EIT() {} - - EIT& operator=(const EIT& rhs) - { - _data = rhs._data; - _transportStreamId = rhs._transportStreamId; - return (*this); - } - bool operator==(const EIT& rhs) const - { - return ((_transportStreamId == rhs._transportStreamId) && (_data == rhs._data)); - } - bool operator!=(const EIT& rhs) const { return (!operator==(rhs)); } - - public: - inline bool IsValid() const - { - return ((_transportStreamId != static_cast(~0)) && (_data.Size() >= 2)); - } - inline uint16_t TransportStreamId() const { return (_transportStreamId); } - uint16_t OriginalNetworkId() const - { - return (_data.GetNumber(0) & 0x1FFF); - } - ServiceIterator Services() const - { - return (ServiceIterator(Core::DataElement(_data, 3, _data.Size() - 3))); - } - - private: - Core::DataElement _data; - uint16_t _transportStreamId; - }; - - } // namespace DVB -} // namespace Broadcast -} // namespace Thunder - -#endif // DVB_EIT_TABLE_H diff --git a/Source/broadcast/Implementation/V4L/Tuner.cpp b/Source/broadcast/Implementation/V4L/Tuner.cpp deleted file mode 100644 index 0048bb5..0000000 --- a/Source/broadcast/Implementation/V4L/Tuner.cpp +++ /dev/null @@ -1,841 +0,0 @@ - - /* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#include "Definitions.h" -#include "ProgramTable.h" -#include "TunerAdministrator.h" - -#include -#include -#include - -#if (DVB_API_VERSION < 5) -#error "Not supported DVB API version" -#endif - -#define __DEBUG__ - -// -------------------------------------------------------------------- -// SOURCE: https://linuxtv.org/downloads/v4l-dvb-apis/uapi/dvb -// -------------------------------------------------------------------- -namespace Thunder { -namespace Broadcast { - - struct conversion_entry { - int from; // Thunder Broadcast/ITuner value - int to; // LinuxDVB API value - }; - - static constexpr conversion_entry _tableSystemType[] = { - { (ITuner::DVB | ITuner::Cable | ITuner::B), SYS_DVBC_ANNEX_B }, - { (ITuner::DVB | ITuner::Cable | ITuner::C), SYS_DVBC_ANNEX_C }, - { (ITuner::DVB | ITuner::Terrestrial | ITuner::NoAnnex), SYS_DVBT }, - { (ITuner::DVB | ITuner::Terrestrial | ITuner::A), SYS_DVBT2 }, - { (ITuner::DVB | ITuner::Satellite | ITuner::NoAnnex), SYS_DVBS }, - { (ITuner::DVB | ITuner::Satellite | ITuner::A), SYS_DVBS2 }, - { (ITuner::ISDB | ITuner::Satellite | ITuner::NoAnnex), SYS_ISDBS }, - { (ITuner::ISDB | ITuner::Terrestrial | ITuner::NoAnnex), SYS_ISDBT }, - { (ITuner::ISDB | ITuner::Cable | ITuner::NoAnnex), SYS_ISDBC } - }; - - static constexpr conversion_entry _tableInversion[] = { - { Broadcast::Auto, INVERSION_AUTO }, - { Broadcast::Normal, INVERSION_OFF }, - { Broadcast::Inverted, INVERSION_ON } - }; - static constexpr conversion_entry _tableFEC[] = { - { Broadcast::FEC_INNER_NONE, FEC_NONE }, - { Broadcast::FEC_INNER_UNKNOWN, FEC_AUTO }, - { Broadcast::FEC_1_2, FEC_1_2 }, - { Broadcast::FEC_2_3, FEC_2_3 }, - { Broadcast::FEC_2_5, FEC_2_5 }, - { Broadcast::FEC_3_4, FEC_3_4 }, - { Broadcast::FEC_3_5, FEC_3_5 }, - { Broadcast::FEC_4_5, FEC_4_5 }, - { Broadcast::FEC_5_6, FEC_5_6 }, - { Broadcast::FEC_6_7, FEC_6_7 }, - { Broadcast::FEC_7_8, FEC_7_8 }, - { Broadcast::FEC_8_9, FEC_8_9 }, - { Broadcast::FEC_9_10, FEC_9_10 } - }; - static constexpr conversion_entry _tableModulation[] = { - { Broadcast::HORIZONTAL_QPSK, QPSK }, - { Broadcast::VERTICAL_QPSK, QPSK }, - { Broadcast::LEFT_QPSK, QPSK }, - { Broadcast::RIGHT_QPSK, QPSK }, - { Broadcast::HORIZONTAL_8PSK, PSK_8 }, - { Broadcast::VERTICAL_8PSK, PSK_8 }, - { Broadcast::LEFT_8PSK, PSK_8 }, - { Broadcast::RIGHT_8PSK, PSK_8 }, - { Broadcast::QAM16, QAM_16 }, - { Broadcast::QAM32, QAM_32 }, - { Broadcast::QAM64, QAM_64 }, - { Broadcast::QAM128, QAM_128 }, - { Broadcast::QAM256, QAM_256 }, - }; - static constexpr conversion_entry _tableTransmission[] = { - { Broadcast::TRANSMISSION_AUTO, TRANSMISSION_MODE_AUTO }, - { Broadcast::TRANSMISSION_1K, TRANSMISSION_MODE_1K }, - { Broadcast::TRANSMISSION_2K, TRANSMISSION_MODE_2K }, - { Broadcast::TRANSMISSION_4K, TRANSMISSION_MODE_4K }, - { Broadcast::TRANSMISSION_8K, TRANSMISSION_MODE_8K }, - { Broadcast::TRANSMISSION_16K, TRANSMISSION_MODE_16K }, - { Broadcast::TRANSMISSION_32K, TRANSMISSION_MODE_32K }, - { Broadcast::TRANSMISSION_C3780, TRANSMISSION_MODE_C3780 }, - { Broadcast::TRANSMISSION_C1, TRANSMISSION_MODE_C1 } - }; - static constexpr conversion_entry _tableGuard[] = { - { Broadcast::GUARD_AUTO, GUARD_INTERVAL_AUTO }, - { Broadcast::GUARD_1_4, GUARD_INTERVAL_1_4 }, - { Broadcast::GUARD_1_8, GUARD_INTERVAL_1_8 }, - { Broadcast::GUARD_1_16, GUARD_INTERVAL_1_16 }, - { Broadcast::GUARD_1_32, GUARD_INTERVAL_1_32 }, - { Broadcast::GUARD_1_128, GUARD_INTERVAL_1_128 }, - { Broadcast::GUARD_19_128, GUARD_INTERVAL_19_128 }, - { Broadcast::GUARD_19_256, GUARD_INTERVAL_19_256 } - }; - static constexpr conversion_entry _tableHierarchy[] = { - { Broadcast::NoHierarchy, HIERARCHY_NONE }, - { Broadcast::AutoHierarchy, HIERARCHY_AUTO }, - { Broadcast::Hierarchy1, HIERARCHY_1 }, - { Broadcast::Hierarchy2, HIERARCHY_2 }, - { Broadcast::Hierarchy4, HIERARCHY_4 } - }; - /* -static constexpr conversion_entry _tablePilot[] = { - { Broadcast::PILOT_AUTO, PILOT_AUTO }, - { Broadcast::PILOT_ON, PILOT_ON }, - { Broadcast::PILOT_OFF, PILOT_OFF } -}; -static constexpr conversion_entry _tableRollOff[] = { - { Broadcast::HIERARCHY_AUTO, ROLLOFF_AUTO }, - { Broadcast::ROLLOFF_20, ROLLOFF_20 }, - { Broadcast::ROLLOFF_25, ROLLOFF_25 }, - { Broadcast::ROLLOFF_35, ROLLOFF_35 } -}; -*/ - - template - int Convert(const conversion_entry (&table)[N], const int from, const int ifnotfound) - { - uint16_t index = 0; - while ((index < N) && (from != table[index].from)) { - index++; - } - return (index < N ? table[index].to : ifnotfound); - } - - void Property(dtv_property& property, const int command, const int value) - { - property.cmd = command; - property.u.data = value; - } - - static uint16_t IndexToFrontend(const uint8_t /* index */) - { - uint8_t adapter = 0; - uint8_t frontend = 0; - - // Count the number of frontends you have per adapter, substract those from the index.. - - return ((adapter << 8) | frontend); - } - - class __attribute__((visibility("hidden"))) Tuner : public ITuner { - private: - Tuner() = delete; - Tuner(const Tuner&) = delete; - Tuner& operator=(const Tuner&) = delete; - - class Observer : public Core::Thread { - public: - Observer(const Observer&) = delete; - Observer& operator=(const Observer&) = delete; - - Observer() : Core::Thread(Thread::DefaultStackSize(), _T("Tuner")), _adminLock(), _entries() { - } - ~Observer() override { - } - - public: - static Observer& Instance() - { - static Observer& _instance = Core::SingletonType::Instance(); - return (_instance); - } - void Register(Tuner& callback) { - _adminLock.Lock(); - ASSERT (std::find(_entries.begin(), _entries.end(), &callback) == _entries.end()); - _entries.push_back(&callback); - Thread::Run(); - _adminLock.Unlock(); - } - void Unregister(Tuner& callback) { - _adminLock.Lock(); - std::list::iterator index (std::find(_entries.begin(), _entries.end(), &callback)); - if (index != _entries.end()) { - _entries.erase(index); - } - _adminLock.Unlock(); - } - - private: - uint32_t Worker() override { - Block(); - _adminLock.Lock(); - std::list::iterator index (_entries.begin()); - uint32_t result = (_entries.size() > 0 ? 100 : Core::infinite); // Slots of 100 mS; - while (index != _entries.end()) { - if ((*index)->Dispatch() == true) { - index = _entries.erase(index); - } - else { - index++; - } - } - _adminLock.Unlock(); - return (result); - } - - private: - Core::CriticalSection _adminLock; - std::list _entries; - }; - class MuxFilter : public Core::IResource { - public: - MuxFilter() = delete; - MuxFilter(const MuxFilter&) = delete; - MuxFilter& operator= (const MuxFilter&) = delete; - - MuxFilter(const string& path, const uint8_t index, const uint16_t pid, const uint8_t tableId, ISection* callback) - : _mux(-1) - , _offset(0) - , _length(0) - , _size(1024) - , _buffer(reinterpret_cast(::malloc(_size))) - , _callback(callback) { - - static constexpr TCHAR MuxSuffix[] = _T("demux"); - - char deviceName[50]; - char strIndex[4]; - - ::snprintf(strIndex, sizeof(strIndex), "%d", index); - ASSERT(sizeof(deviceName) > (path.size() + strlen(MuxSuffix) + strlen(strIndex))); - - ::snprintf(deviceName, sizeof(deviceName), "%s%s%s", path.c_str(), MuxSuffix, strIndex); - - _mux = open(deviceName, O_RDWR|O_NONBLOCK); - - if (_mux == -1) { - TRACE_L1("Could not open the filter[%s]: %d\n", deviceName, errno); - } - else { - - struct dmx_sct_filter_params sctFilterParams; - - sctFilterParams.pid = pid; - ::memset(&sctFilterParams.filter, 0, sizeof(sctFilterParams.filter)); - sctFilterParams.timeout = 0; - sctFilterParams.flags = DMX_IMMEDIATE_START|DMX_CHECK_CRC; - sctFilterParams.filter.filter[0] = tableId; - sctFilterParams.filter.mask[0] = 0xFF; - - if (ioctl(_mux, DMX_SET_FILTER, &sctFilterParams) < 0) { - TRACE_L1("Could not configue the filter[%d,%d]: %d\n", pid, tableId, errno); - ::close(_mux); - _mux = -1; - } - else { - Core::ResourceMonitor::Instance().Register(*this); - } - } - } - ~MuxFilter() { - if (_mux != -1) { - Core::ResourceMonitor::Instance().Unregister(*this); - ::close(_mux); - } - ::free(_buffer); - } - - public: - bool IsValid() const { - return (_mux != -1); - } - handle Descriptor() const override { - return (_mux); - } - uint16_t Events() override { - return (POLLPRI); - } - void Handle(const uint16_t events VARIABLE_IS_NOT_USED) override { - if (LoadHeader() == true) { - int loaded = ::read(_mux, &(_buffer[_offset]), (_length - (_offset - 3))); - if (loaded < 0) { - int result = errno; - if ((result != EAGAIN) || (result != EWOULDBLOCK)) { - _offset = 0; - } - } - else { - _offset += loaded; - if ((_offset - 3) == _length) { - MPEG::Section newSection(Core::DataElement(_offset, _buffer)); - _callback->Handle(newSection); - _offset = 0; - } - } - } - } - - private: - bool LoadHeader() - { - bool moreToLoad = true; - if (_offset < 3) { - int loaded = ::read(_mux, &(_buffer[_offset]), (3 - _offset)); - if (loaded < 0) { - int result = errno; - if ((result != EAGAIN) || (result != EWOULDBLOCK)) { - _offset = 0; - } - moreToLoad = false; - } - else { - _offset += loaded; - if (_offset != 3) { - moreToLoad = false; - } - else { - _length = (_buffer[1] << 8) | (_buffer[2] & 0xFF); - if ((_length + 3) > _size) { - uint8_t copy = _buffer[0]; - ::free (_buffer); - _size = _length + 3; - _buffer = reinterpret_cast(::malloc(_size)); - _buffer[0] = copy; - _buffer[1] = (_length >> 8) & 0xFF; - _buffer[2] = _length & 0xFF; - } - } - } - } - return (moreToLoad); - } - - - private: - int _mux; - uint16_t _offset; - uint16_t _length; - uint16_t _size; - uint8_t* _buffer; - ISection* _callback; - }; - - public: - class Information { - private: - Information(const Information&) = delete; - Information& operator=(const Information&) = delete; - - private: - class Config : public Core::JSON::Container { - private: - Config(const Config&); - Config& operator=(const Config&); - - public: - Config() - : Core::JSON::Container() - , Frontends(1) - , Decoders(1) - , Standard(ITuner::DVB) - , Annex(ITuner::A) - , Modus(ITuner::Terrestrial) - , Scan(false) - , Callsign("Streamer") - { - Add(_T("frontends"), &Frontends); - Add(_T("decoders"), &Decoders); - Add(_T("standard"), &Standard); - Add(_T("annex"), &Annex); - Add(_T("modus"), &Modus); - Add(_T("scan"), &Scan); - Add(_T("callsign"), &Callsign); - } - ~Config() - { - } - - public: - Core::JSON::DecUInt8 Frontends; - Core::JSON::DecUInt8 Decoders; - Core::JSON::EnumType Standard; - Core::JSON::EnumType Annex; - Core::JSON::EnumType Modus; - Core::JSON::Boolean Scan; - Core::JSON::String Callsign; - }; - - Information() - : _frontends(0) - , _standard() - , _annex() - , _modus() - , _type(SYS_UNDEFINED) - , _scan(false) - { - } - - public: - static Information& Instance() - { - return (_instance); - } - ~Information() - { - } - void Initialize(const string& configuration) - { - - Config config; - config.FromString(configuration); - - _frontends = config.Frontends.Value(); - _standard = config.Standard.Value(); - _annex = config.Annex.Value(); - _scan = config.Scan.Value(); - _modus = config.Modus.Value(); - - _type = Convert(_tableSystemType, _standard | _modus | _annex, SYS_UNDEFINED); - - ASSERT(_type != SYS_UNDEFINED); - - } - void Deinitialize() - { - } - - public: - inline bool IsSupported(const ITuner::modus mode) - { - return ((_type != SYS_UNDEFINED) && (mode == _modus)); - } - inline ITuner::DTVStandard Standard() const - { - return (_standard); - } - inline ITuner::annex Annex() const - { - return (_annex); - } - inline ITuner::modus Modus() const - { - return (_modus); - } - inline int Type() const - { - return (_type); - } - inline bool Scan() const - { - return (_scan); - } - - private: - uint8_t _frontends; - ITuner::DTVStandard _standard; - ITuner::annex _annex; - ITuner::modus _modus; - int _type; - bool _scan; - - static Information _instance; - }; - - private: -PUSH_WARNING(DISABLE_WARNING_MISSING_FIELD_INITIALIZERS) - Tuner(uint8_t index, Broadcast::transmission transmission = Broadcast::TRANSMISSION_AUTO, Broadcast::guard guard = Broadcast::GUARD_AUTO, Broadcast::hierarchy hierarchy = Broadcast::AutoHierarchy) - : _state(IDLE) - , _frontend() - , _transmission() - , _guard() - , _hierarchy() - , _info({ 0 }) - , _devicePath() - , _frontindex(0) - , _callback(nullptr) - { -POP_WARNING() - _callback = TunerAdministrator::Instance().Announce(this); - if (Tuner::Information::Instance().Type() != SYS_UNDEFINED) { - char deviceName[32]; - - uint16_t info = IndexToFrontend(index); - _frontindex = (info & 0xFF); - - ::snprintf(deviceName, sizeof(deviceName), "/dev/dvb/adapter%d/", (info >> 8)); - - _devicePath = deviceName; - - ::snprintf(&(deviceName[_devicePath.length()]), (sizeof(deviceName) - _devicePath.length()), "frontend%d", _frontindex); - - _frontend = open(deviceName, O_RDWR); - - if (_frontend != -1) { - if (::ioctl(_frontend, FE_GET_INFO, &_info) == -1) { - TRACE_L1("Can not get information about the frontend. Error %d.", errno); - close(_frontend); - _frontend = -1; - } - TRACE_L1("Opened frontend %s. Second Generation Support: %s", _info.name, (IsSecondGeneration() ? _T("true") : _T("false"))); - TRACE_L1("Support auto FEC: %s", (HasAutoFEC() ? _T("true") : _T("false"))); - } else { - TRACE_L1("Can not open frontend %s error: %d.", deviceName, errno); - } - - _transmission = Convert(_tableTransmission, transmission, TRANSMISSION_MODE_AUTO); - _guard = Convert(_tableGuard, guard, GUARD_INTERVAL_AUTO); - _hierarchy = Convert(_tableHierarchy, hierarchy, HIERARCHY_AUTO); - } - } - - public: - ~Tuner() - { - TunerAdministrator::Instance().Revoke(this); - - Observer::Instance().Unregister(*this); - - Detach(0); - - if (_frontend != -1) { - close(_frontend); - } - - _callback = nullptr; - } - - static ITuner* Create(const string& info) - { - Tuner* result = nullptr; - - uint8_t index = Core::NumberType(Core::TextFragment(info)).Value(); - - result = new Tuner(index); - - if ((result != nullptr) && (result->IsValid() == false)) { - delete result; - result = nullptr; - } - - return (result); - } - - public: - bool HasAutoFEC() const { - return ((_info.caps & FE_CAN_FEC_AUTO) != 0); - } - bool IsSecondGeneration() const { - return ((_info.caps & FE_CAN_2G_MODULATION) != 0); - } - bool IsValid() const - { - return (_frontend != -1); - } - const char* Name() const - { - return (_info.name); - } - - virtual uint32_t Properties() const override - { - Information& instance = Information::Instance(); - return (instance.Annex() | instance.Standard() | - #ifdef SATELITE - ITuner::modus::Satellite - #else - ITuner::modus::Terrestrial - #endif - ); - - // ITuner::modus::Cable - } - - // Currently locked on ID - // This method return a unique number that will identify the locked on Transport stream. The ID will always - // identify the uniquely locked on to Tune request. ID => 0 is reserved and means not locked on to anything. - virtual uint16_t Id() const override - { - return 0; //(_state == IDLE ? 0 : _settings.frequency / 1000000); - } - - // Using these methods the state of the tuner can be viewed. - // IDLE: Means there is no request, or the frequency requested (with other parameters) can not be locked. - // LOCKED: The stream has been locked, frequency, modulation, symbolrate and spectral inversion seem to be fine. - // PREPARED: The program that was requetsed to prepare fore, has been found in PAT/PMT, the needed information, - // like PIDS is loaded. If Priming is available, this means that the priming has started! - // STREAMING: This means that the requested program is being streamed to decoder or file, depending on implementation/inpuy. - virtual state State() const override - { - return _state; - } - - // Using the next method, the allocated Frontend will try to lock the channel that is found at the given parameters. - // Frequency is always in MHz. - virtual uint32_t Tune(const uint16_t frequency, const Modulation modulation, const uint32_t symbolRate, const uint16_t fec, const SpectralInversion inversion) override - { - uint8_t propertyCount; - struct dtv_property props[16]; - ::memset(&props, 0, sizeof(props)); - - Property(props[0], DTV_DELIVERY_SYSTEM, Tuner::Information::Instance().Type()); - Property(props[1], DTV_FREQUENCY, frequency * 1000000); - Property(props[2], DTV_MODULATION, Convert(_tableModulation, modulation, QAM_64)); - Property(props[3], DTV_INVERSION, Convert(_tableInversion, inversion, INVERSION_AUTO)); - Property(props[4], DTV_SYMBOL_RATE, symbolRate); - Property(props[5], DTV_INNER_FEC, Convert(_tableFEC, fec, FEC_AUTO)); - propertyCount = 6; - - if (Tuner::Information::Instance().Modus() == ITuner::Terrestrial){ - Property(props[6], DTV_BANDWIDTH_HZ, symbolRate); - Property(props[7], DTV_CODE_RATE_HP, Convert(_tableFEC, (fec & 0xFF), FEC_AUTO)); - Property(props[8], DTV_CODE_RATE_LP, Convert(_tableFEC, ((fec >> 8) & 0xFF), FEC_AUTO)); - Property(props[9], DTV_TRANSMISSION_MODE, _transmission); - Property(props[10], DTV_GUARD_INTERVAL, _guard); - Property(props[11], DTV_HIERARCHY, _hierarchy); - propertyCount = 12; - } - - Property(props[propertyCount++], DTV_TUNE, 0); - - struct dtv_properties dtv_prop; - dtv_prop.num = propertyCount; - dtv_prop.props = props; - - _state = IDLE; - - if (ioctl(_frontend, FE_SET_PROPERTY, &dtv_prop) < 0) { - perror("ioctl"); - } else { - #ifdef __DEBUG__ - TRACE_L1("Tuning request send out !!!"); - TRACE_L1(" Delivery: %d ", props[0].u.data); - TRACE_L1(" Frequency: %d Hz", props[1].u.data); - TRACE_L1(" Modulation: %d ", props[2].u.data); - TRACE_L1(" Inversion: %d ", props[3].u.data); - TRACE_L1(" Symbolrate: %d ", props[4].u.data); - TRACE_L1(" Inner FEC: %d ", props[5].u.data); - if (propertyCount > 6) { - TRACE_L1(" Bandwidth: %d ", props[6].u.data); - TRACE_L1(" Coderate HP: %d ", props[7].u.data); - TRACE_L1(" Coderate LP: %d ", props[8].u.data); - TRACE_L1(" Transmission: %d ", props[9].u.data); - TRACE_L1(" Guard Interval: %d ", props[10].u.data); - TRACE_L1(" Hierarchy: %d ", props[11].u.data); - } - _lastState = 0; - #endif - Observer::Instance().Register(*this); - } - - return (Core::ERROR_NONE); - } - - // In case the tuner needs to be tuned to a specific programId, please list it here. Once the PID's associated to this - // programId have been found, and set, the Tuner will reach its PREPARED state. - virtual uint32_t Prepare(const uint16_t programId VARIABLE_IS_NOT_USED) override - { - TRACE_L1("%s:%d %s", __FILE__, __LINE__, __FUNCTION__); - return 0; - } - - // A Tuner can be used to filter PSI/SI. Using the next call a callback can be installed to receive sections associated - // with a table. Each valid section received will be offered as a single section on the ISection interface for the user - // to process. - virtual uint32_t Filter(const uint16_t pid, const uint8_t tableId, ISection* callback) override - { - uint32_t result = Core::ERROR_UNAVAILABLE; - uint32_t id = (pid << 16) | tableId; - - _state.Lock(); - - if (callback != nullptr) { - auto entry = _filters.emplace( - std::piecewise_construct, - std::forward_as_tuple(id), - std::forward_as_tuple(_devicePath, _frontindex, pid, tableId, callback)); - - if (entry.first->second.IsValid() == true) { - result = Core::ERROR_NONE; - } - else { - _filters.erase(entry.first); - result = Core::ERROR_GENERAL; - } - } else { - std::map::iterator index(_filters.find(id)); - if (index != _filters.end()) { - _filters.erase(index); - result = Core::ERROR_NONE; - } - } - - _state.Unlock(); - - return (result); - } - // Using the next two methods, the frontends will be hooked up to decoders or file, and be removed from a decoder or file. - virtual uint32_t Attach(const uint8_t index VARIABLE_IS_NOT_USED) override - { - TRACE_L1("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); - return 0; - } - virtual uint32_t Detach(const uint8_t index VARIABLE_IS_NOT_USED) override - { - TRACE_L1("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); - return 0; - } - - private: - void Lock() { - _state.Lock(); - } - void Unlock() { - _state.Unlock(); - } - bool Dispatch() { - bool remove = false; - unsigned int status; - - // IDLE = 0x01, - // FE_TIMEDOUT No lock within the last about 2 seconds. - // LOCKED = 0x02, - // FE_HAS_CARRIER Has found a signal. - // FE_HAS_LOCK Digital TV were locked and everything is working. - // FE_HAS_SIGNAL Has found something above the noise level. - // FE_HAS_SYNC Synchronization bytes was found. - // FE_HAS_VITERBI FEC inner coding (Viterbi, LDPC or other inner code). is stable. - // FE_REINIT Frontend was reinitialized, application is recommended to reset DiSEqC, tone and parameters. - // PREPARED = 0x04, - // STREAMING = 0x08 - - if (::ioctl(_frontend, FE_READ_STATUS, &status) < 0) { - TRACE_L1("Status could not be read!. Error: %d", errno); - } - else { - TRACE_L1("FE_HAS_LOCK: %s", status & FE_HAS_LOCK ? _T("true") : _T("false")); - TRACE_L1("FE_TIMEDOUT: %s", status & FE_TIMEDOUT ? _T("true") : _T("false")); - - if ((status & FE_HAS_LOCK) != 0) { - remove = true; - _state = ITuner::LOCKED; - } - else if ((status & FE_TIMEDOUT) != 0) { - _state = ITuner::IDLE; - remove = true; - } - - #ifdef __DEBUG__ - if ((status & FE_HAS_LOCK) != 0) { - uint16_t snr, signal; - uint32_t ber, uncorrected_blocks; - - TRACE_L1("Signal,SNR,BER,UNC,Status: %d,%d,%d,%d,%d", signal, snr, ber, uncorrected_blocks, status); - - if (::ioctl(_frontend, FE_READ_SIGNAL_STRENGTH, &signal) < 0) { - signal = ~0; - } - if (::ioctl(_frontend, FE_READ_SNR, &snr) < 0) { - snr = ~0; - } - if (::ioctl(_frontend, FE_READ_BER, &ber) < 0) { - ber = ~0; - } - if (::ioctl(_frontend, FE_READ_UNCORRECTED_BLOCKS, &uncorrected_blocks) < 0) { - uncorrected_blocks = ~0; - } - - unsigned int delta = _lastState ^ status; - if (delta & FE_HAS_SIGNAL) { TRACE_L1 ("FE_HAS_SIGNAL: %s", status & FE_HAS_SIGNAL ? _T("true") : _T("false")); } - if (delta & FE_HAS_CARRIER) { TRACE_L1 ("FE_HAS_CARRIER: %s", status & FE_HAS_CARRIER ? _T("true") : _T("false")); } - if (delta & FE_HAS_VITERBI) { TRACE_L1 ("FE_HAS_VITERBI: %s", status & FE_HAS_VITERBI ? _T("true") : _T("false")); } - if (delta & FE_HAS_SYNC) { TRACE_L1 ("FE_HAS_SYNC: %s", status & FE_HAS_SYNC ? _T("true") : _T("false")); } - if (delta & FE_TIMEDOUT) { TRACE_L1 ("FE_TIMEDOUT: %s", status & FE_TIMEDOUT ? _T("true") : _T("false")); } - if (delta & FE_REINIT) { TRACE_L1 ("FE_REINIT: %s", status & FE_REINIT ? _T("true") : _T("false")); } - if (delta & FE_HAS_LOCK) { TRACE_L1 ("FE_HAS_LOCK: %s", status & FE_HAS_LOCK ? _T("true") : _T("false")); } - _lastState = status; - } - #endif - } - - return (remove); - } - - private: - Core::StateTrigger _state; - int _frontend; - int _transmission; - int _guard; - int _hierarchy; - struct dvb_frontend_info _info; - std::map _filters; - string _devicePath; - uint8_t _frontindex; - TunerAdministrator::ICallback* _callback; - #ifdef __DEBUG__ - unsigned int _lastState; - #endif - }; - - /* static */ Tuner::Information Tuner::Information::_instance; - - // The following methods will be called before any create is called. It allows for an initialization, - // if requires, and a deinitialization, if the Tuners will no longer be used. - /* static */ uint32_t ITuner::Initialize(const string& configuration) - { - Tuner::Information::Instance().Initialize(configuration); - - return (Core::ERROR_NONE); - } - - /* static */ uint32_t ITuner::Deinitialize() - { - Tuner::Information::Instance().Deinitialize(); - return (Core::ERROR_NONE); - } - - // See if the tuner supports the requested mode, or is configured for the requested mode. This method - // only returns proper values if the Initialize has been called before. - /* static */ bool ITuner::IsSupported(const ITuner::modus mode) - { - return (Tuner::Information::Instance().IsSupported(mode)); - } - - // Accessor to create a tuner. - /* static */ ITuner* ITuner::Create(const string& configuration) - { - return (Tuner::Create(configuration)); - } - -} // namespace Broadcast -} // namespace Thunder diff --git a/Source/broadcast/MPEGDescriptor.h b/Source/broadcast/MPEGDescriptor.h deleted file mode 100644 index f416337..0000000 --- a/Source/broadcast/MPEGDescriptor.h +++ /dev/null @@ -1,180 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#ifndef __MPEGDESCRIPTORS_H -#define __MPEGDESCRIPTORS_H - -// ---- Include system wide include files ---- - -// ---- Include local include files ---- -#include "Module.h" - -// ---- Referenced classes and types ---- - -// ---- Helper types and constants ---- - -// ---- Helper functions ---- - -// ---- Class Definition ---- - -namespace Thunder { -namespace Broadcast { - namespace MPEG { - class EXTERNAL Descriptor { - public: - inline Descriptor() - : _descriptor() - { - } - inline Descriptor(const Core::DataElement& data) - : _descriptor(data) - { - } - inline Descriptor(const Descriptor& copy) - : _descriptor(copy._descriptor) - { - } - inline ~Descriptor() {} - - inline Descriptor& operator=(const Descriptor& RHS) - { - _descriptor = RHS._descriptor; - - return (*this); - } - - public: - inline uint8_t Tag() const { return (_descriptor[0]); } - inline uint8_t Length() const { return (_descriptor[1] + 2); } - inline const uint8_t& operator[](const uint8_t index) const - { - ASSERT(index < _descriptor[1]); - return (_descriptor[2 + index]); - } - - private: - Core::DataElement _descriptor; - }; - - class EXTERNAL DescriptorIterator { - public: - inline DescriptorIterator() - : _descriptors() - , _index(NUMBER_MAX_UNSIGNED(uint32_t)) - { - } - inline DescriptorIterator(const Core::DataElement& data) - : _descriptors(data) - , _index(NUMBER_MAX_UNSIGNED(uint32_t)) - { - } - inline DescriptorIterator(const DescriptorIterator& copy) - : _descriptors(copy._descriptors) - , _index(copy._index) - { - } - inline ~DescriptorIterator() {} - - inline DescriptorIterator& operator=(const DescriptorIterator& rhs) - { - _descriptors = rhs._descriptors; - _index = rhs._index; - - return (*this); - } - - public: - inline bool IsValid() const { return (_index < _descriptors.Size()); } - inline void Reset() { _index = NUMBER_MAX_UNSIGNED(uint32_t); } - bool Next() - { - uint8_t descriptorLength; - - if (_index == NUMBER_MAX_UNSIGNED(uint32_t)) { - _index = 0; - descriptorLength = _descriptors[1] + 2; - } else if (_index < _descriptors.Size()) { - _index += (_descriptors[_index + 1] + 2); - if ((_index + 2) < _descriptors.Size()) { - descriptorLength = _descriptors[_index + 1] + 2; - } - } - - // See if we have a valid descriptor, Does it fit the block we have ? - if ((_index + descriptorLength) > _descriptors.Size()) { - // It's too big, Jump to the end.. - _index = static_cast(_descriptors.Size()); - } - - return (IsValid()); - } - inline Descriptor Current() - { - return (Descriptor(Core::DataElement(_descriptors, _index))); - } - inline const Descriptor Current() const - { - return (Descriptor(Core::DataElement(_descriptors, _index))); - } - bool Tag(const uint8_t tagId) - { - - if (_index == NUMBER_MAX_UNSIGNED(uint32_t)) { - _index = 0; - } - - while (((_index + 2) < _descriptors.Size()) && (_descriptors[_index] != tagId)) { - _index += _descriptors[1] + 2; - } - - // See if we have a valid descriptor, Does it fit the block we have ? - if (((_index + 2) >= _descriptors.Size()) || ((_descriptors[_index + 1] + 2 + _index) > _descriptors.Size())) { - // It's too big, or none was found, jump to the end.. - _index = static_cast(_descriptors.Size()); - } - - return (IsValid()); - } - uint32_t Count() const - { - uint32_t count = 0; - uint32_t offset = 0; - while (offset < _descriptors.Size()) { - count++; - offset += Descriptor(Core::DataElement(_descriptors, offset)).Length(); - } - - if (offset > _descriptors.Size()) { - // reduce the count by one, the last one is toooooooo big - count--; - } - - return (count); - } - - private: - Core::DataElement _descriptors; - uint32_t _index; - }; - - } // namespace MPEG -} // namespace Broadcast -} // namespace Thunder - -#endif //__MPEGDESCRIPTORS_H diff --git a/Source/broadcast/MPEGSection.h b/Source/broadcast/MPEGSection.h deleted file mode 100644 index ac67325..0000000 --- a/Source/broadcast/MPEGSection.h +++ /dev/null @@ -1,283 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#ifndef __MPEGSECTION_H -#define __MPEGSECTION_H - -// ---- Include system wide include files ---- - -// ---- Include local include files ---- -#include "Module.h" - -// ---- Referenced classes and types ---- - -// ---- Helper types and constants ---- - -// ---- Helper functions ---- - -// ---- Class Definition ---- - -namespace Thunder { -namespace Broadcast { - namespace MPEG { - class EXTERNAL Section { - public: - inline Section() - : _section() - { - } - inline Section(const Core::DataElement& data) - : _section(data) - { - } - inline Section(const Section& copy) - : _section(copy._section) - { - } - inline ~Section() {} - - inline Section& operator=(const Section& RHS) - { - _section = RHS._section; - - return (*this); - } - - public: - inline bool IsValid() const - { - return ((_section.Size() >= Offset()) && (_section.Size() >= Length()) && (!HasSectionSyntax() || ValidCRC())); - } - inline uint8_t TableId() const { return (_section[0]); } - inline bool HasSectionSyntax() const { return ((_section[1] & 0x80) != 0); } - inline uint16_t Length() const { return (BaseLength() + 3); } - inline uint16_t Extension() const - { - return (HasSectionSyntax() ? ((_section[3] << 8) | _section[4]) : ~0); - } - inline uint8_t Version() const - { - return (HasSectionSyntax() ? ((_section[5] & 0x3E) >> 1) : ~0); - } - inline bool IsCurrent() const - { - return (HasSectionSyntax() ? ((_section[5] & 0x01) != 0) : true); - } - inline bool IsNext() const { return (!IsCurrent()); } - inline uint8_t SectionNumber() const { return (_section[6]); } - inline uint8_t LastSectionNumber() const { return (_section[7]); } - inline uint32_t Hash() const - { - // Extension(16)/TableId(8)/Version(5)/CurNext(1)/SectionIndex(1) - return ((Extension() << 16) | (TableId() << 8) | (Version() << 3) | (IsCurrent() ? 0x04 : 0x00) | (HasSectionSyntax() ? 0x02 : 0x00)); - } - inline Core::DataElement Data() - { - return (Core::DataElement(_section, Offset(), DataLength())); - } - inline const Core::DataElement Data() const - { - return (Core::DataElement(_section, Offset(), DataLength())); - } - template - TYPE GetNumber(const uint16_t offset) const - { - return (_section.GetNumber(offset)); - } - - protected: - inline bool ValidCRC() const - { - uint32_t size = Length() - 4; - uint32_t counterCRC = GetNumber(size); - return (_section.CRC32(0, size) == counterCRC); - } - - private: - inline uint32_t Offset() const { return (HasSectionSyntax() ? 8 : 3); } - inline uint16_t BaseLength() const - { - return ((_section[1] & 0x0F) << 8) | (_section[2]); - } - inline uint16_t DataLength() const - { - return (BaseLength() - (HasSectionSyntax() ? 9 : 0)); - } - - private: - Core::DataElement _section; - }; - - class EXTERNAL Table { - private: - Table() = delete; - Table(const Table&) = delete; - Table& operator=(const Table&) = delete; - - public: - Table(const Core::ProxyType& data) - : _extension(NUMBER_MAX_UNSIGNED(uint16_t)) - , _version(NUMBER_MAX_UNSIGNED(uint8_t)) - , _lastSectionNumber(NUMBER_MAX_UNSIGNED(uint8_t)) - , _tableId(0) - , _sections() - , _data(Core::DataElement(data, 0, 0)) - { - } - ~Table() {} - - public: - inline void Storage(const Core::ProxyType& data) - { - // Drop the current table, load a new storage - _sections.clear(); - _data = Core::DataElement(data); - _lastSectionNumber = NUMBER_MAX_UNSIGNED(uint8_t); - _version = NUMBER_MAX_UNSIGNED(uint8_t); - } - inline bool IsValid() const - { - return ((_sections.size() > 0) && ((_sections.size() - 1) == _lastSectionNumber)); - } - inline uint16_t TableId() const { return (_tableId); } - inline uint16_t Extension() const { return (_extension); } - template - TYPE GetNumber(const uint16_t offset) const - { - return (_data.GetNumber(offset)); - } - inline void Clear() - { - // Drop the current table, load a new storage - _sections.clear(); - _data.Size(0); - _lastSectionNumber = NUMBER_MAX_UNSIGNED(uint8_t); - _version = NUMBER_MAX_UNSIGNED(uint8_t); - } - inline Core::DataElement& Data() { return (_data); } - inline const Core::DataElement& Data() const { return (_data); } - inline bool AddSection(const Section& section) - { - bool addSection = section.IsValid(); - - if (addSection == true) { - if (_sections.size() != 0) { - // Starting something for TableId A and then continue with other - // TableId's Seems to me like a programming error. - if (_tableId != section.TableId()) { - TRACE_L1("Will not add a section, destined for: %d in table: %d", section.TableId(), _tableId); - } - - addSection = (_tableId == section.TableId()); - - if ((addSection == true) && (section.Version() != _version)) { - // Give back all the elemts we do not use.. - _sections.clear(); - _data.Size(0); - _lastSectionNumber = section.LastSectionNumber(); - _version = section.Version(); - - if (_extension != section.Extension()) { - printf("%s, %d -> Interesting the extensions differ\n", - __FUNCTION__, __LINE__); - } - } - } else { - _tableId = section.TableId(); - _data.Size(0); - _lastSectionNumber = section.LastSectionNumber(); - _version = section.Version(); - _extension = section.Extension(); - } - - if (addSection == true) { - uint32_t offset = 0; - uint32_t slotValue = (section.SectionNumber() << 16) | section.Length(); - - std::list::iterator index(_sections.begin()); - - while (index != _sections.end()) { - uint16_t thisLength(*index & 0xFFFF); - uint8_t thisSection((*index >> 16) & 0xFF); - - if (section.SectionNumber() == thisSection) { - // Replace it.. - Insert(section.Data(), thisLength, offset); - *index = slotValue; - break; - } else if (section.SectionNumber() < thisSection) { - // We need to extend the last part - Insert(section.Data(), 0, offset); - index = _sections.insert(index, slotValue); - break; - } - offset += thisLength; - } - - if (index == _sections.end()) { - ASSERT(offset == _data.Size()); - - Insert(section.Data(), 0, offset); - _sections.push_back(slotValue); - } - } - } - - return (addSection); - } - - private: - void Insert(const Core::DataElement& data, const uint16_t allocatedLength, - const uint16_t offset) - { - if (offset < _data.Size()) { - // We need to scrink or extend space... - int32_t needed = (data.Size() - allocatedLength); - uint32_t moveSize = (_data.Size() - offset - allocatedLength); - if (needed > 0) { - // Time to extend - _data.Size(_data.Size() + needed); - ::memmove(&(_data[offset + data.Size()]), - &(_data[offset + allocatedLength]), moveSize); - } else if (needed < 0) { - // time to schrink - ::memmove(&(_data[offset + data.Size()]), - &(_data[offset + allocatedLength]), moveSize); - _data.Size(_data.Size() + needed); - } - } else { - _data.Size(_data.Size() + data.Size()); - } - ::memcpy(&(_data[offset]), data.Buffer(), data.Size()); - } - - private: - uint16_t _extension; - uint8_t _version; - uint8_t _lastSectionNumber; - uint8_t _tableId; - std::list _sections; - Core::DataElement _data; - }; - - } // namespace MPEG -} // namespace Broadcast -} // namespace Thunder - -#endif // __MPEGSECTION_H diff --git a/Source/broadcast/MPEGTable.h b/Source/broadcast/MPEGTable.h deleted file mode 100644 index 9bc233d..0000000 --- a/Source/broadcast/MPEGTable.h +++ /dev/null @@ -1,281 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#ifndef __MPEGTABLE_H -#define __MPEGTABLE_H - -// ---- Include system wide include files ---- - -// ---- Include local include files ---- -#include "MPEGDescriptor.h" -#include "MPEGSection.h" -#include "Module.h" - -// ---- Referenced classes and types ---- - -// ---- Helper types and constants ---- - -// ---- Helper functions ---- - -// ---- Class Definition ---- - -namespace Thunder { -namespace Broadcast { - namespace MPEG { - class EXTERNAL PAT { - private: - PAT(const PAT&) = delete; - PAT& operator=(const PAT&) = delete; - - public: - static const uint8_t ID = 0x00; - - public: - class ProgramIterator { - public: - ProgramIterator() - : _index(~0) - , _programs(0) - , _info() - { - } - ProgramIterator(const Core::DataElement& sections) - : _index(~0) - , _programs(sections.Size() / 4) - , _info(sections) - { - } - ProgramIterator(const ProgramIterator& copy) - : _index(copy._index) - , _programs(copy._programs) - , _info(copy._info) - { - } - ~ProgramIterator() {} - - ProgramIterator& operator=(const ProgramIterator& RHS) - { - _info = RHS._info; - _index = RHS._index; - _programs = RHS._programs; - - return (*this); - } - - public: - inline bool IsValid() const { return (_index < _programs); } - inline void Reset() { _index = ~0; } - bool Next() - { - if (_index < _programs) { - _index++; - } else if (_index == static_cast(~0)) { - _index = 0; - } - - return (IsValid()); - } - inline uint16_t ProgramNumber() const - { - return (_info.GetNumber(_index * 4)); - } - inline uint16_t Pid() const - { - return (_info.GetNumber((_index * 4) + 2) & 0x1FFF); - } - uint16_t Count() const { return (_programs); } - - private: - uint32_t _index; - uint32_t _programs; - Core::DataElement _info; - }; - - public: - PAT() - : _data() - , _transportId(~0) - { - } - PAT(const Table& data) - : _data(data.Data()) - , _transportId(data.Extension()) - { - } - ~PAT() {} - - public: - inline uint16_t TransportStreamId() const { return (_transportId); } - inline ProgramIterator Programs() const { return (ProgramIterator(_data)); } - - private: - Core::DataElement _data; - uint16_t _transportId; - }; - - class EXTERNAL PMT { - public: - static const uint16_t ID = 0x02; - - public: - class StreamIterator { - public: - StreamIterator() - : _info() - , _offset(~0) - { - } - StreamIterator(const Core::DataElement& data) - : _info(data) - , _offset(~0) - { - } - StreamIterator(const StreamIterator& copy) - : _info(copy._info) - , _offset(copy._offset) - { - } - ~StreamIterator() {} - - StreamIterator& operator=(const StreamIterator& RHS) - { - _info = RHS._info; - _offset = RHS._offset; - - return (*this); - } - - public: - inline bool IsValid() const { return (_offset < _info.Size()); } - inline void Reset() { _offset = ~0; } - inline bool Next() - { - if (_offset == static_cast(~0)) { - _offset = 0; - } else if (_offset < _info.Size()) { - _offset += (DescriptorSize() + 5); - } - - return (IsValid()); - } - inline uint8_t StreamType() const { return (_info[_offset]); } - inline uint16_t Pid() const - { - return (((_info[_offset + 1] << 8) | _info[_offset + 2]) & 0x1FFF); - } - inline MPEG::DescriptorIterator Descriptors() const - { - return (MPEG::DescriptorIterator( - Core::DataElement(_info, _offset + 5, DescriptorSize()))); - } - inline uint8_t Streams() const - { - uint8_t count = 0; - uint16_t offset = 0; - while (offset < _info.Size()) { - offset += (((_info[offset + 3] << 8) | _info[offset + 4]) & 0x03FF) + 5; - count++; - } - return (count); - } - - private: - inline uint16_t DescriptorSize() const - { - return ((_info[_offset + 3] << 8) | _info[_offset + 4]) & 0x03FF; - } - - private: - Core::DataElement _info; - uint16_t _offset; - }; - - public: - PMT() - : _data() - , _programNumber(~0) - { - } - PMT(const Table& data) - : _data(data.Data()) - , _programNumber(data.Extension()) - { - } - PMT(const uint16_t programId, const Core::DataElement& data) - : _data(data) - , _programNumber(programId) - { - } - PMT(const PMT& copy) - : _data(copy._data) - , _programNumber(copy._programNumber) - { - } - ~PMT() {} - - PMT& operator=(const PMT& rhs) - { - _data = rhs._data; - _programNumber = rhs._programNumber; - return (*this); - } - bool operator==(const PMT& rhs) const - { - return ((_programNumber == rhs._programNumber) && (_data == rhs._data)); - } - bool operator!=(const PMT& rhs) const { return (!operator==(rhs)); } - - public: - inline bool IsValid() const - { - return ((_programNumber != static_cast(~0)) && (_data.Size() >= 2)); - } - inline uint16_t ProgramNumber() const { return (_programNumber); } - uint16_t PCRPid() const - { - return (_data.GetNumber(0) & 0x1FFF); - } - MPEG::DescriptorIterator Descriptors() const - { - uint16_t size(DescriptorSize()); - return (MPEG::DescriptorIterator(Core::DataElement(_data, 4, size))); - } - StreamIterator Streams() const - { - uint16_t offset(DescriptorSize() + 4); - return (StreamIterator( - Core::DataElement(_data, offset, _data.Size() - offset))); - } - - private: - inline uint16_t DescriptorSize() const - { - return (_data.GetNumber(2) & 0x03FF); - } - - private: - Core::DataElement _data; - uint16_t _programNumber; - }; - - } // namespace MPEG -} // namespace Broadcast -} // namespace Thunder - -#endif // __MPEGTABLE_ diff --git a/Source/broadcast/Module.cpp b/Source/broadcast/Module.cpp deleted file mode 100644 index 393d6a2..0000000 --- a/Source/broadcast/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) diff --git a/Source/broadcast/Module.h b/Source/broadcast/Module.h deleted file mode 100644 index 1fc2eac..0000000 --- a/Source/broadcast/Module.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#pragma once - -#ifndef MODULE_NAME -#define MODULE_NAME Broadcast -#endif - -#include - -#if defined(__WINDOWS__) && defined(BROADCAST_EXPORTS) -#undef EXTERNAL -#define EXTERNAL EXTERNAL_EXPORT -#endif - diff --git a/Source/broadcast/NIT.h b/Source/broadcast/NIT.h deleted file mode 100644 index 5a51d5a..0000000 --- a/Source/broadcast/NIT.h +++ /dev/null @@ -1,192 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#ifndef DVB_NIT_TABLE_H -#define DVB_NIT_TABLE_H - -// ---- Include system wide include files ---- - -// ---- Include local include files ---- -#include "MPEGDescriptor.h" -#include "MPEGSection.h" -#include "Module.h" - -// ---- Referenced classes and types ---- - -// ---- Helper types and constants ---- - -// ---- Helper functions ---- - -// ---- Class Definition ---- - -namespace Thunder { -namespace Broadcast { - namespace DVB { - - class EXTERNAL NIT { - public: - static const uint16_t ACTUAL = 0x40; - static const uint16_t OTHER = 0x41; - - public: - class NetworkIterator { - public: - NetworkIterator() - : _info() - , _offset(~0) - { - } - NetworkIterator(const Core::DataElement& data) - : _info(data) - , _offset(~0) - { - } - NetworkIterator(const NetworkIterator& copy) - : _info(copy._info) - , _offset(copy._offset) - { - } - ~NetworkIterator() {} - - NetworkIterator& operator=(const NetworkIterator& RHS) - { - _info = RHS._info; - _offset = RHS._offset; - - return (*this); - } - - public: - inline bool IsValid() const { return (_offset < _info.Size()); } - inline void Reset() { _offset = ~0; } - inline bool Next() - { - if (_offset == static_cast(~0)) { - _offset = 0; - } else if (_offset < _info.Size()) { - _offset += (DescriptorSize() + 6); - } - - return (IsValid()); - } - inline uint16_t TransportStreamId() const - { - return ((_info[_offset + 0] << 8) | _info[_offset + 1]); - } - inline uint16_t OriginalNetworkId() const - { - return ((_info[_offset + 2] << 8) | _info[_offset + 3]); - } - inline MPEG::DescriptorIterator Descriptors() const - { - return (MPEG::DescriptorIterator( - Core::DataElement(_info, _offset + 6, DescriptorSize()))); - } - inline uint8_t Networks() const - { - uint8_t count = 0; - uint16_t offset = 0; - while (offset < _info.Size()) { - offset += (((_info[offset + 4] << 8) | _info[offset + 5]) & 0x0FFF) + 6; - count++; - } - return (count); - } - - private: - inline uint16_t DescriptorSize() const - { - return ((_info[_offset + 4] << 8) | _info[_offset + 5]) & 0x0FFF; - } - - private: - Core::DataElement _info; - uint16_t _offset; - }; - - public: - NIT() - : _data() - , _networkId(~0) - { - } - NIT(const MPEG::Table& data) - : _data(data.Data()) - , _networkId(data.Extension()) - { - } - NIT(const uint16_t networkId, const Core::DataElement& data) - : _data(data) - , _networkId(networkId) - { - } - NIT(const NIT& copy) - : _data(copy._data) - , _networkId(copy._networkId) - { - } - ~NIT() {} - - NIT& operator=(const NIT& rhs) - { - _data = rhs._data; - _networkId = rhs._networkId; - return (*this); - } - bool operator==(const NIT& rhs) const - { - return ((_networkId == rhs._networkId) && (_data == rhs._data)); - } - bool operator!=(const NIT& rhs) const { return (!operator==(rhs)); } - - public: - inline bool IsValid() const - { - return ((_networkId != static_cast(~0)) && (_data.Size() >= 2)); - } - inline uint16_t NetworkId() const { return (_networkId); } - MPEG::DescriptorIterator Descriptors() const - { - uint16_t size(DescriptorSize()); - return (MPEG::DescriptorIterator(Core::DataElement(_data, 4, size))); - } - NetworkIterator Networks() const - { - uint16_t offset = DescriptorSize() + 2; - uint16_t size = (_data.GetNumber(offset) & 0x0FFF); - ASSERT(size == (_data.Size() - offset - 2)); - return (NetworkIterator(Core::DataElement(_data, offset + 2, size))); - } - - private: - inline uint16_t DescriptorSize() const - { - return (_data.GetNumber(2) & 0x0FFF); - } - - private: - Core::DataElement _data; - uint16_t _networkId; - }; - - } // namespace DVB -} // namespace Broadcast -} // namespace Thunder - -#endif // DVB_NIT_TABLE_H diff --git a/Source/broadcast/Networks.h b/Source/broadcast/Networks.h deleted file mode 100644 index a49f819..0000000 --- a/Source/broadcast/Networks.h +++ /dev/null @@ -1,366 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#ifndef NETWORKS_ADMINISTRATOR_H -#define NETWORKS_ADMINISTRATOR_H - -#include "Definitions.h" -#include "Descriptors.h" -#include "NIT.h" -#include "ProgramTable.h" - -namespace Thunder { - -namespace Broadcast { - - class Networks { - private: - Networks(const Networks&) = delete; - Networks& operator=(const Networks&) = delete; - - class Sink : public ITuner::INotification { - private: - Sink() = delete; - Sink(const Sink&) = delete; - Sink& operator=(const Sink&) = delete; - - public: - Sink(Networks& parent) - : _parent(parent) - { - } - virtual ~Sink() - { - } - - public: - virtual void Activated(ITuner* /* tuner */) override - { - } - virtual void Deactivated(ITuner* tuner) override - { - _parent.Deactivated(tuner); - } - virtual void StateChange(ITuner* tuner) override - { - _parent.StateChange(tuner); - } - - private: - Networks& _parent; - }; - - class Parser : public ISection { - private: - Parser() = delete; - Parser(const Parser&) = delete; - Parser& operator=(const Parser&) = delete; - - public: - Parser(Networks& parent, ITuner* source, const bool scan, const uint16_t pid) - : _parent(parent) - , _source(source) - , _actual(Core::ProxyType::Create(512)) - , _others(Core::ProxyType::Create(512)) - , _pid(pid) - { - if (scan == true) { - Scan(true); - } - } - virtual ~Parser() - { - Scan(false); - } - inline bool operator==(const ITuner* rhs) const - { - return (_source == rhs); - } - inline bool operator!=(const ITuner* rhs) const - { - return (!operator==(rhs)); - } - - public: - void Scan(const bool scan) - { - if (scan == true) { - // Start loading the SDT info - _source->Filter(_pid, DVB::NIT::ACTUAL, this); - _source->Filter(_pid, DVB::NIT::OTHER, this); - } else { - _source->Filter(_pid, DVB::NIT::OTHER, nullptr); - _source->Filter(_pid, DVB::NIT::ACTUAL, nullptr); - } - } - - private: - virtual void Handle(const MPEG::Section& section) override - { - - ASSERT(section.IsValid()); - - if (section.TableId() == DVB::NIT::ACTUAL) { - _actual.AddSection(section); - if (_actual.IsValid() == true) { - _parent.Load(DVB::NIT(_actual)); - } - } else if (section.TableId() == DVB::NIT::OTHER) { - _others.AddSection(section); - if (_others.IsValid() == true) { - _parent.Load(DVB::NIT(_others)); - } - } - } - - private: - Networks& _parent; - ITuner* _source; - MPEG::Table _actual; - MPEG::Table _others; - uint16_t _pid; - }; - - typedef std::list Scanners; - - public: - class Network { - public: - Network() - : _originalNetworkId(~0) - , _transportStreamId(~0) - , _frequency(0) - , _modulation(0) - , _symbolRate(0) - , _name() - { - } - Network(const DVB::NIT::NetworkIterator& info) - : _originalNetworkId(info.OriginalNetworkId()) - , _transportStreamId(info.TransportStreamId()) - , _frequency(0) - , _modulation(0) - , _symbolRate(0) - , _name() - { - MPEG::DescriptorIterator index(info.Descriptors()); - - if (index.Tag(DVB::Descriptors::NetworkName::TAG) == true) { - DVB::Descriptors::NetworkName data(index.Current()); - _name = data.Name(); - } - - // Start searching from the beginning again ! - index.Reset(); - - if (index.Tag(DVB::Descriptors::SatelliteDeliverySystem::TAG) == true) { - DVB::Descriptors::SatelliteDeliverySystem data(index.Current()); - _frequency = data.Frequency(); - _symbolRate = data.SymbolRate(); - _modulation = data.Modulation(); - } else { - // Start searching from the beginning again ! - index.Reset(); - - if (index.Tag(DVB::Descriptors::CableDeliverySystem::TAG) == true) { - DVB::Descriptors::CableDeliverySystem data(index.Current()); - _frequency = data.Frequency(); - _symbolRate = data.SymbolRate(); - _modulation = data.Modulation(); - } - } - } - Network(const Network& copy) - : _originalNetworkId(copy._originalNetworkId) - , _transportStreamId(copy._transportStreamId) - , _frequency(copy._frequency) - , _modulation(copy._modulation) - , _symbolRate(copy._symbolRate) - , _name(copy._name) - { - } - ~Network() - { - } - - Network& operator=(const Network& rhs) - { - _originalNetworkId = rhs._originalNetworkId; - _transportStreamId = rhs._transportStreamId; - _frequency = rhs._frequency; - _modulation = rhs._modulation; - _symbolRate = rhs._symbolRate; - _name = rhs._name; - - return (*this); - } - - public: - bool IsValid() const - { - return (_frequency != 0); - } - inline uint16_t OriginalNetworkId() const - { - return (_originalNetworkId); - } - inline uint16_t TransportStreamId() const - { - return (_transportStreamId); - } - inline uint16_t Frequency() const - { - return (_frequency); - } - inline uint16_t Modulation() const - { - return (_modulation); - } - inline uint16_t SymbolRate() const - { - return (_symbolRate); - } - - private: - uint16_t _originalNetworkId; - uint16_t _transportStreamId; - uint16_t _frequency; - uint16_t _modulation; - uint16_t _symbolRate; - string _name; - }; - - typedef IteratorType Iterator; - - private: - typedef std::map NetworkMap; - - public: - Networks() - : _adminLock() - , _scanners() - , _sink(*this) - , _scan(true) - , _networks() - { - ITuner::Register(&_sink); - } - virtual ~Networks() - { - ITuner::Unregister(&_sink); - } - - public: - void Scan(const bool scan) - { - _adminLock.Lock(); - - if (_scan != scan) { - _scan = scan; - Scanners::iterator index(_scanners.begin()); - while (index != _scanners.end()) { - index->Scan(_scan); - index++; - } - } - _adminLock.Unlock(); - } - Network Id(const uint16_t id) const - { - Network result; - - _adminLock.Lock(); - NetworkMap::const_iterator index(_networks.find(id)); - if (index != _networks.end()) { - result = index->second; - } - _adminLock.Unlock(); - - return (result); - } - Iterator List() const - { - - _adminLock.Lock(); - Iterator value(_networks); - _adminLock.Unlock(); - - return (value); - } - - private: - void Deactivated(ITuner* tuner) - { - _adminLock.Lock(); - - Scanners::iterator index = std::find(_scanners.begin(), _scanners.end(), tuner); - - if (index != _scanners.end()) { - _scanners.erase(index); - } - - _adminLock.Unlock(); - } - void StateChange(ITuner* tuner) - { - - _adminLock.Lock(); - - Scanners::iterator index = std::find(_scanners.begin(), _scanners.end(), tuner); - - if (index != _scanners.end()) { - if (tuner->State() == ITuner::IDLE) { - _scanners.erase(index); - } - } else { - if (tuner->State() != ITuner::IDLE) { - uint16_t pid = ProgramTable::Instance().NITPid(tuner->Id()); - if (pid != static_cast(~0)) { - _scanners.emplace_back(*this, tuner, _scan, pid); - } - } - } - - _adminLock.Unlock(); - } - void Load(const DVB::NIT& table) - { - _adminLock.Lock(); - - DVB::NIT::NetworkIterator index = table.Networks(); - - while (index.Next() == true) { - _networks[index.TransportStreamId()] = Network(index); - } - - _adminLock.Unlock(); - } - - private: - mutable Core::CriticalSection _adminLock; - Scanners _scanners; - Sink _sink; - bool _scan; - NetworkMap _networks; - }; - -} // namespace Broadcast -} // namespace Thunder - -#endif // NETWORKS_ADMINISTRATOR_H diff --git a/Source/broadcast/ProgramTable.cpp b/Source/broadcast/ProgramTable.cpp deleted file mode 100644 index bf9b423..0000000 --- a/Source/broadcast/ProgramTable.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#include "ProgramTable.h" - -namespace Thunder { - -namespace Broadcast { - - /* static */ Core::ProxyPoolType ProgramTable::_storeFactory(2); - - /* static */ ProgramTable& ProgramTable::Instance() - { - static ProgramTable _instance; - return (_instance); - } - - /* virtual */ void - ProgramTable::Observer::Handle(const MPEG::Section& section) - { - bool completedStep = false; - - if (section.IsValid() == true) { - if (section.TableId() == MPEG::PAT::ID) { - _table.AddSection(section); - - if (_table.IsValid() == true) { - // Iterator over this table and find all program Pids - MPEG::PAT patTable(_table); - MPEG::PAT::ProgramIterator index(patTable.Programs()); - while (index.Next() == true) { - - if (index.ProgramNumber() == 0) { - // ProgramNumber == 0 is reserved for the NIT pid - _parent._nitPids[_keyId] = index.Pid(); - } else { - _entries.push_back(index.Pid() | (index.ProgramNumber() << 16)); - TRACE_L1("ProgramNumber: %d on PID: %d", index.ProgramNumber(), index.Pid()); - } - } - completedStep = true; - } - } else if (section.TableId() == MPEG::PMT::ID) { - _table.AddSection(section); - - if (_table.IsValid() == true) { - - completedStep = true; - - uint32_t key = static_cast(_entries.front() & 0xFFFF) | (_table.Extension() << 16); - - ScanMap::iterator index(_entries.begin()); - - while (index != _entries.end()) { - if (*index == key) { - index = _entries.erase(index); - } else { - completedStep = completedStep && ((*index & 0xFFFF) != (key & 0xFFFF)); - index++; - } - } - - if (_parent.AddProgram(_keyId, _table) == true) { - // do not forget to get a new storage space, the previous one is now - // with the AddProgram !!! - _table.Storage(_storeFactory.Element()); - - TRACE_L1("PMT for %d loaded. PID load for PMTs completed: %s", _table.Extension(), completedStep ? _T("true") : _T("false")); - } - } - } - - if (completedStep == true) { - _table.Clear(); - if (_entries.size() > 0) { - _callback->ChangePid(static_cast(_entries.front() & 0xFFFF), - this); - } else { - _callback->ChangePid(0xFFFF, this); - } - } - } - } - -} // namespace Broadcast -} // namespace Thunder diff --git a/Source/broadcast/ProgramTable.h b/Source/broadcast/ProgramTable.h deleted file mode 100644 index f042d1d..0000000 --- a/Source/broadcast/ProgramTable.h +++ /dev/null @@ -1,180 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#ifndef PROGRAMTABLE_H -#define PROGRAMTABLE_H - -#include "Definitions.h" -#include "MPEGTable.h" - -namespace Thunder { - -namespace Broadcast { - - class ProgramTable { - private: - ProgramTable() - : _adminLock() - , _observers() - , _programs() - { - } - ProgramTable(const ProgramTable&) = delete; - ProgramTable& operator=(const ProgramTable&) = delete; - - static Core::ProxyPoolType _storeFactory; - - class Observer : public ISection { - private: - Observer() = delete; - Observer(const Observer&) = delete; - Observer& operator=(const Observer&) = delete; - - typedef std::list ScanMap; - - public: - Observer(ProgramTable* parent, const uint16_t keyId, IMonitor* callback) - : _parent(*parent) - , _callback(callback) - , _keyId(keyId) - , _table(_storeFactory.Element()) - , _entries() - { - } - virtual ~Observer() {} - - public: - virtual void Handle(const MPEG::Section& section) override; - - private: - ProgramTable& _parent; - IMonitor* _callback; - uint16_t _keyId; - MPEG::Table _table; - ScanMap _entries; - }; - - typedef std::map Programs; - typedef std::map Observers; - typedef std::map NITPids; - - public: - static ProgramTable& Instance(); - virtual ~ProgramTable() {} - - public: - inline void Reset() { _programs.clear(); } - ISection* Register(IMonitor* callback, const uint16_t keyId) - { - _adminLock.Lock(); - - ASSERT(_observers.find(callback) == _observers.end()); - - auto index = _observers.emplace( - std::piecewise_construct, std::forward_as_tuple(callback), - std::forward_as_tuple(this, keyId, callback)); - - _adminLock.Unlock(); - - return &(index.first->second); - } - void Unregister(IMonitor* callback) - { - - _adminLock.Lock(); - - Observers::iterator index(_observers.find(callback)); - - if (index != _observers.end()) { - _observers.erase(index); - } - - _adminLock.Unlock(); - } - inline bool Program(const uint16_t keyId, const uint16_t programId, MPEG::PMT& pmt) const - { - bool updated = false; - - _adminLock.Lock(); - - Programs::const_iterator index(_programs.find(Key(keyId, programId))); - if (index != _programs.end()) { - updated = (index->second != pmt); - pmt = index->second; - } - - _adminLock.Unlock(); - - return (updated); - } - uint16_t NITPid(const uint16_t keyId) const - { - uint16_t result(~0); - - NITPids::const_iterator index(_nitPids.find(keyId)); - - if (index != _nitPids.end()) { - result = index->second; - } - - return (result); - } - - private: - inline uint32_t Key(const uint16_t keyId, const uint16_t programId) const - { - uint64_t result = keyId; - return ((result << 16) | programId); - } - bool AddProgram(const uint16_t keyId, const MPEG::Table& data) - { - bool added = false; - uint64_t key(Key(keyId, data.Extension())); - - _adminLock.Lock(); - - Programs::iterator index(_programs.find(key)); - if (index != _programs.end()) { - MPEG::PMT entry(data); - if (index->second != entry) { - added = true; - index->second = entry; - } - } else { - _programs.emplace(std::piecewise_construct, std::forward_as_tuple(key), - std::forward_as_tuple(data.Extension(), data.Data())); - added = true; - } - - _adminLock.Unlock(); - - return (added); - } - - private: - mutable Core::CriticalSection _adminLock; - Observers _observers; - Programs _programs; - NITPids _nitPids; - }; - -} // namespace Broadcast -} // namespace Thunder - -#endif diff --git a/Source/broadcast/SDT.h b/Source/broadcast/SDT.h deleted file mode 100644 index 2a1a650..0000000 --- a/Source/broadcast/SDT.h +++ /dev/null @@ -1,203 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#ifndef DVB_SDT_TABLE_H -#define DVB_SDT_TABLE_H - -// ---- Include system wide include files ---- - -// ---- Include local include files ---- -#include "MPEGDescriptor.h" -#include "MPEGSection.h" -#include "Module.h" - -// ---- Referenced classes and types ---- - -// ---- Helper types and constants ---- - -// ---- Helper functions ---- - -// ---- Class Definition ---- - -namespace Thunder { -namespace Broadcast { - namespace DVB { - - class EXTERNAL SDT { - public: - static const uint16_t ACTUAL = 0x42; - static const uint16_t OTHER = 0x46; - - public: - enum running { - Undefined = 0, - NotRunning = 1, - AboutToStart = 2, - Pausing = 3, - Running = 4 - }; - - public: - class ServiceIterator { - public: - ServiceIterator() - : _info() - , _offset(~0) - { - } - ServiceIterator(const Core::DataElement& data) - : _info(data) - , _offset(~0) - { - } - ServiceIterator(const ServiceIterator& copy) - : _info(copy._info) - , _offset(copy._offset) - { - } - ~ServiceIterator() {} - - ServiceIterator& operator=(const ServiceIterator& RHS) - { - _info = RHS._info; - _offset = RHS._offset; - - return (*this); - } - - public: - inline bool IsValid() const { return (_offset < _info.Size()); } - inline void Reset() { _offset = ~0; } - inline bool Next() - { - if (_offset == static_cast(~0)) { - _offset = 0; - } else if (_offset < _info.Size()) { - _offset += (DescriptorSize() + 5); - } - - return (IsValid()); - } - inline bool EIT_PF() const - { - return ((_info[_offset + 2] & 0x01) != 0); - } - inline bool EIT_Schedule() const - { - return ((_info[_offset + 2] & 0x02) != 0); - } - inline bool IsFreeToAir() const - { - return ((_info[_offset + 3] & 0x10) != 0); - } - inline running RunningMode() const - { - return (static_cast((_info[_offset + 3] & 0xE0) >> 5)); - } - inline uint16_t ServiceId() const - { - return ((_info[_offset + 0] << 8) | _info[_offset + 1]); - } - inline MPEG::DescriptorIterator Descriptors() const - { - return (MPEG::DescriptorIterator( - Core::DataElement(_info, _offset + 5, DescriptorSize()))); - } - inline uint8_t Services() const - { - uint8_t count = 0; - uint16_t offset = 0; - while (offset < _info.Size()) { - offset += (((_info[offset + 3] << 8) | _info[offset + 4]) & 0x0FFF) + 5; - count++; - } - return (count); - } - - private: - inline uint16_t DescriptorSize() const - { - return ((_info[_offset + 3] << 8) | _info[_offset + 4]) & 0x0FFF; - } - - private: - Core::DataElement _info; - uint16_t _offset; - }; - - public: - SDT() - : _data() - , _transportStreamId(~0) - { - } - SDT(const MPEG::Table& data) - : _data(data.Data()) - , _transportStreamId(data.Extension()) - { - } - SDT(const uint16_t transportStreamId, const Core::DataElement& data) - : _data(data) - , _transportStreamId(transportStreamId) - { - } - SDT(const SDT& copy) - : _data(copy._data) - , _transportStreamId(copy._transportStreamId) - { - } - ~SDT() {} - - SDT& operator=(const SDT& rhs) - { - _data = rhs._data; - _transportStreamId = rhs._transportStreamId; - return (*this); - } - bool operator==(const SDT& rhs) const - { - return ((_transportStreamId == rhs._transportStreamId) && (_data == rhs._data)); - } - bool operator!=(const SDT& rhs) const { return (!operator==(rhs)); } - - public: - inline bool IsValid() const - { - return ((_transportStreamId != static_cast(~0)) && (_data.Size() >= 2)); - } - inline uint16_t TransportStreamId() const { return (_transportStreamId); } - uint16_t OriginalNetworkId() const - { - return (_data.GetNumber(0) & 0x1FFF); - } - ServiceIterator Services() const - { - return (ServiceIterator(Core::DataElement(_data, 3, _data.Size() - 3))); - } - - private: - Core::DataElement _data; - uint16_t _transportStreamId; - }; - - } // namespace DVB -} // namespace Broadcast -} // namespace Thunder - -#endif // DVB_SDT_TABLE_H diff --git a/Source/broadcast/Schedule.h b/Source/broadcast/Schedule.h deleted file mode 100644 index 935805f..0000000 --- a/Source/broadcast/Schedule.h +++ /dev/null @@ -1,218 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#ifndef SCHEDULE_ADMINISTRATOR_H -#define SCHEDULE_ADMINISTRATOR_H - -#include "Definitions.h" -#include "Descriptors.h" -#include "EIT.h" - -namespace Thunder { - -namespace Broadcast { - - class Schedules { - private: - Schedules(const Schedules&) = delete; - Schedules& operator=(const Schedules&) = delete; - - class Sink : public ITuner::INotification { - private: - Sink() = delete; - Sink(const Sink&) = delete; - Sink& operator=(const Sink&) = delete; - - public: - Sink(Schedules& parent) - : _parent(parent) - { - } - virtual ~Sink() - { - } - - public: - virtual void Activated(ITuner* tuner) override - { - } - virtual void Deactivated(ITuner* tuner) override - { - _parent.Deactivated(tuner); - } - virtual void StateChange(ITuner* tuner) override - { - _parent.StateChange(tuner); - } - - private: - Schedules& _parent; - }; - - class Parser : public ISection { - private: - Parser() = delete; - Parser(const Parser&) = delete; - Parser& operator=(const Parser&) = delete; - - public: - Parser(Schedules& parent, ITuner* source, const bool scan) - : _parent(parent) - , _source(source) - , _actual(Core::ProxyType::Create(512)) - , _others(Core::ProxyType::Create(512)) - { - if (scan == true) { - Scan(true); - } - } - virtual ~Parser() - { - Scan(false); - } - inline bool operator==(const ITuner* rhs) const - { - return (_source == rhs); - } - inline bool operator!=(const ITuner* rhs) const - { - return (!operator==(rhs)); - } - - public: - void Scan(const bool scan) - { - if (scan == true) { - // Start loading the SDT info - _source->Filter(0x11, DVB::EIT::ACTUAL, this); - _source->Filter(0x11, DVB::EIT::OTHER, this); - } else { - _source->Filter(0x11, DVB::EIT::OTHER, nullptr); - _source->Filter(0x11, DVB::EIT::ACTUAL, nullptr); - } - } - - private: - virtual void Handle(const MPEG::Section& section) override - { - - ASSERT(section.IsValid()); - - if (section.TableId() == DVB::EIT::ACTUAL) { - _actual.AddSection(section); - if (_actual.IsValid() == true) { - _parent.Load(DVB::EIT(_actual)); - } - } else if (section.TableId() == DVB::EIT::OTHER) { - _others.AddSection(section); - if (_others.IsValid() == true) { - _parent.Load(DVB::EIT(_others)); - } - } - } - - private: - Schedules& _parent; - ITuner* _source; - MPEG::Table _actual; - MPEG::Table _others; - }; - - typedef std::list Scanners; - - public: - Schedules() - : _adminLock() - , _scanners() - , _sink(*this) - , _scan(true) - { - ITuner::Register(&_sink); - } - virtual ~Schedules() - { - ITuner::Unregister(&_sink); - } - - public: - void Scan(const bool scan) - { - _adminLock.Lock(); - - if (_scan != scan) { - _scan = scan; - Scanners::iterator index(_scanners.begin()); - while (index != _scanners.end()) { - index->Scan(_scan); - index++; - } - } - _adminLock.Unlock(); - } - - private: - void Deactivated(ITuner* tuner) - { - _adminLock.Lock(); - - Scanners::iterator index = std::find(_scanners.begin(), _scanners.end(), tuner); - - if (index != _scanners.end()) { - _scanners.erase(index); - } - - _adminLock.Unlock(); - } - void StateChange(ITuner* tuner) - { - - _adminLock.Lock(); - - Scanners::iterator index = std::find(_scanners.begin(), _scanners.end(), tuner); - - if (index != _scanners.end()) { - if (tuner->State() == ITuner::IDLE) { - _scanners.erase(index); - } - } else { - if (tuner->State() != ITuner::IDLE) { - _scanners.emplace_back(*this, tuner, _scan); - } - } - - _adminLock.Unlock(); - } - void Load(const DVB::EIT& table) - { - _adminLock.Lock(); - - _adminLock.Unlock(); - } - - private: - mutable Core::CriticalSection _adminLock; - Scanners _scanners; - Sink _sink; - bool _scan; - }; - -} // namespace Broadcast -} // namespace Thunder - -#endif // SCHEDULE_ADMINISTRATOR_H diff --git a/Source/broadcast/Services.h b/Source/broadcast/Services.h deleted file mode 100644 index 2dca943..0000000 --- a/Source/broadcast/Services.h +++ /dev/null @@ -1,329 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#ifndef SERVICE_ADMINISTRATOR_H -#define SERVICE_ADMINISTRATOR_H - -#include "Definitions.h" -#include "Descriptors.h" -#include "SDT.h" - -namespace Thunder { - -namespace Broadcast { - - class Services { - private: - Services(const Services&) = delete; - Services& operator=(const Services&) = delete; - - class Sink : public ITuner::INotification { - private: - Sink() = delete; - Sink(const Sink&) = delete; - Sink& operator=(const Sink&) = delete; - - public: - Sink(Services& parent) - : _parent(parent) - { - } - virtual ~Sink() - { - } - - public: - virtual void Activated(ITuner* /* tuner */) override - { - } - virtual void Deactivated(ITuner* tuner) override - { - _parent.Deactivated(tuner); - } - virtual void StateChange(ITuner* tuner) override - { - _parent.StateChange(tuner); - } - - private: - Services& _parent; - }; - - class Parser : public ISection { - private: - Parser() = delete; - Parser(const Parser&) = delete; - Parser& operator=(const Parser&) = delete; - - public: - Parser(Services& parent, ITuner* source, const bool scan) - : _parent(parent) - , _source(source) - , _actual(Core::ProxyType::Create(512)) - , _others(Core::ProxyType::Create(512)) - { - if (scan == true) { - Scan(true); - } - } - virtual ~Parser() - { - Scan(false); - } - inline bool operator==(const ITuner* rhs) const - { - return (_source == rhs); - } - inline bool operator!=(const ITuner* rhs) const - { - return (!operator==(rhs)); - } - - public: - void Scan(const bool scan) - { - if (scan == true) { - // Start loading the SDT info - _source->Filter(0x11, DVB::SDT::ACTUAL, this); - _source->Filter(0x11, DVB::SDT::OTHER, this); - } else { - _source->Filter(0x11, DVB::SDT::OTHER, nullptr); - _source->Filter(0x11, DVB::SDT::ACTUAL, nullptr); - } - } - - private: - virtual void Handle(const MPEG::Section& section) override - { - - ASSERT(section.IsValid()); - - if (section.TableId() == DVB::SDT::ACTUAL) { - _actual.AddSection(section); - if (_actual.IsValid() == true) { - _parent.Load(DVB::SDT(_actual)); - } - } else if (section.TableId() == DVB::SDT::OTHER) { - _others.AddSection(section); - if (_others.IsValid() == true) { - _parent.Load(DVB::SDT(_others)); - } - } - } - - private: - Services& _parent; - ITuner* _source; - MPEG::Table _actual; - MPEG::Table _others; - }; - - typedef std::list Scanners; - - public: - class Service { - public: - Service() - : _serviceId(~0) - , _info(~0) - , _name() - { - } - Service(const DVB::SDT::ServiceIterator& info) - : _serviceId(info.ServiceId()) - , _info((info.EIT_PF() ? 0x10 : 0x00) | (info.EIT_Schedule() ? 0x20 : 0x00) | (info.IsFreeToAir() ? 0x40 : 0x00) | info.RunningMode()) - , _name(_T("Unknown")) - { - MPEG::DescriptorIterator index(info.Descriptors()); - - if (index.Tag(DVB::Descriptors::Service::TAG) == true) { - DVB::Descriptors::Service nameDescriptor(index.Current()); - _name = nameDescriptor.Name(); - } - } - Service(const Service& copy) - : _serviceId(copy._serviceId) - , _info(copy._info) - , _name(copy._name) - { - } - ~Service() - { - } - - Service& operator=(const Service& rhs) - { - _serviceId = rhs._serviceId; - _info = rhs._info; - _name = rhs._name; - - return (*this); - } - - public: - bool IsValid() const - { - return (_info != static_cast(~0)); - } - const string& Name() const - { - return (_name); - } - inline uint16_t ServiceId() const - { - return (_serviceId); - } - inline bool EIT_PF() const - { - return ((_info & 0x10) != 0); - } - inline bool EIT_Schedule() const - { - return ((_info & 0x20) != 0); - } - inline bool IsFreeToAir() const - { - return ((_info & 0x40) != 0); - } - inline DVB::SDT::running RunningMode() const - { - return (static_cast(_info & 0x07)); - } - - private: - uint16_t _serviceId; - uint8_t _info; - string _name; - }; - - typedef IteratorType Iterator; - - private: - typedef std::map ServiceMap; - - public: - Services() - : _adminLock() - , _scanners() - , _sink(*this) - , _scan(true) - , _services() - { - ITuner::Register(&_sink); - } - virtual ~Services() - { - ITuner::Unregister(&_sink); - } - - public: - void Scan(const bool scan) - { - _adminLock.Lock(); - - if (_scan != scan) { - _scan = scan; - Scanners::iterator index(_scanners.begin()); - while (index != _scanners.end()) { - index->Scan(_scan); - index++; - } - } - _adminLock.Unlock(); - } - Service Id(const uint16_t id) const - { - Service result; - - _adminLock.Lock(); - ServiceMap::const_iterator index(_services.find(id)); - if (index != _services.end()) { - result = index->second; - } - _adminLock.Unlock(); - - return (result); - } - Iterator List() const - { - - _adminLock.Lock(); - Iterator value(_services); - _adminLock.Unlock(); - - return (value); - } - - private: - void Deactivated(ITuner* tuner) - { - _adminLock.Lock(); - - Scanners::iterator index = std::find(_scanners.begin(), _scanners.end(), tuner); - - if (index != _scanners.end()) { - _scanners.erase(index); - } - - _adminLock.Unlock(); - } - void StateChange(ITuner* tuner) - { - - _adminLock.Lock(); - - Scanners::iterator index = std::find(_scanners.begin(), _scanners.end(), tuner); - - if (index != _scanners.end()) { - if (tuner->State() == ITuner::IDLE) { - _scanners.erase(index); - } - } else { - if (tuner->State() != ITuner::IDLE) { - _scanners.emplace_back(*this, tuner, _scan); - } - } - - _adminLock.Unlock(); - } - void Load(const DVB::SDT& table) - { - _adminLock.Lock(); - - DVB::SDT::ServiceIterator index = table.Services(); - - while (index.Next() == true) { - _services[index.ServiceId()] = Service(index); - } - - _adminLock.Unlock(); - } - - private: - mutable Core::CriticalSection _adminLock; - Scanners _scanners; - Sink _sink; - bool _scan; - ServiceMap _services; - }; - -} // namespace Broadcast -} // namespace Thunder - -#endif // SERVICE_ADMINISTRATOR_H diff --git a/Source/broadcast/TDT.h b/Source/broadcast/TDT.h deleted file mode 100644 index f8cfb6b..0000000 --- a/Source/broadcast/TDT.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#ifndef DVB_TDT_TABLE_H -#define DVB_TDT_TABLE_H - -// ---- Include system wide include files ---- - -// ---- Include local include files ---- -#include "MPEGDescriptor.h" -#include "MPEGSection.h" -#include "Module.h" - -// ---- Referenced classes and types ---- - -// ---- Helper types and constants ---- - -// ---- Helper functions ---- - -// ---- Class Definition ---- - -namespace Thunder { -namespace Broadcast { - namespace DVB { - - class EXTERNAL TDT { - private: - TDT& operator=(const TDT& rhs) = delete; - - public: - static const uint16_t ID = 0x70; - - public: - TDT() - : _time() - { - } - TDT(const MPEG::Section& data) - : _time() - { - if (data.IsValid() == true) { - const Core::DataElement info(data.Data()); - - // EXAMPLE: 93/10/13 12:45:00 is coded as "0xC079 124500". - uint16_t MJD = (info[0] << 8) | info[1]; - uint32_t J, C, Y, M; - - J = MJD + 2400001 + 68569; - C = 4 * J / 146097; - J = J - (146097 * C + 3) / 4; - Y = 4000 * (J + 1) / 1461001; - J = J - 1461 * Y / 4 + 31; - M = 80 * J / 2447; - - uint8_t day = static_cast(J - 2447 * M / 80); - J = M / 11; - uint8_t month = static_cast(M + 2 - (12 * J)); - uint16_t year = static_cast(100 * (C - 49) + Y + J); - uint8_t uren = ((info[2] >> 4) * 10) + (info[2] & 0xF); - uint8_t minuten = ((info[3] >> 4) * 10) + (info[3] & 0xF); - uint8_t seconden = ((info[4] >> 4) * 10) + (info[4] & 0xF); - - printf("Loadeded: %d-%d-%d %d:%d.%d\n", day, month, year, uren, minuten, seconden); - _time = Core::Time(year, month, day, uren, minuten, seconden, 0, false); - } - } - TDT(const TDT& copy) - : _time(copy._time) - { - } - ~TDT() {} - - public: - inline bool IsValid() const - { - return (_time.IsValid()); - } - inline const Core::Time& Time() const { return (_time); } - - private: - Core::Time _time; - }; - - class EXTERNAL TOT : public TDT { - private: - TOT& operator=(const TOT& rhs) = delete; - - public: - static const uint16_t ID = 0x73; - - public: - TOT() - : TDT() - , _data() - { - } - TOT(const MPEG::Section& data) - : TDT(data) - , _data(data.Data()) - { - } - TOT(const TOT& copy) - : TDT(copy) - , _data(copy._data) - { - } - ~TOT() {} - - public: - MPEG::DescriptorIterator Descriptors() const - { - uint16_t size(((_data[6] & 0xF) << 8) | _data[7]); - return (MPEG::DescriptorIterator(Core::DataElement(_data, 8, size))); - } - - private: - Core::DataElement _data; - }; - - } // namespace DVB -} // namespace Broadcast -} // namespace Thunder - -#endif // DVB_TDT_TABLE_H diff --git a/Source/broadcast/TimeDate.h b/Source/broadcast/TimeDate.h deleted file mode 100644 index 51c7a31..0000000 --- a/Source/broadcast/TimeDate.h +++ /dev/null @@ -1,227 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#ifndef TIMEDATE_ADMINISTRATOR_H -#define TIMEDATE_ADMINISTRATOR_H - -#include "Definitions.h" -#include "Descriptors.h" -#include "TDT.h" - -namespace Thunder { - -namespace Broadcast { - - class TimeDate { - private: - TimeDate(const TimeDate&) = delete; - TimeDate& operator=(const TimeDate&) = delete; - - class Sink : public ITuner::INotification { - private: - Sink() = delete; - Sink(const Sink&) = delete; - Sink& operator=(const Sink&) = delete; - - public: - Sink(TimeDate& parent) - : _parent(parent) - { - } - virtual ~Sink() - { - } - - public: - virtual void Activated(ITuner* /* tuner */) override - { - } - virtual void Deactivated(ITuner* tuner) override - { - _parent.Deactivated(tuner); - } - virtual void StateChange(ITuner* tuner) override - { - _parent.StateChange(tuner); - } - - private: - TimeDate& _parent; - }; - - class Parser : public ISection { - private: - Parser() = delete; - Parser(const Parser&) = delete; - Parser& operator=(const Parser&) = delete; - - public: - Parser(TimeDate& parent, ITuner* source, const bool scan) - : _parent(parent) - , _source(source) - { - if (scan == true) { - Scan(true); - } - } - virtual ~Parser() - { - Scan(false); - } - inline bool operator==(const ITuner* rhs) const - { - return (_source == rhs); - } - inline bool operator!=(const ITuner* rhs) const - { - return (!operator==(rhs)); - } - - public: - void Scan(const bool scan) - { - if (scan == true) { - // Start loading the SDT info - _source->Filter(0x14, DVB::TDT::ID, this); - _source->Filter(0x14, DVB::TOT::ID, this); - } else { - _source->Filter(0x14, DVB::TOT::ID, nullptr); - _source->Filter(0x14, DVB::TDT::ID, nullptr); - } - } - - private: - virtual void Handle(const MPEG::Section& section) override - { - - ASSERT(section.IsValid()); - - if (section.TableId() == DVB::TDT::ID) { - _parent.Load(DVB::TDT(section)); - } else if (section.TableId() == DVB::TOT::ID) { - _parent.Load(DVB::TOT(section)); - } - } - - private: - TimeDate& _parent; - ITuner* _source; - }; - - typedef std::list Scanners; - - public: - TimeDate() - : _adminLock() - , _scanners() - , _sink(*this) - , _scan(true) - , _time() - { - ITuner::Register(&_sink); - } - virtual ~TimeDate() - { - ITuner::Unregister(&_sink); - } - - public: - void Scan(const bool scan) - { - _adminLock.Lock(); - - if (_scan != scan) { - _scan = scan; - Scanners::iterator index(_scanners.begin()); - while (index != _scanners.end()) { - index->Scan(_scan); - index++; - } - } - _adminLock.Unlock(); - } - - private: - void Deactivated(ITuner* tuner) - { - _adminLock.Lock(); - - Scanners::iterator index = std::find(_scanners.begin(), _scanners.end(), tuner); - - if (index != _scanners.end()) { - _scanners.erase(index); - } - - _adminLock.Unlock(); - } - void StateChange(ITuner* tuner) - { - - _adminLock.Lock(); - - Scanners::iterator index = std::find(_scanners.begin(), _scanners.end(), tuner); - - if (index != _scanners.end()) { - if (tuner->State() == ITuner::IDLE) { - _scanners.erase(index); - } - } else { - if (tuner->State() != ITuner::IDLE) { - _scanners.emplace_back(*this, tuner, _scan); - } - } - - _adminLock.Unlock(); - } - void Load(const DVB::TOT& table) - { - - _adminLock.Lock(); - - MPEG::DescriptorIterator index = table.Descriptors(); - - while (index.Next() == true) { - } - - _time = table.Time(); - - _adminLock.Unlock(); - } - void Load(const DVB::TDT& table) - { - - _adminLock.Lock(); - - _time = table.Time(); - - _adminLock.Unlock(); - } - - private: - mutable Core::CriticalSection _adminLock; - Scanners _scanners; - Sink _sink; - bool _scan; - Core::Time _time; - }; - -} // namespace Broadcast -} // namespace Thunder - -#endif // TIMEDATE_ADMINISTRATOR_H diff --git a/Source/broadcast/TunerAdministrator.cpp b/Source/broadcast/TunerAdministrator.cpp deleted file mode 100644 index e33ab74..0000000 --- a/Source/broadcast/TunerAdministrator.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#include "TunerAdministrator.h" - -namespace Thunder { - -namespace Broadcast { - - /* static */ TunerAdministrator& TunerAdministrator::Instance() - { - static TunerAdministrator _instance; - return (_instance); - } - - // Accessor to metadata on the tuners. - /* static */ void ITuner::Register(ITuner::INotification* notify) - { - TunerAdministrator::Instance().Register(notify); - } - - /* static */ void ITuner::Unregister(ITuner::INotification* notify) - { - TunerAdministrator::Instance().Unregister(notify); - } - -} -} // namespace Thunder::Broadcast diff --git a/Source/broadcast/TunerAdministrator.h b/Source/broadcast/TunerAdministrator.h deleted file mode 100644 index 55a9549..0000000 --- a/Source/broadcast/TunerAdministrator.h +++ /dev/null @@ -1,192 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#ifndef TUNER_ADMINISTRATOR_H -#define TUNER_ADMINISTRATOR_H - -#include "Definitions.h" -#include "MPEGTable.h" - -namespace Thunder { - -namespace Broadcast { - - // This class is the linking pin (Singleton) between the Tuner Implementation and the outside world. - // However the definition of this class should not be shared with the outside world as this class - // should not be directly accessed by anyone in the outside world - // The purpose of this class is to allow SI/PSI parsing on tuners while thay are not yet tuned, or - // if they are tuned, to collect (P)SI information on that transport stream and so it looks to the - // outside world that if one tunes automagically the P(SI) get populated. - // So: DO *NOT* USE THIS CLASS OUTSIDE THE BROADCAST LIBRARY, THAT IS WHY IT IS IN ANY OF THE - // INCLUDES OF ANY OTHER HEADER FILES AND ONLY USED BY THE TUNER IMPLEMENTATIONS !!!! - class TunerAdministrator { - public: - struct ICallback { - virtual ~ICallback() {} - - virtual void StateChange(ITuner* tuner) = 0; - }; - - private: - TunerAdministrator(const TunerAdministrator&) = delete; - TunerAdministrator& operator=(const TunerAdministrator&) = delete; - - class Sink : public ICallback { - private: - Sink() = delete; - Sink(const Sink&) = delete; - Sink& operator=(const Sink&) = delete; - - public: - Sink(TunerAdministrator& parent) - : _parent(parent) - { - } - virtual ~Sink() - { - } - - public: - virtual void StateChange(ITuner* tuner) override - { - _parent.StateChange(tuner); - } - - private: - TunerAdministrator& _parent; - }; - - TunerAdministrator() - : _adminLock() - , _sink(*this) - , _observers() - , _tuners() - { - } - - typedef std::list Observers; - typedef std::list Tuners; - - public: - static TunerAdministrator& Instance(); - virtual ~TunerAdministrator() {} - - public: - void Register(ITuner::INotification* observer) - { - _adminLock.Lock(); - - ASSERT(std::find(_observers.begin(), _observers.end(), observer) == _observers.end()); - - _observers.push_back(observer); - - Tuners::iterator index(_tuners.begin()); - while (index != _tuners.end()) { - observer->Activated(*index); - observer->StateChange(*index); - index++; - } - - _adminLock.Unlock(); - } - void Unregister(ITuner::INotification* observer) - { - _adminLock.Lock(); - - Observers::iterator index(std::find(_observers.begin(), _observers.end(), observer)); - - if (index != _observers.end()) { - _observers.erase(index); - } - - _adminLock.Unlock(); - } - ICallback* Announce(ITuner* tuner) - { - _adminLock.Lock(); - - ASSERT(std::find(_tuners.begin(), _tuners.end(), tuner) == _tuners.end()); - - Observers::iterator index(_observers.begin()); - - while (index != _observers.end()) { - (*index)->Activated(tuner); - index++; - } - - _tuners.push_back(tuner); - - _adminLock.Unlock(); - - return (&_sink); - } - void Revoke(ITuner* tuner) - { - _adminLock.Lock(); - - Tuners::iterator entry(std::find(_tuners.begin(), _tuners.end(), tuner)); - - ASSERT(entry != _tuners.end()); - - if (entry != _tuners.end()) { - - Observers::iterator index(_observers.begin()); - - _tuners.erase(entry); - - while (index != _observers.end()) { - (*index)->Deactivated(tuner); - index++; - } - } - - _adminLock.Unlock(); - } - - private: - void StateChange(ITuner* tuner) - { - // Before notifying the others, lets notify the real user of the ITuner interface - tuner->StateChange(); - - _adminLock.Lock(); - - ASSERT(std::find(_tuners.begin(), _tuners.end(), tuner) != _tuners.end()); - - Observers::iterator index(_observers.begin()); - - while (index != _observers.end()) { - (*index)->StateChange(tuner); - index++; - } - - _adminLock.Unlock(); - } - - private: - Core::CriticalSection _adminLock; - Sink _sink; - Observers _observers; - Tuners _tuners; - }; - -} // namespace Broadcast -} // namespace Thunder - -#endif // TUNER_ADMINISTRATOR_H diff --git a/Source/broadcast/broadcast.h b/Source/broadcast/broadcast.h deleted file mode 100644 index ca21eb6..0000000 --- a/Source/broadcast/broadcast.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#pragma once - -#ifndef MODULE_NAME -#error "Please define a MODULE_NAME that describes the binary/library you are building." -#endif - -#include "Definitions.h" -#include "Descriptors.h" -#include "MPEGDescriptor.h" -#include "MPEGSection.h" -#include "MPEGTable.h" -#include "NIT.h" -#include "Networks.h" -#include "ProgramTable.h" -#include "SDT.h" -#include "Services.h" -#include "TDT.h" -#include "TimeDate.h" - -#ifdef __WINDOWS__ -#pragma comment(lib, "broadcast.lib") -#endif diff --git a/Source/broadcast/cmake/FindNEXUS.cmake b/Source/broadcast/cmake/FindNEXUS.cmake deleted file mode 100644 index 2d18741..0000000 --- a/Source/broadcast/cmake/FindNEXUS.cmake +++ /dev/null @@ -1,83 +0,0 @@ -# - Try to find Broadcom Nexus. -# Once done this will define -# NEXUS_FOUND - System has Nexus -# NEXUS::NEXUS - The Nexus library -# -# Copyright (C) 2019 Metrological B.V -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS CONTRIBUTORS ``AS -# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ITS -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -find_path(LIBNEXUS_INCLUDE nexus_config.h - PATH_SUFFIXES refsw) - -find_library(LIBNEXUS_LIBRARY nexus) - -if(EXISTS "${LIBNEXUS_LIBRARY}") - find_library(LIBB_OS_LIBRARY b_os) - find_library(LIBNEXUS_CLIENT_LIBRARY nexus_client) - find_library(LIBNXCLIENT_LIBRARY nxclient) - - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(NEXUS DEFAULT_MSG LIBNEXUS_INCLUDE LIBNEXUS_LIBRARY) - mark_as_advanced(LIBNEXUS_INCLUDE LIBNEXUS_LIBRARY) - - if(NEXUS_FOUND AND NOT TARGET NEXUS::NEXUS) - add_library(NEXUS::NEXUS UNKNOWN IMPORTED) - set_target_properties(NEXUS::NEXUS PROPERTIES - IMPORTED_LINK_INTERFACE_LANGUAGES "C" - INTERFACE_INCLUDE_DIRECTORIES "${LIBNEXUS_INCLUDE}" - ) - - if(NOT EXISTS "${LIBNEXUS_CLIENT_LIBRARY}") - message(STATUS "Nexus in Proxy mode") - set_target_properties(NEXUS::NEXUS PROPERTIES - IMPORTED_LOCATION "${LIBNEXUS_LIBRARY}" - ) - else() - message(STATUS "Nexus in Client mode") - set_target_properties(NEXUS::NEXUS PROPERTIES - IMPORTED_LOCATION "${LIBNEXUS_CLIENT_LIBRARY}" - ) - endif() - - if(NOT EXISTS "${LIBNXCLIENT_LIBRARY}") - set_target_properties(NEXUS::NEXUS PROPERTIES - INTERFACE_COMPILE_DEFINITIONS NO_NXCLIENT - ) - endif() - - if(EXISTS "${LIBB_OS_LIBRARY}") - set_target_properties(NEXUS::NEXUS PROPERTIES - IMPORTED_LINK_INTERFACE_LIBRARIES "${LIBB_OS_LIBRARY}" - ) - endif() - endif() - set_target_properties(NEXUS::NEXUS PROPERTIES - INTERFACE_COMPILE_DEFINITIONS "PLATFORM_BRCM" - ) -else() - if(NEXUS_FIND_REQUIRED) - message(FATAL_ERROR "LIBNEXUS_LIBRARY not available") - elseif(NOT NEXUS_FIND_QUIETLY) - message(STATUS "LIBNEXUS_LIBRARY not available") - endif() -endif() \ No newline at end of file diff --git a/Source/broadcast/cmake/FindNXCLIENT.cmake b/Source/broadcast/cmake/FindNXCLIENT.cmake deleted file mode 100644 index 2e694db..0000000 --- a/Source/broadcast/cmake/FindNXCLIENT.cmake +++ /dev/null @@ -1,53 +0,0 @@ -# - Try to find Broadcom Nexus client. -# Once done this will define -# NXCLIENT_FOUND - System has a Nexus client -# NXCLIENT::NXCLIENT - The Nexus client library -# -# Copyright (C) 2019 Metrological B.V -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS CONTRIBUTORS ``AS -# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ITS -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -find_path(LIBNXCLIENT_INCLUDE nexus_config.h - PATH_SUFFIXES refsw) - -find_library(LIBNXCLIENT_LIBRARY nxclient) - -if(EXISTS "${LIBNXCLIENT_LIBRARY}") - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(NXCLIENT DEFAULT_MSG LIBNXCLIENT_INCLUDE LIBNXCLIENT_LIBRARY) - mark_as_advanced(LIBNXCLIENT_LIBRARY) - - if(NXCLIENT_FOUND AND NOT TARGET NXCLIENT::NXCLIENT) - add_library(NXCLIENT::NXCLIENT UNKNOWN IMPORTED) - set_target_properties(NXCLIENT::NXCLIENT PROPERTIES - IMPORTED_LINK_INTERFACE_LANGUAGES "C" - IMPORTED_LOCATION "${LIBNXCLIENT_LIBRARY}" - INTERFACE_INCLUDE_DIRECTORIES "${LIBNXCLIENT_INCLUDE}" - ) - endif() -else() - if(NXCLIENT_FIND_REQUIRED) - message(FATAL_ERROR "LIBNXCLIENT_LIBRARY not available") - elseif(NOT NXCLIENT_FIND_QUIETLY) - message(STATUS "LIBNXCLIENT_LIBRARY not available") - endif() -endif() diff --git a/Source/broadcast/test/BroadcastTester.cpp b/Source/broadcast/test/BroadcastTester.cpp deleted file mode 100644 index 7d72404..0000000 --- a/Source/broadcast/test/BroadcastTester.cpp +++ /dev/null @@ -1,165 +0,0 @@ - - /* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * 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. - */ - -#define MODULE_NAME BroadcastTest - -#include -#include - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) -using namespace Thunder; - -void printHelp(){ - printf("Keys to use:\n"); - printf("i -> Initialize \n"); - printf("d -> Deinitialize\n"); - printf("c -> Request a tuner\n"); - printf("t -> Tune\n"); - printf("s -> Switch stream\n"); - printf("? -> This message\n"); - printf("q -> Quit\n"); -} - -int main(int /* argc */, const char** /* argv */) -{ - const string configuration = "{ \ - \"frontends\":1, \ - \"decoders\":1, \ - \"standard\":\"DVB\", \ - \"annex\":\"None\", \ - \"scan\":true, \ - \"modus\":\"Terrestrial\" \ - }"; - - const string information = "0"; - - std::list tuners; - std::list::iterator tuner = tuners.begin(); - - class streamInfo { - public: - streamInfo(uint16_t _frequency, Broadcast::Modulation _modulation, uint32_t _symbolRate, uint16_t _fec, Broadcast::SpectralInversion _si) - : frequency(_frequency) - , modulation(_modulation) - , symbolRate(_symbolRate) - , fec(_fec) - , si(_si) - { - } - - const uint16_t frequency; - const Broadcast::Modulation modulation; - const uint32_t symbolRate; - const uint16_t fec; - const Broadcast::SpectralInversion si; - }; - - std::list streams; - - streams.emplace_back(482, Broadcast::QAM64, 8000000, Broadcast::FEC_1_2, Broadcast::Auto); // Digitenne Enschede - streams.emplace_back(642, Broadcast::QAM64, 8000000, Broadcast::FEC_1_2, Broadcast::Auto); // RTON Zorawina - streams.emplace_back(706, Broadcast::QAM64, 8000000, Broadcast::FEC_1_2, Broadcast::Auto); // Digitenne Amersfoort - streams.emplace_back(618, Broadcast::QAM64, 8000000, Broadcast::FEC_1_2, Broadcast::Auto); // Digitenne Amsterdam - streams.emplace_back(474, Broadcast::QAM64, 8000000, Broadcast::FEC_1_2, Broadcast::Auto); // Digitenne Rotterdam - - std::list::iterator stream = streams.begin(); - - char keyPress; - - printf("Ready to start processing events, start with 0 to connect.\n"); - printHelp(); - do { - keyPress = toupper(getchar()); - - switch (keyPress) { - case 'I': { - printf("%s:%d %s Initialize\n", __FILE__, __LINE__, __FUNCTION__); - Broadcast::ITuner::Initialize(configuration); - } break; - - case 'D': { - printf("%s:%d %s Deinitialize\n", __FILE__, __LINE__, __FUNCTION__); - Broadcast::ITuner::Deinitialize(); - } break; - - case 'C': { - printf("%s:%d %s Create tuner\n", __FILE__, __LINE__, __FUNCTION__); - Broadcast::ITuner* newTuner = Broadcast::ITuner::Create(information); - - if (newTuner != nullptr) { - printf("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); - std::list::iterator entry(std::find(tuners.begin(), tuners.end(), newTuner)); - if (entry == tuners.end()) { - printf("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); - tuners.push_back(newTuner); - printf("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); - if (tuner == tuners.end()) { - tuner = tuners.begin(); - } - } - } else { - printf("Sorry, no more tuners availble!\n"); - } - } break; - - case 'S': { - printf("%s:%d %s Switch tuner\n", __FILE__, __LINE__, __FUNCTION__); - if (++tuner == tuners.end()) { - tuner = tuners.begin(); - } - } break; - - case 'T': { - printf("%s:%d %s Tune\n", __FILE__, __LINE__, __FUNCTION__); - if (*tuner != nullptr) { - printf("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); - if (++stream == streams.end()) { - printf("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); - stream = streams.begin(); - } - printf("%s:%d %s Tune: %d %d %d %d %d\n", __FILE__, __LINE__, __FUNCTION__, stream->frequency, stream->modulation, stream->symbolRate, stream->fec, stream->si); - (*tuner)->Tune(stream->frequency, stream->modulation, stream->symbolRate, stream->fec, stream->si); - printf("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); - } - } break; - - case 'Q': - break; - - case '?': { - printHelp(); - } break; - - case '\n': - break; - - default: { - printf("Not known. Press '?' for help.\n"); - } break; - } - } while (keyPress != 'Q'); - - // Clear the factory we created.. - Thunder::Core::Singleton::Dispose(); - - printf("\nLeaving the test App !!!\n"); - - return 0; -} diff --git a/Source/broadcast/test/CMakeLists.txt b/Source/broadcast/test/CMakeLists.txt deleted file mode 100644 index e495b17..0000000 --- a/Source/broadcast/test/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -# If not stated otherwise in this file or this component's license file the -# following copyright and licenses apply: -# -# Copyright 2020 Metrological -# -# 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. - -include_directories(${CMAKE_CURRENT_LIST_DIR}/../../broadcast) -include_directories($) - -add_executable(BroadcastTester BroadcastTester.cpp) - -target_link_libraries(BroadcastTester - PRIVATE - ${NAMESPACE}Broadcast::${NAMESPACE}Broadcast - ${NAMESPACE}Core::${NAMESPACE}Core -) - -install(TARGETS BroadcastTester DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${NAMESPACE}_Test) diff --git a/Source/compositorbuffer/CMakeLists.txt b/Source/compositorbuffer/CMakeLists.txt deleted file mode 100644 index 47572fc..0000000 --- a/Source/compositorbuffer/CMakeLists.txt +++ /dev/null @@ -1,58 +0,0 @@ -# If not stated otherwise in this file or this component's LICENSE file the -# following copyright and licenses apply: -# -# Copyright 2022 Metrological -# -# 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. - -cmake_minimum_required(VERSION 3.15) - -find_package(Thunder) - -project(CompositorBufferType - VERSION 1.0.0 - DESCRIPTION "Abstraction to share graphics/video buffers between different processes" - LANGUAGES CXX) - -set(MODULE_NAME ${NAMESPACE}${PROJECT_NAME}) - -message("Setup ${MODULE_NAME} v${PROJECT_VERSION}") - -option(INSTALL_EXAMPLES "Install the examples." ON) - -find_package(${NAMESPACE}Core REQUIRED) - -add_library(${MODULE_NAME} INTERFACE) -add_library(${MODULE_NAME}::${MODULE_NAME} ALIAS ${MODULE_NAME}) - -target_include_directories(${MODULE_NAME} INTERFACE - $ - $) - -target_compile_features(${MODULE_NAME} INTERFACE cxx_std_11) - -install(TARGETS ${MODULE_NAME} EXPORT ${MODULE_NAME}Targets) - -install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/compositorbuffer/CompositorBufferType.h - DESTINATION include/${NAMESPACE}/compositorbuffer COMPONENT ${NAMESPACE}_Development) - -include(HeaderOnlyInstall) - -HeaderOnlyInstallPackageConfig(TARGET ${MODULE_NAME} - NAME ${MODULE_NAME} - VERSION ${PROJECT_VERSION} - DESCRIPTION "Header only library for creating and using compositor buffers.") - -HeaderOnlyInstallCMakeConfig(TARGET ${MODULE_NAME} TREAT_AS_NORMAL) - -add_subdirectory(example) diff --git a/Source/compositorbuffer/example/CMakeLists.txt b/Source/compositorbuffer/example/CMakeLists.txt deleted file mode 100644 index 70575e7..0000000 --- a/Source/compositorbuffer/example/CMakeLists.txt +++ /dev/null @@ -1,39 +0,0 @@ -# If not stated otherwise in this file or this component's LICENSE file the -# following copyright and licenses apply: -# -# Copyright 2022 Metrological -# -# 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. - -find_package(Thunder) - -find_package(${NAMESPACE}Definitions REQUIRED) -find_package(${NAMESPACE}Core REQUIRED) -find_package(${NAMESPACE}PrivilegedRequest REQUIRED) -find_package(CompileSettingsDebug REQUIRED) - -add_executable(cb-test main.cpp) - -target_link_libraries(cb-test PRIVATE - CompileSettingsDebug::CompileSettingsDebug - ${NAMESPACE}Definitions::${NAMESPACE}Definitions - ${NAMESPACE}Core::${NAMESPACE}Core - ${NAMESPACE}PrivilegedRequest::${NAMESPACE}PrivilegedRequest - ${NAMESPACE}CompositorBufferType::${NAMESPACE}CompositorBufferType) - -if(INSTALL_EXAMPLES) - install(TARGETS cb-test DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${NAMESPACE}_Test) -endif() - - - diff --git a/Source/compositorbuffer/example/main.cpp b/Source/compositorbuffer/example/main.cpp deleted file mode 100644 index 6a5c2b6..0000000 --- a/Source/compositorbuffer/example/main.cpp +++ /dev/null @@ -1,303 +0,0 @@ -/** - * If not stated otherwise in this file or this component's LICENSE - * file the following copyright and licenses apply: - * - * Copyright 2022 RDK Management - * - * 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. - **/ -#include - -using namespace Thunder; - -MODULE_NAME_ARCHIVE_DECLARATION -namespace Test { - -const char* descriptors[] = { - _T("/tmp/buffer1.txt"), - _T("/tmp/buffer2.txt"), -}; - -const char bridgeConnector[] = _T("/tmp/connector"); - -class CompositorBuffer : public Thunder::Compositor::CompositorBufferType<4>, public Core::IReferenceCounted { -private: - using BaseClass = Thunder::Compositor::CompositorBufferType<4>; - -protected: - CompositorBuffer(const string& callsign, const uint32_t id, - const uint32_t width, const uint32_t height, - const uint32_t format, const uint64_t modifier, - const Exchange::ICompositionBuffer::DataType type) - : BaseClass(callsign, id, width, height, format, modifier, type) - { - - printf("Constructing server buffer.\n"); - - for (uint8_t index = 0; index < (sizeof(descriptors) / sizeof(const char*)); index++) { - Core::File file(string(descriptors[index])); - if (file.Create(Core::File::USER_READ | Core::File::USER_WRITE) == true) { - BaseClass::Add(static_cast(file), 0xAAAA + index, 0x5555 + index); - printf("Opening: [%d] -> name: %s\n", static_cast(file), descriptors[index]); - } - } - // Let's start monitoring the CompositorBuffer to detect changes - Core::ResourceMonitor::Instance().Register(*this); - } - -public: - CompositorBuffer() = delete; - CompositorBuffer(CompositorBuffer&&) = delete; - CompositorBuffer(const CompositorBuffer&) = delete; - CompositorBuffer& operator=(const CompositorBuffer&) = delete; - - static Core::ProxyType Create(const string& callsign, const uint32_t width, const uint32_t height, const Exchange::ICompositionBuffer::DataType type) - { - static uint32_t id = 1; - uint32_t identifier = Core::InterlockedIncrement(id); - return (_map.Instance(callsign, callsign, identifier, width, height, 0xAA, 0x55, type)); - } - static Core::ProxyType Find(const string& callsign) - { - return (_map.Find(callsign)); - } - ~CompositorBuffer() override - { - // Let's stop monitoring the CompositorBuffer to detect changes - Core::ResourceMonitor::Instance().Unregister(*this); - printf("Destructing server buffer.\n"); - } - -public: - // Methods still to be implemented.... - void Render() override - { - printf("We need to do our magic here :-)\n"); - } - -private: - static Core::ProxyMapType _map; -}; - -/* static */ Core::ProxyMapType CompositorBuffer::_map; - -class ClientBuffer : public Thunder::Compositor::CompositorBufferType<4>, public Core::IReferenceCounted { -private: - using BaseClass = Thunder::Compositor::CompositorBufferType<4>; - -protected: - ClientBuffer(const uint32_t id, Core::PrivilegedRequest::Container& descriptors) - : BaseClass(id, descriptors) - { - } - -public: - ClientBuffer() = delete; - ClientBuffer(ClientBuffer&&) = delete; - ClientBuffer(const ClientBuffer&) = delete; - ClientBuffer& operator=(const ClientBuffer&) = delete; - - static Exchange::ICompositionBuffer* Create(const uint32_t id, Core::PrivilegedRequest::Container& descriptors) - { - Core::ProxyType element(Core::ProxyType::Create(id, descriptors)); - Exchange::ICompositionBuffer* result = &(*element); - result->AddRef(); - return (result); - } - -public: - // Methods still to be implemented.... - void Render() override - { - ASSERT(false); - } -}; - -class Dispatcher : public Core::PrivilegedRequest { -public: - Dispatcher(Dispatcher&&) = delete; - Dispatcher(const Dispatcher&) = delete; - Dispatcher& operator=(const Dispatcher&) = delete; - - Dispatcher() = default; - ~Dispatcher() override = default; - - void Add(const uint32_t id, Thunder::Compositor::CompositorBufferType<4>& buffer) - { - _id = id; - _buffer = &buffer; - } - void Remove(const uint32_t id) - { - if (_id == id) { - _id = 0; - _buffer = nullptr; - } - } - uint8_t Service(const uint32_t id, const uint8_t maxSize, int container[]) override - { - if ((id == _id) && (_buffer != nullptr)) { - uint8_t result = _buffer->Descriptors(maxSize, container); - - if (result > 0) { - printf("Handing out: %d descriptors: [", result); - for (uint8_t index = 0; index < (result - 1); index++) { - printf("%d,", container[index]); - } - printf("%d]\n", container[result - 1]); - } - return (result); - } - return 0; - } - -private: - uint32_t _id; - Thunder::Compositor::CompositorBufferType<4>* _buffer; -}; - -} // namespace Test - -bool server = false; -uint32_t bufferId = 0; - -bool ParseOptions(int argc, const char** argv) -{ - int index = 1; - bool showHelp = false; - - while ((index < argc) && (showHelp == false)) { - - if (strcmp(argv[index], "-server") == 0) { - server = true; - } else if (strcmp(argv[index], "-b") == 0) { - - if (((index + 1) < argc) && (argv[index + 1][0] != '-')) { - - index++; - bufferId = atoi(argv[index]); - } - } else { - showHelp = true; - } - index++; - } - - if (showHelp == true) { - printf("Test passing filedescriptos and information over a process boundary.\n"); - printf("%s [-server] [-b ]\n", argv[0]); - printf(" -server Act as a server.\n"); - printf(" -b Act as a client and get the buffer associated with this number.\n"); - } - - return (showHelp == false); -} - -int main(int argc, const char* argv[]) -{ - { - TCHAR element; - ParseOptions(argc, argv); - printf("Running as: [%s]\n", server ? _T("server") : _T("client")); - Test::Dispatcher bridge; - Core::ProxyType serverBuffer; - - Exchange::ICompositionBuffer* buffer = nullptr; - - if (server == true) { - serverBuffer = Test::CompositorBuffer::Create(_T("TestCall"), 1024, 1080, Exchange::ICompositionBuffer::TYPE_RAW); - buffer = &(*serverBuffer); - bridge.Open(string(Test::bridgeConnector)); - printf("Server has created a buffer, known as: [%d]\n", bufferId); - bridge.Add(bufferId, *serverBuffer); - } else { - printf("Client instantiated to get information of buffer: [%d]\n", bufferId); - } - - do { - printf("\n>"); - element = toupper(getchar()); - - switch (element) { - case 'O': - if (buffer == nullptr) { - Core::PrivilegedRequest::Container descriptors; - printf("Get the buffer interface, Sesame open:\n"); - if (bridge.Request(1000, string(Test::bridgeConnector), bufferId, descriptors) == Core::ERROR_NONE) { - printf("Got the buffer on client side.\n"); - buffer = Test::ClientBuffer::Create(bufferId, descriptors); - } else { - printf("Failed to get the buffer.\n"); - } - } else if (server == false) { - printf("Where done, we put it all in, close the vault, Sesame close:\n"); - buffer = nullptr; - } - break; - case 'I': - if (buffer == nullptr) { - printf("There are no buffers\n"); - } else { - printf("Buffer info:\n"); - printf("==========================================\n"); - printf("Width: %d\n", buffer->Width()); - printf("Height: %d\n", buffer->Height()); - printf("Format: %d\n", buffer->Format()); - printf("Type: %d\n", buffer->Type()); - Thunder::Compositor::CompositorBufferType<4>* info = dynamic_cast*>(buffer); - if (info != nullptr) { - printf("Dirty: %s\n", info->IsDirty() ? _T("true") : _T("false")); - } - } - break; - case 'W': - if (buffer == nullptr) { - printf("There are no buffers\n"); - } else { - Exchange::ICompositionBuffer::IIterator* planes = buffer->Planes(10); - - if (planes != nullptr) { - printf("Iterating ove the planes to write:\n"); - while (planes->Next() == true) { - Exchange::ICompositionBuffer::IPlane* plane = planes->Plane(); - ASSERT(plane != nullptr); - int fd = static_cast(plane->Accessor()); - printf("Writing to [%d]:\n", fd); - ::write(fd, "Hello World !!!\n", 16); - ::fsync(fd); - } - } - - buffer->Completed(true); - } - break; - case 'Q': - break; - case '?': - printf("Options available:\n"); - printf("=======================================================================\n"); - printf(" Open/Close the buffer.\n"); - printf(" Information of the buffer.\n"); - printf(" Write a the number in a file.\n"); - printf(" Have no clue what I can do, tell me.\n"); - break; - default: - break; - } - } while (element != 'Q'); - } - - Core::Singleton::Dispose(); - - return EXIT_SUCCESS; -} diff --git a/Source/compositorbuffer/include/compositorbuffer/CompositorBufferType.h b/Source/compositorbuffer/include/compositorbuffer/CompositorBufferType.h deleted file mode 100644 index 25f0f3d..0000000 --- a/Source/compositorbuffer/include/compositorbuffer/CompositorBufferType.h +++ /dev/null @@ -1,515 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 Metrological B.V. - * - * 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. - */ -#pragma once - -#ifndef MODULE_NAME -#define MODULE_NAME Compositor_BufferType -#endif - -#include -#include - -#include - -#include -#include - -namespace Thunder { - -namespace Compositor { - - template - class CompositorBufferType : public Exchange::ICompositionBuffer, public Core::IResource { - private: - /*** - * We need a 64bit according: https://github.com/torvalds/linux/blob/v6.1/fs/eventfd.c#L275 - */ - using EventFrame = uint64_t; - - // We need some shared space for data to exchange, and to create a lock.. - class SharedStorage { - private: - struct PlaneStorage { - uint32_t _stride; - uint32_t _offset; - }; - - public: - void* operator new(size_t stAllocateBlock, int fd) - { - void* result = ::mmap(nullptr, stAllocateBlock, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - return (result != MAP_FAILED ? result : nullptr); - } - // Somehow Purify gets lost if we do not delete it, overide the delete operator - void operator delete(void* stAllocateBlock) - { - ::munmap(stAllocateBlock, sizeof(struct SharedStorage)); - } - - public: - SharedStorage(SharedStorage&&) = delete; - SharedStorage(const SharedStorage&) = delete; - SharedStorage& operator=(const SharedStorage&) = delete; - - // FIXME: - // Do not initialize members for now, this constructor is called after a mmap in the - // placement new operator above. Initializing them now will reset the original values - // of the buffer metadata. - SharedStorage(){}; - - SharedStorage(const uint32_t width, const uint32_t height, const uint32_t format, const uint64_t modifier, const Exchange::ICompositionBuffer::DataType type) - : _width(width) - , _height(height) - , _format(format) - , _modifier(modifier) - , _type(type) - , _dirty() - , _copyOfDirty(false) - { - if (::pthread_mutex_init(&_mutex, nullptr) != 0) { - // That will be the day, if this fails... - ASSERT(false); - } - } - ~SharedStorage() - { -#ifdef __WINDOWS__ - ::CloseHandle(&(_mutex)); -#else - ::pthread_mutex_destroy(&(_mutex)); -#endif - } - - public: - uint32_t Width() const - { - return (_width); - } - uint32_t Height() const - { - return (_height); - } - uint32_t Format() const - { - return (_format); - } - uint32_t Modifier() const - { - return (_modifier); - } - uint32_t Stride(const uint8_t index) const - { // Bytes per row for a plane [(bit-per-pixel/8) * width] - return (_planes[index]._stride); - } - uint32_t Offset(const uint8_t index) const - { // Offset of the plane from where the pixel data starts in the buffer. - return (_planes[index]._offset); - } - void Add(uint8_t index, const uint32_t stride, const uint32_t offset) - { - _planes[index]._stride = stride; - _planes[index]._offset = offset; - } - bool Dirty() - { - _copyOfDirty = false; - return (_dirty.test_and_set() == false); - } - bool IsDirty() - { - return (_copyOfDirty); - } - void Set() - { - _dirty.clear(); - _copyOfDirty = true; - } - Exchange::ICompositionBuffer::DataType Type() const - { - return _type; - } - uint32_t Lock(uint32_t timeout) - { - timespec structTime; - -#ifdef __WINDOWS__ - return (::WaitForSingleObjectEx(&_mutex, timeout, FALSE) == WAIT_OBJECT_0 ? Core::ERROR_NONE : Core::ERROR_TIMEDOUT); -#else - clock_gettime(CLOCK_MONOTONIC, &structTime); - structTime.tv_nsec += ((timeout % 1000) * 1000 * 1000); /* remainder, milliseconds to nanoseconds */ - structTime.tv_sec += (timeout / 1000) + (structTime.tv_nsec / 1000000000); /* milliseconds to seconds */ - structTime.tv_nsec = structTime.tv_nsec % 1000000000; - int result = pthread_mutex_timedlock(&_mutex, &structTime); - return (result == 0 ? Core::ERROR_NONE : Core::ERROR_TIMEDOUT); -#endif - } - uint32_t Unlock() - { -#ifdef __WINDOWS__ - ::LeaveCriticalSection(&_mutex); -#else - pthread_mutex_unlock(&_mutex); -#endif - return (Core::ERROR_NONE); - } - - private: - uint32_t _width; - uint32_t _height; - uint32_t _format; - uint64_t _modifier; - Exchange::ICompositionBuffer::DataType _type; - PlaneStorage _planes[PLANES]; -#ifdef __WINDOWS__ - CRITICAL_SECTION _mutex; -#else - pthread_mutex_t _mutex; -#endif - std::atomic_flag _dirty; - bool _copyOfDirty; - }; - - class Iterator : public Exchange::ICompositionBuffer::IIterator { - private: - class PlaneImplementation : public Exchange::ICompositionBuffer::IPlane { - public: - PlaneImplementation(PlaneImplementation&&) = delete; - PlaneImplementation(const PlaneImplementation&) = delete; - PlaneImplementation& operator=(const PlaneImplementation&) = delete; - - PlaneImplementation() - : _parent(nullptr) - , _index(-1) - { - } - ~PlaneImplementation() override = default; - - public: - void Define(CompositorBufferType& parent, const uint8_t index) - { - _parent = &parent; - _index = index; - } - buffer_id Accessor() const override - { // Access to the actual data. - ASSERT(_parent != nullptr); - return (_parent->Accessor(_index)); - } - uint32_t Stride() const override - { // Bytes per row for a plane [(bit-per-pixel/8) * width] - ASSERT(_parent != nullptr); - ASSERT(_parent->_storage != nullptr); - return (_parent->_storage->Stride(_index)); - } - uint32_t Offset() const override - { // Offset of the plane from where the pixel data starts in the buffer. - ASSERT(_parent != nullptr); - ASSERT(_parent->_storage != nullptr); - return (_parent->_storage->Offset(_index)); - } - - private: - CompositorBufferType* _parent; - uint8_t _index; - }; - - public: - Iterator() = delete; - Iterator(Iterator&&) = delete; - Iterator(const Iterator&) = delete; - Iterator& operator=(const Iterator&) = delete; - - Iterator(CompositorBufferType& parent) - : _parent(parent) - { - // Fill our elements - for (uint8_t index = 0; index < PLANES; index++) { - _planes[index].Define(_parent, index); - } - - Reset(); - } - ~Iterator() override = default; - - public: - bool IsValid() const override - { - return ((_position > 0) && (_position <= _parent.Planes())); - } - void Reset() override - { - _position = 0; - } - bool Next() override - { - if (_position <= _parent.Planes()) { - _position++; - } - return (IsValid()); - } - IPlane* Plane() override - { - ASSERT(IsValid() == true); - return (&(_planes[_position - 1])); - } - - private: - CompositorBufferType& _parent; - PlaneImplementation _planes[PLANES]; - uint8_t _position; - }; - - public: - CompositorBufferType() = delete; - CompositorBufferType(const CompositorBufferType&) = delete; - CompositorBufferType& operator=(const CompositorBufferType&) = delete; - - CompositorBufferType(const string& callsign, const uint32_t id, const uint32_t width, const uint32_t height, const uint32_t format, const uint64_t modifier, const Exchange::ICompositionBuffer::DataType type) - : _id(id) - , _planeCount(0) - , _iterator(*this) - , _virtualFd(-1) - , _eventFd(-1) - , _storage(nullptr) - { - string definition = _T("NotifiableBuffer") + callsign; - _virtualFd = ::memfd_create(definition.c_str(), MFD_ALLOW_SEALING | MFD_CLOEXEC); - if (_virtualFd != -1) { - int length = sizeof(struct SharedStorage); - - /* Size the file as specified by our struct. */ - if (::ftruncate(_virtualFd, length) != -1) { - /* map that file to a memory area we can directly access as a memory mapped file */ - _storage = new (_virtualFd) SharedStorage(width, height, format, modifier, type); - if (_storage != nullptr) { - _eventFd = ::eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK | EFD_SEMAPHORE); - } - } - } - } - CompositorBufferType(const uint32_t id, Core::PrivilegedRequest::Container& descriptors) - : _id(id) - , _planeCount(0) - , _iterator(*this) - , _virtualFd(-1) - , _eventFd(-1) - , _storage(nullptr) - { - ASSERT(descriptors.size() >= 3); - - if (descriptors.size() >= 3) { - Core::PrivilegedRequest::Container::iterator index(descriptors.begin()); - - _virtualFd = index->Move(); - index++; - - ASSERT(_virtualFd != -1); - - _storage = new (_virtualFd) SharedStorage(); - if (_storage == nullptr) { - ::close(_virtualFd); - } else { - _eventFd = index->Move(); - index++; - - ASSERT(_eventFd != -1); - - while ((index != descriptors.end()) && (_planeCount < PLANES)) { - _planes[_planeCount] = index->Move(); - index++; - _planeCount++; - } - } - } - } - ~CompositorBufferType() override - { - if (_eventFd != -1) { - ::close(_eventFd); - _eventFd = -1; - - ASSERT(_storage != nullptr); - } - if (_storage != nullptr) { - delete _storage; - _storage = nullptr; - } - if (_virtualFd != -1) { - ::close(_virtualFd); - _virtualFd = -1; - } - - // Close all the FileDescriptors handed over to us for the planes. - for (uint8_t index = 0; index < _planeCount; index++) { - ::close(_planes[index]); - } - } - - public: - bool IsValid() const - { - return (_eventFd != -1); - } - uint8_t Descriptors(const uint8_t maxSize, int container[]) const - { - ASSERT(IsValid() == true); - ASSERT(maxSize > 2); - uint8_t result = 0; - - if (maxSize > 2) { - container[0] = _virtualFd; - container[1] = _eventFd; - uint8_t count = std::min(_planeCount, static_cast(maxSize - 2)); - for (uint8_t index = 0; (index < count); index++) { - container[index + 2] = _planes[index]; - } - result = 2 + count; - } - return (result); - } - - // - // Implementation of Core::IResource - // ----------------------------------------------------------------- - handle Descriptor() const override - { - return (_eventFd); - } - uint16_t Events() override - { - return (POLLIN); - } - void Handle(const uint16_t events) override - { - EventFrame value; - - if (((events & POLLIN) != 0) && (::read(_eventFd, &value, sizeof(EventFrame)) == sizeof(EventFrame))) { - if (_storage->Dirty() == true) { - Render(); - } - } - } - - // - // Implementation of Exchange::ICompositionBuffer - // ----------------------------------------------------------------- - // Wait time in milliseconds. - IIterator* Planes(const uint32_t waitTimeInMs) override - { // Access to the buffer planes. - if (Lock(waitTimeInMs) == Core::ERROR_NONE) { - _iterator.Reset(); - return (&_iterator); - } - return (nullptr); - } - virtual uint32_t Completed(const bool dirty) - { - Unlock(); - if (dirty == true) { - EventFrame value = 1; - _storage->Set(); - size_t result = ::write(_eventFd, &value, sizeof(value)); - return (result != sizeof(value) ? Core::ERROR_ILLEGAL_STATE : Core::ERROR_NONE); - } - return (Core::ERROR_NONE); - } - - uint32_t Identifier() const override - { - return (_id); - } - uint32_t Width() const override - { // Width of the allocated buffer in pixels - ASSERT(_storage != nullptr); - return (_storage->Width()); - } - uint32_t Height() const override - { // Height of the allocated buffer in pixels - ASSERT(_storage != nullptr); - return (_storage->Height()); - } - uint32_t Format() const override - { // Layout of a pixel according the fourcc format - ASSERT(_storage != nullptr); - return (_storage->Format()); - } - uint64_t Modifier() const override - { // Pixel arrangement in the buffer, used to optimize for hardware - ASSERT(_storage != nullptr); - return (_storage->Modifier()); - } - Exchange::ICompositionBuffer::DataType Type() const override - { - ASSERT(_storage != nullptr); - return (_storage->Type()); - } - uint8_t Planes() const - { - return (_planeCount); - } - bool IsDirty() const - { - ASSERT(_storage != nullptr); - return (_storage->IsDirty()); - } - - protected: - void Add(int fd, const uint32_t stride, const uint32_t offset) - { - ASSERT(fd > 0); - ASSERT((_planeCount + 1) <= PLANES); - _storage->Add(_planeCount, stride, offset); - _planes[_planeCount] = ::dup(fd); - _planeCount++; - } - - private: - buffer_id Accessor(const uint8_t index) const - { // Access to the actual data. - ASSERT(index < _planeCount); - return (_planes[index]); - } - uint32_t Lock(const uint32_t timeout) - { - return (_storage->Lock(timeout)); - } - uint32_t Unlock() - { - return (_storage->Unlock()); - } - - private: - uint32_t _id; - uint8_t _planeCount; - Iterator _iterator; - - // We need a descriptor that is pointing to the virtual memory (shared memory) - int _virtualFd; - - // We need a descriptor we can wait for and that can be signalled - int _eventFd; - - // From the virtual memory we can map the shared data to a memory area in "our" process. - SharedStorage* _storage; - - int _planes[PLANES]; - }; - -} -}