@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,589 @@
|
|
|
1
|
+
package com.mentra.bluetoothsdk.utils
|
|
2
|
+
|
|
3
|
+
import java.nio.ByteBuffer
|
|
4
|
+
import java.io.IOException
|
|
5
|
+
import java.util.UUID
|
|
6
|
+
|
|
7
|
+
import android.content.Context
|
|
8
|
+
import android.util.Log
|
|
9
|
+
|
|
10
|
+
import com.mentra.bluetoothsdk.Bridge
|
|
11
|
+
|
|
12
|
+
import mentraos.ble.MentraosBle.DisplayText
|
|
13
|
+
import mentraos.ble.MentraosBle.ClearDisplay
|
|
14
|
+
import mentraos.ble.MentraosBle.PhoneToGlasses
|
|
15
|
+
import mentraos.ble.MentraosBle.DisplayImage
|
|
16
|
+
import mentraos.ble.MentraosBle.PongResponse
|
|
17
|
+
import mentraos.ble.MentraosBle.BatteryStateRequest
|
|
18
|
+
import mentraos.ble.MentraosBle.MicStateConfig
|
|
19
|
+
import mentraos.ble.MentraosBle.BrightnessConfig
|
|
20
|
+
import mentraos.ble.MentraosBle.AutoBrightnessConfig
|
|
21
|
+
import mentraos.ble.MentraosBle.HeadUpAngleConfig
|
|
22
|
+
import mentraos.ble.MentraosBle.DisplayDistanceConfig
|
|
23
|
+
import mentraos.ble.MentraosBle.DisplayHeightConfig
|
|
24
|
+
import mentraos.ble.MentraosBle.VersionRequest
|
|
25
|
+
|
|
26
|
+
import org.json.JSONArray
|
|
27
|
+
import org.json.JSONException
|
|
28
|
+
import org.json.JSONObject
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
object NexBluetoothConstants {
|
|
32
|
+
val MAIN_SERVICE_UUID: UUID = UUID.fromString("00004860-0000-1000-8000-00805f9b34fb")
|
|
33
|
+
val WRITE_CHAR_UUID: UUID = UUID.fromString("000071FF-0000-1000-8000-00805f9b34fb")
|
|
34
|
+
val NOTIFY_CHAR_UUID: UUID = UUID.fromString("000070FF-0000-1000-8000-00805f9b34fb")
|
|
35
|
+
val CLIENT_CHARACTERISTIC_CONFIG_UUID: UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
object NexDisplayConstants {
|
|
39
|
+
const val DISPLAY_WIDTH: Int = 488
|
|
40
|
+
const val DISPLAY_USE_WIDTH: Int = 488 // How much of the display to use
|
|
41
|
+
const val FONT_MULTIPLIER: Float = 1.0f / 50.0f
|
|
42
|
+
const val OLD_FONT_SIZE: Int = 21 // Font size
|
|
43
|
+
const val FONT_DIVIDER: Float = 2.0f
|
|
44
|
+
const val LINES_PER_SCREEN: Int = 5 // Lines per screen
|
|
45
|
+
|
|
46
|
+
/** Matches dashboard depth slider in app settings (1-3); values outside range clamp. */
|
|
47
|
+
const val DASHBOARD_DEPTH_MIN: Int = 1
|
|
48
|
+
const val DASHBOARD_DEPTH_MAX: Int = 3
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
object NexBluetoothPacketTypes {
|
|
52
|
+
const val PACKET_TYPE_JSON: Byte = 0x01.toByte()
|
|
53
|
+
const val PACKET_TYPE_PROTOBUF: Byte = 0x02.toByte()
|
|
54
|
+
const val PACKET_TYPE_AUDIO: Byte = 0xA0.toByte()
|
|
55
|
+
const val PACKET_TYPE_IMAGE: Byte = 0xB0.toByte()
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
object NexProtobufUtils {
|
|
59
|
+
private const val TAG = "NexProtobufUtils"
|
|
60
|
+
|
|
61
|
+
private const val WHITELIST_CMD: Int = 0x04
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Maps dashboard depth to the value Nex firmware expects in [DisplayDistanceConfig.distance_cm].
|
|
65
|
+
* The protobuf field is still named `distance_cm`, but Nex treats it as a **tier** 1–3, not centimeters.
|
|
66
|
+
* Keep in sync with iOS `NexDashboardDisplayWire.depthToWireTier`.
|
|
67
|
+
*/
|
|
68
|
+
fun dashboardDepthToDistanceCm(depth: Int): Int {
|
|
69
|
+
return depth.coerceIn(
|
|
70
|
+
NexDisplayConstants.DASHBOARD_DEPTH_MIN,
|
|
71
|
+
NexDisplayConstants.DASHBOARD_DEPTH_MAX
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
data class AppInfo(
|
|
76
|
+
val id: String,
|
|
77
|
+
val name: String
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
fun getWhitelistChunks(maxChunkSize: Int): List<ByteArray> {
|
|
81
|
+
// Define the hardcoded whitelist
|
|
82
|
+
val apps = listOf(AppInfo("com.augment.os", "AugmentOS"))
|
|
83
|
+
val whitelistJson = createWhitelistJson(apps)
|
|
84
|
+
|
|
85
|
+
Bridge.log("Creating chunks for hardcoded whitelist: $whitelistJson")
|
|
86
|
+
|
|
87
|
+
// Convert JSON to bytes and split into chunks
|
|
88
|
+
return createWhitelistChunks(whitelistJson, maxChunkSize)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
fun createBmpChunksForNexGlasses(streamId: String, bmpData: ByteArray, totalChunks: Int, bmpChunkSize: Int): List<ByteArray> {
|
|
92
|
+
val chunks = mutableListOf<ByteArray>()
|
|
93
|
+
Bridge.log("Creating $totalChunks chunks from ${bmpData.size} bytes")
|
|
94
|
+
|
|
95
|
+
// Parse hex stream ID to bytes (e.g., "002A" -> 0x00, 0x2A)
|
|
96
|
+
val streamIdInt = streamId.toInt(16)
|
|
97
|
+
|
|
98
|
+
repeat(totalChunks) { i ->
|
|
99
|
+
val start = i * bmpChunkSize
|
|
100
|
+
val end = minOf(start + bmpChunkSize, bmpData.size)
|
|
101
|
+
val chunk = bmpData.copyOfRange(start, end)
|
|
102
|
+
|
|
103
|
+
val header = ByteArray(4 + chunk.size).apply {
|
|
104
|
+
this[0] = NexBluetoothPacketTypes.PACKET_TYPE_IMAGE // 0xB0
|
|
105
|
+
this[1] = (streamIdInt shr 8).toByte() // Stream ID high byte
|
|
106
|
+
this[2] = streamIdInt.toByte() // Stream ID low byte
|
|
107
|
+
this[3] = i.toByte() // Chunk index
|
|
108
|
+
System.arraycopy(chunk, 0, this, 4, chunk.size)
|
|
109
|
+
}
|
|
110
|
+
chunks.add(header)
|
|
111
|
+
}
|
|
112
|
+
return chunks
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
fun constructPongResponse(): ByteArray {
|
|
116
|
+
Bridge.log("Nex: Constructing pong response to glasses ping")
|
|
117
|
+
|
|
118
|
+
// Create the PongResponse message
|
|
119
|
+
val pongResponse = PongResponse.newBuilder().build()
|
|
120
|
+
// Create the PhoneToGlasses message with the pong response
|
|
121
|
+
val phoneToGlasses = PhoneToGlasses.newBuilder().setPong(pongResponse).build()
|
|
122
|
+
return generateProtobufCommandBytes(phoneToGlasses)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Gets the current protobuf schema version from the compiled protobuf descriptor
|
|
127
|
+
*/
|
|
128
|
+
fun getProtobufSchemaVersion(context: Context): Int {
|
|
129
|
+
return try {
|
|
130
|
+
// Get the protobuf descriptor and extract the schema version
|
|
131
|
+
val fileDescriptor = mentraos.ble.MentraosBle.getDescriptor().file
|
|
132
|
+
|
|
133
|
+
Log.d(TAG, "Proto file descriptor: ${fileDescriptor.name}")
|
|
134
|
+
|
|
135
|
+
// Method 1: Try to access the custom mentra_schema_version option
|
|
136
|
+
try {
|
|
137
|
+
// Get the file options from the descriptor
|
|
138
|
+
val options = fileDescriptor.options
|
|
139
|
+
Log.d(TAG, "Got file options: $options")
|
|
140
|
+
|
|
141
|
+
// Try to access the custom option using the extension registry
|
|
142
|
+
try {
|
|
143
|
+
// Look for the generated extension in the MentraosBle class
|
|
144
|
+
mentraos.ble.MentraosBle::class.java.declaredFields.forEach { field ->
|
|
145
|
+
if (field.name.contains("schema", ignoreCase = true) ||
|
|
146
|
+
field.name.contains("version", ignoreCase = true)) {
|
|
147
|
+
Log.d(TAG, "Found potential version field: ${field.name}")
|
|
148
|
+
field.isAccessible = true
|
|
149
|
+
try {
|
|
150
|
+
val value = field.get(null)
|
|
151
|
+
if (value is com.google.protobuf.Extension<*, *>) {
|
|
152
|
+
@Suppress("UNCHECKED_CAST")
|
|
153
|
+
val ext = value as com.google.protobuf.Extension<com.google.protobuf.DescriptorProtos.FileOptions, Int>
|
|
154
|
+
if (options.hasExtension(ext)) {
|
|
155
|
+
val version = options.getExtension(ext)
|
|
156
|
+
Log.d(TAG, "Found schema version via extension: $version")
|
|
157
|
+
return version
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
} catch (fieldException: Exception) {
|
|
161
|
+
Log.d(TAG, "Field access failed for ${field.name}: ${fieldException.message}")
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
} catch (extensionException: Exception) {
|
|
166
|
+
Log.d(TAG, "Extension search failed: ${extensionException.message}")
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
} catch (optionsException: Exception) {
|
|
170
|
+
Log.d(TAG, "Options access failed: ${optionsException.message}")
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Method 2: Try to read from the actual proto file content
|
|
174
|
+
try {
|
|
175
|
+
val protoVersion = readProtoVersionFromProject(context)
|
|
176
|
+
if (protoVersion != null) {
|
|
177
|
+
Log.d(TAG, "Read proto version from project: $protoVersion")
|
|
178
|
+
return protoVersion.toInt()
|
|
179
|
+
}
|
|
180
|
+
} catch (projectException: Exception) {
|
|
181
|
+
Log.d(TAG, "Project file reading failed: ${projectException.message}")
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
Log.w(TAG, "Could not extract protobuf schema version dynamically, using fallback")
|
|
185
|
+
1 // Fallback to version 1
|
|
186
|
+
|
|
187
|
+
} catch (e: Exception) {
|
|
188
|
+
Log.e(TAG, "Error getting protobuf schema version: ${e.message}", e)
|
|
189
|
+
1 // Fallback to version 1
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
fun generateClearDisplayRequestCommandBytes(): ByteArray {
|
|
194
|
+
// Create the clear display protobuf message
|
|
195
|
+
val clearDisplay = ClearDisplay.newBuilder()
|
|
196
|
+
.build()
|
|
197
|
+
val phoneToGlasses = PhoneToGlasses.newBuilder()
|
|
198
|
+
// .setMsgId("clear_disp_001")
|
|
199
|
+
.setClearDisplay(clearDisplay)
|
|
200
|
+
.build();
|
|
201
|
+
return generateProtobufCommandBytes(phoneToGlasses);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
fun generateVersionRequestCommandBytes(): ByteArray {
|
|
205
|
+
val msgId = "ver_req_${System.currentTimeMillis()}"
|
|
206
|
+
val versionRequest = VersionRequest.newBuilder()
|
|
207
|
+
.setMsgId(msgId)
|
|
208
|
+
.build()
|
|
209
|
+
val phoneToGlasses = PhoneToGlasses.newBuilder()
|
|
210
|
+
.setMsgId(msgId)
|
|
211
|
+
.setVersionRequest(versionRequest)
|
|
212
|
+
.build()
|
|
213
|
+
return generateProtobufCommandBytes(phoneToGlasses)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
fun generateBatteryStateRequestCommandBytes(): ByteArray {
|
|
217
|
+
Bridge.log("Nex: === SENDING BATTERY STATUS QUERY TO GLASSES ===")
|
|
218
|
+
val batteryStateRequest = BatteryStateRequest.newBuilder().build()
|
|
219
|
+
val phoneToGlasses = PhoneToGlasses.newBuilder()
|
|
220
|
+
.setBatteryState(batteryStateRequest)
|
|
221
|
+
.build()
|
|
222
|
+
return generateProtobufCommandBytes(phoneToGlasses)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
fun generateDisplayImageCommandBytes(streamId: String, totalChunks: Int, width: Int, height: Int): ByteArray {
|
|
226
|
+
Bridge.log("=== SENDING IMAGE DISPLAY COMMAND TO GLASSES ===")
|
|
227
|
+
Bridge.log("Image Stream ID: $streamId")
|
|
228
|
+
Bridge.log("Total Chunks: $totalChunks")
|
|
229
|
+
Bridge.log("Image Position: X=0, Y=0")
|
|
230
|
+
Bridge.log("Image Dimensions: ${width}x$height")
|
|
231
|
+
Bridge.log("Image Encoding: raw")
|
|
232
|
+
|
|
233
|
+
val displayImage = DisplayImage.newBuilder()
|
|
234
|
+
.setStreamId(streamId)
|
|
235
|
+
.setTotalChunks(totalChunks)
|
|
236
|
+
.setX(0)
|
|
237
|
+
.setY(0)
|
|
238
|
+
.setWidth(width)
|
|
239
|
+
.setHeight(height)
|
|
240
|
+
.setEncoding("raw")
|
|
241
|
+
.build()
|
|
242
|
+
|
|
243
|
+
// Create the PhoneToGlasses using its builder and set the DisplayImage with msg_id
|
|
244
|
+
val phoneToGlasses = PhoneToGlasses.newBuilder()
|
|
245
|
+
.setMsgId("img_start_1")
|
|
246
|
+
.setDisplayImage(displayImage)
|
|
247
|
+
.build()
|
|
248
|
+
return generateProtobufCommandBytes(phoneToGlasses)
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
fun generateDisplayTextCommandBytes(text: String): ByteArray {
|
|
252
|
+
Bridge.log("Nex: === SENDING TEXT TO GLASSES ===")
|
|
253
|
+
Bridge.log("Nex: Text: \"$text\"")
|
|
254
|
+
Bridge.log("Nex: Text Length: ${text.length} characters")
|
|
255
|
+
|
|
256
|
+
// Replace all m-dashes with normal dash
|
|
257
|
+
val textWithNormalDash = text.replace("—", "-")
|
|
258
|
+
|
|
259
|
+
val sanitizedText = textWithNormalDash.replace(
|
|
260
|
+
Regex("""[^A-Za-z0-9 \r\n.,!?;:\-\[\]\(\)\{\}'"+=/]"""),
|
|
261
|
+
""
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
val textNewBuilder = DisplayText.newBuilder()
|
|
265
|
+
.setColor(10000)
|
|
266
|
+
.setText(sanitizedText)
|
|
267
|
+
.setSize(48)
|
|
268
|
+
.setX(20)
|
|
269
|
+
.setY(260)
|
|
270
|
+
.build()
|
|
271
|
+
|
|
272
|
+
// Create the PhoneToGlasses using its builder and set the DisplayText
|
|
273
|
+
val phoneToGlasses = PhoneToGlasses.newBuilder()
|
|
274
|
+
.setDisplayText(textNewBuilder)
|
|
275
|
+
.build()
|
|
276
|
+
|
|
277
|
+
return generateProtobufCommandBytes(phoneToGlasses)
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
fun generateHeadUpAngleConfigCommandBytes(angle: Int): ByteArray {
|
|
281
|
+
val headUpAngleConfig = HeadUpAngleConfig.newBuilder().setAngle(angle).build()
|
|
282
|
+
val phoneToGlasses = PhoneToGlasses.newBuilder()
|
|
283
|
+
.setHeadUpAngle(headUpAngleConfig)
|
|
284
|
+
.build()
|
|
285
|
+
Bridge.log("Nex: Sent headUp angle command => Angle: $angle")
|
|
286
|
+
return generateProtobufCommandBytes(phoneToGlasses)
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
fun generateDisplayHeightCommandBytes(height: Int): ByteArray {
|
|
290
|
+
val clampedHeight = height.coerceIn(0, 8)
|
|
291
|
+
|
|
292
|
+
Bridge.log("Nex: === SENDING DISPLAY HEIGHT COMMAND TO GLASSES ===")
|
|
293
|
+
Bridge.log("Nex: Display height: $clampedHeight (0-8)")
|
|
294
|
+
val displayHeightConfig = DisplayHeightConfig.newBuilder()
|
|
295
|
+
.setHeight(clampedHeight)
|
|
296
|
+
.build()
|
|
297
|
+
|
|
298
|
+
val phoneToGlasses = PhoneToGlasses.newBuilder()
|
|
299
|
+
.setDisplayHeight(displayHeightConfig)
|
|
300
|
+
.build()
|
|
301
|
+
|
|
302
|
+
Bridge.log("Nex: Sent display height command => Height: $clampedHeight")
|
|
303
|
+
|
|
304
|
+
return generateProtobufCommandBytes(phoneToGlasses)
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
fun generateDisplayDistanceCommandBytes(distanceCm: Int): ByteArray {
|
|
308
|
+
val tier = distanceCm.coerceIn(
|
|
309
|
+
NexDisplayConstants.DASHBOARD_DEPTH_MIN,
|
|
310
|
+
NexDisplayConstants.DASHBOARD_DEPTH_MAX
|
|
311
|
+
)
|
|
312
|
+
Bridge.log("Nex: === SENDING DISPLAY DISTANCE COMMAND TO GLASSES ===")
|
|
313
|
+
Bridge.log("Nex: Display distance tier (distance_cm field): $tier")
|
|
314
|
+
|
|
315
|
+
val displayDistanceConfig = DisplayDistanceConfig.newBuilder()
|
|
316
|
+
.setDistanceCm(tier)
|
|
317
|
+
.build()
|
|
318
|
+
|
|
319
|
+
val phoneToGlasses = PhoneToGlasses.newBuilder()
|
|
320
|
+
.setDisplayDistance(displayDistanceConfig)
|
|
321
|
+
.build()
|
|
322
|
+
|
|
323
|
+
Bridge.log("Nex: Sent display distance command => distance_cm (tier): $tier")
|
|
324
|
+
|
|
325
|
+
return generateProtobufCommandBytes(phoneToGlasses)
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
fun generateBrightnessConfigCommandBytes(brightness: Int): ByteArray {
|
|
329
|
+
// Validate brightness range
|
|
330
|
+
val validBrightness = if (brightness != -1) {
|
|
331
|
+
(brightness * 63) / 100
|
|
332
|
+
} else {
|
|
333
|
+
(30 * 63) / 100 // Default to 30% if brightness is -1
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
Bridge.log("Nex: === SENDING BRIGHTNESS COMMAND TO GLASSES ===")
|
|
337
|
+
Bridge.log("Nex: Brightness Value: $brightness (validated: $validBrightness)")
|
|
338
|
+
|
|
339
|
+
val brightnessConfig = BrightnessConfig.newBuilder()
|
|
340
|
+
.setValue(validBrightness)
|
|
341
|
+
.build()
|
|
342
|
+
|
|
343
|
+
val phoneToGlasses = PhoneToGlasses.newBuilder()
|
|
344
|
+
.setBrightness(brightnessConfig)
|
|
345
|
+
.build()
|
|
346
|
+
|
|
347
|
+
Bridge.log("Nex: Sent auto light brightness command => Brightness: $validBrightness")
|
|
348
|
+
|
|
349
|
+
return generateProtobufCommandBytes(phoneToGlasses)
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
fun generateMicStateConfigCommandBytes(enable: Boolean): ByteArray {
|
|
353
|
+
Bridge.log("Nex: Microphone Enabled: $enable")
|
|
354
|
+
val micStateConfig = MicStateConfig.newBuilder()
|
|
355
|
+
.setEnabled(enable)
|
|
356
|
+
.build()
|
|
357
|
+
val phoneToGlasses = PhoneToGlasses.newBuilder()
|
|
358
|
+
.setMicState(micStateConfig)
|
|
359
|
+
.build()
|
|
360
|
+
|
|
361
|
+
return generateProtobufCommandBytes(phoneToGlasses)
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
fun generateAutoBrightnessConfigCommandBytes(autoLight: Boolean): ByteArray {
|
|
365
|
+
Bridge.log("Nex: === SENDING AUTO BRIGHTNESS COMMAND TO GLASSES ===")
|
|
366
|
+
Bridge.log("Nex: Auto Brightness Enabled: $autoLight")
|
|
367
|
+
|
|
368
|
+
val autoBrightnessConfig = AutoBrightnessConfig.newBuilder()
|
|
369
|
+
.setEnabled(autoLight)
|
|
370
|
+
.build()
|
|
371
|
+
|
|
372
|
+
val phoneToGlasses = PhoneToGlasses.newBuilder()
|
|
373
|
+
.setAutoBrightness(autoBrightnessConfig)
|
|
374
|
+
.build()
|
|
375
|
+
|
|
376
|
+
Bridge.log("Nex: Sent auto light sendAutoBrightnessCommand => $autoLight")
|
|
377
|
+
|
|
378
|
+
return generateProtobufCommandBytes(phoneToGlasses)
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
private fun createWhitelistJson(apps: List<AppInfo>): String {
|
|
382
|
+
return try {
|
|
383
|
+
val appList = JSONArray().apply {
|
|
384
|
+
apps.forEach { app ->
|
|
385
|
+
put(JSONObject().apply {
|
|
386
|
+
put("id", app.id)
|
|
387
|
+
put("name", app.name)
|
|
388
|
+
})
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
JSONObject().apply {
|
|
393
|
+
put("calendar_enable", false)
|
|
394
|
+
put("call_enable", false)
|
|
395
|
+
put("msg_enable", false)
|
|
396
|
+
put("ios_mail_enable", false)
|
|
397
|
+
put("app", JSONObject().apply {
|
|
398
|
+
put("list", appList)
|
|
399
|
+
put("enable", true)
|
|
400
|
+
})
|
|
401
|
+
}.toString()
|
|
402
|
+
} catch (e: JSONException) {
|
|
403
|
+
Log.e(TAG, "Error creating whitelist JSON: ${e.message}", e)
|
|
404
|
+
"{}"
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
private fun createWhitelistChunks(json: String, maxChunkSize: Int): List<ByteArray> {
|
|
409
|
+
val jsonBytes = json.toByteArray(Charsets.UTF_8)
|
|
410
|
+
val totalChunks = (jsonBytes.size + maxChunkSize - 1) / maxChunkSize
|
|
411
|
+
|
|
412
|
+
return List(totalChunks) { chunkIndex ->
|
|
413
|
+
val start = chunkIndex * maxChunkSize
|
|
414
|
+
val end = (start + maxChunkSize).coerceAtMost(jsonBytes.size)
|
|
415
|
+
val payloadChunk = jsonBytes.copyOfRange(start, end)
|
|
416
|
+
|
|
417
|
+
// Create the header: [WHITELIST_CMD, total_chunks, chunk_index]
|
|
418
|
+
val header = byteArrayOf(
|
|
419
|
+
WHITELIST_CMD.toByte(),
|
|
420
|
+
totalChunks.toByte(),
|
|
421
|
+
chunkIndex.toByte()
|
|
422
|
+
)
|
|
423
|
+
|
|
424
|
+
header + payloadChunk
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
private fun generateProtobufCommandBytes(phoneToGlasses: PhoneToGlasses): ByteArray {
|
|
429
|
+
val contentBytes = phoneToGlasses.toByteArray()
|
|
430
|
+
val chunk = ByteBuffer.allocate(contentBytes.size + 1)
|
|
431
|
+
|
|
432
|
+
chunk.put(NexBluetoothPacketTypes.PACKET_TYPE_PROTOBUF)
|
|
433
|
+
chunk.put(contentBytes)
|
|
434
|
+
|
|
435
|
+
// Enhanced logging for protobuf messages
|
|
436
|
+
val result = chunk.array()
|
|
437
|
+
logProtobufMessage(phoneToGlasses, result)
|
|
438
|
+
|
|
439
|
+
return result
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
private fun logProtobufMessage(phoneToGlasses: PhoneToGlasses, fullMessage: ByteArray) {
|
|
443
|
+
val logMessage = buildString {
|
|
444
|
+
appendLine("=== PROTOBUF MESSAGE TO GLASSES ===")
|
|
445
|
+
appendLine("Message Type: ${phoneToGlasses.payloadCase}")
|
|
446
|
+
|
|
447
|
+
// Extract and log text content if present
|
|
448
|
+
when {
|
|
449
|
+
phoneToGlasses.hasDisplayText() -> {
|
|
450
|
+
val text = phoneToGlasses.displayText.text
|
|
451
|
+
appendLine("Text Content: \"$text\"")
|
|
452
|
+
appendLine("Text Length: ${text.length} characters")
|
|
453
|
+
}
|
|
454
|
+
phoneToGlasses.hasDisplayScrollingText() -> {
|
|
455
|
+
val text = phoneToGlasses.displayScrollingText.text
|
|
456
|
+
appendLine("Scrolling Text Content: \"$text\"")
|
|
457
|
+
appendLine("Text Length: ${text.length} characters")
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// Log message size information
|
|
462
|
+
appendLine("Protobuf Payload Size: ${phoneToGlasses.toByteArray().size} bytes")
|
|
463
|
+
appendLine("Total Message Size: ${fullMessage.size} bytes")
|
|
464
|
+
appendLine("Packet Type: 0x${NexBluetoothPacketTypes.PACKET_TYPE_PROTOBUF.toString(16).padStart(2, '0').uppercase()}")
|
|
465
|
+
append("=====================================")
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
Bridge.log("Nex: $logMessage")
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
private fun readProtoVersionFromAssets(context: Context): String? {
|
|
472
|
+
return try {
|
|
473
|
+
context.assets.open("mentraos_ble.proto").use { inputStream ->
|
|
474
|
+
val content = inputStream.bufferedReader().use { it.readText() }
|
|
475
|
+
extractVersionFromProtoContent(content)
|
|
476
|
+
}
|
|
477
|
+
} catch (e: IOException) {
|
|
478
|
+
Bridge.log("Could not read proto from assets: ${e.message}")
|
|
479
|
+
null
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
private fun readProtoVersionFromResources(context: Context): String? {
|
|
484
|
+
return try {
|
|
485
|
+
val resId = context.resources.getIdentifier("mentraos_ble", "raw", context.packageName)
|
|
486
|
+
if (resId != 0) {
|
|
487
|
+
context.resources.openRawResource(resId).use { inputStream ->
|
|
488
|
+
val content = inputStream.bufferedReader().use { it.readText() }
|
|
489
|
+
extractVersionFromProtoContent(content)
|
|
490
|
+
}
|
|
491
|
+
} else {
|
|
492
|
+
null
|
|
493
|
+
}
|
|
494
|
+
} catch (e: Exception) {
|
|
495
|
+
Bridge.log("Could not read proto from resources: ${e.message}")
|
|
496
|
+
null
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
private fun readProtoVersionFromProject(context: Context): String? {
|
|
501
|
+
val projectPaths = arrayOf(
|
|
502
|
+
"../../mcu_client/mentraos_ble.proto",
|
|
503
|
+
"../../../mcu_client/mentraos_ble.proto",
|
|
504
|
+
"../../../../mcu_client/mentraos_ble.proto",
|
|
505
|
+
"/data/data/${context.packageName}/../../mcu_client/mentraos_ble.proto",
|
|
506
|
+
"${android.os.Environment.getExternalStorageDirectory()}/MentraOS/mcu_client/mentraos_ble.proto"
|
|
507
|
+
)
|
|
508
|
+
|
|
509
|
+
return projectPaths.firstNotNullOfOrNull { path ->
|
|
510
|
+
try {
|
|
511
|
+
val protoFile = java.io.File(path)
|
|
512
|
+
if (protoFile.exists() && protoFile.canRead()) {
|
|
513
|
+
val content = protoFile.readText(Charsets.UTF_8)
|
|
514
|
+
extractVersionFromProtoContent(content)
|
|
515
|
+
} else {
|
|
516
|
+
null
|
|
517
|
+
}
|
|
518
|
+
} catch (e: Exception) {
|
|
519
|
+
null
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
private fun extractVersionFromProtoContent(content: String): String? {
|
|
525
|
+
return try {
|
|
526
|
+
val pattern = Regex("""option\s*\(\s*mentra_schema_version\s*\)\s*=\s*(\d+)\s*;""")
|
|
527
|
+
pattern.find(content)?.groupValues?.get(1)
|
|
528
|
+
} catch (e: Exception) {
|
|
529
|
+
Log.e(TAG, "Error extracting version from proto content: ${e.message}", e)
|
|
530
|
+
null
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
object NexEventUtils {
|
|
536
|
+
private const val TAG = "NexEventUtils"
|
|
537
|
+
|
|
538
|
+
fun sendHeartbeatSentEvent(timestamp: Long) {
|
|
539
|
+
try {
|
|
540
|
+
val data = HashMap<String, Any>()
|
|
541
|
+
data["timestamp"] = timestamp
|
|
542
|
+
|
|
543
|
+
Bridge.sendTypedMessage("heartbeat_sent", data as Map<String, Any>)
|
|
544
|
+
Bridge.log("NOTIF: Successfully queued heartbeat sent event")
|
|
545
|
+
} catch (e: Exception) {
|
|
546
|
+
Log.e(TAG, "NOTIF: Error sending heartbeat sent event", e)
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
fun sendHeartbeatReceivedEvent(timestamp: Long) {
|
|
551
|
+
try {
|
|
552
|
+
val data = HashMap<String, Any>()
|
|
553
|
+
data["timestamp"] = timestamp
|
|
554
|
+
|
|
555
|
+
Bridge.sendTypedMessage("heartbeat_received", data as Map<String, Any>)
|
|
556
|
+
Bridge.log("NOTIF: Successfully queued heartbeat received event")
|
|
557
|
+
} catch (e: Exception) {
|
|
558
|
+
Log.e(TAG, "NOTIF: Error sending heartbeat received event", e)
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
fun sendBleCommandSentEvent(payloadCase: String, packetHex: String, timestamp: Long) {
|
|
563
|
+
try {
|
|
564
|
+
val data = HashMap<String, Any>()
|
|
565
|
+
data["command"] = payloadCase
|
|
566
|
+
data["commandText"] = packetHex
|
|
567
|
+
data["timestamp"] = timestamp
|
|
568
|
+
|
|
569
|
+
Bridge.sendTypedMessage("send_command_to_ble", data as Map<String, Any>)
|
|
570
|
+
Bridge.log("NOTIF: Successfully queued ble command sent event")
|
|
571
|
+
} catch (e: Exception) {
|
|
572
|
+
Log.e(TAG, "NOTIF: Error sending ble command sent event", e)
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
fun sendBleCommandReceivedEvent(payloadCase: String, packetHex: String, timestamp: Long) {
|
|
577
|
+
try {
|
|
578
|
+
val data = HashMap<String, Any>()
|
|
579
|
+
data["command"] = payloadCase
|
|
580
|
+
data["commandText"] = packetHex
|
|
581
|
+
data["timestamp"] = timestamp
|
|
582
|
+
|
|
583
|
+
Bridge.sendTypedMessage("receive_command_from_ble", data as Map<String, Any>)
|
|
584
|
+
Bridge.log("NOTIF: Successfully queued ble command received event")
|
|
585
|
+
} catch (e: Exception) {
|
|
586
|
+
Log.e(TAG, "NOTIF: Error sending ble command received event", e)
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
}
|