@mentra/bluetooth-sdk 0.1.21-beta.3 → 0.1.21-beta.5

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.
@@ -948,15 +948,20 @@ class DeviceManager {
948
948
 
949
949
  when (currentViewState.layoutType) {
950
950
  "text_wall" -> {
951
- sgc?.sendTextWall(currentViewState.text)
951
+ sgc?.sendTextWall(parsePlaceholders(currentViewState.text))
952
952
  }
953
953
 
954
954
  "double_text_wall" -> {
955
- sgc?.sendDoubleTextWall(currentViewState.topText, currentViewState.bottomText)
955
+ sgc?.sendDoubleTextWall(
956
+ parsePlaceholders(currentViewState.topText),
957
+ parsePlaceholders(currentViewState.bottomText)
958
+ )
956
959
  }
957
960
 
958
961
  "reference_card" -> {
959
- sgc?.sendTextWall("${currentViewState.title}\n\n${currentViewState.text}")
962
+ val title = parsePlaceholders(currentViewState.title)
963
+ val text = parsePlaceholders(currentViewState.text)
964
+ sgc?.sendTextWall("$title\n\n$text")
960
965
  }
961
966
 
962
967
  "bitmap_view" -> {
@@ -973,7 +978,7 @@ class DeviceManager {
973
978
 
974
979
  "positioned_text" -> {
975
980
  sgc?.sendPositionedText(
976
- currentViewState.text,
981
+ parsePlaceholders(currentViewState.text),
977
982
  currentViewState.bmpX ?: 0,
978
983
  currentViewState.bmpY ?: 0,
979
984
  currentViewState.bmpWidth ?: 576,
@@ -994,6 +999,8 @@ class DeviceManager {
994
999
  }
995
1000
 
996
1001
  private fun parsePlaceholders(text: String): String {
1002
+ if (!text.contains('$')) return text
1003
+
997
1004
  val dateFormatter = SimpleDateFormat("M/dd, h:mm", Locale.getDefault())
998
1005
  val formattedDate = dateFormatter.format(Date())
999
1006
 
@@ -0,0 +1,49 @@
1
+ package com.mentra.bluetoothsdk.sgcs
2
+
3
+ import java.util.Locale
4
+
5
+ /**
6
+ * Temporarily suppresses phone heartbeats while BES OTA owns the ASG-to-BES UART.
7
+ *
8
+ * The lease is renewable so a lost terminal status cannot disable heartbeats permanently. It is
9
+ * deliberately longer than ASG's 30-second BES response watchdog: after the lease expires, the
10
+ * raw transfer has already completed or failed and ordinary UART liveness traffic is safe again.
11
+ */
12
+ internal class BesOtaHeartbeatGuard(
13
+ private val leaseDurationMs: Long = DEFAULT_LEASE_DURATION_MS,
14
+ ) {
15
+ @Volatile private var suppressionDeadlineMs = 0L
16
+
17
+ init {
18
+ require(leaseDurationMs > 0) { "leaseDurationMs must be positive" }
19
+ }
20
+
21
+ fun refresh(nowMs: Long) {
22
+ suppressionDeadlineMs =
23
+ if (nowMs > Long.MAX_VALUE - leaseDurationMs) Long.MAX_VALUE
24
+ else nowMs + leaseDurationMs
25
+ }
26
+
27
+ fun clear() {
28
+ suppressionDeadlineMs = 0L
29
+ }
30
+
31
+ fun observeOtaStatus(stepType: String, phase: String, status: String, nowMs: Long) {
32
+ if (!stepType.equals("bes", ignoreCase = true) ||
33
+ !phase.equals("install", ignoreCase = true)
34
+ ) {
35
+ return
36
+ }
37
+
38
+ when (status.lowercase(Locale.US)) {
39
+ "failed", "complete", "step_complete", "finished", "success" -> clear()
40
+ else -> refresh(nowMs)
41
+ }
42
+ }
43
+
44
+ fun shouldSuppress(nowMs: Long): Boolean = nowMs < suppressionDeadlineMs
45
+
46
+ companion object {
47
+ internal const val DEFAULT_LEASE_DURATION_MS = 120_000L
48
+ }
49
+ }
@@ -0,0 +1,27 @@
1
+ package com.mentra.bluetoothsdk.sgcs
2
+
3
+ internal data class BesOtaProgressMapping(
4
+ val status: String,
5
+ val progress: Int,
6
+ val errorMessage: String? = null,
7
+ )
8
+
9
+ /** Map the BES sr_adota protocol without inferring terminal state from transfer progress. */
10
+ internal fun mapBesOtaProgress(
11
+ type: String,
12
+ rawProgress: Int,
13
+ message: String?,
14
+ ): BesOtaProgressMapping {
15
+ val roundedProgress = (((rawProgress.coerceIn(0, 100) + 2) / 5) * 5).coerceAtMost(100)
16
+ return when {
17
+ type == "success" -> BesOtaProgressMapping("FINISHED", 100)
18
+ type == "error" || type == "fail" ->
19
+ BesOtaProgressMapping(
20
+ "FAILED",
21
+ roundedProgress,
22
+ message?.takeIf { it.isNotBlank() } ?: "BES update failed",
23
+ )
24
+ // A raw update:100 is emitted before whole-image CRC/apply and is not terminal.
25
+ else -> BesOtaProgressMapping("PROGRESS", minOf(roundedProgress, 95))
26
+ }
27
+ }