Files
tustu/app_qml/DataLoggingView.qml
johndoe6345789 741702cedf feat: Add Offline Activation Dialog and Registration Dialog
- Implemented OfflineActivationDialog.qml for offline activation process with detailed instructions and file handling.
- Created RegistrationDialog.qml for user registration with manual input and email parsing options.
- Added new components: RoundGauge.qml, ScalarEditor.qml, Table2DEditor.qml, Table3DEditor.qml, TableEditorPanel.qml, and TableEditorView.qml for enhanced table editing features.
- Updated main.py to include clipboard operations and file handling for saving/loading activation requests and codes.
- Enhanced README.md to document new features and file structure.
2026-01-11 03:11:28 +00:00

260 lines
10 KiB
QML

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Item {
id: dataLoggingView
ColumnLayout {
anchors.fill: parent
anchors.margins: 10
spacing: 10
// Control panel
RowLayout {
Layout.fillWidth: true
spacing: 10
Button {
text: "Start Logging"
highlighted: true
onClicked: console.log("Start logging")
}
Button {
text: "Stop Logging"
enabled: false
}
Button {
text: "Load Log File..."
onClicked: console.log("Load log")
}
Item { Layout.fillWidth: true }
Label {
text: "Sample Rate:"
}
ComboBox {
model: ["10 Hz", "20 Hz", "50 Hz", "100 Hz"]
currentIndex: 2
}
}
// Chart area
Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
color: "#2c3e50"
border.color: "#34495e"
border.width: 2
radius: 5
ColumnLayout {
anchors.fill: parent
anchors.margins: 10
spacing: 5
Label {
text: "Data Log Chart"
color: "white"
font.pixelSize: 16
font.bold: true
Layout.alignment: Qt.AlignHCenter
}
// Chart canvas
Canvas {
id: chartCanvas
Layout.fillWidth: true
Layout.fillHeight: true
property var dataPoints: []
property int logTime: 0
property real logRpm: 850
property real logTemp: 85
property real logAfr: 14.7
Timer {
interval: 100
running: true
repeat: true
onTriggered: {
chartCanvas.logTime++
var t = chartCanvas.logTime
// Simulate driving around the block (synchronized with dashboard)
if (t < 30) {
// Idle
chartCanvas.logRpm = 850 + Math.sin(t * 0.5) * 30
chartCanvas.logAfr = 14.7
} else if (t < 80) {
// Accelerate
var accel = (t - 30) / 50
chartCanvas.logRpm = 850 + accel * 2700 + Math.sin(t * 0.3) * 100
chartCanvas.logAfr = 13.2 + accel * 0.8
chartCanvas.logTemp = Math.min(95, 85 + accel * 10)
} else if (t < 160) {
// Cruise
chartCanvas.logRpm = 2200 + Math.sin(t * 0.1) * 300
chartCanvas.logAfr = 14.5 + Math.sin(t * 0.15) * 0.3
chartCanvas.logTemp = Math.min(98, chartCanvas.logTemp + 0.05)
} else if (t < 185) {
// Brake
var brake = (t - 160) / 25
chartCanvas.logRpm = 2200 - brake * 1350
chartCanvas.logAfr = 15.5
} else if (t < 225) {
// Turn
chartCanvas.logRpm = 1200 + Math.sin(t * 0.2) * 200
chartCanvas.logAfr = 13.8
} else if (t < 285) {
// Hard accelerate
var hardAccel = (t - 225) / 60
chartCanvas.logRpm = 1500 + hardAccel * 4900 + Math.sin(t * 0.3) * 150
chartCanvas.logAfr = 12.8 + hardAccel * 0.5
chartCanvas.logTemp = Math.min(103, chartCanvas.logTemp + 0.08)
} else if (t < 355) {
// Cruise 2
chartCanvas.logRpm = 2500 + Math.sin(t * 0.12) * 350
chartCanvas.logAfr = 14.3 + Math.sin(t * 0.18) * 0.4
} else if (t < 375) {
// Brake 2
var brake2 = (t - 355) / 20
chartCanvas.logRpm = 2500 - brake2 * 1650
chartCanvas.logAfr = 15.2
} else if (t < 410) {
// Turn 2
chartCanvas.logRpm = 1400 + Math.sin(t * 0.25) * 150
chartCanvas.logAfr = 14.0
} else if (t < 450) {
// Decel
var decel = (t - 410) / 40
chartCanvas.logRpm = 1400 - decel * 550
chartCanvas.logAfr = 15.0
chartCanvas.logTemp = Math.max(85, chartCanvas.logTemp - 0.1)
} else if (t < 500) {
// Back to idle
chartCanvas.logRpm = 850 + Math.sin(t * 0.4) * 25
chartCanvas.logAfr = 14.7
chartCanvas.logTemp = Math.max(85, chartCanvas.logTemp - 0.05)
} else {
// Reset and loop
chartCanvas.logTime = 0
}
chartCanvas.dataPoints.push({
rpm: chartCanvas.logRpm,
afr: chartCanvas.logAfr,
temp: chartCanvas.logTemp
})
if (chartCanvas.dataPoints.length > 100) {
chartCanvas.dataPoints.shift()
}
chartCanvas.requestPaint()
}
}
onPaint: {
var ctx = getContext("2d")
ctx.reset()
// Draw background grid
ctx.strokeStyle = "#34495e"
ctx.lineWidth = 1
for (var i = 0; i < 10; i++) {
var y = height * i / 10
ctx.beginPath()
ctx.moveTo(0, y)
ctx.lineTo(width, y)
ctx.stroke()
}
for (var j = 0; j < 20; j++) {
var x = width * j / 20
ctx.beginPath()
ctx.moveTo(x, 0)
ctx.lineTo(x, height)
ctx.stroke()
}
if (dataPoints.length < 2) return
// Draw RPM line
ctx.beginPath()
ctx.strokeStyle = "#3498db"
ctx.lineWidth = 2
for (var k = 0; k < dataPoints.length; k++) {
var xPos = (k / dataPoints.length) * width
var yPos = height - (dataPoints[k].rpm / 8000 * height)
if (k === 0) {
ctx.moveTo(xPos, yPos)
} else {
ctx.lineTo(xPos, yPos)
}
}
ctx.stroke()
// Draw AFR line
ctx.beginPath()
ctx.strokeStyle = "#2ecc71"
ctx.lineWidth = 2
for (var m = 0; m < dataPoints.length; m++) {
var xPos2 = (m / dataPoints.length) * width
var yPos2 = height - ((dataPoints[m].afr - 10) / 8 * height)
if (m === 0) {
ctx.moveTo(xPos2, yPos2)
} else {
ctx.lineTo(xPos2, yPos2)
}
}
ctx.stroke()
}
}
// Legend
RowLayout {
Layout.alignment: Qt.AlignHCenter
spacing: 20
Row {
spacing: 5
Rectangle {
width: 20
height: 10
color: "#3498db"
anchors.verticalCenter: parent.verticalCenter
}
Label {
text: "RPM"
color: "white"
}
}
Row {
spacing: 5
Rectangle {
width: 20
height: 10
color: "#2ecc71"
anchors.verticalCenter: parent.verticalCenter
}
Label {
text: "AFR"
color: "white"
}
}
}
}
}
}
}