com.xrlab.labframe_brainbit 1.0.1 → 1.0.2

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 CHANGED
@@ -70,19 +70,68 @@ BrainBitManager.Instance.SetImpedanceTag("Another_Phase_Impedance");
70
70
  BrainBitManager.Instance.StopImpedanceStream();
71
71
  ```
72
72
 
73
- #### 👉 判斷各通道阻抗是否過高
74
- 在檢測狀態下,呼叫以下的 API 一次取得四個通道的數值與警示結果:
73
+ #### 👉 判斷各通道阻抗是否過高與取得數值
74
+ 可以在 `Update()` 或檢查迴圈中呼叫此段程式碼,一次取得四個通道的數值與警示結果:
75
75
  ```csharp
76
- var data = BrainBitManager.Instance.GetLatestImpedanceData();
77
- if (data != null)
76
+ void CheckImpedanceStatus()
78
77
  {
79
- // 直接一次性取得所有數值與 Boolean (檢查是否大於 200,000)
78
+ // 確保有資料進來
79
+ var data = BrainBitManager.Instance.GetLatestImpedanceData();
80
+ if (data == null) return;
81
+
82
+ // 直接一次性取得所有數值與 Boolean (各通道大於 200,000 即為 true)
80
83
  var (t3_val, t3_high, t4_val, t4_high, o1_val, o1_high, o2_val, o2_high) = data.GetImpedanceValues();
81
84
 
82
- if (t3_high)
83
- Debug.LogWarning($"T3 沒接好,當前阻抗值: {t3_val}");
84
- if (t4_high)
85
- Debug.LogWarning($"T4 沒接好,當前阻抗值: {t4_val}");
85
+ // 判斷是否「整體」阻抗都正常 (< 200,000)
86
+ if (data.IsImpedanceGood)
87
+ {
88
+ Debug.Log(" 所有通道阻抗良好!可以開始遊戲/實驗了!");
89
+ // 進入下一階段、開啟 EEG 等等...
90
+ }
91
+ else
92
+ {
93
+ Debug.LogWarning("❌ 有通道阻抗太高!");
94
+
95
+ // 具體顯示是哪個通道有問題
96
+ if (t3_high) Debug.LogWarning($"- 左側前額 (T3) 接觸不良,目前數值高達: {t3_val}");
97
+ if (t4_high) Debug.LogWarning($"- 右側前額 (T4) 接觸不良,目前數值高達: {t4_val}");
98
+ if (o1_high) Debug.LogWarning($"- 左後腦 (O1) 接觸不良,目前數值高達: {o1_val}");
99
+ if (o2_high) Debug.LogWarning($"- 右後腦 (O2) 接觸不良,目前數值高達: {o2_val}");
100
+ }
101
+ }
102
+ ```
103
+
104
+ ---
105
+
106
+ ### 4. 設備搜尋與多設備選擇機制
107
+
108
+ 預設情況下,`BrainBitManager` 會自動過濾周遭的藍牙設備,只尋找型號為 `SensorLEBrainBit` 的腦波儀。
109
+
110
+ 如果現場有多台 BrainBit 同時開啟,系統如何決定連哪台?
111
+ 你可以在 Unity Inspector 或是程式碼中修改 `BrainBitConfig.AutoSelectBestSignal` 的設定:
112
+
113
+ - **`AutoSelectBestSignal = false`(預設):** 先搶先贏。系統會直接連線到藍牙掃描名單上的第一台設備。
114
+ - **`AutoSelectBestSignal = true`:** 訊號最強優先。系統會比較所有掃描到的 BrainBit 訊號強度 (RSSI),並自動連線到訊號最強(距離接收器最近)的那台設備。建議在展位或多人環境中開啟此設定。
115
+
116
+ ---
117
+
118
+ ### 5. 實用除錯工具:獲取設備詳細參數
119
+
120
+ 如果需要查看設備底層的詳細資訊(例如:電量、硬體版本、韌體版本、取樣頻率等),可使用內建的解析器 `SensorInfoProvider.cs` 將複雜的底層參數結構化。
121
+
122
+ ```csharp
123
+ using NeuroSDK;
124
+
125
+ void ShowDeviceInfo(BrainBitSensor sensor)
126
+ {
127
+ // 將龐雜的系統屬性轉換為易讀的 Dictionary
128
+ Dictionary<string, string> parameters = SensorInfoProvider.GetBrainBitSensorParameters(sensor);
129
+
130
+ foreach (var param in parameters)
131
+ {
132
+ Debug.Log($"[{param.Key}]: {param.Value}");
133
+ // 範例輸出: [BattPower]: 85, [State]: StateInRange, [SamplingFrequency]: 250
134
+ }
86
135
  }
