@glassly/bluetooth-sdk 0.3.1-dev.540 → 0.3.1-dev.548

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.
@@ -364,8 +364,8 @@ afterEvaluate {
364
364
  url = 'https://github.com/tetramo-labs/glassly'
365
365
  licenses {
366
366
  license {
367
- name = 'GNU Affero General Public License v3.0'
368
- url = 'https://www.gnu.org/licenses/agpl-3.0.txt'
367
+ name = 'MIT License'
368
+ url = 'https://opensource.org/licenses/MIT'
369
369
  }
370
370
  }
371
371
  developers {
@@ -159,8 +159,8 @@ afterEvaluate {
159
159
  url = 'https://github.com/tetramo-labs/glassly'
160
160
  licenses {
161
161
  license {
162
- name = 'GNU Affero General Public License v3.0'
163
- url = 'https://www.gnu.org/licenses/agpl-3.0.txt'
162
+ name = 'MIT License'
163
+ url = 'https://opensource.org/licenses/MIT'
164
164
  }
165
165
  }
166
166
  developers {
@@ -3,9 +3,9 @@ package com.glassly.bluetoothsdk
3
3
  /** Generated by release CI. Do not edit in a release checkout. */
4
4
  internal object GeneratedReleaseMetadata {
5
5
  const val FAMILY_BASE_VERSION: String = "0.3.1"
6
- const val RELEASE_IDENTITY: String = "0.3.1-dev.540"
7
- const val RELEASE_SET_ID: String = "glassly-0.3.1-dev.540"
8
- const val SOURCE_COMMIT: String = "b019d32a3c71f3a39cb27c93265e667b4469cdc0"
6
+ const val RELEASE_IDENTITY: String = "0.3.1-dev.548"
7
+ const val RELEASE_SET_ID: String = "glassly-0.3.1-dev.548"
8
+ const val SOURCE_COMMIT: String = "8de673988aed75061b39b243d324fcf0b5050224"
9
9
  const val OTA_MANIFEST_URL: String = ""
10
10
  const val OTA_MANIFEST_SHA256: String = ""
11
11
  }
@@ -54,10 +54,11 @@ private object R1BLE {
54
54
  * Scan-response manufacturer data (openCFW: `0x5245` company id, the six
55
55
  * address bytes in SoftDevice order, then an optional 15-byte serial).
56
56
  * Android hands us the payload with the company id already stripped. The
57
- * GAP name is `EVEN R1_` + address bytes 3,2,1, which pins the byte order;
58
- * the returned string keeps SoftDevice order, the form the glasses have
59
- * accepted in RING_CONNECT_INFO. Taking the LAST six bytes was wrong for
60
- * rings with a serial (it returned ASCII digits).
57
+ * GAP name is `EVEN R1_` + the first three address bytes reversed
58
+ * (`R1_26081B` ↔ `1B 08 26 …`), which pins the byte order; the returned
59
+ * string keeps SoftDevice order, the form the glasses have accepted in
60
+ * RING_CONNECT_INFO. Taking the LAST six bytes was wrong for rings with a
61
+ * serial (it returned ASCII digits).
61
62
  */
62
63
  fun macAddress(mfgBytes: ByteArray, ringId: String?): String? {
63
64
  if (mfgBytes.size < 6) return null
@@ -66,14 +67,22 @@ private object R1BLE {
66
67
  val id = ringId?.uppercase()
67
68
  val chosen = when {
68
69
  id.isNullOrEmpty() -> addr
69
- hex(byteArrayOf(addr[3], addr[2], addr[1])) == id -> addr
70
+ hex(byteArrayOf(addr[2], addr[1], addr[0])) == id -> addr
70
71
  else -> {
71
72
  val flipped = addr.reversedArray()
72
- if (hex(byteArrayOf(flipped[3], flipped[2], flipped[1])) == id) flipped else return null
73
+ if (hex(byteArrayOf(flipped[2], flipped[1], flipped[0])) == id) flipped else return null
73
74
  }
74
75
  }
75
76
  return chosen.joinToString(":") { String.format("%02X", it) }
76
77
  }
78
+
79
+ /** A stored "AA:BB:…" address is only trusted when it still agrees with the
80
+ * ring's name; older builds persisted serial digits as the address. */
81
+ fun macMatches(mac: String, ringId: String): Boolean {
82
+ val parts = mac.split(":")
83
+ if (parts.size != 6) return false
84
+ return (parts[2] + parts[1] + parts[0]).uppercase() == ringId.uppercase()
85
+ }
77
86
  }
78
87
 
79
88
  // MARK: - Ring → phone touch report (channel 1)
@@ -140,12 +149,20 @@ private object R1Eus {
140
149
  * the ring stores both targets and fast-advertises for them */
141
150
  const val SUBCMD_ADV_START = 0x0A
142
151
  /** system subcommand 0x82 (removeRingNotify): one-byte SET erases both
143
- * stored glasses targets and the "glasses paired" flag. While the ring
144
- * holds glasses targets its touch reports go to the glasses and the
145
- * phone link carries telemetry only, so this is what puts input on the
146
- * phone link. */
152
+ * stored glasses targets and the "glasses paired" flag — the stock
153
+ * "unpair" state, in which the ring accepts ANY glasses that connect. */
147
154
  const val SUBCMD_REMOVE_RING = 0x82
148
155
 
156
+ /** Two targets no glasses will ever present. The ring's advStart consumer
157
+ * compares the connected glasses peer with the supplied targets, drops a
158
+ * mismatch (after a ~20 s firmware delay), stores both targets, and from
159
+ * then on admits a glasses peer only when it equals one of them. That is
160
+ * the only ring-side lever that makes it refuse the glasses: with the
161
+ * targets erased (removeRingNotify) it accepts every glasses peer, and
162
+ * the glasses reconnect on their own. Non-zero and non-FF, which the
163
+ * firmware treats as "configured". */
164
+ val DECOY_TARGETS = byteArrayOf(0x02, 0, 0, 0, 0, 0x01, 0x02, 0, 0, 0, 0, 0x02)
165
+
149
166
  private fun crc16Step(crc: Int, byte: Int): Int {
150
167
  var c = ((crc shr 8) or (crc shl 8)) and 0xFFFF
151
168
  c = c xor (byte and 0xFF)
@@ -321,6 +338,11 @@ class R1 : ControllerManager() {
321
338
 
322
339
  private fun getRingMacFromMap(name: String): String? = loadRingMacAddressMap()[name]
323
340
 
341
+ private fun removeRingMacFromMap(name: String) {
342
+ val map = loadRingMacAddressMap()
343
+ if (map.remove(name) != null) saveRingMacAddressMap(map)
344
+ }
345
+
324
346
  // Reconnection
325
347
  private val reconnectionManager = R1ReconnectionManager()
326
348
 
@@ -639,10 +661,10 @@ class R1 : ControllerManager() {
639
661
  get() = DeviceStore.get("bluetooth", "ring_via_glasses") as? Boolean ?: false
640
662
 
641
663
  /**
642
- * Phone route (default): erase the ring's stored glasses targets so its
643
- * touch reports come to this link, and have the glasses drop any ring
644
- * link they still hold. Glasses route (debug): hand the ring the glasses
645
- * MACs, then ask the glasses to connect.
664
+ * Phone route (default): point the ring at decoy glasses targets so it
665
+ * drops and then refuses the real glasses, which puts its touch reports
666
+ * on this link; also ask the glasses to let go. Glasses route (debug):
667
+ * hand the ring the glasses MACs, then ask the glasses to connect.
646
668
  */
647
669
  private fun applyRoute(viaGlasses: Boolean) {
648
670
  if (viaGlasses) {
@@ -653,7 +675,7 @@ class R1 : ControllerManager() {
653
675
  DeviceManager.getInstance().sgc?.connectController()
654
676
  }
655
677
  } else {
656
- sendEusCommand(R1Eus.SUBCMD_REMOVE_RING, byteArrayOf(0x01), "removeRingNotify")
678
+ sendEusCommand(R1Eus.SUBCMD_ADV_START, R1Eus.DECOY_TARGETS, "advStart(decoy targets)")
657
679
  DeviceManager.getInstance().sgc?.releaseController()
658
680
  }
659
681
  }
@@ -761,6 +783,17 @@ class R1 : ControllerManager() {
761
783
 
762
784
  val timestamp = System.currentTimeMillis()
763
785
 
786
+ // EUS reply on channel 2: [seq][crc32][12-byte model header][payload].
787
+ // The model status byte is 0x03 | (result << 2); result 0 = success,
788
+ // 1 = error, 2 = refused (needs the bonded phone role), 3 = unsupported.
789
+ if (characteristic.uuid == R1BLE.NOTIFY_CHAR_2 && data.size >= 17 && data[0] == 0.toByte()) {
790
+ val subcmd = data[12].toInt() and 0xFF
791
+ val result = (data[10].toInt() and 0xFF) shr 2
792
+ val len = (data[13].toInt() and 0xFF) or ((data[14].toInt() and 0xFF) shl 8)
793
+ Bridge.log("R1: EUS reply subcmd=0x%02X result=%d len=%d".format(subcmd, result, len))
794
+ return
795
+ }
796
+
764
797
  // Touch report: [00 09 61 00 wireType aux speed 00 tick4]
765
798
  R1TouchReport.parse(data)?.let { (gesture, wireType) ->
766
799
  if (gesture != null) {
@@ -850,7 +883,13 @@ class R1 : ControllerManager() {
850
883
  // peripheral isn't in the map we don't have its true public MAC — drop the
851
884
  // connection and rescan rather than publishing a stale/wrong MAC. Mirrors
852
885
  // iOS R1.swift didConnect.
853
- val mappedMac = name?.let { getRingMacFromMap(it) }
886
+ var mappedMac = name?.let { getRingMacFromMap(it) }
887
+ val ringId = name?.let { extractRingId(it) }
888
+ if (mappedMac != null && ringId != null && !R1BLE.macMatches(mappedMac, ringId)) {
889
+ Bridge.log("R1: Stored MAC for $name does not match its name; rescanning for the advertisement")
890
+ removeRingMacFromMap(name)
891
+ mappedMac = null
892
+ }
854
893
  if (mappedMac == null) {
855
894
  Bridge.log("R1: No MAC stored in map found for ${name ?: "ring"}")
856
895
  mainHandler.post {
@@ -1056,6 +1095,12 @@ class R1 : ControllerManager() {
1056
1095
  }
1057
1096
 
1058
1097
  override fun forget() {
1098
+ // Hand the ring back in its stock unpaired state: erase the glasses
1099
+ // targets (the phone route left decoys behind) so the Even app, or a
1100
+ // later pairing here, starts clean.
1101
+ if (DeviceStore.get("glasses", "controllerConnected") as? Boolean == true) {
1102
+ sendEusCommand(R1Eus.SUBCMD_REMOVE_RING, byteArrayOf(0x01), "removeRingNotify")
1103
+ }
1059
1104
  disconnect()
1060
1105
  ringMacAddress = null
1061
1106
  ringBleAddress = null
@@ -1,9 +1,9 @@
1
1
  export const BLUETOOTH_SDK_RELEASE_METADATA = Object.freeze({
2
2
  "schemaVersion": 1,
3
3
  "familyBaseVersion": "0.3.1",
4
- "releaseIdentity": "0.3.1-dev.540",
5
- "releaseSetId": "glassly-0.3.1-dev.540",
6
- "sourceCommit": "b019d32a3c71f3a39cb27c93265e667b4469cdc0",
4
+ "releaseIdentity": "0.3.1-dev.548",
5
+ "releaseSetId": "glassly-0.3.1-dev.548",
6
+ "sourceCommit": "8de673988aed75061b39b243d324fcf0b5050224",
7
7
  "otaManifestUrl": null,
8
8
  "otaManifestSha256": null
9
9
  });
@@ -1 +1 @@
1
- {"version":3,"file":"releaseMetadata.js","sourceRoot":"","sources":["../../src/generated/releaseMetadata.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,8BAA8B,GAA0C,MAAM,CAAC,MAAM,CAAC;IACjG,eAAe,EAAE,CAAC;IAClB,mBAAmB,EAAE,OAAO;IAC5B,iBAAiB,EAAE,eAAe;IAClC,cAAc,EAAE,uBAAuB;IACvC,cAAc,EAAE,0CAA0C;IAC1D,gBAAgB,EAAE,IAAI;IACtB,mBAAmB,EAAE,IAAI;CAC1B,CAAC,CAAA","sourcesContent":["/** Generated by release CI. Do not edit in a release checkout. */\nexport interface BluetoothSdkReleaseMetadata {\n schemaVersion: 1\n familyBaseVersion: string | null\n releaseIdentity: string | null\n releaseSetId: string | null\n sourceCommit: string | null\n otaManifestUrl: string | null\n otaManifestSha256: string | null\n}\n\nexport const BLUETOOTH_SDK_RELEASE_METADATA: Readonly<BluetoothSdkReleaseMetadata> = Object.freeze({\n \"schemaVersion\": 1,\n \"familyBaseVersion\": \"0.3.1\",\n \"releaseIdentity\": \"0.3.1-dev.540\",\n \"releaseSetId\": \"glassly-0.3.1-dev.540\",\n \"sourceCommit\": \"b019d32a3c71f3a39cb27c93265e667b4469cdc0\",\n \"otaManifestUrl\": null,\n \"otaManifestSha256\": null\n})\n"]}
1
+ {"version":3,"file":"releaseMetadata.js","sourceRoot":"","sources":["../../src/generated/releaseMetadata.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,8BAA8B,GAA0C,MAAM,CAAC,MAAM,CAAC;IACjG,eAAe,EAAE,CAAC;IAClB,mBAAmB,EAAE,OAAO;IAC5B,iBAAiB,EAAE,eAAe;IAClC,cAAc,EAAE,uBAAuB;IACvC,cAAc,EAAE,0CAA0C;IAC1D,gBAAgB,EAAE,IAAI;IACtB,mBAAmB,EAAE,IAAI;CAC1B,CAAC,CAAA","sourcesContent":["/** Generated by release CI. Do not edit in a release checkout. */\nexport interface BluetoothSdkReleaseMetadata {\n schemaVersion: 1\n familyBaseVersion: string | null\n releaseIdentity: string | null\n releaseSetId: string | null\n sourceCommit: string | null\n otaManifestUrl: string | null\n otaManifestSha256: string | null\n}\n\nexport const BLUETOOTH_SDK_RELEASE_METADATA: Readonly<BluetoothSdkReleaseMetadata> = Object.freeze({\n \"schemaVersion\": 1,\n \"familyBaseVersion\": \"0.3.1\",\n \"releaseIdentity\": \"0.3.1-dev.548\",\n \"releaseSetId\": \"glassly-0.3.1-dev.548\",\n \"sourceCommit\": \"8de673988aed75061b39b243d324fcf0b5050224\",\n \"otaManifestUrl\": null,\n \"otaManifestSha256\": null\n})\n"]}
@@ -11,7 +11,7 @@ enum BluetoothSdkDefaults {
11
11
  static let voiceActivityDetectionEnabled = false
12
12
  static let loudnessGateEnabled = true
13
13
  private static let infoSdkVersionKey = "BluetoothSdkVersion"
14
- private static let swiftPackageSdkVersion = "0.3.1-dev.540"
14
+ private static let swiftPackageSdkVersion = "0.3.1-dev.548"
15
15
  private static let swiftPackageSdkVersionPlaceholder = "__GLASSLY" + "_BLUETOOTH_SDK_VERSION__"
16
16
 
17
17
  private static func normalizedSdkVersion(_ value: String?) -> String? {
@@ -3,9 +3,9 @@ import Foundation
3
3
  /// Generated by release CI. Do not edit in a release checkout.
4
4
  enum GeneratedReleaseMetadata {
5
5
  static let familyBaseVersion = "0.3.1"
6
- static let releaseIdentity = "0.3.1-dev.540"
7
- static let releaseSetId = "glassly-0.3.1-dev.540"
8
- static let sourceCommit = "b019d32a3c71f3a39cb27c93265e667b4469cdc0"
6
+ static let releaseIdentity = "0.3.1-dev.548"
7
+ static let releaseSetId = "glassly-0.3.1-dev.548"
8
+ static let sourceCommit = "8de673988aed75061b39b243d324fcf0b5050224"
9
9
  static let otaManifestUrl = ""
10
10
  static let otaManifestSha256 = ""
11
11
  }
@@ -14,22 +14,31 @@ import Foundation
14
14
  private enum R1BLE {
15
15
  /// Scan-response manufacturer data (openCFW: `0x5245` company id, the six
16
16
  /// address bytes in SoftDevice order, then an optional 15-byte serial).
17
- /// The GAP name is `EVEN R1_` + address bytes 3,2,1, which pins the byte
18
- /// order; the stored string keeps SoftDevice order, the form the glasses
19
- /// have accepted in RING_CONNECT_INFO. Taking the LAST six bytes was wrong
20
- /// for rings with a serial (it returned ASCII digits).
17
+ /// The GAP name is `EVEN R1_` + the first three address bytes reversed
18
+ /// (`R1_26081B` ↔ `1B 08 26 …`), which pins the byte order; the stored
19
+ /// string keeps SoftDevice order, the form the glasses have accepted in
20
+ /// RING_CONNECT_INFO. Taking the LAST six bytes was wrong for rings with
21
+ /// a serial (it returned ASCII digits).
21
22
  static func macAddress(mfgData: Data, ringId: String?) -> Data? {
22
23
  let bytes = [UInt8](mfgData)
23
24
  guard bytes.count >= 8, bytes[0] == 0x45, bytes[1] == 0x52 else { return nil }
24
25
  let addr = Array(bytes[2 ..< 8])
25
26
  guard let ringId, !ringId.isEmpty else { return Data(addr) }
26
27
  let hex = { (b: [UInt8]) in b.map { String(format: "%02X", $0) }.joined() }
27
- if hex([addr[3], addr[2], addr[1]]) == ringId.uppercased() { return Data(addr) }
28
+ if hex([addr[2], addr[1], addr[0]]) == ringId.uppercased() { return Data(addr) }
28
29
  let flipped = Array(addr.reversed())
29
- if hex([flipped[3], flipped[2], flipped[1]]) == ringId.uppercased() { return Data(flipped) }
30
+ if hex([flipped[2], flipped[1], flipped[0]]) == ringId.uppercased() { return Data(flipped) }
30
31
  return nil
31
32
  }
32
33
 
34
+ /// A stored address is only trusted when it still agrees with the ring's
35
+ /// name; older builds persisted serial digits as the address.
36
+ static func macMatches(_ mac: Data, ringId: String) -> Bool {
37
+ let b = [UInt8](mac)
38
+ guard b.count == 6 else { return false }
39
+ return [b[2], b[1], b[0]].map { String(format: "%02X", $0) }.joined() == ringId.uppercased()
40
+ }
41
+
33
42
  /// Ring custom service
34
43
  static let SERVICE_UUID = CBUUID(string: "BAE80001-4F05-4503-8E65-3AF1F7329D1F")
35
44
 
@@ -117,12 +126,20 @@ private enum R1Eus {
117
126
  /// the ring stores both targets and fast-advertises for them
118
127
  static let SUBCMD_ADV_START: UInt8 = 0x0A
119
128
  /// system subcommand 0x82 (removeRingNotify): one-byte SET erases both
120
- /// stored glasses targets and the "glasses paired" flag. While the ring
121
- /// holds glasses targets its touch reports go to the glasses and the
122
- /// phone link carries telemetry only, so this is what puts input on the
123
- /// phone link.
129
+ /// stored glasses targets and the "glasses paired" flag — the stock
130
+ /// "unpair" state, in which the ring accepts ANY glasses that connect.
124
131
  static let SUBCMD_REMOVE_RING: UInt8 = 0x82
125
132
 
133
+ /// Two targets no glasses will ever present. The ring's advStart consumer
134
+ /// compares the connected glasses peer with the supplied targets, drops a
135
+ /// mismatch (after a ~20 s firmware delay), stores both targets, and from
136
+ /// then on admits a glasses peer only when it equals one of them. That is
137
+ /// the only ring-side lever that makes it refuse the glasses: with the
138
+ /// targets erased (removeRingNotify) it accepts every glasses peer, and
139
+ /// the glasses reconnect on their own. Non-zero and non-FF, which the
140
+ /// firmware treats as "configured".
141
+ static let DECOY_TARGETS = Data([0x02, 0, 0, 0, 0, 0x01, 0x02, 0, 0, 0, 0, 0x02])
142
+
126
143
  private static func crc16Step(_ crc: UInt16, _ byte: UInt8) -> UInt16 {
127
144
  var c = (crc >> 8) | (crc << 8)
128
145
  c ^= UInt16(byte)
@@ -485,10 +502,10 @@ class R1: NSObject, ControllerManager {
485
502
  startHeartbeat()
486
503
  }
487
504
 
488
- /// Phone route (default): erase the ring's stored glasses targets so its
489
- /// touch reports come to this link, and have the glasses drop any ring
490
- /// link they still hold. Glasses route (debug): hand the ring the glasses
491
- /// MACs, then ask the glasses to connect.
505
+ /// Phone route (default): point the ring at decoy glasses targets so it
506
+ /// drops and then refuses the real glasses, which puts its touch reports
507
+ /// on this link; also ask the glasses to let go. Glasses route (debug):
508
+ /// hand the ring the glasses MACs, then ask the glasses to connect.
492
509
  private func applyRoute(viaGlasses: Bool) {
493
510
  if viaGlasses {
494
511
  connectToGlasses()
@@ -498,7 +515,7 @@ class R1: NSObject, ControllerManager {
498
515
  await DeviceManager.shared.sgc?.connectController()
499
516
  }
500
517
  } else {
501
- sendEusCommand(R1Eus.SUBCMD_REMOVE_RING, payload: Data([0x01]), log: "removeRingNotify")
518
+ sendEusCommand(R1Eus.SUBCMD_ADV_START, payload: R1Eus.DECOY_TARGETS, log: "advStart(decoy targets)")
502
519
  Task { await DeviceManager.shared.sgc?.releaseController() }
503
520
  }
504
521
  }
@@ -552,6 +569,15 @@ class R1: NSObject, ControllerManager {
552
569
 
553
570
  let timestamp = Int64(Date().timeIntervalSince1970 * 1000)
554
571
 
572
+ // EUS reply on channel 2: [seq][crc32][12-byte model header][payload].
573
+ // The model status byte is 0x03 | (result << 2); result 0 = success,
574
+ // 1 = error, 2 = refused (needs the bonded phone role), 3 = unsupported.
575
+ if characteristic.uuid == R1BLE.NOTIFY_CHAR_2, data.count >= 17, data[0] == 0 {
576
+ let b = [UInt8](data)
577
+ Bridge.log("R1: EUS reply subcmd=0x\(String(format: "%02X", b[12])) result=\(b[10] >> 2) len=\(Int(b[13]) | Int(b[14]) << 8)")
578
+ return
579
+ }
580
+
555
581
  // Touch report: [00 09 61 00 wireType aux speed 00 tick4]
556
582
  if let report = R1TouchReport.parse(data) {
557
583
  if let gesture = report.gesture {
@@ -660,6 +686,12 @@ class R1: NSObject, ControllerManager {
660
686
  }
661
687
 
662
688
  func forget() {
689
+ // Hand the ring back in its stock unpaired state: erase the glasses
690
+ // targets (the phone route left decoys behind) so the Even app, or a
691
+ // later pairing here, starts clean.
692
+ if DeviceStore.shared.get("glasses", "controllerConnected") as? Bool ?? false {
693
+ sendEusCommand(R1Eus.SUBCMD_REMOVE_RING, payload: Data([0x01]), log: "removeRingNotify")
694
+ }
663
695
  disconnect()
664
696
  ringUUID = nil
665
697
  ringMacAddress = nil
@@ -816,7 +848,14 @@ extension R1: CBCentralManagerDelegate {
816
848
 
817
849
  self.ringUUID = peripheral.identifier
818
850
 
819
- guard let name = peripheral.name, let mac = self.ringMacAddressMap[name] else {
851
+ let storedMac = peripheral.name.flatMap { name -> Data? in
852
+ guard let mac = self.ringMacAddressMap[name] else { return nil }
853
+ guard let id = self.extractRingId(name), !R1BLE.macMatches(mac, ringId: id) else { return mac }
854
+ Bridge.log("R1: Stored MAC for \(name) does not match its name; rescanning for the advertisement")
855
+ self.ringMacAddressMap[name] = nil
856
+ return nil
857
+ }
858
+ guard let name = peripheral.name, let mac = storedMac else {
820
859
  Bridge.log("R1: No MAC stored in map found for \(peripheral.name ?? "ring")")
821
860
  // stop the scan, disconnect, remove the uuid, and try again as we need the mac address to connect:
822
861
  self.disconnect()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glassly/bluetooth-sdk",
3
- "version": "0.3.1-dev.540",
3
+ "version": "0.3.1-dev.548",
4
4
  "description": "SDK for communicating with smart glasses",
5
5
  "main": "build/index.js",
6
6
  "react-native": "src/index.ts",
@@ -107,7 +107,7 @@
107
107
  "url": "https://github.com/tetramo-labs/glassly/issues"
108
108
  },
109
109
  "author": "Glassly",
110
- "license": "AGPL-3.0-only",
110
+ "license": "MIT",
111
111
  "homepage": "https://github.com/tetramo-labs/glassly/tree/main/mobile/modules/bluetooth-sdk#readme",
112
112
  "publishConfig": {
113
113
  "access": "public",
@@ -12,9 +12,9 @@ export interface BluetoothSdkReleaseMetadata {
12
12
  export const BLUETOOTH_SDK_RELEASE_METADATA: Readonly<BluetoothSdkReleaseMetadata> = Object.freeze({
13
13
  "schemaVersion": 1,
14
14
  "familyBaseVersion": "0.3.1",
15
- "releaseIdentity": "0.3.1-dev.540",
16
- "releaseSetId": "glassly-0.3.1-dev.540",
17
- "sourceCommit": "b019d32a3c71f3a39cb27c93265e667b4469cdc0",
15
+ "releaseIdentity": "0.3.1-dev.548",
16
+ "releaseSetId": "glassly-0.3.1-dev.548",
17
+ "sourceCommit": "8de673988aed75061b39b243d324fcf0b5050224",
18
18
  "otaManifestUrl": null,
19
19
  "otaManifestSha256": null
20
20
  })