@mentra/bluetooth-sdk 0.1.12 → 0.1.13

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 (65) hide show
  1. package/README.md +16 -9
  2. package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +51 -3
  3. package/android/src/main/java/com/mentra/bluetoothsdk/DeviceManager.kt +73 -21
  4. package/android/src/main/java/com/mentra/bluetoothsdk/DeviceStore.kt +1 -1
  5. package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +190 -26
  6. package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdkDebug.kt +14 -0
  7. package/android/src/main/java/com/mentra/bluetoothsdk/ObservableStore.kt +20 -0
  8. package/android/src/main/java/com/mentra/bluetoothsdk/OtaManifest.kt +153 -0
  9. package/android/src/main/java/com/mentra/bluetoothsdk/camera/CameraModels.kt +78 -10
  10. package/android/src/main/java/com/mentra/bluetoothsdk/controllers/ControllerManager.kt +3 -14
  11. package/android/src/main/java/com/mentra/bluetoothsdk/controllers/R1.kt +3 -6
  12. package/android/src/main/java/com/mentra/bluetoothsdk/services/PhoneMic.kt +90 -4
  13. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G1.kt +3835 -0
  14. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G2.kt +20 -23
  15. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/{Mach1.java → Mach1.kt} +517 -560
  16. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.kt +8712 -0
  17. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraNex.kt +11 -1
  18. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/SGCManager.kt +3 -13
  19. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Simulated.kt +7 -14
  20. package/build/BluetoothSdk.types.d.ts +39 -9
  21. package/build/BluetoothSdk.types.d.ts.map +1 -1
  22. package/build/BluetoothSdk.types.js.map +1 -1
  23. package/build/_private/BluetoothSdkModule.d.ts +8 -6
  24. package/build/_private/BluetoothSdkModule.d.ts.map +1 -1
  25. package/build/_private/BluetoothSdkModule.js +0 -2
  26. package/build/_private/BluetoothSdkModule.js.map +1 -1
  27. package/build/_private/photoRequestPayload.d.ts +3 -1
  28. package/build/_private/photoRequestPayload.d.ts.map +1 -1
  29. package/build/_private/photoRequestPayload.js +43 -1
  30. package/build/_private/photoRequestPayload.js.map +1 -1
  31. package/build/debug.d.ts +3 -0
  32. package/build/debug.d.ts.map +1 -0
  33. package/build/debug.js +8 -0
  34. package/build/debug.js.map +1 -0
  35. package/build/index.d.ts +1 -1
  36. package/build/index.d.ts.map +1 -1
  37. package/build/index.js +14 -5
  38. package/build/index.js.map +1 -1
  39. package/ios/BluetoothSdkModule.swift +38 -57
  40. package/ios/Source/BluetoothSdkDefaults.swift +23 -3
  41. package/ios/Source/DeviceManager.swift +37 -26
  42. package/ios/Source/DeviceStore.swift +5 -1
  43. package/ios/Source/MentraBluetoothSDK.swift +197 -26
  44. package/ios/Source/MentraBluetoothSDKDebug.swift +12 -0
  45. package/ios/Source/ObservableStore.swift +11 -0
  46. package/ios/Source/OtaManifest.swift +170 -0
  47. package/ios/Source/camera/CameraModels.swift +218 -8
  48. package/ios/Source/controllers/ControllerManager.swift +2 -5
  49. package/ios/Source/controllers/R1.swift +2 -5
  50. package/ios/Source/sgcs/G1.swift +6 -5
  51. package/ios/Source/sgcs/G2.swift +20 -18
  52. package/ios/Source/sgcs/Mach1.swift +6 -5
  53. package/ios/Source/sgcs/MentraLive.swift +129 -33
  54. package/ios/Source/sgcs/MentraNex.swift +6 -5
  55. package/ios/Source/sgcs/SGCManager.swift +3 -5
  56. package/ios/Source/sgcs/Simulated.swift +7 -3
  57. package/ios/Source/status/DeviceStatus.swift +1 -1
  58. package/package.json +6 -1
  59. package/src/BluetoothSdk.types.ts +40 -9
  60. package/src/_private/BluetoothSdkModule.ts +8 -9
  61. package/src/_private/photoRequestPayload.ts +45 -2
  62. package/src/debug.ts +9 -0
  63. package/src/index.ts +23 -6
  64. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G1.java +0 -3974
  65. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.java +0 -7434