87
136
  ```
88
137
 
@@ -0,0 +1,61 @@
1
+ using System;
2
+ using System.Collections;
3
+ using System.Collections.Generic;
4
+ using System.Threading;
5
+ using UnityEngine;
6
+
7
+ public class MainThreadDispatcher : MonoBehaviour
8
+ {
9
+ public static void RunAsync(Action action)
10
+ {
11
+ ThreadPool.QueueUserWorkItem(o => action());
12
+ }
13
+
14
+ public static void RunAsync(Action<object> action, object state)
15
+ {
16
+ ThreadPool.QueueUserWorkItem(o => action(o), state);
17
+ }
18
+
19
+ public static void RunOnMainThread(Action action)
20
+ {
21
+ lock (_backlog)
22
+ {
23
+ _backlog.Add(action);
24
+ _queued = true;
25
+ }
26
+ }
27
+
28
+ [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
29
+ private static void Initialize()
30
+ {
31
+ if (_instance == null)
32
+ {
33
+ _instance = new GameObject("MainThreadDispatcher").AddComponent<MainThreadDispatcher>();
34
+ DontDestroyOnLoad(_instance.gameObject);
35
+ }
36
+ }
37
+
38
+ private void Update()
39
+ {
40
+ if (_queued)
41
+ {
42
+ lock (_backlog)
43
+ {
44
+ var tmp = _actions;
45
+ _actions = _backlog;
46
+ _backlog = tmp;
47
+ _queued = false;
48
+ }
49
+
50
+ foreach (var action in _actions)
51
+ action();
52
+
53
+ _actions.Clear();
54
+ }
55
+ }
56
+
57
+ static MainThreadDispatcher _instance;
58
+ static volatile bool _queued = false;
59
+ static List<Action> _backlog = new List<Action>(8);
60
+ static List<Action> _actions = new List<Action>(8);
61
+ }
@@ -0,0 +1,87 @@
1
+ using System;
2
+ using System.Collections.Generic;
3
+ using System.Linq;
4
+
5
+ namespace NeuroSDK
6
+ {
7
+ public static class SensorInfoProvider
8
+ {
9
+ public static Dictionary<string, string> GetBrainBitSensorParameters(BrainBitSensor sensor)
10
+ {
11
+ var dictionary = GetGeneralSensorParameter(sensor);
12
+ var parameters = sensor.Parameters;
13
+ if (sensor is not BrainBitBlackSensor black) return dictionary;
14
+ foreach (var parInfo in parameters)
15
+ {
16
+ var paramName = parInfo.Param.ToString().Replace("Parameter", "");
17
+ var paramValue = parInfo.Param switch
18
+ {
19
+ SensorParameter.ParameterSamplingFrequencyMEMS => black.SamplingFrequencyMEMS.ToString(),
20
+ SensorParameter.ParameterSamplingFrequencyFPG => black.SamplingFrequencyFPG.ToString(),
21
+ SensorParameter.ParameterAccelerometerSens => black.AccSens.ToString(),
22
+ SensorParameter.ParameterGyroscopeSens => black.GyroSens.ToString(),
23
+ SensorParameter.ParameterIrAmplitude => black.IrAmplitudeFPGSensor.ToString(),
24
+ SensorParameter.ParameterRedAmplitude=> black.RedAmplitudeFPGSensor.ToString(),
25
+ _ => null
26
+ };
27
+ if (paramValue != null)
28
+ {
29
+ dictionary[paramName] = paramValue;
30
+ }
31
+ }
32
+
33
+ dictionary["Amp mode"] = black.AmpMode.ToString();
34
+
35
+ return dictionary;
36
+ }
37
+
38
+ public static List<string> GetSensorCommands(ISensor sensor)
39
+ {
40
+ return sensor.Commands.Select(x => x.ToString().Replace("Command", "")).ToList();
41
+ }
42
+
43
+ public static List<string> GetSensorFeatures(ISensor sensor)
44
+ {
45
+ return sensor.Features.Select(x => x.ToString().Replace("Feature", "")).ToList();
46
+ }
47
+
48
+ private static Dictionary<string, string> GetGeneralSensorParameter(ISensor sensor)
49
+ {
50
+ var dictionary = new Dictionary<string, string>();
51
+ var parameters = sensor.Parameters;
52
+ foreach (var parInfo in parameters)
53
+ {
54
+ var paramName = parInfo.Param.ToString().Replace("Parameter", "");
55
+ var paramValue = parInfo.Param switch
56
+ {
57
+ SensorParameter.ParameterName => sensor.Name,
58
+ SensorParameter.ParameterSensorFamily => sensor.SensFamily.ToString(),
59
+ SensorParameter.ParameterAddress => sensor.Address,
60
+ SensorParameter.ParameterSerialNumber => sensor.SerialNumber,
61
+ SensorParameter.ParameterBattPower => sensor.BattPower.ToString(),
62
+ SensorParameter.ParameterState => sensor.State.ToString(),
63
+ SensorParameter.ParameterSamplingFrequency => sensor.SamplingFrequency.ToString(),
64
+ SensorParameter.ParameterGain => sensor.Gain.ToString(),
65
+ SensorParameter.ParameterOffset => sensor.DataOffset.ToString(),
66
+ SensorParameter.ParameterFirmwareMode => sensor.FirmwareMode.ToString(),
67
+ _ => null
68
+ };
69
+ if (paramValue != null)
70
+ {
71
+ dictionary[paramName] = paramValue;
72
+ }
73
+
74
+ var ver = sensor.Version;
75
+ dictionary["ExtMajor"] = ver.ExtMajor.ToString();
76
+ dictionary["FwMajor"] = ver.FwMajor.ToString();
77
+ dictionary["HwMajor"] = ver.HwMajor.ToString();
78
+ dictionary["FwMinor"] = ver.FwMinor.ToString();
79
+ dictionary["HwMinor"] = ver.HwMinor.ToString();
80
+ dictionary["FwPatch"] = ver.FwPatch.ToString();
81
+ dictionary["HwPatch"] = ver.HwPatch.ToString();
82
+ }
83
+
84
+ return dictionary;
85
+ }
86
+ }
87
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "com.xrlab.labframe_brainbit",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "displayName": "Lab Frame 2023 - BrainBit Plugin",
5
5
  "description": "BrainBit Support for LabFrame2023.\nNote: Currently only supports BrainBit in lab!!",
6
6
  "unity": "2022.3",
File without changes
File without changes
File without changes