import QtQuick import QtQuick.Controls import QtQuick.Controls.Material import QtQuick.Layouts import QmlCustomPlot 1.0 import "request.js" as XHR import eurydice ApplicationWindow { id: mainWindowRoot width: 640 height: 480 visible: true // visibility: Window.Maximized visibility: ApplicationWindow.Maximized // visibility: ApplicationWindow.FullScreen title: qsTr("Hello World") // // pistache // // readonly property string apiRoot: "http://rpi5:8080/v1" // // qhttpserver // readonly property string apiRoot: "http://rpi5:8081/v1" readonly property string apiRoot: "http://rpizero:8081/v1" Shortcut { sequence: "ctrl+q" onActivated: mainWindowRoot.close() } Material.theme: Material.Dark Material.accent: Material.Indigo function requestExposureTime(type, uri) { console.log("request url: ", apiRoot + uri); XHR.sendRequest("GET", apiRoot + uri, function(response) { if (response.status != "200") { console.log("response status: ", response.status); return; } let isPlainText = response.contentType.length === 0 if (!isPlainText) { console.log("invalid response: ", response); return; } exposureTimeSpinBox.value = parseInt(response.content) }); } function readParams() { var url = apiRoot + "/sensor/params" console.log("readParams:", url); XHR.sendRequest("GET", url, function(response) { if (response.status != "200") { console.log("response status: ", response.status); return; } let isPlainText = response.contentType.length === 0 if (!isPlainText) { console.log("invalid response: ", response); return; } var json = JSON.parse(response.content); console.log("readParams result:", json) if (exposureTimeSpinBox.value != json.exposureTime) { console.log("update exposureTimeSpinBox to", json.exposureTime) exposureTimeSpinBox.value = json.exposureTime; } if (laserLevelSpinBox.value != json.laserLevel) { console.log("update laserLevelSpinBox to", json.laserLevel) laserLevelSpinBox.value = json.laserLevel; } if (enableAutoExposureCheckbox.checked != (json.aeEnable == "true")) { console.log("update enableAutoExposureCheckbox to", json.aeEnable) enableAutoExposureCheckbox.checked = json.aeEnable == "true"; } }); } Component.onCompleted: readParams() function writeParams() { var url = apiRoot + "/sensor/params"; console.log("writeParams:", url); var json = new Object(); json["aeEnable"] = enableAutoExposureCheckbox.checked; json["exposureTime"] = exposureTimeSpinBox.value; json["laserLevel"] = laserLevelSpinBox.value; json["gain"] = gainSpinBox.value; console.log(JSON.stringify(json)); XHR.sendRequest("POST", url, function(response) { if (response.status != "200") { console.log("response status: ", response.status); return; } let isPlainText = response.contentType.length === 0; if (!isPlainText) { console.log("invalid response: ", response); return; } console.log("writeParams result:", response.content); // var json = JSON.parse(response.content); }, JSON.stringify(json)); } function resetEncoder() { var url = apiRoot + "/commands/resetEncoder"; console.log("resetEncoder:", url); XHR.sendRequest("POST", url, function(response) { if (response.status != "200") { console.log("response status: ", response.status); return; } }); } function startCalibration() { var url = apiRoot + "/commands/startCalibration"; console.log("startCalibration:", url); XHR.sendRequest("POST", url, function(response) { if (response.status != "200") { console.log("response status: ", response.status); return; } }); } function sendGCode(gcode) { var url = apiRoot + "/commands/gCode"; console.log("gCode:", url); var withFeedRate = gcode + " F" + feedRateSpinBox.value XHR.sendRequest("POST", url, function(response) { if (response.status != "200") { console.log("response status: ", response.status); return; } }, withFeedRate); } RowLayout { id: horizontalLayout anchors.fill: parent spacing: 0 Pane { id: pane Layout.fillHeight: true Layout.fillWidth: true Layout.minimumWidth: 250 ColumnLayout { id: columnLayout anchors.fill: parent function color_by_value(value) { const limit = 0.02; if (value >= limit) { return "red"; } return "green"; } Label { id: fpsLabel Layout.fillWidth: true Layout.alignment: Qt.AlignTop color: "green" } Label { id: maxDiffLabel Layout.fillWidth: true Layout.alignment: Qt.AlignTop color: columnLayout.color_by_value(max_diff) text: "max diff: " + max_diff.toFixed(3) } Label { id: maxDiffIdxLabel Layout.fillWidth: true Layout.alignment: Qt.AlignTop text: "max diff: " + max_diff_idx } Label { id: minDiffLabel Layout.fillWidth: true Layout.alignment: Qt.AlignTop color: columnLayout.color_by_value(-min_diff) text: "min diff: " + min_diff.toFixed(3) } Label { id: minDiffIdxLabel Layout.fillWidth: true Layout.alignment: Qt.AlignTop text: "min diff: " + min_diff_idx } Label { id: avgDiffLabel Layout.fillWidth: true Layout.alignment: Qt.AlignTop color: columnLayout.color_by_value(avg_diff) text: "avg diff: " + avg_diff.toFixed(3) } Label { id: medianhDiffLabel Layout.fillWidth: true Layout.alignment: Qt.AlignTop color: columnLayout.color_by_value(median_diff) text: "med. diff: " + median_diff.toFixed(3) } Label { Layout.fillWidth: true Layout.alignment: Qt.AlignTop text: "Pos: " + (parseFloat(encoderPosition) / 200.).toFixed(3) } Label { Layout.fillWidth: true Layout.alignment: Qt.AlignTop text: "Measurement: " + measurementCounter } Label { Layout.fillWidth: true Layout.alignment: Qt.AlignTop text: "Timestamp (ms): " + (parseFloat(timestampUs % (1000 * 1000 * 1000)) / 1000.).toFixed(1) } Label { text: qsTr("Exposure time (us):") } SpinBox { id: exposureTimeSpinBox Layout.fillWidth: true from: 10 to: 30000000 stepSize: 100 editable: true value: 1000 onValueChanged: writeParams() } Label { text: qsTr("Laser level (1/50K):") } SpinBox { id: laserLevelSpinBox Layout.fillWidth: true from: 0 to: 50000 stepSize: 1 editable: true value: 3 onValueChanged: writeParams() } Label { text: qsTr("Gain [1,254]:") } SpinBox { id: gainSpinBox Layout.fillWidth: true from: 0 to: 254 stepSize: 1 editable: true value: 3 onValueChanged: writeParams() } CheckBox { id: enableAutoExposureCheckbox text: qsTr("Auto exposure") onCheckedChanged: writeParams() } Label { text: qsTr("Printer distance (mm):") } TextField { id: printerDistanceMmTextField Layout.fillWidth: true text: "10" // onValueChanged: writeParams() } Label { text: qsTr("Feed rate (%):") } SpinBox { id: feedRateSpinBox Layout.fillWidth: true from: 1 to: 500 stepSize: 50 editable: true value: 300 } GridLayout { id: printerControlGridLayout columns: 4 Label { Layout.row: 0 Layout.column: 1 text: "X/Y" } Label { Layout.row: 0 Layout.column: 3 text: "Z" } Button { id: yUpButton Layout.row: 1 Layout.column: 1 text: "\u2191" onClicked: sendGCode("G1 Y" + printerDistanceMmTextField.text) highlighted: true } Button { id: zUpButton Layout.row: 1 Layout.column: 3 text: "\u2191" onClicked: sendGCode("G1 Z" + printerDistanceMmTextField.text) highlighted: true } Button { id: xDownButton Layout.row: 2 Layout.column: 0 text: "\u2190" onClicked: sendGCode("G1 X-" + printerDistanceMmTextField.text) highlighted: true } Button { id: xyHomeButton Layout.row: 2 Layout.column: 1 text: "\u2302" // onClicked: sendGCode("G1 X-" + printerDistanceMmSpinBox.text) highlighted: true } Button { id: xUpButton Layout.row: 2 Layout.column: 2 text: "\u2192" onClicked: sendGCode("G1 X" + printerDistanceMmTextField.text) highlighted: true } Button { id: zHomeButton Layout.row: 2 Layout.column: 3 text: "\u2302" // onClicked: sendGCode("G1 X-" + printerDistanceMmSpinBox.text) highlighted: true } Button { id: yDownButton Layout.row: 3 Layout.column: 1 text: "\u2193" onClicked: sendGCode("G1 Y-" + printerDistanceMmTextField.text) highlighted: true } Button { id: zDownButton Layout.row: 3 Layout.column: 3 text: "\u2193" onClicked: sendGCode("G1 Z-" + printerDistanceMmTextField.text) highlighted: true } } Button { Layout.fillWidth: true text: qsTr("Reset encoder") onClicked: resetEncoder() highlighted: true } Button { Layout.fillWidth: true text: qsTr("Start calibration") onClicked: startCalibration() highlighted: true } Item { Layout.fillHeight: true } } } ColumnLayout { TabBar { id: tabBar Layout.fillWidth: true currentIndex: 0 Shortcut { sequence: "alt+1" onActivated: tabBar.currentIndex = 0 } Shortcut { sequence: "alt+2" onActivated: tabBar.currentIndex = 1 } Shortcut { sequence: "alt+3" onActivated: tabBar.currentIndex = 2 } TabButton { text: qsTr("Image") } TabButton { text: qsTr("Pixels") } TabButton { text: qsTr("Profile") } } SwipeView { Layout.fillHeight: true Layout.fillWidth: true Layout.minimumWidth: mainWindowRoot.width * 0.8 currentIndex: tabBar.currentIndex clip: true interactive: false ImageViewer { id: image } QmlCustomPlot { id: pixelsQmlCustomPlot objectName: "pixelsCustomPlot" Label { anchors { top: parent.top topMargin: 8 * 2 horizontalCenter: parent.horizontalCenter } text: pixelsQmlCustomPlot.fps color: Material.accent } plot: pixelsPlot // Component.onCompleted: setRange(Qt.rect(-640, 0, 1280, 800)) // Component.onCompleted: initCustomPlot() } QmlCustomPlot { id: profileQmlCustomPlot objectName: "profileCustomPlot" Label { anchors { top: parent.top topMargin: 8 * 2 horizontalCenter: parent.horizontalCenter } text: profileQmlCustomPlot.fps color: Material.accent } plot: profilePlot // Component.onCompleted: setRange(Qt.rect(-640, 0, 1280, 800)) // Component.onCompleted: initCustomPlot() } } } } }