@@ -1,17 +1,44 @@
1
1
  import Foundation
2
2
 
3
3
  public enum PhotoSize: String {
4
- case small
4
+ case low
5
5
  case medium
6
- case large
7
- case full
6
+ case high
7
+ case max
8
+
9
+ public static func normalizeLegacy(_ value: String?) -> String {
10
+ switch value {
11
+ case "small":
12
+ return PhotoSize.low.rawValue
13
+ case "large":
14
+ return PhotoSize.high.rawValue
15
+ case "full":
16
+ return PhotoSize.max.rawValue
17
+ default:
18
+ return value ?? PhotoSize.medium.rawValue
19
+ }
20
+ }
21
+
22
+ public init(normalizedRawValue value: String?) {
23
+ let normalized = PhotoSize.normalizeLegacy(value)
24
+ self = PhotoSize(rawValue: normalized) ?? .medium
25
+ }
8
26
  }
9
27
 
10
28
  public enum ButtonPhotoSize: String {
11
- case small
29
+ case low
12
30
  case medium
13
- case large
31
+ case high
14
32
  case max
33
+
34
+ public static func normalizeLegacy(_ value: String?) -> String {
35
+ PhotoSize.normalizeLegacy(value)
36
+ }
37
+
38
+ public init(normalizedRawValue value: String?) {
39
+ let normalized = ButtonPhotoSize.normalizeLegacy(value)
40
+ self = ButtonPhotoSize(rawValue: normalized) ?? .medium
41
+ }
15
42
  }
16
43
 
