From eedcece169c0173f99a6346c967dcf306bd41188 Mon Sep 17 00:00:00 2001 From: jyong15 Date: Tue, 15 Apr 2025 13:19:32 +0800 Subject: [PATCH 01/13] DEV-221 Initial commit --- Shimmer.xcworkspace/contents.xcworkspacedata | 3 + ShimmerBLEGrpc/Package.resolved | 159 ++ ShimmerBLEGrpc/Package.swift | 43 + ShimmerBLEGrpc/Readme.md | 2 + .../ShimmerBLEGrpc.xcodeproj/project.pbxproj | 467 +++++ .../xcschemes/ShimmerBLEGrpc.xcscheme | 85 + ShimmerBLEGrpc/Sources/HelloWorld.swift | 26 + ...himmerBLEGrpcAndPacketByteArray.grpc.swift | 1565 +++++++++++++++++ .../ShimmerBLEGrpcAndPacketByteArray.pb.swift | 445 +++++ .../Sources/ShimmerBLEService.swift | 207 +++ .../Sources/Subcommands/Serve.swift | 97 + .../project.pbxproj | 4 + .../ShimmerBluetooth/BleByteRadio.swift | 8 + .../ShimmerBluetooth/ConcurrentQueue.swift | 46 + 14 files changed, 3157 insertions(+) create mode 100644 ShimmerBLEGrpc/Package.resolved create mode 100644 ShimmerBLEGrpc/Package.swift create mode 100644 ShimmerBLEGrpc/Readme.md create mode 100644 ShimmerBLEGrpc/ShimmerBLEGrpc.xcodeproj/project.pbxproj create mode 100644 ShimmerBLEGrpc/ShimmerBLEGrpc.xcodeproj/xcshareddata/xcschemes/ShimmerBLEGrpc.xcscheme create mode 100644 ShimmerBLEGrpc/Sources/HelloWorld.swift create mode 100644 ShimmerBLEGrpc/Sources/Protos/ShimmerBLEGrpcAndPacketByteArray.grpc.swift create mode 100644 ShimmerBLEGrpc/Sources/Protos/ShimmerBLEGrpcAndPacketByteArray.pb.swift create mode 100644 ShimmerBLEGrpc/Sources/ShimmerBLEService.swift create mode 100644 ShimmerBLEGrpc/Sources/Subcommands/Serve.swift create mode 100644 ShimmerBluetooth/ShimmerBluetooth/ConcurrentQueue.swift diff --git a/Shimmer.xcworkspace/contents.xcworkspacedata b/Shimmer.xcworkspace/contents.xcworkspacedata index 2d8f159..45b57e2 100644 --- a/Shimmer.xcworkspace/contents.xcworkspacedata +++ b/Shimmer.xcworkspace/contents.xcworkspacedata @@ -1,6 +1,9 @@ + + diff --git a/ShimmerBLEGrpc/Package.resolved b/ShimmerBLEGrpc/Package.resolved new file mode 100644 index 0000000..3fa9cb0 --- /dev/null +++ b/ShimmerBLEGrpc/Package.resolved @@ -0,0 +1,159 @@ +{ + "originHash" : "2587735e4e75b1e7432b81355b6e9f6393d7831ce12d12f713d63e706b91fc9c", + "pins" : [ + { + "identity" : "grpc-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/grpc/grpc-swift.git", + "state" : { + "revision" : "c4d6281784f50bf2e60d3af45e83be1194056062", + "version" : "2.1.2" + } + }, + { + "identity" : "grpc-swift-nio-transport", + "kind" : "remoteSourceControl", + "location" : "https://github.com/grpc/grpc-swift-nio-transport.git", + "state" : { + "revision" : "9bd1b5b5e31f3fae497e84c2806777899183679b", + "version" : "1.0.3" + } + }, + { + "identity" : "grpc-swift-protobuf", + "kind" : "remoteSourceControl", + "location" : "https://github.com/grpc/grpc-swift-protobuf.git", + "state" : { + "revision" : "63982ca29f11d2c6a7e559c1899fee812dd55cd9", + "version" : "1.1.0" + } + }, + { + "identity" : "swift-algorithms", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-algorithms.git", + "state" : { + "revision" : "87e50f483c54e6efd60e885f7f5aa946cee68023", + "version" : "1.2.1" + } + }, + { + "identity" : "swift-argument-parser", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-argument-parser.git", + "state" : { + "revision" : "41982a3656a71c768319979febd796c6fd111d5c", + "version" : "1.5.0" + } + }, + { + "identity" : "swift-atomics", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-atomics.git", + "state" : { + "revision" : "cd142fd2f64be2100422d658e7411e39489da985", + "version" : "1.2.0" + } + }, + { + "identity" : "swift-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-collections.git", + "state" : { + "revision" : "671108c96644956dddcd89dd59c203dcdb36cec7", + "version" : "1.1.4" + } + }, + { + "identity" : "swift-http-structured-headers", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-http-structured-headers.git", + "state" : { + "revision" : "8e769facea6b7d46ea60e5e93635a384fd573480", + "version" : "1.2.1" + } + }, + { + "identity" : "swift-http-types", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-http-types.git", + "state" : { + "revision" : "a0a57e949a8903563aba4615869310c0ebf14c03", + "version" : "1.4.0" + } + }, + { + "identity" : "swift-nio", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio.git", + "state" : { + "revision" : "c51907a839e63ebf0ba2076bba73dd96436bd1b9", + "version" : "2.81.0" + } + }, + { + "identity" : "swift-nio-extras", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio-extras.git", + "state" : { + "revision" : "00f3f72d2f9942d0e2dc96057ab50a37ced150d4", + "version" : "1.25.0" + } + }, + { + "identity" : "swift-nio-http2", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio-http2.git", + "state" : { + "revision" : "170f4ca06b6a9c57b811293cebcb96e81b661310", + "version" : "1.35.0" + } + }, + { + "identity" : "swift-nio-ssl", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio-ssl.git", + "state" : { + "revision" : "0cc3528ff48129d64ab9cab0b1cd621634edfc6b", + "version" : "2.29.3" + } + }, + { + "identity" : "swift-nio-transport-services", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio-transport-services.git", + "state" : { + "revision" : "3c394067c08d1225ba8442e9cffb520ded417b64", + "version" : "1.23.1" + } + }, + { + "identity" : "swift-numerics", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-numerics.git", + "state" : { + "revision" : "e0ec0f5f3af6f3e4d5e7a19d2af26b481acb6ba8", + "version" : "1.0.3" + } + }, + { + "identity" : "swift-protobuf", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-protobuf.git", + "state" : { + "revision" : "d72aed98f8253ec1aa9ea1141e28150f408cf17f", + "version" : "1.29.0" + } + }, + { + "identity" : "swift-system", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-system.git", + "state" : { + "revision" : "a34201439c74b53f0fd71ef11741af7e7caf01e1", + "version" : "1.4.2" + } + } + ], + "version" : 3 +} diff --git a/ShimmerBLEGrpc/Package.swift b/ShimmerBLEGrpc/Package.swift new file mode 100644 index 0000000..daa71a5 --- /dev/null +++ b/ShimmerBLEGrpc/Package.swift @@ -0,0 +1,43 @@ +// swift-tools-version:6.0 +/* + * Copyright 2024, gRPC Authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import PackageDescription + +let package = Package( + name: "hello-world", + platforms: [.macOS("15.0")], + dependencies: [ + .package(url: "https://github.com/grpc/grpc-swift.git", from: "2.0.0"), + .package(url: "https://github.com/grpc/grpc-swift-protobuf.git", from: "1.0.0"), + .package(url: "https://github.com/grpc/grpc-swift-nio-transport.git", from: "1.0.0"), + .package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.5.0"), + ], + targets: [ + .executableTarget( + name: "hello-world", + dependencies: [ + .product(name: "GRPCCore", package: "grpc-swift"), + .product(name: "GRPCNIOTransportHTTP2", package: "grpc-swift-nio-transport"), + .product(name: "GRPCProtobuf", package: "grpc-swift-protobuf"), + .product(name: "ArgumentParser", package: "swift-argument-parser"), + ], + plugins: [ + .plugin(name: "GRPCProtobufGenerator", package: "grpc-swift-protobuf") + ] + ) + ] +) diff --git a/ShimmerBLEGrpc/Readme.md b/ShimmerBLEGrpc/Readme.md new file mode 100644 index 0000000..2799f48 --- /dev/null +++ b/ShimmerBLEGrpc/Readme.md @@ -0,0 +1,2 @@ +To run the BLE gRPC server, open the Mac Terminal to this folder. +Then, run the following: diff --git a/ShimmerBLEGrpc/ShimmerBLEGrpc.xcodeproj/project.pbxproj b/ShimmerBLEGrpc/ShimmerBLEGrpc.xcodeproj/project.pbxproj new file mode 100644 index 0000000..5c6ca80 --- /dev/null +++ b/ShimmerBLEGrpc/ShimmerBLEGrpc.xcodeproj/project.pbxproj @@ -0,0 +1,467 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 77; + objects = { + +/* Begin PBXBuildFile section */ + 45345ACA2DA62FA100EA7B41 /* ShimmerBluetooth.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 45345AC92DA62FA100EA7B41 /* ShimmerBluetooth.framework */; }; + 45345ACB2DA62FA100EA7B41 /* ShimmerBluetooth.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 45345AC92DA62FA100EA7B41 /* ShimmerBluetooth.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 45345ACF2DA6361500EA7B41 /* SwiftProtobuf in Frameworks */ = {isa = PBXBuildFile; productRef = 45345ACE2DA6361500EA7B41 /* SwiftProtobuf */; }; + 45345AD12DA6361500EA7B41 /* SwiftProtobufPluginLibrary in Frameworks */ = {isa = PBXBuildFile; productRef = 45345AD02DA6361500EA7B41 /* SwiftProtobufPluginLibrary */; }; + 45345AEA2DA6399900EA7B41 /* GRPCCodeGen in Frameworks */ = {isa = PBXBuildFile; productRef = 45345AE92DA6399900EA7B41 /* GRPCCodeGen */; }; + 45345AEC2DA6399900EA7B41 /* GRPCCore in Frameworks */ = {isa = PBXBuildFile; productRef = 45345AEB2DA6399900EA7B41 /* GRPCCore */; }; + 45345AEE2DA6399900EA7B41 /* GRPCInProcessTransport in Frameworks */ = {isa = PBXBuildFile; productRef = 45345AED2DA6399900EA7B41 /* GRPCInProcessTransport */; }; + 45345AF12DA639C300EA7B41 /* GRPCProtobuf in Frameworks */ = {isa = PBXBuildFile; productRef = 45345AF02DA639C300EA7B41 /* GRPCProtobuf */; }; + 45345AF42DA639F300EA7B41 /* GRPCNIOTransportHTTP2 in Frameworks */ = {isa = PBXBuildFile; productRef = 45345AF32DA639F300EA7B41 /* GRPCNIOTransportHTTP2 */; }; + 45345AF62DA639F300EA7B41 /* GRPCNIOTransportHTTP2Posix in Frameworks */ = {isa = PBXBuildFile; productRef = 45345AF52DA639F300EA7B41 /* GRPCNIOTransportHTTP2Posix */; }; + 45345AF82DA639F300EA7B41 /* GRPCNIOTransportHTTP2TransportServices in Frameworks */ = {isa = PBXBuildFile; productRef = 45345AF72DA639F300EA7B41 /* GRPCNIOTransportHTTP2TransportServices */; }; + 45345AFB2DA63A1100EA7B41 /* ArgumentParser in Frameworks */ = {isa = PBXBuildFile; productRef = 45345AFA2DA63A1100EA7B41 /* ArgumentParser */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 45345ACC2DA62FA100EA7B41 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 45345ACB2DA62FA100EA7B41 /* ShimmerBluetooth.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; + 456851932DA395630047A883 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 45345AB62DA4F12500EA7B41 /* Readme.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Readme.md; sourceTree = ""; }; + 45345AC22DA62CD700EA7B41 /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; + 45345AC92DA62FA100EA7B41 /* ShimmerBluetooth.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = ShimmerBluetooth.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 456851952DA395630047A883 /* ShimmerBLEGrpc */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ShimmerBLEGrpc; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFileSystemSynchronizedRootGroup section */ + 45345AAF2DA4F0EF00EA7B41 /* Sources */ = { + isa = PBXFileSystemSynchronizedRootGroup; + path = Sources; + sourceTree = ""; + }; +/* End PBXFileSystemSynchronizedRootGroup section */ + +/* Begin PBXFrameworksBuildPhase section */ + 456851922DA395630047A883 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 45345AF12DA639C300EA7B41 /* GRPCProtobuf in Frameworks */, + 45345AFB2DA63A1100EA7B41 /* ArgumentParser in Frameworks */, + 45345AEA2DA6399900EA7B41 /* GRPCCodeGen in Frameworks */, + 45345AD12DA6361500EA7B41 /* SwiftProtobufPluginLibrary in Frameworks */, + 45345AEC2DA6399900EA7B41 /* GRPCCore in Frameworks */, + 45345AF62DA639F300EA7B41 /* GRPCNIOTransportHTTP2Posix in Frameworks */, + 45345ACA2DA62FA100EA7B41 /* ShimmerBluetooth.framework in Frameworks */, + 45345ACF2DA6361500EA7B41 /* SwiftProtobuf in Frameworks */, + 45345AF42DA639F300EA7B41 /* GRPCNIOTransportHTTP2 in Frameworks */, + 45345AF82DA639F300EA7B41 /* GRPCNIOTransportHTTP2TransportServices in Frameworks */, + 45345AEE2DA6399900EA7B41 /* GRPCInProcessTransport in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 45345AC82DA62FA100EA7B41 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 45345AC92DA62FA100EA7B41 /* ShimmerBluetooth.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 4568518C2DA395630047A883 = { + isa = PBXGroup; + children = ( + 45345AC22DA62CD700EA7B41 /* Package.swift */, + 45345AB62DA4F12500EA7B41 /* Readme.md */, + 45345AAF2DA4F0EF00EA7B41 /* Sources */, + 45345AC82DA62FA100EA7B41 /* Frameworks */, + 456851962DA395630047A883 /* Products */, + ); + sourceTree = ""; + }; + 456851962DA395630047A883 /* Products */ = { + isa = PBXGroup; + children = ( + 456851952DA395630047A883 /* ShimmerBLEGrpc */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 456851942DA395630047A883 /* ShimmerBLEGrpc */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4568519C2DA395630047A883 /* Build configuration list for PBXNativeTarget "ShimmerBLEGrpc" */; + buildPhases = ( + 456851912DA395630047A883 /* Sources */, + 456851922DA395630047A883 /* Frameworks */, + 456851932DA395630047A883 /* CopyFiles */, + 45345ACC2DA62FA100EA7B41 /* Embed Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + fileSystemSynchronizedGroups = ( + 45345AAF2DA4F0EF00EA7B41 /* Sources */, + ); + name = ShimmerBLEGrpc; + packageProductDependencies = ( + 45345ACE2DA6361500EA7B41 /* SwiftProtobuf */, + 45345AD02DA6361500EA7B41 /* SwiftProtobufPluginLibrary */, + 45345AE92DA6399900EA7B41 /* GRPCCodeGen */, + 45345AEB2DA6399900EA7B41 /* GRPCCore */, + 45345AED2DA6399900EA7B41 /* GRPCInProcessTransport */, + 45345AF02DA639C300EA7B41 /* GRPCProtobuf */, + 45345AF32DA639F300EA7B41 /* GRPCNIOTransportHTTP2 */, + 45345AF52DA639F300EA7B41 /* GRPCNIOTransportHTTP2Posix */, + 45345AF72DA639F300EA7B41 /* GRPCNIOTransportHTTP2TransportServices */, + 45345AFA2DA63A1100EA7B41 /* ArgumentParser */, + ); + productName = ShimmerBLEGrpc; + productReference = 456851952DA395630047A883 /* ShimmerBLEGrpc */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 4568518D2DA395630047A883 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1610; + LastUpgradeCheck = 1610; + TargetAttributes = { + 456851942DA395630047A883 = { + CreatedOnToolsVersion = 16.1; + }; + }; + }; + buildConfigurationList = 456851902DA395630047A883 /* Build configuration list for PBXProject "ShimmerBLEGrpc" */; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 4568518C2DA395630047A883; + minimizedProjectReferenceProxies = 1; + packageReferences = ( + 45345ACD2DA6361500EA7B41 /* XCRemoteSwiftPackageReference "swift-protobuf" */, + 45345AE82DA6399900EA7B41 /* XCRemoteSwiftPackageReference "grpc-swift" */, + 45345AEF2DA639C300EA7B41 /* XCRemoteSwiftPackageReference "grpc-swift-protobuf" */, + 45345AF22DA639F300EA7B41 /* XCRemoteSwiftPackageReference "grpc-swift-nio-transport" */, + 45345AF92DA63A1100EA7B41 /* XCRemoteSwiftPackageReference "swift-argument-parser" */, + ); + preferredProjectObjectVersion = 77; + productRefGroup = 456851962DA395630047A883 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 456851942DA395630047A883 /* ShimmerBLEGrpc */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 456851912DA395630047A883 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 4568519A2DA395630047A883 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 15.1; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 4568519B2DA395630047A883 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 15.1; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + }; + name = Release; + }; + 4568519D2DA395630047A883 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; + CODE_SIGN_STYLE = Manual; + DEVELOPMENT_TEAM = ""; + "DEVELOPMENT_TEAM[sdk=macosx*]" = ""; + ENABLE_HARDENED_RUNTIME = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.shimmersensing.ShimmerBLEGrpc; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 4568519E2DA395630047A883 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; + CODE_SIGN_STYLE = Manual; + DEVELOPMENT_TEAM = ""; + "DEVELOPMENT_TEAM[sdk=macosx*]" = ""; + ENABLE_HARDENED_RUNTIME = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.shimmersensing.ShimmerBLEGrpc; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 456851902DA395630047A883 /* Build configuration list for PBXProject "ShimmerBLEGrpc" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4568519A2DA395630047A883 /* Debug */, + 4568519B2DA395630047A883 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4568519C2DA395630047A883 /* Build configuration list for PBXNativeTarget "ShimmerBLEGrpc" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4568519D2DA395630047A883 /* Debug */, + 4568519E2DA395630047A883 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + 45345ACD2DA6361500EA7B41 /* XCRemoteSwiftPackageReference "swift-protobuf" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/apple/swift-protobuf.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.29.0; + }; + }; + 45345AE82DA6399900EA7B41 /* XCRemoteSwiftPackageReference "grpc-swift" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/grpc/grpc-swift.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 2.1.2; + }; + }; + 45345AEF2DA639C300EA7B41 /* XCRemoteSwiftPackageReference "grpc-swift-protobuf" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/grpc/grpc-swift-protobuf.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.1.0; + }; + }; + 45345AF22DA639F300EA7B41 /* XCRemoteSwiftPackageReference "grpc-swift-nio-transport" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/grpc/grpc-swift-nio-transport.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.0.3; + }; + }; + 45345AF92DA63A1100EA7B41 /* XCRemoteSwiftPackageReference "swift-argument-parser" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/apple/swift-argument-parser.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.5.0; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 45345ACE2DA6361500EA7B41 /* SwiftProtobuf */ = { + isa = XCSwiftPackageProductDependency; + package = 45345ACD2DA6361500EA7B41 /* XCRemoteSwiftPackageReference "swift-protobuf" */; + productName = SwiftProtobuf; + }; + 45345AD02DA6361500EA7B41 /* SwiftProtobufPluginLibrary */ = { + isa = XCSwiftPackageProductDependency; + package = 45345ACD2DA6361500EA7B41 /* XCRemoteSwiftPackageReference "swift-protobuf" */; + productName = SwiftProtobufPluginLibrary; + }; + 45345AE92DA6399900EA7B41 /* GRPCCodeGen */ = { + isa = XCSwiftPackageProductDependency; + package = 45345AE82DA6399900EA7B41 /* XCRemoteSwiftPackageReference "grpc-swift" */; + productName = GRPCCodeGen; + }; + 45345AEB2DA6399900EA7B41 /* GRPCCore */ = { + isa = XCSwiftPackageProductDependency; + package = 45345AE82DA6399900EA7B41 /* XCRemoteSwiftPackageReference "grpc-swift" */; + productName = GRPCCore; + }; + 45345AED2DA6399900EA7B41 /* GRPCInProcessTransport */ = { + isa = XCSwiftPackageProductDependency; + package = 45345AE82DA6399900EA7B41 /* XCRemoteSwiftPackageReference "grpc-swift" */; + productName = GRPCInProcessTransport; + }; + 45345AF02DA639C300EA7B41 /* GRPCProtobuf */ = { + isa = XCSwiftPackageProductDependency; + package = 45345AEF2DA639C300EA7B41 /* XCRemoteSwiftPackageReference "grpc-swift-protobuf" */; + productName = GRPCProtobuf; + }; + 45345AF32DA639F300EA7B41 /* GRPCNIOTransportHTTP2 */ = { + isa = XCSwiftPackageProductDependency; + package = 45345AF22DA639F300EA7B41 /* XCRemoteSwiftPackageReference "grpc-swift-nio-transport" */; + productName = GRPCNIOTransportHTTP2; + }; + 45345AF52DA639F300EA7B41 /* GRPCNIOTransportHTTP2Posix */ = { + isa = XCSwiftPackageProductDependency; + package = 45345AF22DA639F300EA7B41 /* XCRemoteSwiftPackageReference "grpc-swift-nio-transport" */; + productName = GRPCNIOTransportHTTP2Posix; + }; + 45345AF72DA639F300EA7B41 /* GRPCNIOTransportHTTP2TransportServices */ = { + isa = XCSwiftPackageProductDependency; + package = 45345AF22DA639F300EA7B41 /* XCRemoteSwiftPackageReference "grpc-swift-nio-transport" */; + productName = GRPCNIOTransportHTTP2TransportServices; + }; + 45345AFA2DA63A1100EA7B41 /* ArgumentParser */ = { + isa = XCSwiftPackageProductDependency; + package = 45345AF92DA63A1100EA7B41 /* XCRemoteSwiftPackageReference "swift-argument-parser" */; + productName = ArgumentParser; + }; +/* End XCSwiftPackageProductDependency section */ + }; + rootObject = 4568518D2DA395630047A883 /* Project object */; +} diff --git a/ShimmerBLEGrpc/ShimmerBLEGrpc.xcodeproj/xcshareddata/xcschemes/ShimmerBLEGrpc.xcscheme b/ShimmerBLEGrpc/ShimmerBLEGrpc.xcodeproj/xcshareddata/xcschemes/ShimmerBLEGrpc.xcscheme new file mode 100644 index 0000000..6561201 --- /dev/null +++ b/ShimmerBLEGrpc/ShimmerBLEGrpc.xcodeproj/xcshareddata/xcschemes/ShimmerBLEGrpc.xcscheme @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ShimmerBLEGrpc/Sources/HelloWorld.swift b/ShimmerBLEGrpc/Sources/HelloWorld.swift new file mode 100644 index 0000000..31afbae --- /dev/null +++ b/ShimmerBLEGrpc/Sources/HelloWorld.swift @@ -0,0 +1,26 @@ +/* + * Copyright 2024, gRPC Authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import ArgumentParser + +@main +struct HelloWorld: AsyncParsableCommand { + static let configuration = CommandConfiguration( + commandName: "hello-world", + abstract: "A multi-tool to run a greeter server and execute RPCs against it.", + subcommands: [Serve.self] + ) +} diff --git a/ShimmerBLEGrpc/Sources/Protos/ShimmerBLEGrpcAndPacketByteArray.grpc.swift b/ShimmerBLEGrpc/Sources/Protos/ShimmerBLEGrpcAndPacketByteArray.grpc.swift new file mode 100644 index 0000000..a0dcbff --- /dev/null +++ b/ShimmerBLEGrpc/Sources/Protos/ShimmerBLEGrpcAndPacketByteArray.grpc.swift @@ -0,0 +1,1565 @@ +///using +///protoc-3.13.0-win64 +///protoc-gen-grpc-java-1.32.1-windows-x86_64.exe +///.nuget\packages\grpc.tools\2.34.0\tools\windows_x64\grpc_csharp_plugin.exe + +// DO NOT EDIT. +// swift-format-ignore-file +// +// Generated by the gRPC Swift generator plugin for the protocol buffer compiler. +// Source: ShimmerBLEGrpcAndPacketByteArray.proto +// +// For information on using the generated types, please see the documentation: +// https://github.com/grpc/grpc-swift + +import GRPCCore +import GRPCProtobuf + +// MARK: - shimmerBLEGRPC.ShimmerBLEByteServer + +/// Namespace containing generated types for the "shimmerBLEGRPC.ShimmerBLEByteServer" service. +internal enum ShimmerBLEGRPC_ShimmerBLEByteServer { + /// Service descriptor for the "shimmerBLEGRPC.ShimmerBLEByteServer" service. + internal static let descriptor = GRPCCore.ServiceDescriptor(fullyQualifiedService: "shimmerBLEGRPC.ShimmerBLEByteServer") + /// Namespace for method metadata. + internal enum Method { + /// Namespace for "GetDataStream" metadata. + internal enum GetDataStream { + /// Request type for "GetDataStream". + internal typealias Input = ShimmerBLEGRPC_StreamRequest + /// Response type for "GetDataStream". + internal typealias Output = ShimmerBLEGRPC_ObjectClusterByteArray + /// Descriptor for "GetDataStream". + internal static let descriptor = GRPCCore.MethodDescriptor( + service: GRPCCore.ServiceDescriptor(fullyQualifiedService: "shimmerBLEGRPC.ShimmerBLEByteServer"), + method: "GetDataStream" + ) + } + /// Namespace for "GetTestDataStream" metadata. + internal enum GetTestDataStream { + /// Request type for "GetTestDataStream". + internal typealias Input = ShimmerBLEGRPC_StreamRequest + /// Response type for "GetTestDataStream". + internal typealias Output = ShimmerBLEGRPC_ObjectClusterByteArray + /// Descriptor for "GetTestDataStream". + internal static let descriptor = GRPCCore.MethodDescriptor( + service: GRPCCore.ServiceDescriptor(fullyQualifiedService: "shimmerBLEGRPC.ShimmerBLEByteServer"), + method: "GetTestDataStream" + ) + } + /// Namespace for "SendDataStream" metadata. + internal enum SendDataStream { + /// Request type for "SendDataStream". + internal typealias Input = ShimmerBLEGRPC_ObjectClusterByteArray + /// Response type for "SendDataStream". + internal typealias Output = ShimmerBLEGRPC_Reply + /// Descriptor for "SendDataStream". + internal static let descriptor = GRPCCore.MethodDescriptor( + service: GRPCCore.ServiceDescriptor(fullyQualifiedService: "shimmerBLEGRPC.ShimmerBLEByteServer"), + method: "SendDataStream" + ) + } + /// Namespace for "ConnectShimmer" metadata. + internal enum ConnectShimmer { + /// Request type for "ConnectShimmer". + internal typealias Input = ShimmerBLEGRPC_Request + /// Response type for "ConnectShimmer". + internal typealias Output = ShimmerBLEGRPC_StateStatus + /// Descriptor for "ConnectShimmer". + internal static let descriptor = GRPCCore.MethodDescriptor( + service: GRPCCore.ServiceDescriptor(fullyQualifiedService: "shimmerBLEGRPC.ShimmerBLEByteServer"), + method: "ConnectShimmer" + ) + } + /// Namespace for "DisconnectShimmer" metadata. + internal enum DisconnectShimmer { + /// Request type for "DisconnectShimmer". + internal typealias Input = ShimmerBLEGRPC_Request + /// Response type for "DisconnectShimmer". + internal typealias Output = ShimmerBLEGRPC_Reply + /// Descriptor for "DisconnectShimmer". + internal static let descriptor = GRPCCore.MethodDescriptor( + service: GRPCCore.ServiceDescriptor(fullyQualifiedService: "shimmerBLEGRPC.ShimmerBLEByteServer"), + method: "DisconnectShimmer" + ) + } + /// Namespace for "WriteBytesShimmer" metadata. + internal enum WriteBytesShimmer { + /// Request type for "WriteBytesShimmer". + internal typealias Input = ShimmerBLEGRPC_WriteBytes + /// Response type for "WriteBytesShimmer". + internal typealias Output = ShimmerBLEGRPC_Reply + /// Descriptor for "WriteBytesShimmer". + internal static let descriptor = GRPCCore.MethodDescriptor( + service: GRPCCore.ServiceDescriptor(fullyQualifiedService: "shimmerBLEGRPC.ShimmerBLEByteServer"), + method: "WriteBytesShimmer" + ) + } + /// Namespace for "SayHello" metadata. + internal enum SayHello { + /// Request type for "SayHello". + internal typealias Input = ShimmerBLEGRPC_Request + /// Response type for "SayHello". + internal typealias Output = ShimmerBLEGRPC_Reply + /// Descriptor for "SayHello". + internal static let descriptor = GRPCCore.MethodDescriptor( + service: GRPCCore.ServiceDescriptor(fullyQualifiedService: "shimmerBLEGRPC.ShimmerBLEByteServer"), + method: "SayHello" + ) + } + /// Descriptors for all methods in the "shimmerBLEGRPC.ShimmerBLEByteServer" service. + internal static let descriptors: [GRPCCore.MethodDescriptor] = [ + GetDataStream.descriptor, + GetTestDataStream.descriptor, + SendDataStream.descriptor, + ConnectShimmer.descriptor, + DisconnectShimmer.descriptor, + WriteBytesShimmer.descriptor, + SayHello.descriptor + ] + } +} + +extension GRPCCore.ServiceDescriptor { + /// Service descriptor for the "shimmerBLEGRPC.ShimmerBLEByteServer" service. + internal static let shimmerBlegrpc_ShimmerBLEByteServer = GRPCCore.ServiceDescriptor(fullyQualifiedService: "shimmerBLEGRPC.ShimmerBLEByteServer") +} + +// MARK: shimmerBLEGRPC.ShimmerBLEByteServer (server) + +extension ShimmerBLEGRPC_ShimmerBLEByteServer { + /// Streaming variant of the service protocol for the "shimmerBLEGRPC.ShimmerBLEByteServer" service. + /// + /// This protocol is the lowest-level of the service protocols generated for this service + /// giving you the most flexibility over the implementation of your service. This comes at + /// the cost of more verbose and less strict APIs. Each RPC requires you to implement it in + /// terms of a request stream and response stream. Where only a single request or response + /// message is expected, you are responsible for enforcing this invariant is maintained. + /// + /// Where possible, prefer using the stricter, less-verbose ``ServiceProtocol`` + /// or ``SimpleServiceProtocol`` instead. + /// + /// > Source IDL Documentation: + /// > + /// > The greeter service definition. + internal protocol StreamingServiceProtocol: GRPCCore.RegistrableRPCService { + /// Handle the "GetDataStream" method. + /// + /// > Source IDL Documentation: + /// > + /// > lient asking for data + /// + /// - Parameters: + /// - request: A streaming request of `ShimmerBLEGRPC_StreamRequest` messages. + /// - context: Context providing information about the RPC. + /// - Throws: Any error which occurred during the processing of the request. Thrown errors + /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted + /// to an internal error. + /// - Returns: A streaming response of `ShimmerBLEGRPC_ObjectClusterByteArray` messages. + func getDataStream( + request: GRPCCore.StreamingServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.StreamingServerResponse + + /// Handle the "GetTestDataStream" method. + /// + /// > Source IDL Documentation: + /// > + /// > lient asking for data + /// + /// - Parameters: + /// - request: A streaming request of `ShimmerBLEGRPC_StreamRequest` messages. + /// - context: Context providing information about the RPC. + /// - Throws: Any error which occurred during the processing of the request. Thrown errors + /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted + /// to an internal error. + /// - Returns: A streaming response of `ShimmerBLEGRPC_ObjectClusterByteArray` messages. + func getTestDataStream( + request: GRPCCore.StreamingServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.StreamingServerResponse + + /// Handle the "SendDataStream" method. + /// + /// > Source IDL Documentation: + /// > + /// > lient sending data + /// + /// - Parameters: + /// - request: A streaming request of `ShimmerBLEGRPC_ObjectClusterByteArray` messages. + /// - context: Context providing information about the RPC. + /// - Throws: Any error which occurred during the processing of the request. Thrown errors + /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted + /// to an internal error. + /// - Returns: A streaming response of `ShimmerBLEGRPC_Reply` messages. + func sendDataStream( + request: GRPCCore.StreamingServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.StreamingServerResponse + + /// Handle the "ConnectShimmer" method. + /// + /// - Parameters: + /// - request: A streaming request of `ShimmerBLEGRPC_Request` messages. + /// - context: Context providing information about the RPC. + /// - Throws: Any error which occurred during the processing of the request. Thrown errors + /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted + /// to an internal error. + /// - Returns: A streaming response of `ShimmerBLEGRPC_StateStatus` messages. + func connectShimmer( + request: GRPCCore.StreamingServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.StreamingServerResponse + + /// Handle the "DisconnectShimmer" method. + /// + /// - Parameters: + /// - request: A streaming request of `ShimmerBLEGRPC_Request` messages. + /// - context: Context providing information about the RPC. + /// - Throws: Any error which occurred during the processing of the request. Thrown errors + /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted + /// to an internal error. + /// - Returns: A streaming response of `ShimmerBLEGRPC_Reply` messages. + func disconnectShimmer( + request: GRPCCore.StreamingServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.StreamingServerResponse + + /// Handle the "WriteBytesShimmer" method. + /// + /// - Parameters: + /// - request: A streaming request of `ShimmerBLEGRPC_WriteBytes` messages. + /// - context: Context providing information about the RPC. + /// - Throws: Any error which occurred during the processing of the request. Thrown errors + /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted + /// to an internal error. + /// - Returns: A streaming response of `ShimmerBLEGRPC_Reply` messages. + func writeBytesShimmer( + request: GRPCCore.StreamingServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.StreamingServerResponse + + /// Handle the "SayHello" method. + /// + /// - Parameters: + /// - request: A streaming request of `ShimmerBLEGRPC_Request` messages. + /// - context: Context providing information about the RPC. + /// - Throws: Any error which occurred during the processing of the request. Thrown errors + /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted + /// to an internal error. + /// - Returns: A streaming response of `ShimmerBLEGRPC_Reply` messages. + func sayHello( + request: GRPCCore.StreamingServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.StreamingServerResponse + } + + /// Service protocol for the "shimmerBLEGRPC.ShimmerBLEByteServer" service. + /// + /// This protocol is higher level than ``StreamingServiceProtocol`` but lower level than + /// the ``SimpleServiceProtocol``, it provides access to request and response metadata and + /// trailing response metadata. If you don't need these then consider using + /// the ``SimpleServiceProtocol``. If you need fine grained control over your RPCs then + /// use ``StreamingServiceProtocol``. + /// + /// > Source IDL Documentation: + /// > + /// > The greeter service definition. + internal protocol ServiceProtocol: ShimmerBLEGRPC_ShimmerBLEByteServer.StreamingServiceProtocol { + /// Handle the "GetDataStream" method. + /// + /// > Source IDL Documentation: + /// > + /// > lient asking for data + /// + /// - Parameters: + /// - request: A request containing a single `ShimmerBLEGRPC_StreamRequest` message. + /// - context: Context providing information about the RPC. + /// - Throws: Any error which occurred during the processing of the request. Thrown errors + /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted + /// to an internal error. + /// - Returns: A streaming response of `ShimmerBLEGRPC_ObjectClusterByteArray` messages. + func getDataStream( + request: GRPCCore.ServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.StreamingServerResponse + + /// Handle the "GetTestDataStream" method. + /// + /// > Source IDL Documentation: + /// > + /// > lient asking for data + /// + /// - Parameters: + /// - request: A request containing a single `ShimmerBLEGRPC_StreamRequest` message. + /// - context: Context providing information about the RPC. + /// - Throws: Any error which occurred during the processing of the request. Thrown errors + /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted + /// to an internal error. + /// - Returns: A streaming response of `ShimmerBLEGRPC_ObjectClusterByteArray` messages. + func getTestDataStream( + request: GRPCCore.ServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.StreamingServerResponse + + /// Handle the "SendDataStream" method. + /// + /// > Source IDL Documentation: + /// > + /// > lient sending data + /// + /// - Parameters: + /// - request: A streaming request of `ShimmerBLEGRPC_ObjectClusterByteArray` messages. + /// - context: Context providing information about the RPC. + /// - Throws: Any error which occurred during the processing of the request. Thrown errors + /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted + /// to an internal error. + /// - Returns: A response containing a single `ShimmerBLEGRPC_Reply` message. + func sendDataStream( + request: GRPCCore.StreamingServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse + + /// Handle the "ConnectShimmer" method. + /// + /// - Parameters: + /// - request: A request containing a single `ShimmerBLEGRPC_Request` message. + /// - context: Context providing information about the RPC. + /// - Throws: Any error which occurred during the processing of the request. Thrown errors + /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted + /// to an internal error. + /// - Returns: A streaming response of `ShimmerBLEGRPC_StateStatus` messages. + func connectShimmer( + request: GRPCCore.ServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.StreamingServerResponse + + /// Handle the "DisconnectShimmer" method. + /// + /// - Parameters: + /// - request: A request containing a single `ShimmerBLEGRPC_Request` message. + /// - context: Context providing information about the RPC. + /// - Throws: Any error which occurred during the processing of the request. Thrown errors + /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted + /// to an internal error. + /// - Returns: A response containing a single `ShimmerBLEGRPC_Reply` message. + func disconnectShimmer( + request: GRPCCore.ServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse + + /// Handle the "WriteBytesShimmer" method. + /// + /// - Parameters: + /// - request: A request containing a single `ShimmerBLEGRPC_WriteBytes` message. + /// - context: Context providing information about the RPC. + /// - Throws: Any error which occurred during the processing of the request. Thrown errors + /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted + /// to an internal error. + /// - Returns: A response containing a single `ShimmerBLEGRPC_Reply` message. + func writeBytesShimmer( + request: GRPCCore.ServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse + + /// Handle the "SayHello" method. + /// + /// - Parameters: + /// - request: A request containing a single `ShimmerBLEGRPC_Request` message. + /// - context: Context providing information about the RPC. + /// - Throws: Any error which occurred during the processing of the request. Thrown errors + /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted + /// to an internal error. + /// - Returns: A response containing a single `ShimmerBLEGRPC_Reply` message. + func sayHello( + request: GRPCCore.ServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse + } + + /// Simple service protocol for the "shimmerBLEGRPC.ShimmerBLEByteServer" service. + /// + /// This is the highest level protocol for the service. The API is the easiest to use but + /// doesn't provide access to request or response metadata. If you need access to these + /// then use ``ServiceProtocol`` instead. + /// + /// > Source IDL Documentation: + /// > + /// > The greeter service definition. + internal protocol SimpleServiceProtocol: ShimmerBLEGRPC_ShimmerBLEByteServer.ServiceProtocol { + /// Handle the "GetDataStream" method. + /// + /// > Source IDL Documentation: + /// > + /// > lient asking for data + /// + /// - Parameters: + /// - request: A `ShimmerBLEGRPC_StreamRequest` message. + /// - response: A response stream of `ShimmerBLEGRPC_ObjectClusterByteArray` messages. + /// - context: Context providing information about the RPC. + /// - Throws: Any error which occurred during the processing of the request. Thrown errors + /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted + /// to an internal error. + func getDataStream( + request: ShimmerBLEGRPC_StreamRequest, + response: GRPCCore.RPCWriter, + context: GRPCCore.ServerContext + ) async throws + + /// Handle the "GetTestDataStream" method. + /// + /// > Source IDL Documentation: + /// > + /// > lient asking for data + /// + /// - Parameters: + /// - request: A `ShimmerBLEGRPC_StreamRequest` message. + /// - response: A response stream of `ShimmerBLEGRPC_ObjectClusterByteArray` messages. + /// - context: Context providing information about the RPC. + /// - Throws: Any error which occurred during the processing of the request. Thrown errors + /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted + /// to an internal error. + func getTestDataStream( + request: ShimmerBLEGRPC_StreamRequest, + response: GRPCCore.RPCWriter, + context: GRPCCore.ServerContext + ) async throws + + /// Handle the "SendDataStream" method. + /// + /// > Source IDL Documentation: + /// > + /// > lient sending data + /// + /// - Parameters: + /// - request: A stream of `ShimmerBLEGRPC_ObjectClusterByteArray` messages. + /// - context: Context providing information about the RPC. + /// - Throws: Any error which occurred during the processing of the request. Thrown errors + /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted + /// to an internal error. + /// - Returns: A `ShimmerBLEGRPC_Reply` to respond with. + func sendDataStream( + request: GRPCCore.RPCAsyncSequence, + context: GRPCCore.ServerContext + ) async throws -> ShimmerBLEGRPC_Reply + + /// Handle the "ConnectShimmer" method. + /// + /// - Parameters: + /// - request: A `ShimmerBLEGRPC_Request` message. + /// - response: A response stream of `ShimmerBLEGRPC_StateStatus` messages. + /// - context: Context providing information about the RPC. + /// - Throws: Any error which occurred during the processing of the request. Thrown errors + /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted + /// to an internal error. + func connectShimmer( + request: ShimmerBLEGRPC_Request, + response: GRPCCore.RPCWriter, + context: GRPCCore.ServerContext + ) async throws + + /// Handle the "DisconnectShimmer" method. + /// + /// - Parameters: + /// - request: A `ShimmerBLEGRPC_Request` message. + /// - context: Context providing information about the RPC. + /// - Throws: Any error which occurred during the processing of the request. Thrown errors + /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted + /// to an internal error. + /// - Returns: A `ShimmerBLEGRPC_Reply` to respond with. + func disconnectShimmer( + request: ShimmerBLEGRPC_Request, + context: GRPCCore.ServerContext + ) async throws -> ShimmerBLEGRPC_Reply + + /// Handle the "WriteBytesShimmer" method. + /// + /// - Parameters: + /// - request: A `ShimmerBLEGRPC_WriteBytes` message. + /// - context: Context providing information about the RPC. + /// - Throws: Any error which occurred during the processing of the request. Thrown errors + /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted + /// to an internal error. + /// - Returns: A `ShimmerBLEGRPC_Reply` to respond with. + func writeBytesShimmer( + request: ShimmerBLEGRPC_WriteBytes, + context: GRPCCore.ServerContext + ) async throws -> ShimmerBLEGRPC_Reply + + /// Handle the "SayHello" method. + /// + /// - Parameters: + /// - request: A `ShimmerBLEGRPC_Request` message. + /// - context: Context providing information about the RPC. + /// - Throws: Any error which occurred during the processing of the request. Thrown errors + /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted + /// to an internal error. + /// - Returns: A `ShimmerBLEGRPC_Reply` to respond with. + func sayHello( + request: ShimmerBLEGRPC_Request, + context: GRPCCore.ServerContext + ) async throws -> ShimmerBLEGRPC_Reply + } +} + +// Default implementation of 'registerMethods(with:)'. +extension ShimmerBLEGRPC_ShimmerBLEByteServer.StreamingServiceProtocol { + internal func registerMethods(with router: inout GRPCCore.RPCRouter) where Transport: GRPCCore.ServerTransport { + router.registerHandler( + forMethod: ShimmerBLEGRPC_ShimmerBLEByteServer.Method.GetDataStream.descriptor, + deserializer: GRPCProtobuf.ProtobufDeserializer(), + serializer: GRPCProtobuf.ProtobufSerializer(), + handler: { request, context in + try await self.getDataStream( + request: request, + context: context + ) + } + ) + router.registerHandler( + forMethod: ShimmerBLEGRPC_ShimmerBLEByteServer.Method.GetTestDataStream.descriptor, + deserializer: GRPCProtobuf.ProtobufDeserializer(), + serializer: GRPCProtobuf.ProtobufSerializer(), + handler: { request, context in + try await self.getTestDataStream( + request: request, + context: context + ) + } + ) + router.registerHandler( + forMethod: ShimmerBLEGRPC_ShimmerBLEByteServer.Method.SendDataStream.descriptor, + deserializer: GRPCProtobuf.ProtobufDeserializer(), + serializer: GRPCProtobuf.ProtobufSerializer(), + handler: { request, context in + try await self.sendDataStream( + request: request, + context: context + ) + } + ) + router.registerHandler( + forMethod: ShimmerBLEGRPC_ShimmerBLEByteServer.Method.ConnectShimmer.descriptor, + deserializer: GRPCProtobuf.ProtobufDeserializer(), + serializer: GRPCProtobuf.ProtobufSerializer(), + handler: { request, context in + try await self.connectShimmer( + request: request, + context: context + ) + } + ) + router.registerHandler( + forMethod: ShimmerBLEGRPC_ShimmerBLEByteServer.Method.DisconnectShimmer.descriptor, + deserializer: GRPCProtobuf.ProtobufDeserializer(), + serializer: GRPCProtobuf.ProtobufSerializer(), + handler: { request, context in + try await self.disconnectShimmer( + request: request, + context: context + ) + } + ) + router.registerHandler( + forMethod: ShimmerBLEGRPC_ShimmerBLEByteServer.Method.WriteBytesShimmer.descriptor, + deserializer: GRPCProtobuf.ProtobufDeserializer(), + serializer: GRPCProtobuf.ProtobufSerializer(), + handler: { request, context in + try await self.writeBytesShimmer( + request: request, + context: context + ) + } + ) + router.registerHandler( + forMethod: ShimmerBLEGRPC_ShimmerBLEByteServer.Method.SayHello.descriptor, + deserializer: GRPCProtobuf.ProtobufDeserializer(), + serializer: GRPCProtobuf.ProtobufSerializer(), + handler: { request, context in + try await self.sayHello( + request: request, + context: context + ) + } + ) + } +} + +// Default implementation of streaming methods from 'StreamingServiceProtocol'. +extension ShimmerBLEGRPC_ShimmerBLEByteServer.ServiceProtocol { + internal func getDataStream( + request: GRPCCore.StreamingServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.StreamingServerResponse { + let response = try await self.getDataStream( + request: GRPCCore.ServerRequest(stream: request), + context: context + ) + return response + } + + internal func getTestDataStream( + request: GRPCCore.StreamingServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.StreamingServerResponse { + let response = try await self.getTestDataStream( + request: GRPCCore.ServerRequest(stream: request), + context: context + ) + return response + } + + internal func sendDataStream( + request: GRPCCore.StreamingServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.StreamingServerResponse { + let response = try await self.sendDataStream( + request: request, + context: context + ) + return GRPCCore.StreamingServerResponse(single: response) + } + + internal func connectShimmer( + request: GRPCCore.StreamingServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.StreamingServerResponse { + let response = try await self.connectShimmer( + request: GRPCCore.ServerRequest(stream: request), + context: context + ) + return response + } + + internal func disconnectShimmer( + request: GRPCCore.StreamingServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.StreamingServerResponse { + let response = try await self.disconnectShimmer( + request: GRPCCore.ServerRequest(stream: request), + context: context + ) + return GRPCCore.StreamingServerResponse(single: response) + } + + internal func writeBytesShimmer( + request: GRPCCore.StreamingServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.StreamingServerResponse { + let response = try await self.writeBytesShimmer( + request: GRPCCore.ServerRequest(stream: request), + context: context + ) + return GRPCCore.StreamingServerResponse(single: response) + } + + internal func sayHello( + request: GRPCCore.StreamingServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.StreamingServerResponse { + let response = try await self.sayHello( + request: GRPCCore.ServerRequest(stream: request), + context: context + ) + return GRPCCore.StreamingServerResponse(single: response) + } +} + +// Default implementation of methods from 'ServiceProtocol'. +extension ShimmerBLEGRPC_ShimmerBLEByteServer.SimpleServiceProtocol { + internal func getDataStream( + request: GRPCCore.ServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.StreamingServerResponse { + return GRPCCore.StreamingServerResponse( + metadata: [:], + producer: { writer in + try await self.getDataStream( + request: request.message, + response: writer, + context: context + ) + return [:] + } + ) + } + + internal func getTestDataStream( + request: GRPCCore.ServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.StreamingServerResponse { + return GRPCCore.StreamingServerResponse( + metadata: [:], + producer: { writer in + try await self.getTestDataStream( + request: request.message, + response: writer, + context: context + ) + return [:] + } + ) + } + + internal func sendDataStream( + request: GRPCCore.StreamingServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse { + return GRPCCore.ServerResponse( + message: try await self.sendDataStream( + request: request.messages, + context: context + ), + metadata: [:] + ) + } + + internal func connectShimmer( + request: GRPCCore.ServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.StreamingServerResponse { + return GRPCCore.StreamingServerResponse( + metadata: [:], + producer: { writer in + try await self.connectShimmer( + request: request.message, + response: writer, + context: context + ) + return [:] + } + ) + } + + internal func disconnectShimmer( + request: GRPCCore.ServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse { + return GRPCCore.ServerResponse( + message: try await self.disconnectShimmer( + request: request.message, + context: context + ), + metadata: [:] + ) + } + + internal func writeBytesShimmer( + request: GRPCCore.ServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse { + return GRPCCore.ServerResponse( + message: try await self.writeBytesShimmer( + request: request.message, + context: context + ), + metadata: [:] + ) + } + + internal func sayHello( + request: GRPCCore.ServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse { + return GRPCCore.ServerResponse( + message: try await self.sayHello( + request: request.message, + context: context + ), + metadata: [:] + ) + } +} + +// MARK: shimmerBLEGRPC.ShimmerBLEByteServer (client) + +extension ShimmerBLEGRPC_ShimmerBLEByteServer { + /// Generated client protocol for the "shimmerBLEGRPC.ShimmerBLEByteServer" service. + /// + /// You don't need to implement this protocol directly, use the generated + /// implementation, ``Client``. + /// + /// > Source IDL Documentation: + /// > + /// > The greeter service definition. + internal protocol ClientProtocol: Sendable { + /// Call the "GetDataStream" method. + /// + /// > Source IDL Documentation: + /// > + /// > lient asking for data + /// + /// - Parameters: + /// - request: A request containing a single `ShimmerBLEGRPC_StreamRequest` message. + /// - serializer: A serializer for `ShimmerBLEGRPC_StreamRequest` messages. + /// - deserializer: A deserializer for `ShimmerBLEGRPC_ObjectClusterByteArray` messages. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + func getDataStream( + request: GRPCCore.ClientRequest, + serializer: some GRPCCore.MessageSerializer, + deserializer: some GRPCCore.MessageDeserializer, + options: GRPCCore.CallOptions, + onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> Result + ) async throws -> Result where Result: Sendable + + /// Call the "GetTestDataStream" method. + /// + /// > Source IDL Documentation: + /// > + /// > lient asking for data + /// + /// - Parameters: + /// - request: A request containing a single `ShimmerBLEGRPC_StreamRequest` message. + /// - serializer: A serializer for `ShimmerBLEGRPC_StreamRequest` messages. + /// - deserializer: A deserializer for `ShimmerBLEGRPC_ObjectClusterByteArray` messages. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + func getTestDataStream( + request: GRPCCore.ClientRequest, + serializer: some GRPCCore.MessageSerializer, + deserializer: some GRPCCore.MessageDeserializer, + options: GRPCCore.CallOptions, + onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> Result + ) async throws -> Result where Result: Sendable + + /// Call the "SendDataStream" method. + /// + /// > Source IDL Documentation: + /// > + /// > lient sending data + /// + /// - Parameters: + /// - request: A streaming request producing `ShimmerBLEGRPC_ObjectClusterByteArray` messages. + /// - serializer: A serializer for `ShimmerBLEGRPC_ObjectClusterByteArray` messages. + /// - deserializer: A deserializer for `ShimmerBLEGRPC_Reply` messages. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + func sendDataStream( + request: GRPCCore.StreamingClientRequest, + serializer: some GRPCCore.MessageSerializer, + deserializer: some GRPCCore.MessageDeserializer, + options: GRPCCore.CallOptions, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result + ) async throws -> Result where Result: Sendable + + /// Call the "ConnectShimmer" method. + /// + /// - Parameters: + /// - request: A request containing a single `ShimmerBLEGRPC_Request` message. + /// - serializer: A serializer for `ShimmerBLEGRPC_Request` messages. + /// - deserializer: A deserializer for `ShimmerBLEGRPC_StateStatus` messages. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + func connectShimmer( + request: GRPCCore.ClientRequest, + serializer: some GRPCCore.MessageSerializer, + deserializer: some GRPCCore.MessageDeserializer, + options: GRPCCore.CallOptions, + onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> Result + ) async throws -> Result where Result: Sendable + + /// Call the "DisconnectShimmer" method. + /// + /// - Parameters: + /// - request: A request containing a single `ShimmerBLEGRPC_Request` message. + /// - serializer: A serializer for `ShimmerBLEGRPC_Request` messages. + /// - deserializer: A deserializer for `ShimmerBLEGRPC_Reply` messages. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + func disconnectShimmer( + request: GRPCCore.ClientRequest, + serializer: some GRPCCore.MessageSerializer, + deserializer: some GRPCCore.MessageDeserializer, + options: GRPCCore.CallOptions, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result + ) async throws -> Result where Result: Sendable + + /// Call the "WriteBytesShimmer" method. + /// + /// - Parameters: + /// - request: A request containing a single `ShimmerBLEGRPC_WriteBytes` message. + /// - serializer: A serializer for `ShimmerBLEGRPC_WriteBytes` messages. + /// - deserializer: A deserializer for `ShimmerBLEGRPC_Reply` messages. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + func writeBytesShimmer( + request: GRPCCore.ClientRequest, + serializer: some GRPCCore.MessageSerializer, + deserializer: some GRPCCore.MessageDeserializer, + options: GRPCCore.CallOptions, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result + ) async throws -> Result where Result: Sendable + + /// Call the "SayHello" method. + /// + /// - Parameters: + /// - request: A request containing a single `ShimmerBLEGRPC_Request` message. + /// - serializer: A serializer for `ShimmerBLEGRPC_Request` messages. + /// - deserializer: A deserializer for `ShimmerBLEGRPC_Reply` messages. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + func sayHello( + request: GRPCCore.ClientRequest, + serializer: some GRPCCore.MessageSerializer, + deserializer: some GRPCCore.MessageDeserializer, + options: GRPCCore.CallOptions, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result + ) async throws -> Result where Result: Sendable + } + + /// Generated client for the "shimmerBLEGRPC.ShimmerBLEByteServer" service. + /// + /// The ``Client`` provides an implementation of ``ClientProtocol`` which wraps + /// a `GRPCCore.GRPCCClient`. The underlying `GRPCClient` provides the long-lived + /// means of communication with the remote peer. + /// + /// > Source IDL Documentation: + /// > + /// > The greeter service definition. + internal struct Client: ClientProtocol where Transport: GRPCCore.ClientTransport { + private let client: GRPCCore.GRPCClient + + /// Creates a new client wrapping the provided `GRPCCore.GRPCClient`. + /// + /// - Parameters: + /// - client: A `GRPCCore.GRPCClient` providing a communication channel to the service. + internal init(wrapping client: GRPCCore.GRPCClient) { + self.client = client + } + + /// Call the "GetDataStream" method. + /// + /// > Source IDL Documentation: + /// > + /// > lient asking for data + /// + /// - Parameters: + /// - request: A request containing a single `ShimmerBLEGRPC_StreamRequest` message. + /// - serializer: A serializer for `ShimmerBLEGRPC_StreamRequest` messages. + /// - deserializer: A deserializer for `ShimmerBLEGRPC_ObjectClusterByteArray` messages. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + internal func getDataStream( + request: GRPCCore.ClientRequest, + serializer: some GRPCCore.MessageSerializer, + deserializer: some GRPCCore.MessageDeserializer, + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> Result + ) async throws -> Result where Result: Sendable { + try await self.client.serverStreaming( + request: request, + descriptor: ShimmerBLEGRPC_ShimmerBLEByteServer.Method.GetDataStream.descriptor, + serializer: serializer, + deserializer: deserializer, + options: options, + onResponse: handleResponse + ) + } + + /// Call the "GetTestDataStream" method. + /// + /// > Source IDL Documentation: + /// > + /// > lient asking for data + /// + /// - Parameters: + /// - request: A request containing a single `ShimmerBLEGRPC_StreamRequest` message. + /// - serializer: A serializer for `ShimmerBLEGRPC_StreamRequest` messages. + /// - deserializer: A deserializer for `ShimmerBLEGRPC_ObjectClusterByteArray` messages. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + internal func getTestDataStream( + request: GRPCCore.ClientRequest, + serializer: some GRPCCore.MessageSerializer, + deserializer: some GRPCCore.MessageDeserializer, + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> Result + ) async throws -> Result where Result: Sendable { + try await self.client.serverStreaming( + request: request, + descriptor: ShimmerBLEGRPC_ShimmerBLEByteServer.Method.GetTestDataStream.descriptor, + serializer: serializer, + deserializer: deserializer, + options: options, + onResponse: handleResponse + ) + } + + /// Call the "SendDataStream" method. + /// + /// > Source IDL Documentation: + /// > + /// > lient sending data + /// + /// - Parameters: + /// - request: A streaming request producing `ShimmerBLEGRPC_ObjectClusterByteArray` messages. + /// - serializer: A serializer for `ShimmerBLEGRPC_ObjectClusterByteArray` messages. + /// - deserializer: A deserializer for `ShimmerBLEGRPC_Reply` messages. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + internal func sendDataStream( + request: GRPCCore.StreamingClientRequest, + serializer: some GRPCCore.MessageSerializer, + deserializer: some GRPCCore.MessageDeserializer, + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { response in + try response.message + } + ) async throws -> Result where Result: Sendable { + try await self.client.clientStreaming( + request: request, + descriptor: ShimmerBLEGRPC_ShimmerBLEByteServer.Method.SendDataStream.descriptor, + serializer: serializer, + deserializer: deserializer, + options: options, + onResponse: handleResponse + ) + } + + /// Call the "ConnectShimmer" method. + /// + /// - Parameters: + /// - request: A request containing a single `ShimmerBLEGRPC_Request` message. + /// - serializer: A serializer for `ShimmerBLEGRPC_Request` messages. + /// - deserializer: A deserializer for `ShimmerBLEGRPC_StateStatus` messages. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + internal func connectShimmer( + request: GRPCCore.ClientRequest, + serializer: some GRPCCore.MessageSerializer, + deserializer: some GRPCCore.MessageDeserializer, + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> Result + ) async throws -> Result where Result: Sendable { + try await self.client.serverStreaming( + request: request, + descriptor: ShimmerBLEGRPC_ShimmerBLEByteServer.Method.ConnectShimmer.descriptor, + serializer: serializer, + deserializer: deserializer, + options: options, + onResponse: handleResponse + ) + } + + /// Call the "DisconnectShimmer" method. + /// + /// - Parameters: + /// - request: A request containing a single `ShimmerBLEGRPC_Request` message. + /// - serializer: A serializer for `ShimmerBLEGRPC_Request` messages. + /// - deserializer: A deserializer for `ShimmerBLEGRPC_Reply` messages. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + internal func disconnectShimmer( + request: GRPCCore.ClientRequest, + serializer: some GRPCCore.MessageSerializer, + deserializer: some GRPCCore.MessageDeserializer, + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { response in + try response.message + } + ) async throws -> Result where Result: Sendable { + try await self.client.unary( + request: request, + descriptor: ShimmerBLEGRPC_ShimmerBLEByteServer.Method.DisconnectShimmer.descriptor, + serializer: serializer, + deserializer: deserializer, + options: options, + onResponse: handleResponse + ) + } + + /// Call the "WriteBytesShimmer" method. + /// + /// - Parameters: + /// - request: A request containing a single `ShimmerBLEGRPC_WriteBytes` message. + /// - serializer: A serializer for `ShimmerBLEGRPC_WriteBytes` messages. + /// - deserializer: A deserializer for `ShimmerBLEGRPC_Reply` messages. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + internal func writeBytesShimmer( + request: GRPCCore.ClientRequest, + serializer: some GRPCCore.MessageSerializer, + deserializer: some GRPCCore.MessageDeserializer, + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { response in + try response.message + } + ) async throws -> Result where Result: Sendable { + try await self.client.unary( + request: request, + descriptor: ShimmerBLEGRPC_ShimmerBLEByteServer.Method.WriteBytesShimmer.descriptor, + serializer: serializer, + deserializer: deserializer, + options: options, + onResponse: handleResponse + ) + } + + /// Call the "SayHello" method. + /// + /// - Parameters: + /// - request: A request containing a single `ShimmerBLEGRPC_Request` message. + /// - serializer: A serializer for `ShimmerBLEGRPC_Request` messages. + /// - deserializer: A deserializer for `ShimmerBLEGRPC_Reply` messages. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + internal func sayHello( + request: GRPCCore.ClientRequest, + serializer: some GRPCCore.MessageSerializer, + deserializer: some GRPCCore.MessageDeserializer, + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { response in + try response.message + } + ) async throws -> Result where Result: Sendable { + try await self.client.unary( + request: request, + descriptor: ShimmerBLEGRPC_ShimmerBLEByteServer.Method.SayHello.descriptor, + serializer: serializer, + deserializer: deserializer, + options: options, + onResponse: handleResponse + ) + } + } +} + +// Helpers providing default arguments to 'ClientProtocol' methods. +extension ShimmerBLEGRPC_ShimmerBLEByteServer.ClientProtocol { + /// Call the "GetDataStream" method. + /// + /// > Source IDL Documentation: + /// > + /// > lient asking for data + /// + /// - Parameters: + /// - request: A request containing a single `ShimmerBLEGRPC_StreamRequest` message. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + internal func getDataStream( + request: GRPCCore.ClientRequest, + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> Result + ) async throws -> Result where Result: Sendable { + try await self.getDataStream( + request: request, + serializer: GRPCProtobuf.ProtobufSerializer(), + deserializer: GRPCProtobuf.ProtobufDeserializer(), + options: options, + onResponse: handleResponse + ) + } + + /// Call the "GetTestDataStream" method. + /// + /// > Source IDL Documentation: + /// > + /// > lient asking for data + /// + /// - Parameters: + /// - request: A request containing a single `ShimmerBLEGRPC_StreamRequest` message. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + internal func getTestDataStream( + request: GRPCCore.ClientRequest, + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> Result + ) async throws -> Result where Result: Sendable { + try await self.getTestDataStream( + request: request, + serializer: GRPCProtobuf.ProtobufSerializer(), + deserializer: GRPCProtobuf.ProtobufDeserializer(), + options: options, + onResponse: handleResponse + ) + } + + /// Call the "SendDataStream" method. + /// + /// > Source IDL Documentation: + /// > + /// > lient sending data + /// + /// - Parameters: + /// - request: A streaming request producing `ShimmerBLEGRPC_ObjectClusterByteArray` messages. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + internal func sendDataStream( + request: GRPCCore.StreamingClientRequest, + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { response in + try response.message + } + ) async throws -> Result where Result: Sendable { + try await self.sendDataStream( + request: request, + serializer: GRPCProtobuf.ProtobufSerializer(), + deserializer: GRPCProtobuf.ProtobufDeserializer(), + options: options, + onResponse: handleResponse + ) + } + + /// Call the "ConnectShimmer" method. + /// + /// - Parameters: + /// - request: A request containing a single `ShimmerBLEGRPC_Request` message. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + internal func connectShimmer( + request: GRPCCore.ClientRequest, + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> Result + ) async throws -> Result where Result: Sendable { + try await self.connectShimmer( + request: request, + serializer: GRPCProtobuf.ProtobufSerializer(), + deserializer: GRPCProtobuf.ProtobufDeserializer(), + options: options, + onResponse: handleResponse + ) + } + + /// Call the "DisconnectShimmer" method. + /// + /// - Parameters: + /// - request: A request containing a single `ShimmerBLEGRPC_Request` message. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + internal func disconnectShimmer( + request: GRPCCore.ClientRequest, + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { response in + try response.message + } + ) async throws -> Result where Result: Sendable { + try await self.disconnectShimmer( + request: request, + serializer: GRPCProtobuf.ProtobufSerializer(), + deserializer: GRPCProtobuf.ProtobufDeserializer(), + options: options, + onResponse: handleResponse + ) + } + + /// Call the "WriteBytesShimmer" method. + /// + /// - Parameters: + /// - request: A request containing a single `ShimmerBLEGRPC_WriteBytes` message. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + internal func writeBytesShimmer( + request: GRPCCore.ClientRequest, + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { response in + try response.message + } + ) async throws -> Result where Result: Sendable { + try await self.writeBytesShimmer( + request: request, + serializer: GRPCProtobuf.ProtobufSerializer(), + deserializer: GRPCProtobuf.ProtobufDeserializer(), + options: options, + onResponse: handleResponse + ) + } + + /// Call the "SayHello" method. + /// + /// - Parameters: + /// - request: A request containing a single `ShimmerBLEGRPC_Request` message. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + internal func sayHello( + request: GRPCCore.ClientRequest, + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { response in + try response.message + } + ) async throws -> Result where Result: Sendable { + try await self.sayHello( + request: request, + serializer: GRPCProtobuf.ProtobufSerializer(), + deserializer: GRPCProtobuf.ProtobufDeserializer(), + options: options, + onResponse: handleResponse + ) + } +} + +// Helpers providing sugared APIs for 'ClientProtocol' methods. +extension ShimmerBLEGRPC_ShimmerBLEByteServer.ClientProtocol { + /// Call the "GetDataStream" method. + /// + /// > Source IDL Documentation: + /// > + /// > lient asking for data + /// + /// - Parameters: + /// - message: request message to send. + /// - metadata: Additional metadata to send, defaults to empty. + /// - options: Options to apply to this RPC, defaults to `.defaults`. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + internal func getDataStream( + _ message: ShimmerBLEGRPC_StreamRequest, + metadata: GRPCCore.Metadata = [:], + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> Result + ) async throws -> Result where Result: Sendable { + let request = GRPCCore.ClientRequest( + message: message, + metadata: metadata + ) + return try await self.getDataStream( + request: request, + options: options, + onResponse: handleResponse + ) + } + + /// Call the "GetTestDataStream" method. + /// + /// > Source IDL Documentation: + /// > + /// > lient asking for data + /// + /// - Parameters: + /// - message: request message to send. + /// - metadata: Additional metadata to send, defaults to empty. + /// - options: Options to apply to this RPC, defaults to `.defaults`. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + internal func getTestDataStream( + _ message: ShimmerBLEGRPC_StreamRequest, + metadata: GRPCCore.Metadata = [:], + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> Result + ) async throws -> Result where Result: Sendable { + let request = GRPCCore.ClientRequest( + message: message, + metadata: metadata + ) + return try await self.getTestDataStream( + request: request, + options: options, + onResponse: handleResponse + ) + } + + /// Call the "SendDataStream" method. + /// + /// > Source IDL Documentation: + /// > + /// > lient sending data + /// + /// - Parameters: + /// - metadata: Additional metadata to send, defaults to empty. + /// - options: Options to apply to this RPC, defaults to `.defaults`. + /// - producer: A closure producing request messages to send to the server. The request + /// stream is closed when the closure returns. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + internal func sendDataStream( + metadata: GRPCCore.Metadata = [:], + options: GRPCCore.CallOptions = .defaults, + requestProducer producer: @Sendable @escaping (GRPCCore.RPCWriter) async throws -> Void, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { response in + try response.message + } + ) async throws -> Result where Result: Sendable { + let request = GRPCCore.StreamingClientRequest( + metadata: metadata, + producer: producer + ) + return try await self.sendDataStream( + request: request, + options: options, + onResponse: handleResponse + ) + } + + /// Call the "ConnectShimmer" method. + /// + /// - Parameters: + /// - message: request message to send. + /// - metadata: Additional metadata to send, defaults to empty. + /// - options: Options to apply to this RPC, defaults to `.defaults`. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + internal func connectShimmer( + _ message: ShimmerBLEGRPC_Request, + metadata: GRPCCore.Metadata = [:], + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> Result + ) async throws -> Result where Result: Sendable { + let request = GRPCCore.ClientRequest( + message: message, + metadata: metadata + ) + return try await self.connectShimmer( + request: request, + options: options, + onResponse: handleResponse + ) + } + + /// Call the "DisconnectShimmer" method. + /// + /// - Parameters: + /// - message: request message to send. + /// - metadata: Additional metadata to send, defaults to empty. + /// - options: Options to apply to this RPC, defaults to `.defaults`. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + internal func disconnectShimmer( + _ message: ShimmerBLEGRPC_Request, + metadata: GRPCCore.Metadata = [:], + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { response in + try response.message + } + ) async throws -> Result where Result: Sendable { + let request = GRPCCore.ClientRequest( + message: message, + metadata: metadata + ) + return try await self.disconnectShimmer( + request: request, + options: options, + onResponse: handleResponse + ) + } + + /// Call the "WriteBytesShimmer" method. + /// + /// - Parameters: + /// - message: request message to send. + /// - metadata: Additional metadata to send, defaults to empty. + /// - options: Options to apply to this RPC, defaults to `.defaults`. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + internal func writeBytesShimmer( + _ message: ShimmerBLEGRPC_WriteBytes, + metadata: GRPCCore.Metadata = [:], + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { response in + try response.message + } + ) async throws -> Result where Result: Sendable { + let request = GRPCCore.ClientRequest( + message: message, + metadata: metadata + ) + return try await self.writeBytesShimmer( + request: request, + options: options, + onResponse: handleResponse + ) + } + + /// Call the "SayHello" method. + /// + /// - Parameters: + /// - message: request message to send. + /// - metadata: Additional metadata to send, defaults to empty. + /// - options: Options to apply to this RPC, defaults to `.defaults`. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + internal func sayHello( + _ message: ShimmerBLEGRPC_Request, + metadata: GRPCCore.Metadata = [:], + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { response in + try response.message + } + ) async throws -> Result where Result: Sendable { + let request = GRPCCore.ClientRequest( + message: message, + metadata: metadata + ) + return try await self.sayHello( + request: request, + options: options, + onResponse: handleResponse + ) + } +} \ No newline at end of file diff --git a/ShimmerBLEGrpc/Sources/Protos/ShimmerBLEGrpcAndPacketByteArray.pb.swift b/ShimmerBLEGrpc/Sources/Protos/ShimmerBLEGrpcAndPacketByteArray.pb.swift new file mode 100644 index 0000000..5a4f404 --- /dev/null +++ b/ShimmerBLEGrpc/Sources/Protos/ShimmerBLEGrpcAndPacketByteArray.pb.swift @@ -0,0 +1,445 @@ +// DO NOT EDIT. +// swift-format-ignore-file +// swiftlint:disable all +// +// Generated by the Swift generator plugin for the protocol buffer compiler. +// Source: ShimmerBLEGrpcAndPacketByteArray.proto +// +// For information on using the generated types, please see the documentation: +// https://github.com/apple/swift-protobuf/ + +///using +///protoc-3.13.0-win64 +///protoc-gen-grpc-java-1.32.1-windows-x86_64.exe +///.nuget\packages\grpc.tools\2.34.0\tools\windows_x64\grpc_csharp_plugin.exe + +import Foundation +import SwiftProtobuf + +// If the compiler emits an error on this type, it is because this file +// was generated by a version of the `protoc` Swift plug-in that is +// incompatible with the version of SwiftProtobuf to which you are linking. +// Please ensure that you are building against the same version of the API +// that was used to generate this file. +fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck { + struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {} + typealias Version = _2 +} + +enum ShimmerBLEGRPC_BluetoothState: SwiftProtobuf.Enum, Swift.CaseIterable { + typealias RawValue = Int + case connected // = 0 + case connecting // = 1 + case disconnected // = 2 + case UNRECOGNIZED(Int) + + init() { + self = .connected + } + + init?(rawValue: Int) { + switch rawValue { + case 0: self = .connected + case 1: self = .connecting + case 2: self = .disconnected + default: self = .UNRECOGNIZED(rawValue) + } + } + + var rawValue: Int { + switch self { + case .connected: return 0 + case .connecting: return 1 + case .disconnected: return 2 + case .UNRECOGNIZED(let i): return i + } + } + + // The compiler won't synthesize support with the UNRECOGNIZED case. + static let allCases: [ShimmerBLEGRPC_BluetoothState] = [ + .connected, + .connecting, + .disconnected, + ] + +} + +/// The response message containing the greetings +struct ShimmerBLEGRPC_Reply: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + var message: String = String() + + var unknownFields = SwiftProtobuf.UnknownStorage() + + init() {} +} + +/// The request message containing the user's name. +struct ShimmerBLEGRPC_Request: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + var name: String = String() + + var unknownFields = SwiftProtobuf.UnknownStorage() + + init() {} +} + +struct ShimmerBLEGRPC_WriteBytes: @unchecked Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + var address: String = String() + + var byteToWrite: Data = Data() + + var unknownFields = SwiftProtobuf.UnknownStorage() + + init() {} +} + +struct ShimmerBLEGRPC_StreamRequest: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + var message: String = String() + + var unknownFields = SwiftProtobuf.UnknownStorage() + + init() {} +} + +struct ShimmerBLEGRPC_StateStatus: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + var state: ShimmerBLEGRPC_BluetoothState = .connected + + var message: String = String() + + var unknownFields = SwiftProtobuf.UnknownStorage() + + init() {} +} + +struct ShimmerBLEGRPC_ObjectClusterByteArray: @unchecked Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + var uuid: String = String() + + var bluetoothAddress: String = String() + + var communicationType: ShimmerBLEGRPC_ObjectClusterByteArray.CommunicationType = .bt + + var systemTime: Int64 = 0 + + var calibratedTimeStamp: Double = 0 + + var binaryData: Data = Data() + + var unknownFields = SwiftProtobuf.UnknownStorage() + + enum CommunicationType: SwiftProtobuf.Enum, Swift.CaseIterable { + typealias RawValue = Int + case bt // = 0 + case sd // = 1 + case radio802154 // = 2 + case UNRECOGNIZED(Int) + + init() { + self = .bt + } + + init?(rawValue: Int) { + switch rawValue { + case 0: self = .bt + case 1: self = .sd + case 2: self = .radio802154 + default: self = .UNRECOGNIZED(rawValue) + } + } + + var rawValue: Int { + switch self { + case .bt: return 0 + case .sd: return 1 + case .radio802154: return 2 + case .UNRECOGNIZED(let i): return i + } + } + + // The compiler won't synthesize support with the UNRECOGNIZED case. + static let allCases: [ShimmerBLEGRPC_ObjectClusterByteArray.CommunicationType] = [ + .bt, + .sd, + .radio802154, + ] + + } + + init() {} +} + +// MARK: - Code below here is support for the SwiftProtobuf runtime. + +fileprivate let _protobuf_package = "shimmerBLEGRPC" + +extension ShimmerBLEGRPC_BluetoothState: SwiftProtobuf._ProtoNameProviding { + static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 0: .same(proto: "Connected"), + 1: .same(proto: "Connecting"), + 2: .same(proto: "Disconnected"), + ] +} + +extension ShimmerBLEGRPC_Reply: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + static let protoMessageName: String = _protobuf_package + ".Reply" + static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 1: .same(proto: "message"), + ] + + mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularStringField(value: &self.message) }() + default: break + } + } + } + + func traverse(visitor: inout V) throws { + if !self.message.isEmpty { + try visitor.visitSingularStringField(value: self.message, fieldNumber: 1) + } + try unknownFields.traverse(visitor: &visitor) + } + + static func ==(lhs: ShimmerBLEGRPC_Reply, rhs: ShimmerBLEGRPC_Reply) -> Bool { + if lhs.message != rhs.message {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension ShimmerBLEGRPC_Request: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + static let protoMessageName: String = _protobuf_package + ".Request" + static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 1: .same(proto: "name"), + ] + + mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularStringField(value: &self.name) }() + default: break + } + } + } + + func traverse(visitor: inout V) throws { + if !self.name.isEmpty { + try visitor.visitSingularStringField(value: self.name, fieldNumber: 1) + } + try unknownFields.traverse(visitor: &visitor) + } + + static func ==(lhs: ShimmerBLEGRPC_Request, rhs: ShimmerBLEGRPC_Request) -> Bool { + if lhs.name != rhs.name {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension ShimmerBLEGRPC_WriteBytes: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + static let protoMessageName: String = _protobuf_package + ".WriteBytes" + static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 1: .same(proto: "address"), + 2: .standard(proto: "byte_to_write"), + ] + + mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularStringField(value: &self.address) }() + case 2: try { try decoder.decodeSingularBytesField(value: &self.byteToWrite) }() + default: break + } + } + } + + func traverse(visitor: inout V) throws { + if !self.address.isEmpty { + try visitor.visitSingularStringField(value: self.address, fieldNumber: 1) + } + if !self.byteToWrite.isEmpty { + try visitor.visitSingularBytesField(value: self.byteToWrite, fieldNumber: 2) + } + try unknownFields.traverse(visitor: &visitor) + } + + static func ==(lhs: ShimmerBLEGRPC_WriteBytes, rhs: ShimmerBLEGRPC_WriteBytes) -> Bool { + if lhs.address != rhs.address {return false} + if lhs.byteToWrite != rhs.byteToWrite {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension ShimmerBLEGRPC_StreamRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + static let protoMessageName: String = _protobuf_package + ".StreamRequest" + static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 1: .same(proto: "message"), + ] + + mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularStringField(value: &self.message) }() + default: break + } + } + } + + func traverse(visitor: inout V) throws { + if !self.message.isEmpty { + try visitor.visitSingularStringField(value: self.message, fieldNumber: 1) + } + try unknownFields.traverse(visitor: &visitor) + } + + static func ==(lhs: ShimmerBLEGRPC_StreamRequest, rhs: ShimmerBLEGRPC_StreamRequest) -> Bool { + if lhs.message != rhs.message {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension ShimmerBLEGRPC_StateStatus: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + static let protoMessageName: String = _protobuf_package + ".StateStatus" + static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 1: .same(proto: "State"), + 2: .same(proto: "message"), + ] + + mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularEnumField(value: &self.state) }() + case 2: try { try decoder.decodeSingularStringField(value: &self.message) }() + default: break + } + } + } + + func traverse(visitor: inout V) throws { + if self.state != .connected { + try visitor.visitSingularEnumField(value: self.state, fieldNumber: 1) + } + if !self.message.isEmpty { + try visitor.visitSingularStringField(value: self.message, fieldNumber: 2) + } + try unknownFields.traverse(visitor: &visitor) + } + + static func ==(lhs: ShimmerBLEGRPC_StateStatus, rhs: ShimmerBLEGRPC_StateStatus) -> Bool { + if lhs.state != rhs.state {return false} + if lhs.message != rhs.message {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension ShimmerBLEGRPC_ObjectClusterByteArray: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + static let protoMessageName: String = _protobuf_package + ".ObjectClusterByteArray" + static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 1: .same(proto: "uuid"), + 2: .same(proto: "bluetoothAddress"), + 3: .same(proto: "communicationType"), + 4: .same(proto: "systemTime"), + 5: .same(proto: "calibratedTimeStamp"), + 6: .standard(proto: "binary_data"), + ] + + mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularStringField(value: &self.uuid) }() + case 2: try { try decoder.decodeSingularStringField(value: &self.bluetoothAddress) }() + case 3: try { try decoder.decodeSingularEnumField(value: &self.communicationType) }() + case 4: try { try decoder.decodeSingularInt64Field(value: &self.systemTime) }() + case 5: try { try decoder.decodeSingularDoubleField(value: &self.calibratedTimeStamp) }() + case 6: try { try decoder.decodeSingularBytesField(value: &self.binaryData) }() + default: break + } + } + } + + func traverse(visitor: inout V) throws { + if !self.uuid.isEmpty { + try visitor.visitSingularStringField(value: self.uuid, fieldNumber: 1) + } + if !self.bluetoothAddress.isEmpty { + try visitor.visitSingularStringField(value: self.bluetoothAddress, fieldNumber: 2) + } + if self.communicationType != .bt { + try visitor.visitSingularEnumField(value: self.communicationType, fieldNumber: 3) + } + if self.systemTime != 0 { + try visitor.visitSingularInt64Field(value: self.systemTime, fieldNumber: 4) + } + if self.calibratedTimeStamp.bitPattern != 0 { + try visitor.visitSingularDoubleField(value: self.calibratedTimeStamp, fieldNumber: 5) + } + if !self.binaryData.isEmpty { + try visitor.visitSingularBytesField(value: self.binaryData, fieldNumber: 6) + } + try unknownFields.traverse(visitor: &visitor) + } + + static func ==(lhs: ShimmerBLEGRPC_ObjectClusterByteArray, rhs: ShimmerBLEGRPC_ObjectClusterByteArray) -> Bool { + if lhs.uuid != rhs.uuid {return false} + if lhs.bluetoothAddress != rhs.bluetoothAddress {return false} + if lhs.communicationType != rhs.communicationType {return false} + if lhs.systemTime != rhs.systemTime {return false} + if lhs.calibratedTimeStamp != rhs.calibratedTimeStamp {return false} + if lhs.binaryData != rhs.binaryData {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension ShimmerBLEGRPC_ObjectClusterByteArray.CommunicationType: SwiftProtobuf._ProtoNameProviding { + static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 0: .same(proto: "BT"), + 1: .same(proto: "SD"), + 2: .same(proto: "Radio_802_15_4"), + ] +} diff --git a/ShimmerBLEGrpc/Sources/ShimmerBLEService.swift b/ShimmerBLEGrpc/Sources/ShimmerBLEService.swift new file mode 100644 index 0000000..4d848e7 --- /dev/null +++ b/ShimmerBLEGrpc/Sources/ShimmerBLEService.swift @@ -0,0 +1,207 @@ +// +// ShimmerBLEService.swift +// ShimmerBLEGrpc +// +// Created by Joseph Yong on 09/04/2025. +// + +import Combine +import CoreBluetooth +import ShimmerBluetooth +import ArgumentParser +import GRPCCore +import GRPCNIOTransportHTTP2 +import GRPCProtobuf + +final class ShimmerBLEService: ShimmerBLEGRPC_ShimmerBLEByteServer.SimpleServiceProtocol { + + private var bluetoothManager: BluetoothManager? + private var centralManager: CBCentralManager? + private var radio: BleByteRadio? + private var shimmer3Protocol: Shimmer3Protocol? + public var protocolShimmer3 = 0 + private var deviceNameToConnect: String = "" + private var isConnecting: Bool = false + + private var bluetoothDeviceMap = [String: CBPeripheral]() + private var serviceMap = [String: CBService]() + private var uartTXMap = [String: CBCharacteristic]() + private var uartRXMap = [String: CBCharacteristic]() +// private var queueMap = [String: [Data]]() // Mimics a concurrent queue for binary data. +// private var queueMap = [String: [UInt8]]() // Mimics a concurrent queue for binary data. + private var queueMap = [String: ConcurrentQueue]() +// private var queueMap = [String: Data]() +// private var connectStreamMap: [String: GRPCCore.RPCWriter] = [:] + private var connectStreamMap = [String: GRPCCore.RPCWriter]() +// private var radioMap = [String: ] + private var hashMap = [String: Int64]() + + init() { + self.centralManager = CBCentralManager() + self.bluetoothManager = BluetoothManager(centralmanager: self.centralManager!) + bluetoothManager?.delegate = self + } + + func sayHello(request: ShimmerBLEGRPC_Request, context: GRPCCore.ServerContext) async throws -> ShimmerBLEGRPC_Reply { + return ShimmerBLEGRPC_Reply.with { + $0.message = "Hello " + request.name + } + } + + func writeBytesShimmer(request: ShimmerBLEGRPC_WriteBytes, context: GRPCCore.ServerContext) async throws -> ShimmerBLEGRPC_Reply { + print("Received writeBytes request for: " + request.address) + radio!.writeData(data: request.byteToWrite) + return ShimmerBLEGRPC_Reply.with { + $0.message = "Written " + request.address + } + } + + func disconnectShimmer(request: ShimmerBLEGRPC_Request, context: GRPCCore.ServerContext) async throws -> ShimmerBLEGRPC_Reply { +// print("Received disconnectShimmer request for: " + request.name) + startDisconnectShimmer(name: request.name) + return ShimmerBLEGRPC_Reply.with { + $0.message = "Disconnect " + request.name + } + } + + //Initiates a BLE scan first, before completing the process in startConnectShimmer() + func connectShimmer(request: ShimmerBLEGRPC_Request, response: GRPCCore.RPCWriter, context: GRPCCore.ServerContext) async throws { + deviceNameToConnect = request.name + print("Received connectShimmer request for: " + deviceNameToConnect) + isConnecting = true + print("Start Bluetooth Manager Scan") + var res = bluetoothManager?.startScanning(deviceName: deviceNameToConnect, timeout: 3) + connectStreamMap[deviceNameToConnect] = response + await testWrite(response: response) + try await Task.sleep(for: .seconds(4)) + while(bluetoothDeviceMap.keys.contains(deviceNameToConnect)) { + try await Task.sleep(for: .seconds(0.1)) //sleep 100ms + } + } + + private func testWrite(response: GRPCCore.RPCWriter) async { + var status = ShimmerBLEGRPC_StateStatus() + status.state = ShimmerBLEGRPC_BluetoothState.connecting + status.message = "Connecting" + let stateStatusStream = connectStreamMap[deviceNameToConnect] + do { + try await stateStatusStream?.write(status) + } catch let error { + print(error) + } + } + + func sendDataStream(request: GRPCCore.RPCAsyncSequence, context: GRPCCore.ServerContext) async throws -> ShimmerBLEGRPC_Reply { + let reply = ShimmerBLEGRPC_Reply() + return reply + } + + func getTestDataStream(request: ShimmerBLEGRPC_StreamRequest, response: GRPCCore.RPCWriter, context: GRPCCore.ServerContext) async throws { + print("Received getTestDataStream request for: " + request.message) + } + + func getDataStream(request: ShimmerBLEGRPC_StreamRequest, response: GRPCCore.RPCWriter, context: GRPCCore.ServerContext) async throws { + print("Received getDataStream request for: " + request.message) + while(bluetoothDeviceMap.keys.contains(request.message)) { + if(queueMap.keys.contains(request.message)) { + var data = Data() + while(!queueMap[request.message]!.isEmpty) { + data.append(queueMap[request.message]?.dequeue() ?? Data()) + } + + let unixTimestampMillis = Double(Date().timeIntervalSince1970 * 1_000) + + var res = ShimmerBLEGRPC_ObjectClusterByteArray() + res.bluetoothAddress = request.message + res.binaryData = data + res.calibratedTimeStamp = unixTimestampMillis + + try await response.write(res) + } + try await Task.sleep(for: .seconds(0.001)) //sleep 1ms + } + + } + + func startConnectShimmer() async { + var peripheral = bluetoothManager?.getPeripheral(deviceName: deviceNameToConnect) + + bluetoothDeviceMap[deviceNameToConnect] = peripheral + queueMap[deviceNameToConnect] = ConcurrentQueue() + + self.radio = BleByteRadio(deviceName: deviceNameToConnect,cbperipheral: peripheral!,bluetoothManager: bluetoothManager!) + self.radio?.delegate = self +// shimmer3Protocol = Shimmer3Protocol(radio: self.radio!) +// shimmer3Protocol?.delegate = self + +// var success = await shimmer3Protocol?.connect() + var success = await radio?.connect() + if(success ?? false) { + //TODO: update init below + var status = ShimmerBLEGRPC_StateStatus() + status.state = ShimmerBLEGRPC_BluetoothState.connected + status.message = "Success" + let stateStatusStream = connectStreamMap[deviceNameToConnect] + do { + try await stateStatusStream?.write(status) + } catch let error { + print(error) + } +// await UartRX.StartNotificationsAsync(); +// var data = new StateStatus +// { +// Message = "Success", +// State = BluetoothState.Connected +// }; +// bluetoothDevice.GattServerDisconnected += BluetoothDevice_GattServerDisconnected; +// ConnectStreamMap.TryAdd(macAddress, stateStatusStream); +// await stateStatusStream.WriteAsync(data); + } + isConnecting = false + } + + func startDisconnectShimmer(name: String) { + Task { +// await shimmer3Protocol!.disconnect() + await radio?.disconnect() + bluetoothDeviceMap.removeValue(forKey: name) + connectStreamMap.removeValue(forKey: name) + queueMap.removeValue(forKey: name) + } + } + +} + +extension ShimmerBLEService : BluetoothManagerDelegate { + func scanCompleted() { + print("Bluetooth Manager Scan Completed") + if(isConnecting) { + Task { + await startConnectShimmer() + } + } + } + + func isConnected() { + print("Bluetooth Manager Connected Device") + } + + func isDisconnected() { + print("Bluetooth Manager Disconnected Device") + } +} + +extension ShimmerBLEService : ByteCommunicationDelegate { + func byteCommunicationConnected() { + } + + func byteCommunicationDisconnected(connectionloss: Bool) { + } + + func byteCommunicationDataReceived(data: Data?) { + var queue = queueMap[deviceNameToConnect] + if(data != nil) { + queue?.enqueue(data ?? Data()) + } + } +} diff --git a/ShimmerBLEGrpc/Sources/Subcommands/Serve.swift b/ShimmerBLEGrpc/Sources/Subcommands/Serve.swift new file mode 100644 index 0000000..01d2060 --- /dev/null +++ b/ShimmerBLEGrpc/Sources/Subcommands/Serve.swift @@ -0,0 +1,97 @@ +/* + * Copyright 2024, gRPC Authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import ArgumentParser +import GRPCCore +import GRPCNIOTransportHTTP2 +import GRPCProtobuf + +struct Serve: AsyncParsableCommand { + static let configuration = CommandConfiguration(abstract: "Starts a greeter server.") + + @Option(help: "The port to listen on") + var port: Int = 5000 + + func run() async throws { + let server = GRPCServer( + transport: .http2NIOPosix( + address: .ipv4(host: "127.0.0.1", port: self.port), + transportSecurity: .plaintext + ), + services: [ShimmerBLEService()] + ) + + try await withThrowingDiscardingTaskGroup { group in + group.addTask { try await server.serve() } + if let address = try await server.listeningAddress { + print("Greeter listening on \(address)") + } + } + } +} + +struct Greeter: ShimmerBLEGRPC_ShimmerBLEByteServer.SimpleServiceProtocol { + func sayHello(request: ShimmerBLEGRPC_Request, context: GRPCCore.ServerContext) async throws -> ShimmerBLEGRPC_Reply { +// let reply = Reply.with { +// $0.message = "Hello " + request.name +// } +// return context.eventLoop.makeSucceededFuture(reply) + print("Received sayHello request") + let reply = ShimmerBLEGRPC_Reply() + return reply + } + + func writeBytesShimmer(request: ShimmerBLEGRPC_WriteBytes, context: GRPCCore.ServerContext) async throws -> ShimmerBLEGRPC_Reply { + let reply = ShimmerBLEGRPC_Reply() + return reply + } + + func disconnectShimmer(request: ShimmerBLEGRPC_Request, context: GRPCCore.ServerContext) async throws -> ShimmerBLEGRPC_Reply { + let reply = ShimmerBLEGRPC_Reply() + return reply + } + + func connectShimmer(request: ShimmerBLEGRPC_Request, response: GRPCCore.RPCWriter, context: GRPCCore.ServerContext) async throws { + print("Received connectShimmer request -> " + request.name) + } + + func sendDataStream(request: GRPCCore.RPCAsyncSequence, context: GRPCCore.ServerContext) async throws -> ShimmerBLEGRPC_Reply { + let reply = ShimmerBLEGRPC_Reply() + return reply + } + + func getTestDataStream(request: ShimmerBLEGRPC_StreamRequest, response: GRPCCore.RPCWriter, context: GRPCCore.ServerContext) async throws { + + } + + func getDataStream(request: ShimmerBLEGRPC_StreamRequest, response: GRPCCore.RPCWriter, context: GRPCCore.ServerContext) async throws { + + } +} + +//struct ShimmerBLEServiceImpl: ShimmerBLEByteServer.ShimmerBLEByteServerBase + +//struct Greeter: Helloworld_Greeter.SimpleServiceProtocol { +// func sayHello( +// request: Helloworld_HelloRequest, +// context: ServerContext +// ) async throws -> Helloworld_HelloReply { +// var reply = Helloworld_HelloReply() +// let recipient = request.name.isEmpty ? "stranger" : request.name +// reply.message = "Hello, \(recipient)" +// return reply +// } +//} diff --git a/ShimmerBluetooth/ShimmerBluetooth.xcodeproj/project.pbxproj b/ShimmerBluetooth/ShimmerBluetooth.xcodeproj/project.pbxproj index e480098..117f638 100644 --- a/ShimmerBluetooth/ShimmerBluetooth.xcodeproj/project.pbxproj +++ b/ShimmerBluetooth/ShimmerBluetooth.xcodeproj/project.pbxproj @@ -37,6 +37,7 @@ 3AED206D2B0B10960066A0F8 /* ShimmerUtilitiesTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AED206C2B0B10960066A0F8 /* ShimmerUtilitiesTest.swift */; }; 3AED20712B0C4BA60066A0F8 /* MagSensor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AED20702B0C4BA60066A0F8 /* MagSensor.swift */; }; 3AED20732B0C587B0066A0F8 /* GyroSensor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AED20722B0C587B0066A0F8 /* GyroSensor.swift */; }; + 451EC81A2DACCFFE00D8F269 /* ConcurrentQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 451EC8192DACCFF900D8F269 /* ConcurrentQueue.swift */; }; 9299E50E2B85054E001EEFE0 /* PressureTempSensor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9299E50D2B85054E001EEFE0 /* PressureTempSensor.swift */; }; 9299E5102B850571001EEFE0 /* BattVoltageSensor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9299E50F2B850571001EEFE0 /* BattVoltageSensor.swift */; }; 92B1067A2B7DAFBC00AB9952 /* EXGSensor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92B106792B7DAFBC00AB9952 /* EXGSensor.swift */; }; @@ -84,6 +85,7 @@ 3AED206C2B0B10960066A0F8 /* ShimmerUtilitiesTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShimmerUtilitiesTest.swift; sourceTree = ""; }; 3AED20702B0C4BA60066A0F8 /* MagSensor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MagSensor.swift; sourceTree = ""; }; 3AED20722B0C587B0066A0F8 /* GyroSensor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GyroSensor.swift; sourceTree = ""; }; + 451EC8192DACCFF900D8F269 /* ConcurrentQueue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConcurrentQueue.swift; sourceTree = ""; }; 9299E50D2B85054E001EEFE0 /* PressureTempSensor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PressureTempSensor.swift; sourceTree = ""; }; 9299E50F2B850571001EEFE0 /* BattVoltageSensor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BattVoltageSensor.swift; sourceTree = ""; }; 92B106792B7DAFBC00AB9952 /* EXGSensor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EXGSensor.swift; sourceTree = ""; }; @@ -131,6 +133,7 @@ 3A780C872AE12BEB00EAF050 /* ShimmerBluetooth */ = { isa = PBXGroup; children = ( + 451EC8192DACCFF900D8F269 /* ConcurrentQueue.swift */, 3AEB12F82BCE6F7E00B5F6F1 /* Shimmer3SpeedTestProtocol.swift */, 3A780C882AE12BEB00EAF050 /* ShimmerBluetooth.h */, 3A780C892AE12BEB00EAF050 /* ShimmerBluetooth.docc */, @@ -294,6 +297,7 @@ 3A780CDA2AE12D8300EAF050 /* VerisenseProtocol.swift in Sources */, 3AED20732B0C587B0066A0F8 /* GyroSensor.swift in Sources */, 92B1067A2B7DAFBC00AB9952 /* EXGSensor.swift in Sources */, + 451EC81A2DACCFFE00D8F269 /* ConcurrentQueue.swift in Sources */, 3A7712892AE1773E006213A8 /* BluetoothManager.swift in Sources */, 9299E5102B850571001EEFE0 /* BattVoltageSensor.swift in Sources */, 3AB320E62B070830003D94F8 /* Sensor.swift in Sources */, diff --git a/ShimmerBluetooth/ShimmerBluetooth/BleByteRadio.swift b/ShimmerBluetooth/ShimmerBluetooth/BleByteRadio.swift index 5d3b413..22297d0 100644 --- a/ShimmerBluetooth/ShimmerBluetooth/BleByteRadio.swift +++ b/ShimmerBluetooth/ShimmerBluetooth/BleByteRadio.swift @@ -93,6 +93,14 @@ public class BleByteRadio : NSObject, ByteCommunication { return true } + public func writeData(data: Data) ->Bool { + guard let char = self.characteristics[RBL_CHAR_TX_UUID] else { return false} + print("Write Data \(data)") + print(char.uuid.uuidString) + self.activePeripheral?.writeValue(data, for: char, type: .withResponse) + return true + } + public func enableNotifications(enable: Bool) { guard let char = self.characteristics[RBL_CHAR_RX_UUID] else { return } diff --git a/ShimmerBluetooth/ShimmerBluetooth/ConcurrentQueue.swift b/ShimmerBluetooth/ShimmerBluetooth/ConcurrentQueue.swift new file mode 100644 index 0000000..9264850 --- /dev/null +++ b/ShimmerBluetooth/ShimmerBluetooth/ConcurrentQueue.swift @@ -0,0 +1,46 @@ +// +// ConcurrentQueue.swift +// ShimmerBluetooth +// +// Created by Joseph Yong on 14/04/2025. +// + +import Foundation + +public class ConcurrentQueue { + private var queue: [T] = [] + private let dispatchQueue = DispatchQueue(label: "com.concurrentQueue", attributes: .concurrent) + + public init() { } + + public func enqueue(_ element: T) { + dispatchQueue.async(flags: .barrier) { + self.queue.append(element) + } + } + + public func dequeue() -> T? { + return dispatchQueue.sync(flags: .barrier) { + guard !self.queue.isEmpty else { return nil } + return self.queue.removeFirst() + } + } + + func peek() -> T? { + return dispatchQueue.sync { + return queue.first + } + } + + public var isEmpty: Bool { + return dispatchQueue.sync { + return queue.isEmpty + } + } + + var count: Int { + return dispatchQueue.sync { + return queue.count + } + } +} From 9afe73c095a4590df7dddc411d4804b2c479d350 Mon Sep 17 00:00:00 2001 From: jyong15 Date: Tue, 15 Apr 2025 14:03:19 +0800 Subject: [PATCH 02/13] DEV-221 Code tidy and implementation of multi-Shimmer support in BleByteRadio.swift --- ShimmerBLEGrpc/Readme.md | 7 +- .../Sources/ShimmerBLEService.swift | 81 ++++++++----------- .../ShimmerBluetooth/BleByteRadio.swift | 2 +- .../ShimmerBluetooth/ByteCommunication.swift | 2 +- .../ShimmerBluetooth/Shimmer3Protocol.swift | 2 +- .../Shimmer3SpeedTestProtocol.swift | 2 +- .../ShimmerBluetooth/VerisenseProtocol.swift | 2 +- 7 files changed, 42 insertions(+), 56 deletions(-) diff --git a/ShimmerBLEGrpc/Readme.md b/ShimmerBLEGrpc/Readme.md index 2799f48..c6be6e4 100644 --- a/ShimmerBLEGrpc/Readme.md +++ b/ShimmerBLEGrpc/Readme.md @@ -1,2 +1,5 @@ -To run the BLE gRPC server, open the Mac Terminal to this folder. -Then, run the following: +To run the BLE gRPC server, set the active scheme at the top-middle of Xcode to ShimmerBLEGrpc, target My Mac +Then, select the Start button at the top-left of Xcode to start the app +Then, open the Shimmer-Java-Android-API ShimmerGRPC.java class from: https://github.com/ShimmerEngineering/Shimmer-Java-Android-API/blob/master/ShimmerDriverPC/src/main/java/com/shimmerresearch/pcDriver/ShimmerGRPC.java +Set the name of the device you want to connect to, in Line 101 of the class. This is e.g. "Shimmer3-XXXX". +Note that this is not the Bluetooth Mac address, as MacOS BLE is limited to using Bluetooth device names. diff --git a/ShimmerBLEGrpc/Sources/ShimmerBLEService.swift b/ShimmerBLEGrpc/Sources/ShimmerBLEService.swift index 4d848e7..4a96e8e 100644 --- a/ShimmerBLEGrpc/Sources/ShimmerBLEService.swift +++ b/ShimmerBLEGrpc/Sources/ShimmerBLEService.swift @@ -18,24 +18,15 @@ final class ShimmerBLEService: ShimmerBLEGRPC_ShimmerBLEByteServer.SimpleService private var bluetoothManager: BluetoothManager? private var centralManager: CBCentralManager? private var radio: BleByteRadio? - private var shimmer3Protocol: Shimmer3Protocol? - public var protocolShimmer3 = 0 private var deviceNameToConnect: String = "" private var isConnecting: Bool = false - private var bluetoothDeviceMap = [String: CBPeripheral]() - private var serviceMap = [String: CBService]() - private var uartTXMap = [String: CBCharacteristic]() - private var uartRXMap = [String: CBCharacteristic]() -// private var queueMap = [String: [Data]]() // Mimics a concurrent queue for binary data. -// private var queueMap = [String: [UInt8]]() // Mimics a concurrent queue for binary data. - private var queueMap = [String: ConcurrentQueue]() -// private var queueMap = [String: Data]() -// private var connectStreamMap: [String: GRPCCore.RPCWriter] = [:] - private var connectStreamMap = [String: GRPCCore.RPCWriter]() -// private var radioMap = [String: ] - private var hashMap = [String: Int64]() - + //The key for all Dictionaries below is the Bluetooth device name + private var bluetoothDeviceMap = [String: CBPeripheral]() //stores the currently connected devices + private var queueMap = [String: ConcurrentQueue]() //stores the received bytes from connected devices which are written back to gRPC client in getDataStream() + private var connectStreamMap = [String: GRPCCore.RPCWriter]() //stores the writers for the status streams back to gRPC client + private var radioMap = [String: BleByteRadio]() + init() { self.centralManager = CBCentralManager() self.bluetoothManager = BluetoothManager(centralmanager: self.centralManager!) @@ -57,7 +48,7 @@ final class ShimmerBLEService: ShimmerBLEGRPC_ShimmerBLEByteServer.SimpleService } func disconnectShimmer(request: ShimmerBLEGRPC_Request, context: GRPCCore.ServerContext) async throws -> ShimmerBLEGRPC_Reply { -// print("Received disconnectShimmer request for: " + request.name) + print("Received disconnectShimmer request for: " + request.name) startDisconnectShimmer(name: request.name) return ShimmerBLEGRPC_Reply.with { $0.message = "Disconnect " + request.name @@ -67,19 +58,23 @@ final class ShimmerBLEService: ShimmerBLEGRPC_ShimmerBLEByteServer.SimpleService //Initiates a BLE scan first, before completing the process in startConnectShimmer() func connectShimmer(request: ShimmerBLEGRPC_Request, response: GRPCCore.RPCWriter, context: GRPCCore.ServerContext) async throws { deviceNameToConnect = request.name - print("Received connectShimmer request for: " + deviceNameToConnect) isConnecting = true + print("Received connectShimmer request for: " + deviceNameToConnect) + print("Start Bluetooth Manager Scan") var res = bluetoothManager?.startScanning(deviceName: deviceNameToConnect, timeout: 3) + connectStreamMap[deviceNameToConnect] = response - await testWrite(response: response) + await writeConnectingState(response: response) + try await Task.sleep(for: .seconds(4)) while(bluetoothDeviceMap.keys.contains(deviceNameToConnect)) { + //this keeps the response GRPCCore.RPCWriter<> open try await Task.sleep(for: .seconds(0.1)) //sleep 100ms } } - private func testWrite(response: GRPCCore.RPCWriter) async { + private func writeConnectingState(response: GRPCCore.RPCWriter) async { var status = ShimmerBLEGRPC_StateStatus() status.state = ShimmerBLEGRPC_BluetoothState.connecting status.message = "Connecting" @@ -90,12 +85,14 @@ final class ShimmerBLEService: ShimmerBLEGRPC_ShimmerBLEByteServer.SimpleService print(error) } } - + + //Currently unused func sendDataStream(request: GRPCCore.RPCAsyncSequence, context: GRPCCore.ServerContext) async throws -> ShimmerBLEGRPC_Reply { let reply = ShimmerBLEGRPC_Reply() return reply } + //Currently unused func getTestDataStream(request: ShimmerBLEGRPC_StreamRequest, response: GRPCCore.RPCWriter, context: GRPCCore.ServerContext) async throws { print("Received getTestDataStream request for: " + request.message) } @@ -108,61 +105,47 @@ final class ShimmerBLEService: ShimmerBLEGRPC_ShimmerBLEByteServer.SimpleService while(!queueMap[request.message]!.isEmpty) { data.append(queueMap[request.message]?.dequeue() ?? Data()) } - - let unixTimestampMillis = Double(Date().timeIntervalSince1970 * 1_000) - - var res = ShimmerBLEGRPC_ObjectClusterByteArray() - res.bluetoothAddress = request.message - res.binaryData = data - res.calibratedTimeStamp = unixTimestampMillis - + + let res = ShimmerBLEGRPC_ObjectClusterByteArray.with { + $0.bluetoothAddress = request.message + $0.binaryData = data + $0.calibratedTimeStamp = Double(Date().timeIntervalSince1970 * 1_000) //Unix timestamp in milliseconds + } try await response.write(res) } + try await Task.sleep(for: .seconds(0.001)) //sleep 1ms } } func startConnectShimmer() async { - var peripheral = bluetoothManager?.getPeripheral(deviceName: deviceNameToConnect) + let peripheral = bluetoothManager?.getPeripheral(deviceName: deviceNameToConnect) bluetoothDeviceMap[deviceNameToConnect] = peripheral queueMap[deviceNameToConnect] = ConcurrentQueue() self.radio = BleByteRadio(deviceName: deviceNameToConnect,cbperipheral: peripheral!,bluetoothManager: bluetoothManager!) self.radio?.delegate = self -// shimmer3Protocol = Shimmer3Protocol(radio: self.radio!) -// shimmer3Protocol?.delegate = self - -// var success = await shimmer3Protocol?.connect() + var success = await radio?.connect() if(success ?? false) { - //TODO: update init below - var status = ShimmerBLEGRPC_StateStatus() - status.state = ShimmerBLEGRPC_BluetoothState.connected - status.message = "Success" + let status = ShimmerBLEGRPC_StateStatus.with { + $0.state = ShimmerBLEGRPC_BluetoothState.connected + $0.message = "Success" + } let stateStatusStream = connectStreamMap[deviceNameToConnect] do { try await stateStatusStream?.write(status) } catch let error { print(error) } -// await UartRX.StartNotificationsAsync(); -// var data = new StateStatus -// { -// Message = "Success", -// State = BluetoothState.Connected -// }; -// bluetoothDevice.GattServerDisconnected += BluetoothDevice_GattServerDisconnected; -// ConnectStreamMap.TryAdd(macAddress, stateStatusStream); -// await stateStatusStream.WriteAsync(data); } isConnecting = false } func startDisconnectShimmer(name: String) { Task { -// await shimmer3Protocol!.disconnect() await radio?.disconnect() bluetoothDeviceMap.removeValue(forKey: name) connectStreamMap.removeValue(forKey: name) @@ -198,8 +181,8 @@ extension ShimmerBLEService : ByteCommunicationDelegate { func byteCommunicationDisconnected(connectionloss: Bool) { } - func byteCommunicationDataReceived(data: Data?) { - var queue = queueMap[deviceNameToConnect] + func byteCommunicationDataReceived(data: Data?, deviceName: String) { + var queue = queueMap[deviceName] if(data != nil) { queue?.enqueue(data ?? Data()) } diff --git a/ShimmerBluetooth/ShimmerBluetooth/BleByteRadio.swift b/ShimmerBluetooth/ShimmerBluetooth/BleByteRadio.swift index 22297d0..7c93136 100644 --- a/ShimmerBluetooth/ShimmerBluetooth/BleByteRadio.swift +++ b/ShimmerBluetooth/ShimmerBluetooth/BleByteRadio.swift @@ -271,7 +271,7 @@ extension BleByteRadio : CBPeripheralDelegate { if let data = characteristic.value { //self.processData(data) print(data) - self.delegate?.byteCommunicationDataReceived(data: data) + self.delegate?.byteCommunicationDataReceived(data: data, deviceName: (deviceName ?? "")) } } } diff --git a/ShimmerBluetooth/ShimmerBluetooth/ByteCommunication.swift b/ShimmerBluetooth/ShimmerBluetooth/ByteCommunication.swift index 34e430f..f2121ab 100644 --- a/ShimmerBluetooth/ShimmerBluetooth/ByteCommunication.swift +++ b/ShimmerBluetooth/ShimmerBluetooth/ByteCommunication.swift @@ -16,5 +16,5 @@ public protocol ByteCommunication { public protocol ByteCommunicationDelegate { func byteCommunicationConnected() func byteCommunicationDisconnected(connectionloss: Bool) - func byteCommunicationDataReceived(data: Data?) + func byteCommunicationDataReceived(data: Data?, deviceName: String) } diff --git a/ShimmerBluetooth/ShimmerBluetooth/Shimmer3Protocol.swift b/ShimmerBluetooth/ShimmerBluetooth/Shimmer3Protocol.swift index ae3c1d5..3e52683 100644 --- a/ShimmerBluetooth/ShimmerBluetooth/Shimmer3Protocol.swift +++ b/ShimmerBluetooth/ShimmerBluetooth/Shimmer3Protocol.swift @@ -1823,7 +1823,7 @@ extension Shimmer3Protocol : ByteCommunicationDelegate { print("Current State: \(BTState)") } - public func byteCommunicationDataReceived(data: Data?) { + public func byteCommunicationDataReceived(data: Data?, deviceName: String) { self.processData(data!) } diff --git a/ShimmerBluetooth/ShimmerBluetooth/Shimmer3SpeedTestProtocol.swift b/ShimmerBluetooth/ShimmerBluetooth/Shimmer3SpeedTestProtocol.swift index b545557..bf40a09 100644 --- a/ShimmerBluetooth/ShimmerBluetooth/Shimmer3SpeedTestProtocol.swift +++ b/ShimmerBluetooth/ShimmerBluetooth/Shimmer3SpeedTestProtocol.swift @@ -155,7 +155,7 @@ extension Shimmer3SpeedTestProtocol : ByteCommunicationDelegate { stopProcessing() } - public func byteCommunicationDataReceived(data: Data?) { + public func byteCommunicationDataReceived(data: Data?, deviceName: String) { self.processData(data!) } diff --git a/ShimmerBluetooth/ShimmerBluetooth/VerisenseProtocol.swift b/ShimmerBluetooth/ShimmerBluetooth/VerisenseProtocol.swift index b98cfdf..7f25c59 100644 --- a/ShimmerBluetooth/ShimmerBluetooth/VerisenseProtocol.swift +++ b/ShimmerBluetooth/ShimmerBluetooth/VerisenseProtocol.swift @@ -146,7 +146,7 @@ extension VerisenseProtocol : ByteCommunicationDelegate { } - public func byteCommunicationDataReceived(data: Data?) { + public func byteCommunicationDataReceived(data: Data?, deviceName: String) { self.processData(data!) self.continuation?.resume(returning: true) self.continuation = nil From 3ba49d1fddd6442cc09ed3b80c3b17ace5916ed7 Mon Sep 17 00:00:00 2001 From: jyong15 Date: Tue, 15 Apr 2025 15:41:15 +0800 Subject: [PATCH 03/13] DEV-221 Update server port --- ShimmerBLEGrpc/Sources/Subcommands/Serve.swift | 2 +- ShimmerBluetooth/ShimmerBluetooth/ConcurrentQueue.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ShimmerBLEGrpc/Sources/Subcommands/Serve.swift b/ShimmerBLEGrpc/Sources/Subcommands/Serve.swift index 01d2060..c191dd9 100644 --- a/ShimmerBLEGrpc/Sources/Subcommands/Serve.swift +++ b/ShimmerBLEGrpc/Sources/Subcommands/Serve.swift @@ -23,7 +23,7 @@ struct Serve: AsyncParsableCommand { static let configuration = CommandConfiguration(abstract: "Starts a greeter server.") @Option(help: "The port to listen on") - var port: Int = 5000 + var port: Int = 50052 func run() async throws { let server = GRPCServer( diff --git a/ShimmerBluetooth/ShimmerBluetooth/ConcurrentQueue.swift b/ShimmerBluetooth/ShimmerBluetooth/ConcurrentQueue.swift index 9264850..099d32f 100644 --- a/ShimmerBluetooth/ShimmerBluetooth/ConcurrentQueue.swift +++ b/ShimmerBluetooth/ShimmerBluetooth/ConcurrentQueue.swift @@ -14,7 +14,7 @@ public class ConcurrentQueue { public init() { } public func enqueue(_ element: T) { - dispatchQueue.async(flags: .barrier) { + dispatchQueue.sync(flags: .barrier) { self.queue.append(element) } } From edf242f444d2474ccd550a54fc6c07dfaf02625a Mon Sep 17 00:00:00 2001 From: jyong15 Date: Tue, 15 Apr 2025 15:42:28 +0800 Subject: [PATCH 04/13] DEV-221 Code tidy --- .../Sources/Subcommands/Serve.swift | 53 ------------------- 1 file changed, 53 deletions(-) diff --git a/ShimmerBLEGrpc/Sources/Subcommands/Serve.swift b/ShimmerBLEGrpc/Sources/Subcommands/Serve.swift index c191dd9..add819b 100644 --- a/ShimmerBLEGrpc/Sources/Subcommands/Serve.swift +++ b/ShimmerBLEGrpc/Sources/Subcommands/Serve.swift @@ -42,56 +42,3 @@ struct Serve: AsyncParsableCommand { } } } - -struct Greeter: ShimmerBLEGRPC_ShimmerBLEByteServer.SimpleServiceProtocol { - func sayHello(request: ShimmerBLEGRPC_Request, context: GRPCCore.ServerContext) async throws -> ShimmerBLEGRPC_Reply { -// let reply = Reply.with { -// $0.message = "Hello " + request.name -// } -// return context.eventLoop.makeSucceededFuture(reply) - print("Received sayHello request") - let reply = ShimmerBLEGRPC_Reply() - return reply - } - - func writeBytesShimmer(request: ShimmerBLEGRPC_WriteBytes, context: GRPCCore.ServerContext) async throws -> ShimmerBLEGRPC_Reply { - let reply = ShimmerBLEGRPC_Reply() - return reply - } - - func disconnectShimmer(request: ShimmerBLEGRPC_Request, context: GRPCCore.ServerContext) async throws -> ShimmerBLEGRPC_Reply { - let reply = ShimmerBLEGRPC_Reply() - return reply - } - - func connectShimmer(request: ShimmerBLEGRPC_Request, response: GRPCCore.RPCWriter, context: GRPCCore.ServerContext) async throws { - print("Received connectShimmer request -> " + request.name) - } - - func sendDataStream(request: GRPCCore.RPCAsyncSequence, context: GRPCCore.ServerContext) async throws -> ShimmerBLEGRPC_Reply { - let reply = ShimmerBLEGRPC_Reply() - return reply - } - - func getTestDataStream(request: ShimmerBLEGRPC_StreamRequest, response: GRPCCore.RPCWriter, context: GRPCCore.ServerContext) async throws { - - } - - func getDataStream(request: ShimmerBLEGRPC_StreamRequest, response: GRPCCore.RPCWriter, context: GRPCCore.ServerContext) async throws { - - } -} - -//struct ShimmerBLEServiceImpl: ShimmerBLEByteServer.ShimmerBLEByteServerBase - -//struct Greeter: Helloworld_Greeter.SimpleServiceProtocol { -// func sayHello( -// request: Helloworld_HelloRequest, -// context: ServerContext -// ) async throws -> Helloworld_HelloReply { -// var reply = Helloworld_HelloReply() -// let recipient = request.name.isEmpty ? "stranger" : request.name -// reply.message = "Hello, \(recipient)" -// return reply -// } -//} From 6972785cac34577580e22f54183c1cd7faaf519f Mon Sep 17 00:00:00 2001 From: jyong15 Date: Tue, 15 Apr 2025 15:49:09 +0800 Subject: [PATCH 05/13] DEV-221 more updates for multi-Shimmer support --- ShimmerBLEGrpc/Sources/ShimmerBLEService.swift | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/ShimmerBLEGrpc/Sources/ShimmerBLEService.swift b/ShimmerBLEGrpc/Sources/ShimmerBLEService.swift index 4a96e8e..3a126c0 100644 --- a/ShimmerBLEGrpc/Sources/ShimmerBLEService.swift +++ b/ShimmerBLEGrpc/Sources/ShimmerBLEService.swift @@ -17,7 +17,6 @@ final class ShimmerBLEService: ShimmerBLEGRPC_ShimmerBLEByteServer.SimpleService private var bluetoothManager: BluetoothManager? private var centralManager: CBCentralManager? - private var radio: BleByteRadio? private var deviceNameToConnect: String = "" private var isConnecting: Bool = false @@ -40,8 +39,8 @@ final class ShimmerBLEService: ShimmerBLEGRPC_ShimmerBLEByteServer.SimpleService } func writeBytesShimmer(request: ShimmerBLEGRPC_WriteBytes, context: GRPCCore.ServerContext) async throws -> ShimmerBLEGRPC_Reply { - print("Received writeBytes request for: " + request.address) - radio!.writeData(data: request.byteToWrite) +// print("Received writeBytes request for: " + request.address) + radioMap[request.address]!.writeData(data: request.byteToWrite) return ShimmerBLEGRPC_Reply.with { $0.message = "Written " + request.address } @@ -125,11 +124,12 @@ final class ShimmerBLEService: ShimmerBLEGRPC_ShimmerBLEByteServer.SimpleService bluetoothDeviceMap[deviceNameToConnect] = peripheral queueMap[deviceNameToConnect] = ConcurrentQueue() - self.radio = BleByteRadio(deviceName: deviceNameToConnect,cbperipheral: peripheral!,bluetoothManager: bluetoothManager!) - self.radio?.delegate = self + var radio = BleByteRadio(deviceName: deviceNameToConnect,cbperipheral: peripheral!,bluetoothManager: bluetoothManager!) + radio.delegate = self - var success = await radio?.connect() + var success = await radio.connect() if(success ?? false) { + radioMap[deviceNameToConnect] = radio let status = ShimmerBLEGRPC_StateStatus.with { $0.state = ShimmerBLEGRPC_BluetoothState.connected $0.message = "Success" @@ -146,10 +146,11 @@ final class ShimmerBLEService: ShimmerBLEGRPC_ShimmerBLEByteServer.SimpleService func startDisconnectShimmer(name: String) { Task { - await radio?.disconnect() + await radioMap[name]?.disconnect() bluetoothDeviceMap.removeValue(forKey: name) connectStreamMap.removeValue(forKey: name) queueMap.removeValue(forKey: name) + radioMap.removeValue(forKey: name) } } From f503bccd06561d73db438cd52576d41770db51d5 Mon Sep 17 00:00:00 2001 From: jyong15 Date: Wed, 16 Apr 2025 16:21:11 +0800 Subject: [PATCH 06/13] DEV-221 Fix timer not firing --- .../ShimmerBluetooth/BluetoothManager.swift | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/ShimmerBluetooth/ShimmerBluetooth/BluetoothManager.swift b/ShimmerBluetooth/ShimmerBluetooth/BluetoothManager.swift index 963a305..fe79042 100644 --- a/ShimmerBluetooth/ShimmerBluetooth/BluetoothManager.swift +++ b/ShimmerBluetooth/ShimmerBluetooth/BluetoothManager.swift @@ -33,12 +33,11 @@ public class BluetoothManager: NSObject { } @objc private func scanTimeout() { - print("[DEBUG] Scanning stopped") self.centralManager.stopScan() self.delegate?.scanCompleted() } - + public func startScanning(uuid:String, timeout: Double) -> Bool { deviceName = "" if self.centralManager.state != .poweredOn { @@ -50,7 +49,9 @@ public class BluetoothManager: NSObject { print("[DEBUG] Scanning started") // CBCentralManagerScanOptionAllowDuplicatesKey - timer = Timer.scheduledTimer(timeInterval: timeout, target: self, selector: #selector(BluetoothManager.scanTimeout), userInfo: nil, repeats: false) + DispatchQueue.main.async { + self.timer = Timer.scheduledTimer(timeInterval: timeout, target: self, selector: #selector(BluetoothManager.scanTimeout), userInfo: nil, repeats: false) + } self.centralManager.scanForPeripherals(withServices: [CBUUID(string: uuid)], options: nil) //self.centralManager.scanForPeripherals(withServices: nil, options: nil) print(self.centralManager.isScanning) @@ -68,7 +69,9 @@ public class BluetoothManager: NSObject { print("[DEBUG] Scanning started") // CBCentralManagerScanOptionAllowDuplicatesKey - timer = Timer.scheduledTimer(timeInterval: timeout, target: self, selector: #selector(BluetoothManager.scanTimeout), userInfo: nil, repeats: false) + DispatchQueue.main.async { + self.timer = Timer.scheduledTimer(timeInterval: timeout, target: self, selector: #selector(BluetoothManager.scanTimeout), userInfo: nil, repeats: false) + } //self.centralManager.scanForPeripherals(withServices: [CBUUID(string: uuid)], options: nil) self.centralManager.scanForPeripherals(withServices: nil, options: nil) print(self.centralManager.isScanning) @@ -86,7 +89,9 @@ public class BluetoothManager: NSObject { print("[DEBUG] Scanning started") // CBCentralManagerScanOptionAllowDuplicatesKey - timer = Timer.scheduledTimer(timeInterval: timeout, target: self, selector: #selector(BluetoothManager.scanTimeout), userInfo: nil, repeats: false) + DispatchQueue.main.async { + self.timer = Timer.scheduledTimer(timeInterval: timeout, target: self, selector: #selector(BluetoothManager.scanTimeout), userInfo: nil, repeats: false) + } //self.centralManager.scanForPeripherals(withServices: [CBUUID(string: uuid)], options: nil) self.centralManager.scanForPeripherals(withServices: nil, options: nil) print(self.centralManager.isScanning) From 12a93523a2396b2bcdee172ba0328986523cc32a Mon Sep 17 00:00:00 2001 From: jyong15 Date: Thu, 17 Apr 2025 10:07:45 +0800 Subject: [PATCH 07/13] DEV-221 Improve connection error handling --- .../Sources/ShimmerBLEService.swift | 60 +++++++++---------- .../ShimmerBluetooth/BleByteRadio.swift | 2 +- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/ShimmerBLEGrpc/Sources/ShimmerBLEService.swift b/ShimmerBLEGrpc/Sources/ShimmerBLEService.swift index 3a126c0..b74fb1f 100644 --- a/ShimmerBLEGrpc/Sources/ShimmerBLEService.swift +++ b/ShimmerBLEGrpc/Sources/ShimmerBLEService.swift @@ -61,10 +61,10 @@ final class ShimmerBLEService: ShimmerBLEGRPC_ShimmerBLEByteServer.SimpleService print("Received connectShimmer request for: " + deviceNameToConnect) print("Start Bluetooth Manager Scan") - var res = bluetoothManager?.startScanning(deviceName: deviceNameToConnect, timeout: 3) + var res = self.bluetoothManager?.startScanning(deviceName: self.deviceNameToConnect, timeout: 3) connectStreamMap[deviceNameToConnect] = response - await writeConnectingState(response: response) + await writeStatusResponse(deviceName: deviceNameToConnect, state: ShimmerBLEGRPC_BluetoothState.connecting, message: "Connecting") try await Task.sleep(for: .seconds(4)) while(bluetoothDeviceMap.keys.contains(deviceNameToConnect)) { @@ -73,15 +73,18 @@ final class ShimmerBLEService: ShimmerBLEGRPC_ShimmerBLEByteServer.SimpleService } } - private func writeConnectingState(response: GRPCCore.RPCWriter) async { - var status = ShimmerBLEGRPC_StateStatus() - status.state = ShimmerBLEGRPC_BluetoothState.connecting - status.message = "Connecting" - let stateStatusStream = connectStreamMap[deviceNameToConnect] - do { - try await stateStatusStream?.write(status) - } catch let error { - print(error) + private func writeStatusResponse(deviceName: String, state: ShimmerBLEGRPC_BluetoothState, message: String) async { + var stateStatusStream = connectStreamMap[deviceName] + if(stateStatusStream != nil) { + let status = ShimmerBLEGRPC_StateStatus.with { + $0.state = state + $0.message = message + } + do { + try await stateStatusStream?.write(status) + } catch let error { + print(error) + } } } @@ -120,27 +123,24 @@ final class ShimmerBLEService: ShimmerBLEGRPC_ShimmerBLEByteServer.SimpleService func startConnectShimmer() async { let peripheral = bluetoothManager?.getPeripheral(deviceName: deviceNameToConnect) - - bluetoothDeviceMap[deviceNameToConnect] = peripheral - queueMap[deviceNameToConnect] = ConcurrentQueue() - - var radio = BleByteRadio(deviceName: deviceNameToConnect,cbperipheral: peripheral!,bluetoothManager: bluetoothManager!) - radio.delegate = self - - var success = await radio.connect() - if(success ?? false) { - radioMap[deviceNameToConnect] = radio - let status = ShimmerBLEGRPC_StateStatus.with { - $0.state = ShimmerBLEGRPC_BluetoothState.connected - $0.message = "Success" - } - let stateStatusStream = connectStreamMap[deviceNameToConnect] - do { - try await stateStatusStream?.write(status) - } catch let error { - print(error) + if(peripheral != nil) { + bluetoothDeviceMap[deviceNameToConnect] = peripheral + queueMap[deviceNameToConnect] = ConcurrentQueue() + + let radio = BleByteRadio(deviceName: deviceNameToConnect,cbperipheral: peripheral!,bluetoothManager: bluetoothManager!) + radio.delegate = self + + let success = await radio.connect() + if(success ?? false) { + radioMap[deviceNameToConnect] = radio + await writeStatusResponse(deviceName: deviceNameToConnect, state: ShimmerBLEGRPC_BluetoothState.connected, message: "Success") + } else { + await writeStatusResponse(deviceName: deviceNameToConnect, state: ShimmerBLEGRPC_BluetoothState.disconnected, message: "Radio failed to connect") } + } else { + await writeStatusResponse(deviceName: deviceNameToConnect, state: ShimmerBLEGRPC_BluetoothState.disconnected, message: "Failed to discover device") } + isConnecting = false } diff --git a/ShimmerBluetooth/ShimmerBluetooth/BleByteRadio.swift b/ShimmerBluetooth/ShimmerBluetooth/BleByteRadio.swift index 7c93136..0783790 100644 --- a/ShimmerBluetooth/ShimmerBluetooth/BleByteRadio.swift +++ b/ShimmerBluetooth/ShimmerBluetooth/BleByteRadio.swift @@ -95,7 +95,7 @@ public class BleByteRadio : NSObject, ByteCommunication { public func writeData(data: Data) ->Bool { guard let char = self.characteristics[RBL_CHAR_TX_UUID] else { return false} - print("Write Data \(data)") + print("[DEBUG] Write Data \(data)") print(char.uuid.uuidString) self.activePeripheral?.writeValue(data, for: char, type: .withResponse) return true From 7296c226dee364955827e6cb8283f80d52d86d8b Mon Sep 17 00:00:00 2001 From: jyong15 Date: Thu, 17 Apr 2025 10:18:13 +0800 Subject: [PATCH 08/13] DEV-221 Remove duplicate debug prints --- ShimmerBLEGrpc/Sources/ShimmerBLEService.swift | 3 --- 1 file changed, 3 deletions(-) diff --git a/ShimmerBLEGrpc/Sources/ShimmerBLEService.swift b/ShimmerBLEGrpc/Sources/ShimmerBLEService.swift index b74fb1f..2627b4b 100644 --- a/ShimmerBLEGrpc/Sources/ShimmerBLEService.swift +++ b/ShimmerBLEGrpc/Sources/ShimmerBLEService.swift @@ -59,8 +59,6 @@ final class ShimmerBLEService: ShimmerBLEGRPC_ShimmerBLEByteServer.SimpleService deviceNameToConnect = request.name isConnecting = true print("Received connectShimmer request for: " + deviceNameToConnect) - - print("Start Bluetooth Manager Scan") var res = self.bluetoothManager?.startScanning(deviceName: self.deviceNameToConnect, timeout: 3) connectStreamMap[deviceNameToConnect] = response @@ -158,7 +156,6 @@ final class ShimmerBLEService: ShimmerBLEGRPC_ShimmerBLEByteServer.SimpleService extension ShimmerBLEService : BluetoothManagerDelegate { func scanCompleted() { - print("Bluetooth Manager Scan Completed") if(isConnecting) { Task { await startConnectShimmer() From e2cff639734ad97b048acad1c9dc957e1db14b8e Mon Sep 17 00:00:00 2001 From: jyong15 Date: Tue, 22 Apr 2025 15:35:00 +0800 Subject: [PATCH 09/13] DEV-232 Disallow simultaneous connection attempts --- .../Sources/ShimmerBLEService.swift | 40 ++++++++++++------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/ShimmerBLEGrpc/Sources/ShimmerBLEService.swift b/ShimmerBLEGrpc/Sources/ShimmerBLEService.swift index 2627b4b..6026a3c 100644 --- a/ShimmerBLEGrpc/Sources/ShimmerBLEService.swift +++ b/ShimmerBLEGrpc/Sources/ShimmerBLEService.swift @@ -39,7 +39,6 @@ final class ShimmerBLEService: ShimmerBLEGRPC_ShimmerBLEByteServer.SimpleService } func writeBytesShimmer(request: ShimmerBLEGRPC_WriteBytes, context: GRPCCore.ServerContext) async throws -> ShimmerBLEGRPC_Reply { -// print("Received writeBytes request for: " + request.address) radioMap[request.address]!.writeData(data: request.byteToWrite) return ShimmerBLEGRPC_Reply.with { $0.message = "Written " + request.address @@ -56,30 +55,41 @@ final class ShimmerBLEService: ShimmerBLEGRPC_ShimmerBLEByteServer.SimpleService //Initiates a BLE scan first, before completing the process in startConnectShimmer() func connectShimmer(request: ShimmerBLEGRPC_Request, response: GRPCCore.RPCWriter, context: GRPCCore.ServerContext) async throws { - deviceNameToConnect = request.name - isConnecting = true - print("Received connectShimmer request for: " + deviceNameToConnect) - var res = self.bluetoothManager?.startScanning(deviceName: self.deviceNameToConnect, timeout: 3) - - connectStreamMap[deviceNameToConnect] = response - await writeStatusResponse(deviceName: deviceNameToConnect, state: ShimmerBLEGRPC_BluetoothState.connecting, message: "Connecting") - - try await Task.sleep(for: .seconds(4)) - while(bluetoothDeviceMap.keys.contains(deviceNameToConnect)) { - //this keeps the response GRPCCore.RPCWriter<> open - try await Task.sleep(for: .seconds(0.1)) //sleep 100ms + if(!isConnecting) { + deviceNameToConnect = request.name + isConnecting = true + print("Received connectShimmer request for: " + deviceNameToConnect) + var res = self.bluetoothManager?.startScanning(deviceName: self.deviceNameToConnect, timeout: 3) + + connectStreamMap[deviceNameToConnect] = response + await writeStatusResponse(deviceName: deviceNameToConnect, state: ShimmerBLEGRPC_BluetoothState.connecting, message: "Connecting") + + try await Task.sleep(for: .seconds(4)) + while(bluetoothDeviceMap.keys.contains(deviceNameToConnect)) { + //this keeps the response GRPCCore.RPCWriter<> open + try await Task.sleep(for: .seconds(0.1)) //sleep 100ms + } + } else { + print("Received connectShimmer request for: " + deviceNameToConnect) + print("Error: connection attempt already in progress!") + await writeStatusResponseWithRPCWriter(deviceName: request.name, state: ShimmerBLEGRPC_BluetoothState.disconnected, + message: "Connection failed! Existing connection attempt in progress", writer: response) } } private func writeStatusResponse(deviceName: String, state: ShimmerBLEGRPC_BluetoothState, message: String) async { var stateStatusStream = connectStreamMap[deviceName] - if(stateStatusStream != nil) { + await writeStatusResponseWithRPCWriter(deviceName: deviceName, state: state, message: message, writer: stateStatusStream) + } + + private func writeStatusResponseWithRPCWriter(deviceName: String, state: ShimmerBLEGRPC_BluetoothState, message: String, writer: GRPCCore.RPCWriter?) async { + if(writer != nil) { let status = ShimmerBLEGRPC_StateStatus.with { $0.state = state $0.message = message } do { - try await stateStatusStream?.write(status) + try await writer?.write(status) } catch let error { print(error) } From 4a2f7a7e332199b492ff7284cef2eaceea51cede Mon Sep 17 00:00:00 2001 From: jyong15 Date: Tue, 22 Apr 2025 15:51:32 +0800 Subject: [PATCH 10/13] DEV-232 minor refactor --- ShimmerBLEGrpc/Sources/ShimmerBLEService.swift | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ShimmerBLEGrpc/Sources/ShimmerBLEService.swift b/ShimmerBLEGrpc/Sources/ShimmerBLEService.swift index 6026a3c..d016a12 100644 --- a/ShimmerBLEGrpc/Sources/ShimmerBLEService.swift +++ b/ShimmerBLEGrpc/Sources/ShimmerBLEService.swift @@ -72,17 +72,16 @@ final class ShimmerBLEService: ShimmerBLEGRPC_ShimmerBLEByteServer.SimpleService } else { print("Received connectShimmer request for: " + deviceNameToConnect) print("Error: connection attempt already in progress!") - await writeStatusResponseWithRPCWriter(deviceName: request.name, state: ShimmerBLEGRPC_BluetoothState.disconnected, - message: "Connection failed! Existing connection attempt in progress", writer: response) + await writeStatusResponseWithRPCWriter(state: ShimmerBLEGRPC_BluetoothState.disconnected, message: "Connection failed! Existing connection attempt in progress", writer: response) } } private func writeStatusResponse(deviceName: String, state: ShimmerBLEGRPC_BluetoothState, message: String) async { var stateStatusStream = connectStreamMap[deviceName] - await writeStatusResponseWithRPCWriter(deviceName: deviceName, state: state, message: message, writer: stateStatusStream) + await writeStatusResponseWithRPCWriter(state: state, message: message, writer: stateStatusStream) } - private func writeStatusResponseWithRPCWriter(deviceName: String, state: ShimmerBLEGRPC_BluetoothState, message: String, writer: GRPCCore.RPCWriter?) async { + private func writeStatusResponseWithRPCWriter(state: ShimmerBLEGRPC_BluetoothState, message: String, writer: GRPCCore.RPCWriter?) async { if(writer != nil) { let status = ShimmerBLEGRPC_StateStatus.with { $0.state = state From a8f180669b5eeb574f1335135a61d3b425ff5811 Mon Sep 17 00:00:00 2001 From: jyong15 Date: Mon, 28 Apr 2025 13:01:21 +0800 Subject: [PATCH 11/13] DEV-232 Fix command line tool export Also, code refactors --- ShimmerBLEGrpc/ShimmerBLEGrpc.entitlements | 8 +++++ .../ShimmerBLEGrpc.xcodeproj/project.pbxproj | 10 ++++-- .../xcschemes/ShimmerBLEGrpc.xcscheme | 21 +++++++++-- ShimmerBLEGrpc/Sources/HelloWorld.swift | 26 -------------- .../Sources/ShimmerBLEService.swift | 6 ++-- ShimmerBLEGrpc/Sources/ShimmerServer.swift | 36 +++++++++++++++++++ .../Sources/Subcommands/Serve.swift | 4 +-- .../project.pbxproj | 6 ++++ 8 files changed, 82 insertions(+), 35 deletions(-) create mode 100644 ShimmerBLEGrpc/ShimmerBLEGrpc.entitlements delete mode 100644 ShimmerBLEGrpc/Sources/HelloWorld.swift create mode 100644 ShimmerBLEGrpc/Sources/ShimmerServer.swift diff --git a/ShimmerBLEGrpc/ShimmerBLEGrpc.entitlements b/ShimmerBLEGrpc/ShimmerBLEGrpc.entitlements new file mode 100644 index 0000000..8cc185a --- /dev/null +++ b/ShimmerBLEGrpc/ShimmerBLEGrpc.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.cs.disable-library-validation + + + diff --git a/ShimmerBLEGrpc/ShimmerBLEGrpc.xcodeproj/project.pbxproj b/ShimmerBLEGrpc/ShimmerBLEGrpc.xcodeproj/project.pbxproj index 5c6ca80..cac8bbe 100644 --- a/ShimmerBLEGrpc/ShimmerBLEGrpc.xcodeproj/project.pbxproj +++ b/ShimmerBLEGrpc/ShimmerBLEGrpc.xcodeproj/project.pbxproj @@ -36,7 +36,7 @@ 456851932DA395630047A883 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; + dstPath = /usr/share/man/man1; dstSubfolderSpec = 0; files = ( ); @@ -49,6 +49,7 @@ 45345AC22DA62CD700EA7B41 /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; 45345AC92DA62FA100EA7B41 /* ShimmerBluetooth.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = ShimmerBluetooth.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 456851952DA395630047A883 /* ShimmerBLEGrpc */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ShimmerBLEGrpc; sourceTree = BUILT_PRODUCTS_DIR; }; + 45A656212DBB4F2E001F8C55 /* ShimmerBLEGrpc.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ShimmerBLEGrpc.entitlements; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFileSystemSynchronizedRootGroup section */ @@ -64,13 +65,13 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 45345ACA2DA62FA100EA7B41 /* ShimmerBluetooth.framework in Frameworks */, 45345AF12DA639C300EA7B41 /* GRPCProtobuf in Frameworks */, 45345AFB2DA63A1100EA7B41 /* ArgumentParser in Frameworks */, 45345AEA2DA6399900EA7B41 /* GRPCCodeGen in Frameworks */, 45345AD12DA6361500EA7B41 /* SwiftProtobufPluginLibrary in Frameworks */, 45345AEC2DA6399900EA7B41 /* GRPCCore in Frameworks */, 45345AF62DA639F300EA7B41 /* GRPCNIOTransportHTTP2Posix in Frameworks */, - 45345ACA2DA62FA100EA7B41 /* ShimmerBluetooth.framework in Frameworks */, 45345ACF2DA6361500EA7B41 /* SwiftProtobuf in Frameworks */, 45345AF42DA639F300EA7B41 /* GRPCNIOTransportHTTP2 in Frameworks */, 45345AF82DA639F300EA7B41 /* GRPCNIOTransportHTTP2TransportServices in Frameworks */, @@ -92,6 +93,7 @@ 4568518C2DA395630047A883 = { isa = PBXGroup; children = ( + 45A656212DBB4F2E001F8C55 /* ShimmerBLEGrpc.entitlements */, 45345AC22DA62CD700EA7B41 /* Package.swift */, 45345AB62DA4F12500EA7B41 /* Readme.md */, 45345AAF2DA4F0EF00EA7B41 /* Sources */, @@ -317,11 +319,13 @@ 4568519D2DA395630047A883 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CODE_SIGN_ENTITLEMENTS = ShimmerBLEGrpc.entitlements; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; CODE_SIGN_STYLE = Manual; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=macosx*]" = ""; ENABLE_HARDENED_RUNTIME = YES; + "LD_RUNPATH_SEARCH_PATHS[arch=*]" = "@executable_path"; PRODUCT_BUNDLE_IDENTIFIER = com.shimmersensing.ShimmerBLEGrpc; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -332,11 +336,13 @@ 4568519E2DA395630047A883 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CODE_SIGN_ENTITLEMENTS = ShimmerBLEGrpc.entitlements; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; CODE_SIGN_STYLE = Manual; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=macosx*]" = ""; ENABLE_HARDENED_RUNTIME = YES; + "LD_RUNPATH_SEARCH_PATHS[arch=*]" = "@executable_path"; PRODUCT_BUNDLE_IDENTIFIER = com.shimmersensing.ShimmerBLEGrpc; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/ShimmerBLEGrpc/ShimmerBLEGrpc.xcodeproj/xcshareddata/xcschemes/ShimmerBLEGrpc.xcscheme b/ShimmerBLEGrpc/ShimmerBLEGrpc.xcodeproj/xcshareddata/xcschemes/ShimmerBLEGrpc.xcscheme index 6561201..5893bc3 100644 --- a/ShimmerBLEGrpc/ShimmerBLEGrpc.xcodeproj/xcshareddata/xcschemes/ShimmerBLEGrpc.xcscheme +++ b/ShimmerBLEGrpc/ShimmerBLEGrpc.xcodeproj/xcshareddata/xcschemes/ShimmerBLEGrpc.xcscheme @@ -1,7 +1,7 @@ + version = "2.2"> + + + + + isEnabled = "NO"> + + + + Date: Mon, 28 Apr 2025 13:02:59 +0800 Subject: [PATCH 12/13] DEV-232 update Readme --- ShimmerBLEGrpc/Readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ShimmerBLEGrpc/Readme.md b/ShimmerBLEGrpc/Readme.md index c6be6e4..28e61a7 100644 --- a/ShimmerBLEGrpc/Readme.md +++ b/ShimmerBLEGrpc/Readme.md @@ -3,3 +3,4 @@ Then, select the Start button at the top-left of Xcode to start the app Then, open the Shimmer-Java-Android-API ShimmerGRPC.java class from: https://github.com/ShimmerEngineering/Shimmer-Java-Android-API/blob/master/ShimmerDriverPC/src/main/java/com/shimmerresearch/pcDriver/ShimmerGRPC.java Set the name of the device you want to connect to, in Line 101 of the class. This is e.g. "Shimmer3-XXXX". Note that this is not the Bluetooth Mac address, as MacOS BLE is limited to using Bluetooth device names. +Then, run ShimmerGRPC.java From 47b660ea3cb57eb7f649140903f7f45d43160973 Mon Sep 17 00:00:00 2001 From: jyong15 Date: Fri, 16 May 2025 16:20:39 +0800 Subject: [PATCH 13/13] DEV-270 DEV-221 remove print data --- ShimmerBluetooth/ShimmerBluetooth/BleByteRadio.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ShimmerBluetooth/ShimmerBluetooth/BleByteRadio.swift b/ShimmerBluetooth/ShimmerBluetooth/BleByteRadio.swift index 0783790..a90517b 100644 --- a/ShimmerBluetooth/ShimmerBluetooth/BleByteRadio.swift +++ b/ShimmerBluetooth/ShimmerBluetooth/BleByteRadio.swift @@ -270,7 +270,7 @@ extension BleByteRadio : CBPeripheralDelegate { if characteristic.uuid.uuidString == RBL_CHAR_RX_UUID { if let data = characteristic.value { //self.processData(data) - print(data) +// print(data) self.delegate?.byteCommunicationDataReceived(data: data, deviceName: (deviceName ?? "")) } }