@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.
- package/README.md +16 -9
- package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +51 -3
- package/android/src/main/java/com/mentra/bluetoothsdk/DeviceManager.kt +73 -21
- package/android/src/main/java/com/mentra/bluetoothsdk/DeviceStore.kt +1 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +190 -26
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdkDebug.kt +14 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/ObservableStore.kt +20 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/OtaManifest.kt +153 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/camera/CameraModels.kt +78 -10
- package/android/src/main/java/com/mentra/bluetoothsdk/controllers/ControllerManager.kt +3 -14
- package/android/src/main/java/com/mentra/bluetoothsdk/controllers/R1.kt +3 -6
- package/android/src/main/java/com/mentra/bluetoothsdk/services/PhoneMic.kt +90 -4
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G1.kt +3835 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G2.kt +20 -23
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/{Mach1.java → Mach1.kt} +517 -560
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.kt +8712 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraNex.kt +11 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/SGCManager.kt +3 -13
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Simulated.kt +7 -14
- package/build/BluetoothSdk.types.d.ts +39 -9
- package/build/BluetoothSdk.types.d.ts.map +1 -1
- package/build/BluetoothSdk.types.js.map +1 -1
- package/build/_private/BluetoothSdkModule.d.ts +8 -6
- package/build/_private/BluetoothSdkModule.d.ts.map +1 -1
- package/build/_private/BluetoothSdkModule.js +0 -2
- package/build/_private/BluetoothSdkModule.js.map +1 -1
- package/build/_private/photoRequestPayload.d.ts +3 -1
- package/build/_private/photoRequestPayload.d.ts.map +1 -1
- package/build/_private/photoRequestPayload.js +43 -1
- package/build/_private/photoRequestPayload.js.map +1 -1
- package/build/debug.d.ts +3 -0
- package/build/debug.d.ts.map +1 -0
- package/build/debug.js +8 -0
- package/build/debug.js.map +1 -0
- package/build/index.d.ts +1 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +14 -5
- package/build/index.js.map +1 -1
- package/ios/BluetoothSdkModule.swift +38 -57
- package/ios/Source/BluetoothSdkDefaults.swift +23 -3
- package/ios/Source/DeviceManager.swift +37 -26
- package/ios/Source/DeviceStore.swift +5 -1
- package/ios/Source/MentraBluetoothSDK.swift +197 -26
- package/ios/Source/MentraBluetoothSDKDebug.swift +12 -0
- package/ios/Source/ObservableStore.swift +11 -0
- package/ios/Source/OtaManifest.swift +170 -0
- package/ios/Source/camera/CameraModels.swift +218 -8
- package/ios/Source/controllers/ControllerManager.swift +2 -5
- package/ios/Source/controllers/R1.swift +2 -5
- package/ios/Source/sgcs/G1.swift +6 -5
- package/ios/Source/sgcs/G2.swift +20 -18
- package/ios/Source/sgcs/Mach1.swift +6 -5
- package/ios/Source/sgcs/MentraLive.swift +129 -33
- package/ios/Source/sgcs/MentraNex.swift +6 -5
- package/ios/Source/sgcs/SGCManager.swift +3 -5
- package/ios/Source/sgcs/Simulated.swift +7 -3
- package/ios/Source/status/DeviceStatus.swift +1 -1
- package/package.json +6 -1
- package/src/BluetoothSdk.types.ts +40 -9
- package/src/_private/BluetoothSdkModule.ts +8 -9
- package/src/_private/photoRequestPayload.ts +45 -2
- package/src/debug.ts +9 -0
- package/src/index.ts +23 -6
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G1.java +0 -3974
- 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
|
|
4
|
+
case low
|
|
5
5
|
case medium
|
|
6
|
-
case
|
|
7
|
-
case
|
|
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
|
|
29
|
+
case low
|
|
12
30
|
case medium
|
|
13
|
-
case
|
|
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(
|
|
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() {}
|
package/ios/Source/sgcs/G1.swift
CHANGED
|
@@ -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)
|
package/ios/Source/sgcs/G2.swift
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
2016
|
-
|
|
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
|
-
|
|
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 {
|