@mentra/bluetooth-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +278 -0
- package/android/build.gradle +167 -0
- package/android/lc3Lib/CMakeLists.txt +6 -0
- package/android/lc3Lib/build.gradle +109 -0
- package/android/lc3Lib/proguard-rules.pro +33 -0
- package/android/lc3Lib/src/main/AndroidManifest.xml +2 -0
- package/android/lc3Lib/src/main/cpp/CMakeLists.txt +8 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/CMakeLists.txt +30 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/jni/CMakeLists.txt +7 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/jni/ogg_opus_encoder.cc +96 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/jni/ogg_opus_encoder.h +53 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/Makefile.am +6 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/config_types.h +26 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/config_types.h.in +26 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/ogg.h +209 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/os_types.h +158 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus.h +981 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_custom.h +342 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_defines.h +799 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_multistream.h +660 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_projection.h +568 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_types.h +166 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/ogg_opus_encoder.cc +268 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/ogg_opus_encoder.h +115 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/opus_tools/opus_header.h +59 -0
- package/android/lc3Lib/src/main/cpp/liblc3/CMakeLists.txt +38 -0
- package/android/lc3Lib/src/main/cpp/liblc3/include/lc3.h +309 -0
- package/android/lc3Lib/src/main/cpp/liblc3/include/lc3_private.h +162 -0
- package/android/lc3Lib/src/main/cpp/liblc3/include/rnnoise.h +114 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/CMakeLists.txt +19 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/attdet.c +92 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/attdet.h +44 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bits.c +375 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bits.h +315 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bwdet.c +129 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bwdet.h +69 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/common.h +148 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/energy.c +70 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/energy.h +43 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/fastmath.h +158 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/lc3.c +702 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf.c +893 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf.h +111 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf_arm.h +506 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf_neon.h +281 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/makefile.mk +35 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/mdct.c +452 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/mdct.h +57 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/mdct_neon.h +296 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/meson.build +46 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/plc.c +61 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/plc.h +57 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/sns.c +880 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/sns.h +103 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/spec.c +904 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/spec.h +119 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tables.c +3457 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tables.h +94 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tns.c +457 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tns.h +99 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3.cpp +159 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/_kiss_fft_guts.h +182 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/arch.h +261 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/celt_lpc.c +279 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/celt_lpc.h +59 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/common.h +48 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/compile.sh +3 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/denoise.c +646 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/kiss_fft.c +601 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/kiss_fft.h +203 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/opus_types.h +159 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/pitch.c +526 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/pitch.h +149 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn.c +178 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn.h +69 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_data.c +11051 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_data.h +34 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_reader.c +168 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_train.py +66 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/tansig_table.h +45 -0
- package/android/lc3Lib/src/main/java/com/mentra/lc3Lib/Lc3Cpp.java +38 -0
- package/android/lc3Lib/third_party/CMakeLists.txt +23 -0
- package/android/lc3Lib/third_party/CMakeLists_libogg.txt +18 -0
- package/android/lc3Lib/third_party/CMakeLists_libopus.txt +18 -0
- package/android/lc3Lib/third_party/CMakeLists_opus-tools.txt +23 -0
- package/android/lc3Lib/third_party/opus_tools/src/AUTHORS +5 -0
- package/android/lc3Lib/third_party/opus_tools/src/CMakeLists.txt +4 -0
- package/android/lc3Lib/third_party/opus_tools/src/COPYING +371 -0
- package/android/lc3Lib/third_party/opus_tools/src/ChangeLog +3 -0
- package/android/lc3Lib/third_party/opus_tools/src/Makefile.am +42 -0
- package/android/lc3Lib/third_party/opus_tools/src/Makefile.unix +23 -0
- package/android/lc3Lib/third_party/opus_tools/src/NEWS +0 -0
- package/android/lc3Lib/third_party/opus_tools/src/README +0 -0
- package/android/lc3Lib/third_party/opus_tools/src/autogen.sh +115 -0
- package/android/lc3Lib/third_party/opus_tools/src/configure.ac +293 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/arch.h +239 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/audio-in.c +1046 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/diag_range.c +245 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/diag_range.h +28 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/info_opus.c +320 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/info_opus.h +51 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/lpc.c +157 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/lpc.h +27 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opus_header.c +286 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opus_header.h +59 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opusdec.c +884 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opusenc.c +1021 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opusenc.h +101 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opusinfo.c +639 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opusinfo.h +51 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/os_support.h +167 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/resample.c +1137 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/speex_resampler.h +344 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/stack_alloc.h +115 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/wav_io.c +125 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/wav_io.h +62 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/wave_out.c +223 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/wave_out.h +60 -0
- package/android/settings.gradle +1 -0
- package/android/src/main/AndroidManifest.xml +40 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +528 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/Bridge.kt +610 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/DeviceManager.kt +1616 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/DeviceStore.kt +314 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothModels.kt +1710 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +554 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/ObservableStore.kt +68 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/controllers/ControllerManager.kt +158 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/controllers/R1.kt +934 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/services/Foreground.kt +175 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/services/PhoneMic.kt +1109 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G1.java +3974 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G2.kt +3551 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Mach1.java +1327 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.java +6959 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraNex.kt +1655 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraosBle.java +53675 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/SGCManager.kt +202 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Simulated.kt +224 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/stt/STTTools.kt +340 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/stt/SherpaOnnxTranscriber.kt +465 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/stt/VadGateSpeechPolicy.kt +221 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/AES.java +106 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/AudioSessionMonitor.kt +189 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/BitmapJavaUtils.java +169 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/BlePhotoUploadService.java +179 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/Constants.kt +44 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/G1Text.kt +436 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/IncidentLogBleRelayNaming.java +29 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/IncidentLogBleUploadService.java +76 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/K900ProtocolUtils.java +791 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/MessageChunker.java +186 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/NexSGCUtils.kt +589 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/PhoneAudioMonitor.kt +303 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/SmartGlassesConnectionState.java +9 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/audio/ByteUtilAudioPlayer.java +655 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/audio/Lc3Player.java +441 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/audio/PCMAudioPlayer.java +431 -0
- package/android/src/main/res/values/strings.xml +4 -0
- package/app.plugin.js +1 -0
- package/build/BluetoothSdk.types.d.ts +498 -0
- package/build/BluetoothSdk.types.d.ts.map +1 -0
- package/build/BluetoothSdk.types.js +23 -0
- package/build/BluetoothSdk.types.js.map +1 -0
- package/build/BluetoothSdkModule.d.ts +71 -0
- package/build/BluetoothSdkModule.d.ts.map +1 -0
- package/build/BluetoothSdkModule.js +106 -0
- package/build/BluetoothSdkModule.js.map +1 -0
- package/build/index.d.ts +3 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +5 -0
- package/build/index.js.map +1 -0
- package/expo-module.config.json +9 -0
- package/ios/BluetoothSdkModule.swift +665 -0
- package/ios/MentraBluetoothSDK.podspec +77 -0
- package/ios/Packages/CoreObjC/CoreObjC.xcodeproj/project.pbxproj +213 -0
- package/ios/Packages/CoreObjC/PcmConverter.h +22 -0
- package/ios/Packages/CoreObjC/PcmConverter.m +266 -0
- package/ios/Packages/CoreObjC/attdet.c +92 -0
- package/ios/Packages/CoreObjC/attdet.h +44 -0
- package/ios/Packages/CoreObjC/bits.c +375 -0
- package/ios/Packages/CoreObjC/bits.h +315 -0
- package/ios/Packages/CoreObjC/bwdet.c +129 -0
- package/ios/Packages/CoreObjC/bwdet.h +69 -0
- package/ios/Packages/CoreObjC/common.h +151 -0
- package/ios/Packages/CoreObjC/energy.c +70 -0
- package/ios/Packages/CoreObjC/energy.h +43 -0
- package/ios/Packages/CoreObjC/fastmath.h +158 -0
- package/ios/Packages/CoreObjC/lc3.c +704 -0
- package/ios/Packages/CoreObjC/lc3.h +313 -0
- package/ios/Packages/CoreObjC/lc3_cpp.h +283 -0
- package/ios/Packages/CoreObjC/lc3_private.h +163 -0
- package/ios/Packages/CoreObjC/ltpf.c +905 -0
- package/ios/Packages/CoreObjC/ltpf.h +111 -0
- package/ios/Packages/CoreObjC/ltpf_arm.h +506 -0
- package/ios/Packages/CoreObjC/ltpf_neon.h +281 -0
- package/ios/Packages/CoreObjC/makefile.mk +35 -0
- package/ios/Packages/CoreObjC/mdct.c +469 -0
- package/ios/Packages/CoreObjC/mdct.h +57 -0
- package/ios/Packages/CoreObjC/mdct_neon.h +296 -0
- package/ios/Packages/CoreObjC/meson.build +61 -0
- package/ios/Packages/CoreObjC/plc.c +61 -0
- package/ios/Packages/CoreObjC/plc.h +57 -0
- package/ios/Packages/CoreObjC/rnnoise.h +114 -0
- package/ios/Packages/CoreObjC/sns.c +880 -0
- package/ios/Packages/CoreObjC/sns.h +103 -0
- package/ios/Packages/CoreObjC/spec.c +907 -0
- package/ios/Packages/CoreObjC/spec.h +119 -0
- package/ios/Packages/CoreObjC/tables.c +3457 -0
- package/ios/Packages/CoreObjC/tables.h +94 -0
- package/ios/Packages/CoreObjC/tns.c +457 -0
- package/ios/Packages/CoreObjC/tns.h +99 -0
- package/ios/Packages/SherpaOnnx/Model/joiner.onnx +0 -0
- package/ios/Packages/SherpaOnnx/Model/tokens.txt +502 -0
- package/ios/Packages/SherpaOnnx/SherpaOnnx.swift +1659 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Headers/cargs.h +162 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Headers/sherpa-onnx/c-api/c-api.h +1852 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Headers/sherpa-onnx/c-api/cxx-api.h +674 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Info.plist +44 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/libsherpa-onnx.a +0 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/sherpa-onnx.a +0 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/libsherpa-onnx.a +0 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/sherpa-onnx.a +0 -0
- package/ios/Packages/VAD/Common/VAD/VADQuality.swift +41 -0
- package/ios/Packages/VAD/Common/VAD/VADState.swift +26 -0
- package/ios/Packages/VAD/Common/VAD/VADStrategy.swift +29 -0
- package/ios/Packages/VAD/Common/VAD/VADType.swift +14 -0
- package/ios/Packages/VAD/Data/Configuration.swift +68 -0
- package/ios/Packages/VAD/Data/FrameSize.swift +39 -0
- package/ios/Packages/VAD/Data/Record.swift +13 -0
- package/ios/Packages/VAD/Data/Result.swift +22 -0
- package/ios/Packages/VAD/Data/SampleRate.swift +48 -0
- package/ios/Packages/VAD/Silero/Model/silero_vad.onnx +0 -0
- package/ios/Packages/VAD/Silero/SileroVAD.swift +284 -0
- package/ios/Packages/VAD/Silero/SileroVADStrategy.swift +64 -0
- package/ios/Packages/libbz2/module.modulemap +5 -0
- package/ios/Packages/libbz2/shim.h +1 -0
- package/ios/Source/Bridge.swift +353 -0
- package/ios/Source/Bridging-Header.h +16 -0
- package/ios/Source/DeviceManager.swift +1478 -0
- package/ios/Source/DeviceStore.swift +295 -0
- package/ios/Source/MentraBluetoothSDK.swift +2439 -0
- package/ios/Source/ObservableStore.swift +88 -0
- package/ios/Source/PrivacyInfo.xcprivacy +23 -0
- package/ios/Source/controllers/ControllerManager.swift +187 -0
- package/ios/Source/controllers/R1.swift +827 -0
- package/ios/Source/services/PhoneMic.swift +662 -0
- package/ios/Source/sgcs/Frame.swift +651 -0
- package/ios/Source/sgcs/G1.swift +2505 -0
- package/ios/Source/sgcs/G2.swift +3730 -0
- package/ios/Source/sgcs/Mach1.swift +543 -0
- package/ios/Source/sgcs/MentraLive.swift +4708 -0
- package/ios/Source/sgcs/MentraNex.swift +2479 -0
- package/ios/Source/sgcs/SGCManager.swift +243 -0
- package/ios/Source/sgcs/Simulated.swift +270 -0
- package/ios/Source/sgcs/mentraos_ble.pb.swift +3811 -0
- package/ios/Source/stt/STTTools.swift +154 -0
- package/ios/Source/stt/SherpaOnnxTranscriber.swift +401 -0
- package/ios/Source/utils/AudioSessionMonitor.swift +283 -0
- package/ios/Source/utils/Constants.swift +74 -0
- package/ios/Source/utils/Enums.swift +95 -0
- package/ios/Source/utils/G1Text.swift +2067 -0
- package/ios/Source/utils/JSCExperiment.swift +241 -0
- package/ios/Source/utils/MemoryMonitor.swift +44 -0
- package/ios/Source/utils/MessageChunker.swift +164 -0
- package/ios/Source/utils/Models.swift +135 -0
- package/ios/Source/utils/PhoneAudioMonitor.swift +226 -0
- package/ios/Source/utils/TarBz2Extractor.swift +206 -0
- package/package.json +78 -0
- package/plugin/build/index.d.ts +6 -0
- package/plugin/build/index.js +12 -0
- package/plugin/build/withAndroid.d.ts +4 -0
- package/plugin/build/withAndroid.js +80 -0
- package/plugin/build/withIos.d.ts +4 -0
- package/plugin/build/withIos.js +64 -0
- package/src/BluetoothSdk.types.ts +581 -0
- package/src/BluetoothSdkModule.ts +259 -0
- package/src/index.ts +4 -0
|
@@ -0,0 +1,651 @@
|
|
|
1
|
+
// //
|
|
2
|
+
// // Frame.swift
|
|
3
|
+
// // AOS
|
|
4
|
+
// //
|
|
5
|
+
// // Created by Matthew Fosse on 8/20/25.
|
|
6
|
+
// //
|
|
7
|
+
|
|
8
|
+
// //
|
|
9
|
+
// // FrameManager.swift
|
|
10
|
+
// // AOS
|
|
11
|
+
// //
|
|
12
|
+
// // Created for Brilliant Labs Frame support
|
|
13
|
+
// //
|
|
14
|
+
|
|
15
|
+
// import Combine
|
|
16
|
+
// import CoreBluetooth
|
|
17
|
+
// import Foundation
|
|
18
|
+
// import React
|
|
19
|
+
// import UIKit
|
|
20
|
+
|
|
21
|
+
// // MARK: - Supporting Types
|
|
22
|
+
|
|
23
|
+
// struct FrameDevice {
|
|
24
|
+
// let name: String
|
|
25
|
+
// let address: String
|
|
26
|
+
// }
|
|
27
|
+
|
|
28
|
+
// struct FrameCommand {
|
|
29
|
+
// let command: String
|
|
30
|
+
// let completion: ((Bool) -> Void)?
|
|
31
|
+
// }
|
|
32
|
+
|
|
33
|
+
// // MARK: - FrameManager
|
|
34
|
+
|
|
35
|
+
// @objc(FrameManager) class FrameManager: NSObject, SGCManager {
|
|
36
|
+
// func sendButtonMaxRecordingTime() {}
|
|
37
|
+
|
|
38
|
+
// var appVersion: String = ""
|
|
39
|
+
|
|
40
|
+
// var buildNumber: String = ""
|
|
41
|
+
|
|
42
|
+
// var deviceModel: String = ""
|
|
43
|
+
|
|
44
|
+
// var androidVersion: String = ""
|
|
45
|
+
|
|
46
|
+
// var otaVersionUrl: String = ""
|
|
47
|
+
|
|
48
|
+
// var serialNumber: String = ""
|
|
49
|
+
|
|
50
|
+
// var style: String = ""
|
|
51
|
+
|
|
52
|
+
// var color: String = ""
|
|
53
|
+
|
|
54
|
+
// var caseBatteryLevel: Int = -1
|
|
55
|
+
|
|
56
|
+
// var wifiSsid: String = ""
|
|
57
|
+
|
|
58
|
+
// var wifiConnected: Bool = false
|
|
59
|
+
|
|
60
|
+
// var wifiLocalIp: String = ""
|
|
61
|
+
|
|
62
|
+
// var isHotspotEnabled: Bool = false
|
|
63
|
+
|
|
64
|
+
// var hotspotSsid: String = ""
|
|
65
|
+
|
|
66
|
+
// var hotspotPassword: String = ""
|
|
67
|
+
|
|
68
|
+
// var hotspotGatewayIp: String = ""
|
|
69
|
+
|
|
70
|
+
// func sendJson(_: [String: Any], wakeUp _: Bool, requireAck _: Bool) {}
|
|
71
|
+
|
|
72
|
+
// func sendButtonPhotoSettings() {}
|
|
73
|
+
|
|
74
|
+
// func sendButtonVideoRecordingSettings() {}
|
|
75
|
+
|
|
76
|
+
// func sendButtonMaxRecordingTime(_: Int) {}
|
|
77
|
+
|
|
78
|
+
// func sendButtonCameraLedSetting() {}
|
|
79
|
+
|
|
80
|
+
func exit() {}
|
|
81
|
+
|
|
82
|
+
func sendRgbLedControl(requestId: String, packageName _: String?, action _: String, color _: String?, ontime _: Int, offtime _: Int, count _: Int) {
|
|
83
|
+
Bridge.sendRgbLedControlResponse(requestId: requestId, success: false, error: "device_not_supported")
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// func requestWifiScan() {}
|
|
87
|
+
|
|
88
|
+
// func sendWifiCredentials(_: String, _: String) {}
|
|
89
|
+
|
|
90
|
+
// func sendHotspotState(_: Bool) {}
|
|
91
|
+
|
|
92
|
+
// func queryGalleryStatus() {}
|
|
93
|
+
|
|
94
|
+
// func showDashboard() {}
|
|
95
|
+
|
|
96
|
+
// func getConnectedBluetoothName() -> String? {
|
|
97
|
+
// return nil
|
|
98
|
+
// }
|
|
99
|
+
|
|
100
|
+
// func setDashboardPosition(_: Int, _: Int) {}
|
|
101
|
+
|
|
102
|
+
// func setSilentMode(_: Bool) {}
|
|
103
|
+
|
|
104
|
+
// func findCompatibleDevices() {}
|
|
105
|
+
|
|
106
|
+
// func connectById(_: String) {}
|
|
107
|
+
|
|
108
|
+
// func displayBitmap(base64ImageData _: String) async -> Bool {
|
|
109
|
+
// return true
|
|
110
|
+
// }
|
|
111
|
+
|
|
112
|
+
// func sendDoubleTextWall(_: String, _: String) {}
|
|
113
|
+
|
|
114
|
+
// func sendJson(_: [String: Any], wakeUp _: Bool) {}
|
|
115
|
+
|
|
116
|
+
// func requestPhoto(_: String, appId _: String, size _: String?, webhookUrl _: String?) {}
|
|
117
|
+
|
|
118
|
+
// func forget() {}
|
|
119
|
+
|
|
120
|
+
// func setBrightness(_: Int, autoMode _: Bool) {}
|
|
121
|
+
|
|
122
|
+
// let type = "frame"
|
|
123
|
+
// let hasMic = false
|
|
124
|
+
// var ready = false
|
|
125
|
+
// var isHeadUp = false
|
|
126
|
+
// var caseOpen = false
|
|
127
|
+
// var caseRemoved = true
|
|
128
|
+
// var caseCharging = false
|
|
129
|
+
|
|
130
|
+
// func setMicEnabled(_: Bool) {}
|
|
131
|
+
|
|
132
|
+
// func startRtmpStream(_: [String: Any]) {}
|
|
133
|
+
|
|
134
|
+
// func stopRtmpStream() {}
|
|
135
|
+
|
|
136
|
+
// func sendRtmpKeepAlive(_: [String: Any]) {}
|
|
137
|
+
|
|
138
|
+
// func startVideoRecording(requestId _: String, save _: Bool) {}
|
|
139
|
+
|
|
140
|
+
// func stopVideoRecording(requestId _: String) {}
|
|
141
|
+
|
|
142
|
+
// func setHeadUpAngle(_: Int) {}
|
|
143
|
+
|
|
144
|
+
// func getBatteryStatus() {}
|
|
145
|
+
|
|
146
|
+
// // Frame BLE Service and Characteristic UUIDs
|
|
147
|
+
// private let FRAME_SERVICE_UUID = CBUUID(string: "7A230001-5475-A6A4-654C-8431F6AD49C4")
|
|
148
|
+
// private let FRAME_TX_CHAR_UUID = CBUUID(string: "7A230002-5475-A6A4-654C-8431F6AD49C4") // Phone → Frame
|
|
149
|
+
// private let FRAME_RX_CHAR_UUID = CBUUID(string: "7A230003-5475-A6A4-654C-8431F6AD49C4") // Frame → Phone
|
|
150
|
+
|
|
151
|
+
// private static let TAG = "FrameManager"
|
|
152
|
+
// private static let COMMAND_DELAY_MS = 100
|
|
153
|
+
// private static let MAX_QUEUE_SIZE = 10
|
|
154
|
+
// private static let MTU_SIZE = 251
|
|
155
|
+
|
|
156
|
+
// // MARK: - Properties
|
|
157
|
+
|
|
158
|
+
// private var centralManager: CBCentralManager?
|
|
159
|
+
// private var framePeripheral: CBPeripheral?
|
|
160
|
+
// private var txCharacteristic: CBCharacteristic?
|
|
161
|
+
// private var rxCharacteristic: CBCharacteristic?
|
|
162
|
+
|
|
163
|
+
// private var isScanning = false
|
|
164
|
+
// private var isConnecting = false
|
|
165
|
+
// private var isConnected = false
|
|
166
|
+
|
|
167
|
+
// // Command queue system
|
|
168
|
+
// private var commandQueue = [FrameCommand]()
|
|
169
|
+
// private var isProcessingQueue = false
|
|
170
|
+
// private let queueLock = NSLock()
|
|
171
|
+
// private var currentWriteCompletion: ((Bool) -> Void)?
|
|
172
|
+
|
|
173
|
+
// // Device tracking
|
|
174
|
+
// private var discoveredDevices = Set<String>()
|
|
175
|
+
// private var savedDeviceName: String?
|
|
176
|
+
|
|
177
|
+
// // Callbacks
|
|
178
|
+
// var onConnectionStateChanged: (() -> Void)?
|
|
179
|
+
// var onDeviceDiscovered: ((String) -> Void)?
|
|
180
|
+
|
|
181
|
+
// // Published properties for SwiftUI/Combine
|
|
182
|
+
// @Published var connectionState = "DISCONNECTED"
|
|
183
|
+
// @Published var batteryLevel: Int = -1
|
|
184
|
+
|
|
185
|
+
// override init() {
|
|
186
|
+
// super.init()
|
|
187
|
+
// centralManager = CBCentralManager(delegate: self, queue: nil)
|
|
188
|
+
// loadSavedDeviceName()
|
|
189
|
+
// }
|
|
190
|
+
|
|
191
|
+
// // MARK: - Public Methods
|
|
192
|
+
|
|
193
|
+
// func startScanning() {
|
|
194
|
+
// guard let centralManager = centralManager,
|
|
195
|
+
// centralManager.state == .poweredOn,
|
|
196
|
+
// !isScanning
|
|
197
|
+
// else {
|
|
198
|
+
// Bridge.log("\(FrameManager.TAG): Cannot start scan - BLE not ready or already scanning")
|
|
199
|
+
// return
|
|
200
|
+
// }
|
|
201
|
+
|
|
202
|
+
// isScanning = true
|
|
203
|
+
// discoveredDevices.removeAll()
|
|
204
|
+
|
|
205
|
+
// let scanOptions: [String: Any] = [
|
|
206
|
+
// CBCentralManagerScanOptionAllowDuplicatesKey: false,
|
|
207
|
+
// ]
|
|
208
|
+
|
|
209
|
+
// centralManager.scanForPeripherals(
|
|
210
|
+
// withServices: [FRAME_SERVICE_UUID],
|
|
211
|
+
// options: scanOptions
|
|
212
|
+
// )
|
|
213
|
+
|
|
214
|
+
// Bridge.log("\(FrameManager.TAG): Started scanning for Frame devices")
|
|
215
|
+
|
|
216
|
+
// // Stop scan after 10 seconds
|
|
217
|
+
// DispatchQueue.main.asyncAfter(deadline: .now() + 10) { [weak self] in
|
|
218
|
+
// if self?.isScanning == true {
|
|
219
|
+
// self?.stopScanning()
|
|
220
|
+
// }
|
|
221
|
+
// }
|
|
222
|
+
// }
|
|
223
|
+
|
|
224
|
+
// func stopScanning() {
|
|
225
|
+
// guard isScanning else { return }
|
|
226
|
+
|
|
227
|
+
// centralManager?.stopScan()
|
|
228
|
+
// isScanning = false
|
|
229
|
+
// Bridge.log("\(FrameManager.TAG): Stopped scanning")
|
|
230
|
+
// }
|
|
231
|
+
|
|
232
|
+
// func connect(deviceName: String? = nil) {
|
|
233
|
+
// let targetDevice = deviceName ?? savedDeviceName
|
|
234
|
+
|
|
235
|
+
// guard let name = targetDevice else {
|
|
236
|
+
// Bridge.log("\(FrameManager.TAG): No device name available for connection")
|
|
237
|
+
// startScanning()
|
|
238
|
+
// return
|
|
239
|
+
// }
|
|
240
|
+
|
|
241
|
+
// if isConnecting {
|
|
242
|
+
// Bridge.log("\(FrameManager.TAG): Already connecting")
|
|
243
|
+
// return
|
|
244
|
+
// }
|
|
245
|
+
|
|
246
|
+
// isConnecting = true
|
|
247
|
+
// connectionState = "CONNECTING"
|
|
248
|
+
|
|
249
|
+
// // Start targeted scan for specific device
|
|
250
|
+
// startTargetedScan(deviceName: name)
|
|
251
|
+
// }
|
|
252
|
+
|
|
253
|
+
// func disconnect() {
|
|
254
|
+
// guard let peripheral = framePeripheral else { return }
|
|
255
|
+
|
|
256
|
+
// centralManager?.cancelPeripheralConnection(peripheral)
|
|
257
|
+
// cleanup()
|
|
258
|
+
// }
|
|
259
|
+
|
|
260
|
+
// // MARK: - Display Methods
|
|
261
|
+
|
|
262
|
+
// func sendTextWall(_ text: String) {
|
|
263
|
+
// guard isConnected else {
|
|
264
|
+
// Bridge.log("\(FrameManager.TAG): Cannot display text - not connected")
|
|
265
|
+
// return
|
|
266
|
+
// }
|
|
267
|
+
|
|
268
|
+
// // Clear queue for new text display
|
|
269
|
+
// queueLock.lock()
|
|
270
|
+
// commandQueue.removeAll()
|
|
271
|
+
// isProcessingQueue = false
|
|
272
|
+
// queueLock.unlock()
|
|
273
|
+
|
|
274
|
+
// let escapedText = escapeForLua(text)
|
|
275
|
+
// let words = escapedText.split(separator: " ")
|
|
276
|
+
|
|
277
|
+
// let maxLineLength = 30
|
|
278
|
+
// let lineHeight = 55
|
|
279
|
+
// let startY = 20
|
|
280
|
+
// let maxLines = 3
|
|
281
|
+
|
|
282
|
+
// var lines = [String]()
|
|
283
|
+
// var currentLine = ""
|
|
284
|
+
|
|
285
|
+
// for word in words {
|
|
286
|
+
// if lines.count >= maxLines { break }
|
|
287
|
+
|
|
288
|
+
// let wordStr = String(word)
|
|
289
|
+
// if currentLine.count + wordStr.count + 1 > maxLineLength {
|
|
290
|
+
// if !currentLine.isEmpty {
|
|
291
|
+
// lines.append(currentLine.trimmingCharacters(in: .whitespaces))
|
|
292
|
+
// currentLine = ""
|
|
293
|
+
// }
|
|
294
|
+
// }
|
|
295
|
+
|
|
296
|
+
// if !currentLine.isEmpty {
|
|
297
|
+
// currentLine += " "
|
|
298
|
+
// }
|
|
299
|
+
// currentLine += wordStr
|
|
300
|
+
// }
|
|
301
|
+
|
|
302
|
+
// if !currentLine.isEmpty, lines.count < maxLines {
|
|
303
|
+
// lines.append(currentLine.trimmingCharacters(in: .whitespaces))
|
|
304
|
+
// }
|
|
305
|
+
|
|
306
|
+
// // Build commands - lines are already escaped
|
|
307
|
+
// var batchCommand = ""
|
|
308
|
+
// for (index, line) in lines.enumerated() {
|
|
309
|
+
// let yPos = startY + (index * lineHeight)
|
|
310
|
+
// batchCommand += "frame.display.text('\(line)', 10, \(yPos));"
|
|
311
|
+
// }
|
|
312
|
+
// batchCommand += "frame.display.show();print(nil)"
|
|
313
|
+
|
|
314
|
+
// // Send as single command if it fits, otherwise send separately
|
|
315
|
+
// if batchCommand.count < 240 {
|
|
316
|
+
// queueCommand(batchCommand)
|
|
317
|
+
// } else {
|
|
318
|
+
// for (index, line) in lines.enumerated() {
|
|
319
|
+
// let yPos = startY + (index * lineHeight)
|
|
320
|
+
// let lineCommand = "frame.display.text('\(line)', 10, \(yPos));print(nil)"
|
|
321
|
+
// queueCommand(lineCommand)
|
|
322
|
+
// }
|
|
323
|
+
// queueCommand("frame.display.show();print(nil)")
|
|
324
|
+
// }
|
|
325
|
+
// }
|
|
326
|
+
|
|
327
|
+
// func displayTextLine(_ text: String) {
|
|
328
|
+
// let escapedText = escapeForLua(text)
|
|
329
|
+
// let command = "frame.display.text('\(escapedText)', 50, 200);frame.display.show();print(nil)"
|
|
330
|
+
// queueCommand(command)
|
|
331
|
+
// }
|
|
332
|
+
|
|
333
|
+
// func clearDisplay() {
|
|
334
|
+
// queueCommand("frame.display.text(' ', 1, 1);frame.display.show();print(nil)")
|
|
335
|
+
// }
|
|
336
|
+
|
|
337
|
+
// // MARK: - Private Methods
|
|
338
|
+
|
|
339
|
+
// private func startTargetedScan(deviceName: String) {
|
|
340
|
+
// guard let centralManager = centralManager,
|
|
341
|
+
// centralManager.state == .poweredOn
|
|
342
|
+
// else {
|
|
343
|
+
// Bridge.log("\(FrameManager.TAG): BLE not ready for targeted scan")
|
|
344
|
+
// isConnecting = false
|
|
345
|
+
// connectionState = "DISCONNECTED"
|
|
346
|
+
// return
|
|
347
|
+
// }
|
|
348
|
+
|
|
349
|
+
// // Store target name for scan callback
|
|
350
|
+
// savedDeviceName = deviceName
|
|
351
|
+
|
|
352
|
+
// centralManager.scanForPeripherals(
|
|
353
|
+
// withServices: [FRAME_SERVICE_UUID],
|
|
354
|
+
// options: nil
|
|
355
|
+
// )
|
|
356
|
+
|
|
357
|
+
// // Timeout after 10 seconds
|
|
358
|
+
// DispatchQueue.main.asyncAfter(deadline: .now() + 10) { [weak self] in
|
|
359
|
+
// guard let self = self else { return }
|
|
360
|
+
// if self.isConnecting, self.framePeripheral == nil {
|
|
361
|
+
// self.centralManager?.stopScan()
|
|
362
|
+
// self.isConnecting = false
|
|
363
|
+
// self.connectionState = "DISCONNECTED"
|
|
364
|
+
// Bridge.log("\(FrameManager.TAG): Connection timeout - device not found")
|
|
365
|
+
// }
|
|
366
|
+
// }
|
|
367
|
+
// }
|
|
368
|
+
|
|
369
|
+
// private func queueCommand(_ command: String, completion: ((Bool) -> Void)? = nil) {
|
|
370
|
+
// queueLock.lock()
|
|
371
|
+
// commandQueue.append(FrameCommand(command: command, completion: completion))
|
|
372
|
+
// Bridge.log("\(FrameManager.TAG): Queued command (queue size: \(commandQueue.count))")
|
|
373
|
+
// queueLock.unlock()
|
|
374
|
+
|
|
375
|
+
// processQueue()
|
|
376
|
+
// }
|
|
377
|
+
|
|
378
|
+
// private func processQueue() {
|
|
379
|
+
// queueLock.lock()
|
|
380
|
+
|
|
381
|
+
// if isProcessingQueue || commandQueue.isEmpty {
|
|
382
|
+
// queueLock.unlock()
|
|
383
|
+
// return
|
|
384
|
+
// }
|
|
385
|
+
|
|
386
|
+
// guard let command = commandQueue.first else {
|
|
387
|
+
// queueLock.unlock()
|
|
388
|
+
// return
|
|
389
|
+
// }
|
|
390
|
+
|
|
391
|
+
// isProcessingQueue = true
|
|
392
|
+
// commandQueue.removeFirst()
|
|
393
|
+
// queueLock.unlock()
|
|
394
|
+
|
|
395
|
+
// sendLuaCommand(command.command) { [weak self] success in
|
|
396
|
+
// command.completion?(success)
|
|
397
|
+
|
|
398
|
+
// // If failed, clear queue and stop processing
|
|
399
|
+
// if !success {
|
|
400
|
+
// self?.queueLock.lock()
|
|
401
|
+
// self?.commandQueue.removeAll()
|
|
402
|
+
// self?.isProcessingQueue = false
|
|
403
|
+
// self?.queueLock.unlock()
|
|
404
|
+
// return
|
|
405
|
+
// }
|
|
406
|
+
|
|
407
|
+
// // Schedule next command
|
|
408
|
+
// DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in
|
|
409
|
+
// self?.queueLock.lock()
|
|
410
|
+
// self?.isProcessingQueue = false
|
|
411
|
+
// self?.queueLock.unlock()
|
|
412
|
+
// self?.processQueue()
|
|
413
|
+
// }
|
|
414
|
+
// }
|
|
415
|
+
// }
|
|
416
|
+
|
|
417
|
+
// private func sendLuaCommand(_ command: String, completion: @escaping (Bool) -> Void) {
|
|
418
|
+
// guard let txCharacteristic = txCharacteristic,
|
|
419
|
+
// let peripheral = framePeripheral
|
|
420
|
+
// else {
|
|
421
|
+
// Bridge.log("\(FrameManager.TAG): Cannot send command - not connected")
|
|
422
|
+
// completion(false)
|
|
423
|
+
// return
|
|
424
|
+
// }
|
|
425
|
+
|
|
426
|
+
// var finalCommand = command
|
|
427
|
+
|
|
428
|
+
// // Add print(nil) if not present
|
|
429
|
+
// if !command.contains("print(") {
|
|
430
|
+
// if !command.contains(";") {
|
|
431
|
+
// finalCommand = command + ";print(nil)"
|
|
432
|
+
// }
|
|
433
|
+
// }
|
|
434
|
+
|
|
435
|
+
// // Add newline
|
|
436
|
+
// if !finalCommand.hasSuffix("\n") {
|
|
437
|
+
// finalCommand += "\n"
|
|
438
|
+
// }
|
|
439
|
+
|
|
440
|
+
// guard var data = finalCommand.data(using: .utf8) else {
|
|
441
|
+
// Bridge.log("\(FrameManager.TAG): Failed to encode command")
|
|
442
|
+
// completion(false)
|
|
443
|
+
// return
|
|
444
|
+
// }
|
|
445
|
+
|
|
446
|
+
// // Handle MTU limitation
|
|
447
|
+
// if data.count > 247 {
|
|
448
|
+
// Bridge.log("\(FrameManager.TAG): Command too long, truncating")
|
|
449
|
+
// data = data.prefix(247)
|
|
450
|
+
// }
|
|
451
|
+
|
|
452
|
+
// Bridge.log("\(FrameManager.TAG): Sending Lua command: \(finalCommand.trimmingCharacters(in: .whitespacesAndNewlines))")
|
|
453
|
+
|
|
454
|
+
// // Store completion for delegate callback
|
|
455
|
+
// currentWriteCompletion = completion
|
|
456
|
+
// peripheral.writeValue(data, for: txCharacteristic, type: .withResponse)
|
|
457
|
+
// }
|
|
458
|
+
|
|
459
|
+
// private func initializeFrame() {
|
|
460
|
+
// Bridge.log("\(FrameManager.TAG): Initializing Frame display")
|
|
461
|
+
|
|
462
|
+
// // Send break signal to stop any running main.lua
|
|
463
|
+
// sendBreakSignal()
|
|
464
|
+
|
|
465
|
+
// // Wait then send welcome message
|
|
466
|
+
// DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
|
|
467
|
+
// self?.queueCommand("frame.display.text('MentraOS Connected!', 100, 100);frame.display.show();print(nil)")
|
|
468
|
+
// }
|
|
469
|
+
// }
|
|
470
|
+
|
|
471
|
+
// private func sendBreakSignal() {
|
|
472
|
+
// guard let txCharacteristic = txCharacteristic,
|
|
473
|
+
// let peripheral = framePeripheral else { return }
|
|
474
|
+
|
|
475
|
+
// let breakSignal = Data([0x03])
|
|
476
|
+
// peripheral.writeValue(breakSignal, for: txCharacteristic, type: .withResponse)
|
|
477
|
+
// Bridge.log("\(FrameManager.TAG): Sent break signal")
|
|
478
|
+
// }
|
|
479
|
+
|
|
480
|
+
// private func escapeForLua(_ text: String) -> String {
|
|
481
|
+
// return text
|
|
482
|
+
// .replacingOccurrences(of: "\\", with: "\\\\")
|
|
483
|
+
// .replacingOccurrences(of: "'", with: "\\'")
|
|
484
|
+
// .replacingOccurrences(of: "\"", with: "\\\"")
|
|
485
|
+
// .replacingOccurrences(of: "\n", with: " ")
|
|
486
|
+
// .replacingOccurrences(of: "\r", with: " ")
|
|
487
|
+
// .replacingOccurrences(of: "\t", with: " ")
|
|
488
|
+
// }
|
|
489
|
+
|
|
490
|
+
// func cleanup() {
|
|
491
|
+
// txCharacteristic = nil
|
|
492
|
+
// rxCharacteristic = nil
|
|
493
|
+
// framePeripheral = nil
|
|
494
|
+
// isConnected = false
|
|
495
|
+
// isConnecting = false
|
|
496
|
+
// connectionState = "DISCONNECTED"
|
|
497
|
+
|
|
498
|
+
// queueLock.lock()
|
|
499
|
+
// commandQueue.removeAll()
|
|
500
|
+
// isProcessingQueue = false
|
|
501
|
+
// queueLock.unlock()
|
|
502
|
+
// }
|
|
503
|
+
|
|
504
|
+
// private func loadSavedDeviceName() {
|
|
505
|
+
// savedDeviceName = UserDefaults.standard.string(forKey: "FrameDeviceName")
|
|
506
|
+
// }
|
|
507
|
+
|
|
508
|
+
// private func saveDeviceName(_ name: String) {
|
|
509
|
+
// savedDeviceName = name
|
|
510
|
+
// UserDefaults.standard.set(name, forKey: "FrameDeviceName")
|
|
511
|
+
// }
|
|
512
|
+
// }
|
|
513
|
+
|
|
514
|
+
// // MARK: - CBCentralManagerDelegate
|
|
515
|
+
|
|
516
|
+
// extension FrameManager: CBCentralManagerDelegate {
|
|
517
|
+
// func centralManagerDidUpdateState(_ central: CBCentralManager) {
|
|
518
|
+
// switch central.state {
|
|
519
|
+
// case .poweredOn:
|
|
520
|
+
// Bridge.log("\(FrameManager.TAG): Bluetooth powered on")
|
|
521
|
+
// case .poweredOff:
|
|
522
|
+
// Bridge.log("\(FrameManager.TAG): Bluetooth powered off")
|
|
523
|
+
// cleanup()
|
|
524
|
+
// default:
|
|
525
|
+
// Bridge.log("\(FrameManager.TAG): Bluetooth state: \(central.state.rawValue)")
|
|
526
|
+
// }
|
|
527
|
+
// }
|
|
528
|
+
|
|
529
|
+
// func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral,
|
|
530
|
+
// advertisementData _: [String: Any], rssi _: NSNumber)
|
|
531
|
+
// {
|
|
532
|
+
// let deviceName = peripheral.name ?? "Unknown"
|
|
533
|
+
// let address = peripheral.identifier.uuidString
|
|
534
|
+
|
|
535
|
+
// // Check if this is a Frame device
|
|
536
|
+
// if deviceName.contains("Frame") || deviceName.contains("frame") {
|
|
537
|
+
// if !discoveredDevices.contains(address) {
|
|
538
|
+
// discoveredDevices.insert(address)
|
|
539
|
+
// Bridge.log("\(FrameManager.TAG): Found Frame device: \(deviceName) (\(address))")
|
|
540
|
+
// onDeviceDiscovered?(deviceName)
|
|
541
|
+
|
|
542
|
+
// // If we're doing targeted scan, connect to matching device
|
|
543
|
+
// if isConnecting, let targetName = savedDeviceName, deviceName == targetName {
|
|
544
|
+
// central.stopScan()
|
|
545
|
+
// framePeripheral = peripheral
|
|
546
|
+
// peripheral.delegate = self
|
|
547
|
+
// central.connect(peripheral, options: nil)
|
|
548
|
+
// Bridge.log("\(FrameManager.TAG): Connecting to \(deviceName)")
|
|
549
|
+
// }
|
|
550
|
+
// }
|
|
551
|
+
// }
|
|
552
|
+
// }
|
|
553
|
+
|
|
554
|
+
// func centralManager(_: CBCentralManager, didConnect peripheral: CBPeripheral) {
|
|
555
|
+
// Bridge.log("\(FrameManager.TAG): Connected to Frame - negotiating MTU")
|
|
556
|
+
// isConnecting = false
|
|
557
|
+
|
|
558
|
+
// // Save device name
|
|
559
|
+
// if let name = peripheral.name {
|
|
560
|
+
// saveDeviceName(name)
|
|
561
|
+
// }
|
|
562
|
+
|
|
563
|
+
// // Request larger MTU
|
|
564
|
+
// peripheral.maximumWriteValueLength(for: .withResponse)
|
|
565
|
+
|
|
566
|
+
// // Discover services
|
|
567
|
+
// peripheral.discoverServices([FRAME_SERVICE_UUID])
|
|
568
|
+
// }
|
|
569
|
+
|
|
570
|
+
// func centralManager(_: CBCentralManager, didDisconnectPeripheral _: CBPeripheral, error _: Error?) {
|
|
571
|
+
// Bridge.log("\(FrameManager.TAG): Disconnected from Frame")
|
|
572
|
+
// cleanup()
|
|
573
|
+
// onConnectionStateChanged?()
|
|
574
|
+
// }
|
|
575
|
+
|
|
576
|
+
// func centralManager(_: CBCentralManager, didFailToConnect _: CBPeripheral, error: Error?) {
|
|
577
|
+
// Bridge.log("\(FrameManager.TAG): Failed to connect: \(error?.localizedDescription ?? "Unknown error")")
|
|
578
|
+
// isConnecting = false
|
|
579
|
+
// connectionState = "DISCONNECTED"
|
|
580
|
+
// cleanup()
|
|
581
|
+
// }
|
|
582
|
+
// }
|
|
583
|
+
|
|
584
|
+
// // MARK: - CBPeripheralDelegate
|
|
585
|
+
|
|
586
|
+
// extension FrameManager: CBPeripheralDelegate {
|
|
587
|
+
// func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
|
|
588
|
+
// guard error == nil else {
|
|
589
|
+
// Bridge.log("\(FrameManager.TAG): Service discovery failed: \(error!)")
|
|
590
|
+
// return
|
|
591
|
+
// }
|
|
592
|
+
|
|
593
|
+
// guard let services = peripheral.services else { return }
|
|
594
|
+
|
|
595
|
+
// for service in services {
|
|
596
|
+
// if service.uuid == FRAME_SERVICE_UUID {
|
|
597
|
+
// Bridge.log("\(FrameManager.TAG): Found Frame service")
|
|
598
|
+
// peripheral.discoverCharacteristics([FRAME_TX_CHAR_UUID, FRAME_RX_CHAR_UUID], for: service)
|
|
599
|
+
// }
|
|
600
|
+
// }
|
|
601
|
+
// }
|
|
602
|
+
|
|
603
|
+
// func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
|
|
604
|
+
// guard error == nil else {
|
|
605
|
+
// Bridge.log("\(FrameManager.TAG): Characteristic discovery failed: \(error!)")
|
|
606
|
+
// return
|
|
607
|
+
// }
|
|
608
|
+
|
|
609
|
+
// guard let characteristics = service.characteristics else { return }
|
|
610
|
+
|
|
611
|
+
// for characteristic in characteristics {
|
|
612
|
+
// if characteristic.uuid == FRAME_TX_CHAR_UUID {
|
|
613
|
+
// txCharacteristic = characteristic
|
|
614
|
+
// Bridge.log("\(FrameManager.TAG): Found TX characteristic")
|
|
615
|
+
// } else if characteristic.uuid == FRAME_RX_CHAR_UUID {
|
|
616
|
+
// rxCharacteristic = characteristic
|
|
617
|
+
// peripheral.setNotifyValue(true, for: characteristic)
|
|
618
|
+
// Bridge.log("\(FrameManager.TAG): Found RX characteristic, enabling notifications")
|
|
619
|
+
// }
|
|
620
|
+
// }
|
|
621
|
+
|
|
622
|
+
// // Check if we have both characteristics
|
|
623
|
+
// if txCharacteristic != nil, rxCharacteristic != nil {
|
|
624
|
+
// isConnected = true
|
|
625
|
+
// connectionState = "CONNECTED"
|
|
626
|
+
// Bridge.log("\(FrameManager.TAG): Frame fully connected")
|
|
627
|
+
// onConnectionStateChanged?()
|
|
628
|
+
// initializeFrame()
|
|
629
|
+
// }
|
|
630
|
+
// }
|
|
631
|
+
|
|
632
|
+
// func peripheral(_: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error _: Error?) {
|
|
633
|
+
// guard characteristic.uuid == FRAME_RX_CHAR_UUID,
|
|
634
|
+
// let data = characteristic.value else { return }
|
|
635
|
+
|
|
636
|
+
// if let response = String(data: data, encoding: .utf8) {
|
|
637
|
+
// Bridge.log("\(FrameManager.TAG): Received from Frame: \(response)")
|
|
638
|
+
// }
|
|
639
|
+
// }
|
|
640
|
+
|
|
641
|
+
// func peripheral(_: CBPeripheral, didWriteValueFor _: CBCharacteristic, error: Error?) {
|
|
642
|
+
// if let error = error {
|
|
643
|
+
// Bridge.log("\(FrameManager.TAG): Write failed: \(error)")
|
|
644
|
+
// currentWriteCompletion?(false)
|
|
645
|
+
// } else {
|
|
646
|
+
// Bridge.log("\(FrameManager.TAG): Successfully wrote to Frame")
|
|
647
|
+
// currentWriteCompletion?(true)
|
|
648
|
+
// }
|
|
649
|
+
// currentWriteCompletion = nil
|
|
650
|
+
// }
|
|
651
|
+
// }
|