@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.
Files changed (278) hide show
  1. package/README.md +278 -0
  2. package/android/build.gradle +167 -0
  3. package/android/lc3Lib/CMakeLists.txt +6 -0
  4. package/android/lc3Lib/build.gradle +109 -0
  5. package/android/lc3Lib/proguard-rules.pro +33 -0
  6. package/android/lc3Lib/src/main/AndroidManifest.xml +2 -0
  7. package/android/lc3Lib/src/main/cpp/CMakeLists.txt +8 -0
  8. package/android/lc3Lib/src/main/cpp/google_opus_stuff/CMakeLists.txt +30 -0
  9. package/android/lc3Lib/src/main/cpp/google_opus_stuff/jni/CMakeLists.txt +7 -0
  10. package/android/lc3Lib/src/main/cpp/google_opus_stuff/jni/ogg_opus_encoder.cc +96 -0
  11. package/android/lc3Lib/src/main/cpp/google_opus_stuff/jni/ogg_opus_encoder.h +53 -0
  12. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/Makefile.am +6 -0
  13. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/config_types.h +26 -0
  14. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/config_types.h.in +26 -0
  15. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/ogg.h +209 -0
  16. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/os_types.h +158 -0
  17. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus.h +981 -0
  18. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_custom.h +342 -0
  19. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_defines.h +799 -0
  20. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_multistream.h +660 -0
  21. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_projection.h +568 -0
  22. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_types.h +166 -0
  23. package/android/lc3Lib/src/main/cpp/google_opus_stuff/ogg_opus_encoder.cc +268 -0
  24. package/android/lc3Lib/src/main/cpp/google_opus_stuff/ogg_opus_encoder.h +115 -0
  25. package/android/lc3Lib/src/main/cpp/google_opus_stuff/opus_tools/opus_header.h +59 -0
  26. package/android/lc3Lib/src/main/cpp/liblc3/CMakeLists.txt +38 -0
  27. package/android/lc3Lib/src/main/cpp/liblc3/include/lc3.h +309 -0
  28. package/android/lc3Lib/src/main/cpp/liblc3/include/lc3_private.h +162 -0
  29. package/android/lc3Lib/src/main/cpp/liblc3/include/rnnoise.h +114 -0
  30. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/CMakeLists.txt +19 -0
  31. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/attdet.c +92 -0
  32. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/attdet.h +44 -0
  33. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bits.c +375 -0
  34. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bits.h +315 -0
  35. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bwdet.c +129 -0
  36. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bwdet.h +69 -0
  37. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/common.h +148 -0
  38. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/energy.c +70 -0
  39. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/energy.h +43 -0
  40. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/fastmath.h +158 -0
  41. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/lc3.c +702 -0
  42. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf.c +893 -0
  43. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf.h +111 -0
  44. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf_arm.h +506 -0
  45. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf_neon.h +281 -0
  46. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/makefile.mk +35 -0
  47. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/mdct.c +452 -0
  48. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/mdct.h +57 -0
  49. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/mdct_neon.h +296 -0
  50. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/meson.build +46 -0
  51. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/plc.c +61 -0
  52. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/plc.h +57 -0
  53. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/sns.c +880 -0
  54. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/sns.h +103 -0
  55. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/spec.c +904 -0
  56. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/spec.h +119 -0
  57. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tables.c +3457 -0
  58. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tables.h +94 -0
  59. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tns.c +457 -0
  60. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tns.h +99 -0
  61. package/android/lc3Lib/src/main/cpp/liblc3/liblc3.cpp +159 -0
  62. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/_kiss_fft_guts.h +182 -0
  63. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/arch.h +261 -0
  64. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/celt_lpc.c +279 -0
  65. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/celt_lpc.h +59 -0
  66. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/common.h +48 -0
  67. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/compile.sh +3 -0
  68. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/denoise.c +646 -0
  69. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/kiss_fft.c +601 -0
  70. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/kiss_fft.h +203 -0
  71. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/opus_types.h +159 -0
  72. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/pitch.c +526 -0
  73. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/pitch.h +149 -0
  74. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn.c +178 -0
  75. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn.h +69 -0
  76. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_data.c +11051 -0
  77. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_data.h +34 -0
  78. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_reader.c +168 -0
  79. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_train.py +66 -0
  80. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/tansig_table.h +45 -0
  81. package/android/lc3Lib/src/main/java/com/mentra/lc3Lib/Lc3Cpp.java +38 -0
  82. package/android/lc3Lib/third_party/CMakeLists.txt +23 -0
  83. package/android/lc3Lib/third_party/CMakeLists_libogg.txt +18 -0
  84. package/android/lc3Lib/third_party/CMakeLists_libopus.txt +18 -0
  85. package/android/lc3Lib/third_party/CMakeLists_opus-tools.txt +23 -0
  86. package/android/lc3Lib/third_party/opus_tools/src/AUTHORS +5 -0
  87. package/android/lc3Lib/third_party/opus_tools/src/CMakeLists.txt +4 -0
  88. package/android/lc3Lib/third_party/opus_tools/src/COPYING +371 -0
  89. package/android/lc3Lib/third_party/opus_tools/src/ChangeLog +3 -0
  90. package/android/lc3Lib/third_party/opus_tools/src/Makefile.am +42 -0
  91. package/android/lc3Lib/third_party/opus_tools/src/Makefile.unix +23 -0
  92. package/android/lc3Lib/third_party/opus_tools/src/NEWS +0 -0
  93. package/android/lc3Lib/third_party/opus_tools/src/README +0 -0
  94. package/android/lc3Lib/third_party/opus_tools/src/autogen.sh +115 -0
  95. package/android/lc3Lib/third_party/opus_tools/src/configure.ac +293 -0
  96. package/android/lc3Lib/third_party/opus_tools/src/src/arch.h +239 -0
  97. package/android/lc3Lib/third_party/opus_tools/src/src/audio-in.c +1046 -0
  98. package/android/lc3Lib/third_party/opus_tools/src/src/diag_range.c +245 -0
  99. package/android/lc3Lib/third_party/opus_tools/src/src/diag_range.h +28 -0
  100. package/android/lc3Lib/third_party/opus_tools/src/src/info_opus.c +320 -0
  101. package/android/lc3Lib/third_party/opus_tools/src/src/info_opus.h +51 -0
  102. package/android/lc3Lib/third_party/opus_tools/src/src/lpc.c +157 -0
  103. package/android/lc3Lib/third_party/opus_tools/src/src/lpc.h +27 -0
  104. package/android/lc3Lib/third_party/opus_tools/src/src/opus_header.c +286 -0
  105. package/android/lc3Lib/third_party/opus_tools/src/src/opus_header.h +59 -0
  106. package/android/lc3Lib/third_party/opus_tools/src/src/opusdec.c +884 -0
  107. package/android/lc3Lib/third_party/opus_tools/src/src/opusenc.c +1021 -0
  108. package/android/lc3Lib/third_party/opus_tools/src/src/opusenc.h +101 -0
  109. package/android/lc3Lib/third_party/opus_tools/src/src/opusinfo.c +639 -0
  110. package/android/lc3Lib/third_party/opus_tools/src/src/opusinfo.h +51 -0
  111. package/android/lc3Lib/third_party/opus_tools/src/src/os_support.h +167 -0
  112. package/android/lc3Lib/third_party/opus_tools/src/src/resample.c +1137 -0
  113. package/android/lc3Lib/third_party/opus_tools/src/src/speex_resampler.h +344 -0
  114. package/android/lc3Lib/third_party/opus_tools/src/src/stack_alloc.h +115 -0
  115. package/android/lc3Lib/third_party/opus_tools/src/src/wav_io.c +125 -0
  116. package/android/lc3Lib/third_party/opus_tools/src/src/wav_io.h +62 -0
  117. package/android/lc3Lib/third_party/opus_tools/src/src/wave_out.c +223 -0
  118. package/android/lc3Lib/third_party/opus_tools/src/src/wave_out.h +60 -0
  119. package/android/settings.gradle +1 -0
  120. package/android/src/main/AndroidManifest.xml +40 -0
  121. package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +528 -0
  122. package/android/src/main/java/com/mentra/bluetoothsdk/Bridge.kt +610 -0
  123. package/android/src/main/java/com/mentra/bluetoothsdk/DeviceManager.kt +1616 -0
  124. package/android/src/main/java/com/mentra/bluetoothsdk/DeviceStore.kt +314 -0
  125. package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothModels.kt +1710 -0
  126. package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +554 -0
  127. package/android/src/main/java/com/mentra/bluetoothsdk/ObservableStore.kt +68 -0
  128. package/android/src/main/java/com/mentra/bluetoothsdk/controllers/ControllerManager.kt +158 -0
  129. package/android/src/main/java/com/mentra/bluetoothsdk/controllers/R1.kt +934 -0
  130. package/android/src/main/java/com/mentra/bluetoothsdk/services/Foreground.kt +175 -0
  131. package/android/src/main/java/com/mentra/bluetoothsdk/services/PhoneMic.kt +1109 -0
  132. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G1.java +3974 -0
  133. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G2.kt +3551 -0
  134. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Mach1.java +1327 -0
  135. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.java +6959 -0
  136. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraNex.kt +1655 -0
  137. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraosBle.java +53675 -0
  138. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/SGCManager.kt +202 -0
  139. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Simulated.kt +224 -0
  140. package/android/src/main/java/com/mentra/bluetoothsdk/stt/STTTools.kt +340 -0
  141. package/android/src/main/java/com/mentra/bluetoothsdk/stt/SherpaOnnxTranscriber.kt +465 -0
  142. package/android/src/main/java/com/mentra/bluetoothsdk/stt/VadGateSpeechPolicy.kt +221 -0
  143. package/android/src/main/java/com/mentra/bluetoothsdk/utils/AES.java +106 -0
  144. package/android/src/main/java/com/mentra/bluetoothsdk/utils/AudioSessionMonitor.kt +189 -0
  145. package/android/src/main/java/com/mentra/bluetoothsdk/utils/BitmapJavaUtils.java +169 -0
  146. package/android/src/main/java/com/mentra/bluetoothsdk/utils/BlePhotoUploadService.java +179 -0
  147. package/android/src/main/java/com/mentra/bluetoothsdk/utils/Constants.kt +44 -0
  148. package/android/src/main/java/com/mentra/bluetoothsdk/utils/G1Text.kt +436 -0
  149. package/android/src/main/java/com/mentra/bluetoothsdk/utils/IncidentLogBleRelayNaming.java +29 -0
  150. package/android/src/main/java/com/mentra/bluetoothsdk/utils/IncidentLogBleUploadService.java +76 -0
  151. package/android/src/main/java/com/mentra/bluetoothsdk/utils/K900ProtocolUtils.java +791 -0
  152. package/android/src/main/java/com/mentra/bluetoothsdk/utils/MessageChunker.java +186 -0
  153. package/android/src/main/java/com/mentra/bluetoothsdk/utils/NexSGCUtils.kt +589 -0
  154. package/android/src/main/java/com/mentra/bluetoothsdk/utils/PhoneAudioMonitor.kt +303 -0
  155. package/android/src/main/java/com/mentra/bluetoothsdk/utils/SmartGlassesConnectionState.java +9 -0
  156. package/android/src/main/java/com/mentra/bluetoothsdk/utils/audio/ByteUtilAudioPlayer.java +655 -0
  157. package/android/src/main/java/com/mentra/bluetoothsdk/utils/audio/Lc3Player.java +441 -0
  158. package/android/src/main/java/com/mentra/bluetoothsdk/utils/audio/PCMAudioPlayer.java +431 -0
  159. package/android/src/main/res/values/strings.xml +4 -0
  160. package/app.plugin.js +1 -0
  161. package/build/BluetoothSdk.types.d.ts +498 -0
  162. package/build/BluetoothSdk.types.d.ts.map +1 -0
  163. package/build/BluetoothSdk.types.js +23 -0
  164. package/build/BluetoothSdk.types.js.map +1 -0
  165. package/build/BluetoothSdkModule.d.ts +71 -0
  166. package/build/BluetoothSdkModule.d.ts.map +1 -0
  167. package/build/BluetoothSdkModule.js +106 -0
  168. package/build/BluetoothSdkModule.js.map +1 -0
  169. package/build/index.d.ts +3 -0
  170. package/build/index.d.ts.map +1 -0
  171. package/build/index.js +5 -0
  172. package/build/index.js.map +1 -0
  173. package/expo-module.config.json +9 -0
  174. package/ios/BluetoothSdkModule.swift +665 -0
  175. package/ios/MentraBluetoothSDK.podspec +77 -0
  176. package/ios/Packages/CoreObjC/CoreObjC.xcodeproj/project.pbxproj +213 -0
  177. package/ios/Packages/CoreObjC/PcmConverter.h +22 -0
  178. package/ios/Packages/CoreObjC/PcmConverter.m +266 -0
  179. package/ios/Packages/CoreObjC/attdet.c +92 -0
  180. package/ios/Packages/CoreObjC/attdet.h +44 -0
  181. package/ios/Packages/CoreObjC/bits.c +375 -0
  182. package/ios/Packages/CoreObjC/bits.h +315 -0
  183. package/ios/Packages/CoreObjC/bwdet.c +129 -0
  184. package/ios/Packages/CoreObjC/bwdet.h +69 -0
  185. package/ios/Packages/CoreObjC/common.h +151 -0
  186. package/ios/Packages/CoreObjC/energy.c +70 -0
  187. package/ios/Packages/CoreObjC/energy.h +43 -0
  188. package/ios/Packages/CoreObjC/fastmath.h +158 -0
  189. package/ios/Packages/CoreObjC/lc3.c +704 -0
  190. package/ios/Packages/CoreObjC/lc3.h +313 -0
  191. package/ios/Packages/CoreObjC/lc3_cpp.h +283 -0
  192. package/ios/Packages/CoreObjC/lc3_private.h +163 -0
  193. package/ios/Packages/CoreObjC/ltpf.c +905 -0
  194. package/ios/Packages/CoreObjC/ltpf.h +111 -0
  195. package/ios/Packages/CoreObjC/ltpf_arm.h +506 -0
  196. package/ios/Packages/CoreObjC/ltpf_neon.h +281 -0
  197. package/ios/Packages/CoreObjC/makefile.mk +35 -0
  198. package/ios/Packages/CoreObjC/mdct.c +469 -0
  199. package/ios/Packages/CoreObjC/mdct.h +57 -0
  200. package/ios/Packages/CoreObjC/mdct_neon.h +296 -0
  201. package/ios/Packages/CoreObjC/meson.build +61 -0
  202. package/ios/Packages/CoreObjC/plc.c +61 -0
  203. package/ios/Packages/CoreObjC/plc.h +57 -0
  204. package/ios/Packages/CoreObjC/rnnoise.h +114 -0
  205. package/ios/Packages/CoreObjC/sns.c +880 -0
  206. package/ios/Packages/CoreObjC/sns.h +103 -0
  207. package/ios/Packages/CoreObjC/spec.c +907 -0
  208. package/ios/Packages/CoreObjC/spec.h +119 -0
  209. package/ios/Packages/CoreObjC/tables.c +3457 -0
  210. package/ios/Packages/CoreObjC/tables.h +94 -0
  211. package/ios/Packages/CoreObjC/tns.c +457 -0
  212. package/ios/Packages/CoreObjC/tns.h +99 -0
  213. package/ios/Packages/SherpaOnnx/Model/joiner.onnx +0 -0
  214. package/ios/Packages/SherpaOnnx/Model/tokens.txt +502 -0
  215. package/ios/Packages/SherpaOnnx/SherpaOnnx.swift +1659 -0
  216. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Headers/cargs.h +162 -0
  217. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Headers/sherpa-onnx/c-api/c-api.h +1852 -0
  218. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Headers/sherpa-onnx/c-api/cxx-api.h +674 -0
  219. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Info.plist +44 -0
  220. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/libsherpa-onnx.a +0 -0
  221. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/sherpa-onnx.a +0 -0
  222. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/libsherpa-onnx.a +0 -0
  223. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/sherpa-onnx.a +0 -0
  224. package/ios/Packages/VAD/Common/VAD/VADQuality.swift +41 -0
  225. package/ios/Packages/VAD/Common/VAD/VADState.swift +26 -0
  226. package/ios/Packages/VAD/Common/VAD/VADStrategy.swift +29 -0
  227. package/ios/Packages/VAD/Common/VAD/VADType.swift +14 -0
  228. package/ios/Packages/VAD/Data/Configuration.swift +68 -0
  229. package/ios/Packages/VAD/Data/FrameSize.swift +39 -0
  230. package/ios/Packages/VAD/Data/Record.swift +13 -0
  231. package/ios/Packages/VAD/Data/Result.swift +22 -0
  232. package/ios/Packages/VAD/Data/SampleRate.swift +48 -0
  233. package/ios/Packages/VAD/Silero/Model/silero_vad.onnx +0 -0
  234. package/ios/Packages/VAD/Silero/SileroVAD.swift +284 -0
  235. package/ios/Packages/VAD/Silero/SileroVADStrategy.swift +64 -0
  236. package/ios/Packages/libbz2/module.modulemap +5 -0
  237. package/ios/Packages/libbz2/shim.h +1 -0
  238. package/ios/Source/Bridge.swift +353 -0
  239. package/ios/Source/Bridging-Header.h +16 -0
  240. package/ios/Source/DeviceManager.swift +1478 -0
  241. package/ios/Source/DeviceStore.swift +295 -0
  242. package/ios/Source/MentraBluetoothSDK.swift +2439 -0
  243. package/ios/Source/ObservableStore.swift +88 -0
  244. package/ios/Source/PrivacyInfo.xcprivacy +23 -0
  245. package/ios/Source/controllers/ControllerManager.swift +187 -0
  246. package/ios/Source/controllers/R1.swift +827 -0
  247. package/ios/Source/services/PhoneMic.swift +662 -0
  248. package/ios/Source/sgcs/Frame.swift +651 -0
  249. package/ios/Source/sgcs/G1.swift +2505 -0
  250. package/ios/Source/sgcs/G2.swift +3730 -0
  251. package/ios/Source/sgcs/Mach1.swift +543 -0
  252. package/ios/Source/sgcs/MentraLive.swift +4708 -0
  253. package/ios/Source/sgcs/MentraNex.swift +2479 -0
  254. package/ios/Source/sgcs/SGCManager.swift +243 -0
  255. package/ios/Source/sgcs/Simulated.swift +270 -0
  256. package/ios/Source/sgcs/mentraos_ble.pb.swift +3811 -0
  257. package/ios/Source/stt/STTTools.swift +154 -0
  258. package/ios/Source/stt/SherpaOnnxTranscriber.swift +401 -0
  259. package/ios/Source/utils/AudioSessionMonitor.swift +283 -0
  260. package/ios/Source/utils/Constants.swift +74 -0
  261. package/ios/Source/utils/Enums.swift +95 -0
  262. package/ios/Source/utils/G1Text.swift +2067 -0
  263. package/ios/Source/utils/JSCExperiment.swift +241 -0
  264. package/ios/Source/utils/MemoryMonitor.swift +44 -0
  265. package/ios/Source/utils/MessageChunker.swift +164 -0
  266. package/ios/Source/utils/Models.swift +135 -0
  267. package/ios/Source/utils/PhoneAudioMonitor.swift +226 -0
  268. package/ios/Source/utils/TarBz2Extractor.swift +206 -0
  269. package/package.json +78 -0
  270. package/plugin/build/index.d.ts +6 -0
  271. package/plugin/build/index.js +12 -0
  272. package/plugin/build/withAndroid.d.ts +4 -0
  273. package/plugin/build/withAndroid.js +80 -0
  274. package/plugin/build/withIos.d.ts +4 -0
  275. package/plugin/build/withIos.js +64 -0
  276. package/src/BluetoothSdk.types.ts +581 -0
  277. package/src/BluetoothSdkModule.ts +259 -0
  278. 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
+ }