17
44
  public enum PhotoCompression: String {
@@ -21,10 +48,66 @@ public enum PhotoCompression: String {
21
48
  }
22
49
 
23
50
  public struct ButtonPhotoSettings {
24
- public let size: ButtonPhotoSize
51
+ public let size: ButtonPhotoSize?
52
+ public let mfnr: Bool?
53
+ public let zsl: Bool?
54
+ public let noiseReduction: Bool?
55
+ public let edgeEnhancement: Bool?
56
+ public let ispDigitalGain: Int?
57
+ public let ispAnalogGain: String?
58
+ public let aeExposureDivisor: Int?
59
+ public let isoCap: Int?
60
+ public let compress: String?
61
+ public let sound: Bool?
62
+ public let resetCaptureTuning: Bool?
25
63
 
26
- public init(size: ButtonPhotoSize) {
64
+ public init(
65
+ size: ButtonPhotoSize?,
66
+ mfnr: Bool? = nil,
67
+ zsl: Bool? = nil,
68
+ noiseReduction: Bool? = nil,
69
+ edgeEnhancement: Bool? = nil,
70
+ ispDigitalGain: Int? = nil,
71
+ ispAnalogGain: String? = nil,
72
+ aeExposureDivisor: Int? = nil,
73
+ isoCap: Int? = nil,
74
+ compress: String? = nil,
75
+ sound: Bool? = nil,
76
+ resetCaptureTuning: Bool? = nil
77
+ ) {
27
78
  self.size = size
79
+ self.mfnr = mfnr
80
+ self.zsl = zsl
81
+ self.noiseReduction = noiseReduction
82
+ self.edgeEnhancement = edgeEnhancement
83
+ self.ispDigitalGain = ispDigitalGain
84
+ self.ispAnalogGain = ispAnalogGain
85
+ self.aeExposureDivisor = aeExposureDivisor
86
+ self.isoCap = isoCap
87
+ self.compress = compress
88
+ self.sound = sound
89
+ self.resetCaptureTuning = resetCaptureTuning
90
+ }
91
+
92
+ static func from(params: [String: Any]) -> ButtonPhotoSettings {
93
+ let size = (params["size"] as? String).map { ButtonPhotoSize(normalizedRawValue: $0) }
94
+ let aeExposureDivisor =
95
+ optionalIntValue(params, "aeExposureDivisor").flatMap { $0 > 1 ? $0 : nil }
96
+ let isoCap = optionalIntValue(params, "isoCap").flatMap { $0 > 0 ? $0 : nil }
97
+ return ButtonPhotoSettings(
98
+ size: size,
99
+ mfnr: optionalBoolValue(params, "mfnr"),
100
+ zsl: optionalBoolValue(params, "zsl"),
101
+ noiseReduction: optionalBoolValue(params, "noiseReduction"),
102
+ edgeEnhancement: optionalBoolValue(params, "edgeEnhancement"),
103
+ ispDigitalGain: optionalIntValue(params, "ispDigitalGain"),
104
+ ispAnalogGain: optionalStringValue(params, "ispAnalogGain"),
105
+ aeExposureDivisor: aeExposureDivisor,
106
+ isoCap: isoCap,
107
+ compress: optionalStringValue(params, "compress"),
108
+ sound: optionalBoolValue(params, "sound"),
109
+ resetCaptureTuning: optionalBoolValue(params, "resetCaptureTuning")
110
+ )
28
111
  }
29
112
  }
30
113
 
@@ -152,6 +235,14 @@ public struct PhotoRequest {
152
235
  public let exposureTimeNs: Double?
153
236
  /// Sensor ISO for this capture only. Only used when exposureTimeNs enables manual exposure.
154
237
  public let iso: Int?
238
+ public let aeExposureDivisor: Int?
239
+ public let isoCap: Int?
240
+ public let noiseReduction: Bool?
241
+ public let edgeEnhancement: Bool?
242
+ public let mfnr: Bool?
243
+ public let zsl: Bool?
244
+ public let ispDigitalGain: Int?
245
+ public let ispAnalogGain: String?
155
246
 
156
247
  public init(
157
248
  requestId: String,
@@ -164,7 +255,15 @@ public struct PhotoRequest {
164
255
  save: Bool = false,
165
256
  sound: Bool,
166
257
  exposureTimeNs: Double? = nil,
167
- iso: Int? = nil
258
+ iso: Int? = nil,
259
+ aeExposureDivisor: Int? = nil,
260
+ isoCap: Int? = nil,
261
+ noiseReduction: Bool? = nil,
262
+ edgeEnhancement: Bool? = nil,
263
+ mfnr: Bool? = nil,
264
+ zsl: Bool? = nil,
265
+ ispDigitalGain: Int? = nil,
266
+ ispAnalogGain: String? = nil
168
267
  ) {
169
268
  self.requestId = requestId
170
269
  self.appId = appId
@@ -177,6 +276,117 @@ public struct PhotoRequest {
177
276
  self.sound = sound
178
277
  self.exposureTimeNs = exposureTimeNs
179
278
  self.iso = iso
279
+ self.aeExposureDivisor = aeExposureDivisor
280
+ self.isoCap = isoCap
281
+ self.noiseReduction = noiseReduction
282
+ self.edgeEnhancement = edgeEnhancement
283
+ self.mfnr = mfnr
284
+ self.zsl = zsl
285
+ self.ispDigitalGain = ispDigitalGain
286
+ self.ispAnalogGain = ispAnalogGain
287
+ }
288
+
289
+ public static func from(params: [String: Any]) -> PhotoRequest {
290
+ let sizeRaw = params["size"] as? String ?? "medium"
291
+ let compressRaw = params["compress"] as? String ?? "none"
292
+ let exposureTimeNs: Double?
293
+ switch params["exposureTimeNs"] {
294
+ case let value as Double:
295
+ exposureTimeNs = value.isFinite && value > 0 ? value : nil
296
+ case let value as Int:
297
+ exposureTimeNs = value > 0 ? Double(value) : nil
298
+ case let value as NSNumber:
299
+ let d = value.doubleValue
300
+ exposureTimeNs = d.isFinite && d > 0 ? d : nil
301
+ default:
302
+ exposureTimeNs = nil
303
+ }
304
+ let iso: Int?
305
+ switch params["iso"] {
306
+ case let value as Int:
307
+ iso = value > 0 ? value : nil
308
+ case let value as Double:
309
+ iso = value.isFinite && value > 0 && value < Double(Int.max) ? Int(value) : nil
310
+ case let value as NSNumber:
311
+ let intValue = value.intValue
312
+ iso = intValue > 0 ? intValue : nil
313
+ default:
314
+ iso = nil
315
+ }
316
+ func optionalInt(_ key: String, min: Int = Int.min, filter: (Int) -> Bool = { _ in true }) -> Int? {
317
+ guard params.keys.contains(key) else { return nil }
318
+ switch params[key] {
319
+ case let value as Int:
320
+ return filter(value) ? value : nil
321
+ case let value as Double:
322
+ guard value.isFinite, value >= Double(min) else { return nil }
323
+ return filter(Int(value)) ? Int(value) : nil
324
+ case let value as NSNumber:
325
+ let intValue = value.intValue
326
+ return filter(intValue) ? intValue : nil
327
+ default:
328
+ return nil
329
+ }
330
+ }
331
+ func optionalBool(_ key: String) -> Bool? {
332
+ guard params.keys.contains(key) else { return nil }
333
+ return params[key] as? Bool
334
+ }
335
+
336
+ return PhotoRequest(
337
+ requestId: params["requestId"] as? String ?? "",
338
+ appId: params["appId"] as? String ?? "",
339
+ size: PhotoSize(normalizedRawValue: sizeRaw),
340
+ webhookUrl: params["webhookUrl"] as? String,
341
+ authToken: (params["authToken"] as? String)?.nilIfBlank,
342
+ compress: PhotoCompression(rawValue: compressRaw),
343
+ flash: params["flash"] as? Bool ?? true,
344
+ save: (params["save"] as? Bool) ?? (params["saveToGallery"] as? Bool) ?? false,
345
+ sound: params["sound"] as? Bool ?? true,
346
+ exposureTimeNs: exposureTimeNs,
347
+ iso: iso,
348
+ aeExposureDivisor: optionalInt("aeExposureDivisor", min: 2) { $0 > 1 },
349
+ isoCap: optionalInt("isoCap", min: 1) { $0 > 0 },
350
+ noiseReduction: optionalBool("noiseReduction"),
351
+ edgeEnhancement: optionalBool("edgeEnhancement"),
352
+ mfnr: optionalBool("mfnr"),
353
+ zsl: optionalBool("zsl"),
354
+ ispDigitalGain: optionalInt("ispDigitalGain"),
355
+ ispAnalogGain: params["ispAnalogGain"] as? String
356
+ )
357
+ }
358
+
359
+ func appendScanFields(to json: inout [String: Any]) {
360
+ if let aeExposureDivisor {
361
+ json["aeExposureDivisor"] = aeExposureDivisor
362
+ }
363
+ if let isoCap {
364
+ json["isoCap"] = isoCap
365
+ }
366
+ if let noiseReduction {
367
+ json["noiseReduction"] = noiseReduction
368
+ }
369
+ if let edgeEnhancement {
370
+ json["edgeEnhancement"] = edgeEnhancement
371
+ }
372
+ if let mfnr {
373
+ json["mfnr"] = mfnr
374
+ }
375
+ if let zsl {
376
+ json["zsl"] = zsl
377
+ }
378
+ if let ispDigitalGain {
379
+ json["ispDigitalGain"] = ispDigitalGain
380
+ }
381
+ if let ispAnalogGain {
382
+ json["ispAnalogGain"] = ispAnalogGain
383
+ }
384
+ }
385
+ }
386
+
387
+ private extension String {
388
+ var nilIfBlank: String? {
389
+ isEmpty ? nil : self
180
390
  }
181
391
  }
182
392
 
@@ -18,10 +18,7 @@ protocol ControllerManager {
18
18
 
19
19
  // MARK: - Camera & Media
20
20
 
21
- func requestPhoto(
22
- _ requestId: String, appId: String, size: String?, webhookUrl: String?, authToken: String?,
23
- compress: String?, flash: Bool, save: Bool, sound: Bool, exposureTimeNs: Double?, iso: Int?
24
- )
21
+ func requestPhoto(_ request: PhotoRequest)
25
22
  func startStream(_ message: [String: Any])
26
23
  func stopStream()
27
24
  func sendStreamKeepAlive(_ message: [String: Any])
@@ -75,7 +72,7 @@ protocol ControllerManager {
75
72
  func sendWifiCredentials(_ ssid: String, _ password: String)
76
73
  func forgetWifiNetwork(_ ssid: String)
77
74
  func sendHotspotState(_ enabled: Bool)
78
- func sendOtaStart()
75
+ func sendOtaStart(otaVersionUrl: String?)
79
76
  func sendOtaQueryStatus()
80
77
 
81
78
  // MARK: - User Context (for crash reporting)
@@ -504,10 +504,7 @@ class R1: NSObject, ControllerManager {
504
504
  }
505
505
 
506
506
  func sendJson(_: [String: Any], wakeUp _: Bool, requireAck _: Bool) {}
507
- func requestPhoto(
508
- _: String, appId _: String, size _: String?, webhookUrl _: String?, authToken _: String?,
509
- compress _: String?, flash _: Bool, save _: Bool, sound _: Bool, exposureTimeNs _: Double?, iso _: Int?
510
- ) {}
507
+ func requestPhoto(_: PhotoRequest) {}
511
508
  func startVideoRecording(requestId _: String, save _: Bool, flash _: Bool, sound _: Bool) {}
512
509
  func stopVideoRecording(requestId _: String) {}
513
510
  func startStream(_: [String: Any]) {}
@@ -543,7 +540,7 @@ class R1: NSObject, ControllerManager {
543
540
  func sendWifiCredentials(_: String, _: String) {}
544
541
  func forgetWifiNetwork(_: String) {}
545
542
  func sendHotspotState(_: Bool) {}
546
- func sendOtaStart() {}
543
+ func sendOtaStart(otaVersionUrl: String?) {}
547
544
  func sendOtaQueryStatus() {}
548
545
  func sendUserEmailToGlasses(_: String) {}
549
546
  func queryGalleryStatus() {}
@@ -276,10 +276,7 @@ class G1: NSObject, SGCManager {
276
276
 
277
277
  func sendButtonMaxRecordingTime(_: Int) {}
278
278
 
279
- func requestPhoto(
280
- _: String, appId _: String, size _: String?, webhookUrl _: String?, authToken _: String?,
281
- compress _: String?, flash _: Bool, save _: Bool, sound _: Bool, exposureTimeNs _: Double?, iso _: Int?
282
- ) {}
279
+ func requestPhoto(_: PhotoRequest) {}
283
280
 
284
281
  func startStream(_: [String: Any]) {}
285
282
 
@@ -317,7 +314,7 @@ class G1: NSObject, SGCManager {
317
314
 
318
315
  func queryGalleryStatus() {}
319
316
 
320
- func sendOtaStart() {}
317
+ func sendOtaStart(otaVersionUrl: String?) {}
321
318
  func sendOtaQueryStatus() {}
322
319
 
323
320
  func ping() {}
@@ -786,6 +783,10 @@ class G1: NSObject, SGCManager {
786
783
  // }
787
784
  }
788
785
 
786
+ func sendText(_ text: String) async {
787
+ await sendTextWall(text)
788
+ }
789
+
789
790
  func sendTextWall(_ text: String) async {
790
791
  let chunks = textHelper.createTextWallChunks(text)
791
792
  queueChunks(chunks, sleepAfterMs: 10)
@@ -1534,7 +1534,6 @@ class G2: NSObject, SGCManager {
1534
1534
  /// Fixed pool of container IDs the page protocol expects.
1535
1535
  private let imageContainerIDPool: [Int32] = [10, 11, 12, 13]
1536
1536
  private let textContainerIDPool: [Int32] = [1, 2, 3, 4, 5, 6]
1537
- /// Default container seeded into every fresh page: 100x100 in the top-left.
1538
1537
  private static let defaultImgContainer = (
1539
1538
  x: Int32(188), y: Int32(44), width: Int32(200), height: Int32(100)
1540
1539
  )
@@ -1927,7 +1926,7 @@ class G2: NSObject, SGCManager {
1927
1926
  // MARK: - SGCManager: Display Control
1928
1927
 
1929
1928
  func sendTextWall(_ text: String) async {
1930
- await sendText(
1929
+ await sendTextAt(
1931
1930
  text,
1932
1931
  x: G2.defaultTextContainer.x,
1933
1932
  y: G2.defaultTextContainer.y,
@@ -1940,7 +1939,13 @@ class G2: NSObject, SGCManager {
1940
1939
  )
1941
1940
  }
1942
1941
 
1943
- func sendText(
1942
+ // Protocol witness for SGCManager.sendText — G2 renders a simple string as a
1943
+ // default-positioned text wall. The positioned variant is `sendTextAt`.
1944
+ func sendText(_ text: String) async {
1945
+ await sendTextWall(text)
1946
+ }
1947
+
1948
+ func sendTextAt(
1944
1949
  _ text: String, x: Int32? = nil, y: Int32? = nil, width: Int32? = nil, height: Int32? = nil,
1945
1950
  borderWidth: Int32? = nil, borderColor: Int32? = nil, borderRadius: Int32? = nil,
1946
1951
  paddingLength: Int32? = nil
@@ -1983,7 +1988,7 @@ class G2: NSObject, SGCManager {
1983
1988
  let msg = EvenHubProto.updateTextMessage(
1984
1989
  containerID: container.id,
1985
1990
  contentOffset: 0,
1986
- contentLength: Int32(text.utf8.count),
1991
+ contentLength: Int32(container.content.utf8.count),
1987
1992
  content: container.content
1988
1993
  )
1989
1994
  queueEvenHubCommand(msg)
@@ -2011,10 +2016,10 @@ class G2: NSObject, SGCManager {
2011
2016
  // Don't shutdown the EvenHub page — that kills audio streaming too.
2012
2017
  // Instead, just clear the text content by sending a space.
2013
2018
 
2014
- if !pageCreated {
2015
- Bridge.log("G2: clearDisplay() - page not created")
2016
- createPageWithContainers()
2017
- }
2019
+ // if !pageCreated {
2020
+ // Bridge.log("G2: clearDisplay() - page not created")
2021
+ // createPageWithContainers()
2022
+ // }
2018
2023
 
2019
2024
  // reset the content of all text containers to empty:
2020
2025
  for i in textContainers.indices {
@@ -2024,10 +2029,7 @@ class G2: NSObject, SGCManager {
2024
2029
  imageContainers[i].bmpData = Data()
2025
2030
  }
2026
2031
  // shutdown the page and then recreate the containers without the content:
2027
- let msg = EvenHubProto.shutdownMessage()
2028
- sendEvenHubCommand(msg)
2029
- createPageWithContainers()
2030
- restartMicIfAlreadyEnabled()
2032
+ Task { await rebuildPage() }
2031
2033
  }
2032
2034
 
2033
2035
  /// Send BMP data to an image container via fragmented updateImageRawData
@@ -2207,6 +2209,9 @@ class G2: NSObject, SGCManager {
2207
2209
  // )
2208
2210
  // sendEvenHubCommand(msg)
2209
2211
  // }
2212
+
2213
+ try? await Task.sleep(nanoseconds: 300_000_000) // 300ms to settle
2214
+ restartMicIfAlreadyEnabled()
2210
2215
  }
2211
2216
 
2212
2217
  /// Upscale BMP pixel data by 2x (200x100 → 400x200) using nearest-neighbor
@@ -2766,6 +2771,7 @@ class G2: NSObject, SGCManager {
2766
2771
  func disconnect() {
2767
2772
  Bridge.log("G2: disconnect()")
2768
2773
  isDisconnecting = true
2774
+ clearDisplay()
2769
2775
  cancelPairingTimeout()
2770
2776
  stopHeartbeats()
2771
2777
  Task { await reconnectionManager.stop() }
@@ -3140,11 +3146,7 @@ class G2: NSObject, SGCManager {
3140
3146
 
3141
3147
  // MARK: - SGCManager: Camera & Media (not supported on G2)
3142
3148
 
3143
- func requestPhoto(
3144
- _: String, appId _: String, size _: String?, webhookUrl _: String?, authToken _: String?,
3145
- compress _: String?, flash _: Bool, save _: Bool, sound _: Bool, exposureTimeNs _: Double?,
3146
- iso _: Int?
3147
- ) {}
3149
+ func requestPhoto(_: PhotoRequest) {}
3148
3150
  func startVideoRecording(requestId _: String, save _: Bool, flash _: Bool, sound _: Bool) {}
3149
3151
  func startStream(_: [String: Any]) {}
3150
3152
  func stopStream() {}
@@ -3163,7 +3165,7 @@ class G2: NSObject, SGCManager {
3163
3165
  func sendWifiCredentials(_: String, _: String) {}
3164
3166
  func forgetWifiNetwork(_: String) {}
3165
3167
  func sendHotspotState(_: Bool) {}
3166
- func sendOtaStart() {}
3168
+ func sendOtaStart(otaVersionUrl: String?) {}
3167
3169
  func sendOtaQueryStatus() {}
3168
3170
 
3169
3171
  // MARK: - SGCManager: User Context
@@ -15,10 +15,7 @@ import UltraliteSDK
15
15
  class Mach1: UltraliteBaseViewController, SGCManager {
16
16
  func sendIncidentId(_: String, apiBaseUrl _: String?) {}
17
17
 
18
- func requestPhoto(
19
- _: String, appId _: String, size _: String?, webhookUrl _: String?, authToken _: String?,
20
- compress _: String?, flash _: Bool, save _: Bool, sound _: Bool, exposureTimeNs _: Double?, iso _: Int?
21
- ) {}
18
+ func requestPhoto(_: PhotoRequest) {}
22
19
 
23
20
  func sendGalleryMode() {}
24
21
 
@@ -26,7 +23,7 @@ class Mach1: UltraliteBaseViewController, SGCManager {
26
23
 
27
24
  var connectionState: String = ConnTypes.DISCONNECTED
28
25
 
29
- func sendOtaStart() {}
26
+ func sendOtaStart(otaVersionUrl: String?) {}
30
27
  func sendOtaQueryStatus() {}
31
28
 
32
29
  func sendJson(_: [String: Any], wakeUp _: Bool, requireAck _: Bool) {}
@@ -325,6 +322,10 @@ class Mach1: UltraliteBaseViewController, SGCManager {
325
322
  UltraliteManager.shared.stopScan()
326
323
  }
327
324
 
325
+ func sendText(_ text: String) async {
326
+ await sendTextWall(text)
327
+ }
328
+
328
329
  func sendTextWall(_ text: String) async {
329
330
  // displayTextWall(text)
330
331
  guard let device = UltraliteManager.shared.currentDevice else {