first push!
This commit is contained in:
42
Assets/Scripts/Debug/ForceCurveDataLogger.cs
Normal file
42
Assets/Scripts/Debug/ForceCurveDataLogger.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
public class ForceCurveDataLogger : MonoBehaviour
|
||||
{
|
||||
private List<float> _strokeBuffer = new List<float>();
|
||||
|
||||
void Start()
|
||||
{
|
||||
if (PerformanceMonitorManager.Instance != null)
|
||||
PerformanceMonitorManager.Instance.OnForceCurveUpdated += HandleData;
|
||||
}
|
||||
|
||||
void HandleData(List<float> points)
|
||||
{
|
||||
// 1. SIGNAL: Manager sends empty list when a NEW stroke starts
|
||||
if (points.Count == 0)
|
||||
{
|
||||
if (_strokeBuffer.Count > 5)
|
||||
{
|
||||
LogFinishedStroke();
|
||||
}
|
||||
_strokeBuffer.Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// 2. Accumulate the cumulative data
|
||||
_strokeBuffer = new List<float>(points);
|
||||
}
|
||||
}
|
||||
|
||||
void LogFinishedStroke()
|
||||
{
|
||||
float maxForce = _strokeBuffer.Max();
|
||||
float totalImpulse = _strokeBuffer.Sum(); // Area under the curve
|
||||
string csv = string.Join(",", _strokeBuffer.Select(p => p.ToString("0")));
|
||||
|
||||
Debug.Log($"<color=#FF7F00><b>[STROKE RECORDED]</b></color> Impulse: {totalImpulse:N0} | Pts: {_strokeBuffer.Count} | Max: {maxForce}");
|
||||
Debug.Log("CSV:" + csv);
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Debug/ForceCurveDataLogger.cs.meta
Normal file
11
Assets/Scripts/Debug/ForceCurveDataLogger.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a905dc9499e83430980b57cbc956dd70
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
86
Assets/Scripts/Debug/ForceCurveHistoryDebugger.cs
Normal file
86
Assets/Scripts/Debug/ForceCurveHistoryDebugger.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
[RequireComponent(typeof(LineRenderer))]
|
||||
public class ForceCurveHistoryDebugger : MonoBehaviour
|
||||
{
|
||||
private LineRenderer _lr;
|
||||
private List<float> _historyPoints = new List<float>();
|
||||
|
||||
[Header("Settings")]
|
||||
public float xScale = 0.05f; // Distance between points
|
||||
public float yScale = 0.05f; // Height multiplier
|
||||
public int maxPoints = 1000; // Keep last 1000 points (approx 20-30 seconds)
|
||||
|
||||
private int _lastPointsCount = 0;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_lr = GetComponent<LineRenderer>();
|
||||
_lr.positionCount = 0;
|
||||
_lr.startWidth = 0.05f;
|
||||
_lr.endWidth = 0.05f;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (PerformanceMonitorManager.Instance != null)
|
||||
{
|
||||
PerformanceMonitorManager.Instance.OnForceCurveUpdated += OnCurveData;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCurveData(List<float> fullCurve)
|
||||
{
|
||||
// Calculate how many NEW points were added since last update
|
||||
// (Since the Manager sends the whole cumulative curve of the current stroke)
|
||||
int newPointsCount = fullCurve.Count - _lastPointsCount;
|
||||
|
||||
// If count dropped (new stroke started), we take the whole new list
|
||||
if (newPointsCount < 0)
|
||||
{
|
||||
newPointsCount = fullCurve.Count;
|
||||
AddPoints(fullCurve); // Add the whole new stroke start
|
||||
}
|
||||
else if (newPointsCount > 0)
|
||||
{
|
||||
// Just add the tail (the newest packet)
|
||||
List<float> newSegment = fullCurve.GetRange(_lastPointsCount, newPointsCount);
|
||||
AddPoints(newSegment);
|
||||
}
|
||||
|
||||
_lastPointsCount = fullCurve.Count;
|
||||
}
|
||||
|
||||
private void AddPoints(List<float> newPoints)
|
||||
{
|
||||
UnityMainThreadDispatcher.Instance().Enqueue(() => {
|
||||
|
||||
_historyPoints.AddRange(newPoints);
|
||||
|
||||
// Trim history if too long
|
||||
if (_historyPoints.Count > maxPoints)
|
||||
{
|
||||
_historyPoints.RemoveRange(0, _historyPoints.Count - maxPoints);
|
||||
}
|
||||
|
||||
DrawGraph();
|
||||
});
|
||||
}
|
||||
|
||||
private void DrawGraph()
|
||||
{
|
||||
_lr.positionCount = _historyPoints.Count;
|
||||
|
||||
for (int i = 0; i < _historyPoints.Count; i++)
|
||||
{
|
||||
float x = i * xScale;
|
||||
float y = _historyPoints[i] * yScale;
|
||||
|
||||
// Shift x so the graph scrolls to the left
|
||||
// (Optional: Keep it static and let it grow to the right)
|
||||
|
||||
_lr.SetPosition(i, new Vector3(x, y, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Debug/ForceCurveHistoryDebugger.cs.meta
Normal file
11
Assets/Scripts/Debug/ForceCurveHistoryDebugger.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 68892aba1c1c94fd7959380b4718584a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
71
Assets/Scripts/Debug/ForceCurveVisualizer.cs
Normal file
71
Assets/Scripts/Debug/ForceCurveVisualizer.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
[RequireComponent(typeof(LineRenderer))]
|
||||
public class ForceCurveVisualizer : MonoBehaviour
|
||||
{
|
||||
private LineRenderer _lr;
|
||||
|
||||
[Header("Visual Settings")]
|
||||
public float xScale = 0.1f;
|
||||
public float yScale = 0.05f; // Raw force is usually 0-200. 0.05 scales it to 0-10 height.
|
||||
public float lineWidth = 0.1f;
|
||||
public Color lineColor = Color.cyan;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_lr = GetComponent<LineRenderer>();
|
||||
|
||||
// Setup LineRenderer programmatically if not set in Inspector
|
||||
_lr.positionCount = 0;
|
||||
_lr.startWidth = lineWidth;
|
||||
_lr.endWidth = lineWidth;
|
||||
_lr.useWorldSpace = false; // Important for UI/HUD
|
||||
_lr.material = new Material(Shader.Find("Sprites/Default")); // Basic white material
|
||||
_lr.startColor = lineColor;
|
||||
_lr.endColor = lineColor;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (PerformanceMonitorManager.Instance != null)
|
||||
{
|
||||
PerformanceMonitorManager.Instance.OnForceCurveUpdated += UpdateGraph;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateGraph(List<float> points)
|
||||
{
|
||||
UnityMainThreadDispatcher.Instance().Enqueue(() => {
|
||||
if (points.Count < 2)
|
||||
{
|
||||
_lr.positionCount = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
_lr.positionCount = points.Count;
|
||||
|
||||
// Draw
|
||||
for (int i = 0; i < points.Count; i++)
|
||||
{
|
||||
float x = i * xScale;
|
||||
float y = points[i] * yScale;
|
||||
|
||||
// Simple 3-point smoothing
|
||||
if (i > 0 && i < points.Count - 1)
|
||||
{
|
||||
float prev = points[i-1] * yScale;
|
||||
float next = points[i+1] * yScale;
|
||||
y = (prev + y + next) / 3f;
|
||||
}
|
||||
|
||||
_lr.SetPosition(i, new Vector3(x, y, 0));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// JUICE TIP: Use this to check for "Good Form"
|
||||
// A good stroke is a smooth bell curve.
|
||||
// A bad stroke has a "dip" in the middle (two peaks).
|
||||
// You can analyze 'points' here to trigger the "sputtering engine" sound.
|
||||
}
|
||||
11
Assets/Scripts/Debug/ForceCurveVisualizer.cs.meta
Normal file
11
Assets/Scripts/Debug/ForceCurveVisualizer.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a6d1a8e151ddc4bae990fe2e86149e70
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
84
Assets/Scripts/Debug/PM5TestUI.cs
Normal file
84
Assets/Scripts/Debug/PM5TestUI.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
using UnityEngine;
|
||||
using TMPro;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class PM5TestUI : MonoBehaviour
|
||||
{
|
||||
[Header("UI References")]
|
||||
[SerializeField] private TMP_Text wattsText;
|
||||
[SerializeField] private TMP_Text spmText;
|
||||
[SerializeField] private TMP_Text distanceText;
|
||||
[SerializeField] private TMP_Text hrText; // NEW
|
||||
[SerializeField] private TMP_Text caloriesText; // NEW
|
||||
[SerializeField] private TMP_Text statusText;
|
||||
[SerializeField] private Image statusIndicator;
|
||||
[SerializeField] private Button connectButton;
|
||||
|
||||
[Header("Logging")]
|
||||
[SerializeField] private Transform logContent;
|
||||
[SerializeField] private GameObject logItemPrefab;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (PerformanceMonitorManager.Instance != null)
|
||||
{
|
||||
PerformanceMonitorManager.Instance.OnLog += AddLog;
|
||||
PerformanceMonitorManager.Instance.OnConnectionStateChanged += UpdateStatusUI;
|
||||
PerformanceMonitorManager.Instance.OnStatsUpdated += UpdateDashboard;
|
||||
}
|
||||
|
||||
connectButton.onClick.AddListener(() => {
|
||||
PerformanceMonitorManager.Instance.StartScan();
|
||||
});
|
||||
|
||||
UpdateStatusUI(false);
|
||||
}
|
||||
|
||||
private void UpdateDashboard(PerformanceMonitorManager.RowingStats stats)
|
||||
{
|
||||
UnityMainThreadDispatcher.Instance().Enqueue(() => {
|
||||
if (wattsText) wattsText.text = $"{stats.Watts} W";
|
||||
if (spmText) spmText.text = $"{stats.SPM} s/m";
|
||||
if (distanceText) distanceText.text = $"{stats.Distance:F0} m";
|
||||
|
||||
if (hrText) hrText.text = stats.HeartRate > 0 ? $"{stats.HeartRate} bpm" : "--";
|
||||
if (caloriesText) caloriesText.text = $"{stats.Calories} cal";
|
||||
});
|
||||
}
|
||||
|
||||
private void UpdateStatusUI(bool isConnected)
|
||||
{
|
||||
UnityMainThreadDispatcher.Instance().Enqueue(() => {
|
||||
if (statusText)
|
||||
{
|
||||
statusText.text = isConnected ? "CONNECTED" : "DISCONNECTED";
|
||||
statusText.color = isConnected ? Color.green : Color.red;
|
||||
}
|
||||
|
||||
if (statusIndicator)
|
||||
statusIndicator.color = isConnected ? Color.green : Color.red;
|
||||
|
||||
if (connectButton)
|
||||
connectButton.interactable = !isConnected;
|
||||
});
|
||||
}
|
||||
|
||||
private void AddLog(string message)
|
||||
{
|
||||
UnityMainThreadDispatcher.Instance().Enqueue(() => {
|
||||
if (logContent == null || logItemPrefab == null) return;
|
||||
|
||||
// Optional: Limit log size to prevent lag
|
||||
if (logContent.childCount > 20)
|
||||
Destroy(logContent.GetChild(0).gameObject);
|
||||
|
||||
GameObject newItem = Instantiate(logItemPrefab, logContent);
|
||||
TMP_Text txt = newItem.GetComponent<TMP_Text>();
|
||||
if (txt) txt.text = $"[{System.DateTime.Now:HH:mm:ss}] {message}";
|
||||
|
||||
Canvas.ForceUpdateCanvases();
|
||||
ScrollRect sr = logContent.GetComponentInParent<ScrollRect>();
|
||||
if (sr) sr.verticalNormalizedPosition = 0f;
|
||||
});
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Debug/PM5TestUI.cs.meta
Normal file
11
Assets/Scripts/Debug/PM5TestUI.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 039ab1d0f5dab403db97489b34b3aa0e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user