diff --git a/Serial-Studio.pro b/Serial-Studio.pro
index 8c5b2a17..f6c74e37 100644
--- a/Serial-Studio.pro
+++ b/Serial-Studio.pro
@@ -120,8 +120,12 @@ RESOURCES += \
assets/assets.qrc
DISTFILES += \
+ assets/qml/SetupPanes/Network.qml \
+ assets/qml/SetupPanes/Serial.qml \
+ assets/qml/SetupPanes/Settings.qml \
assets/qml/Widgets/*.qml \
assets/qml/Windows/*.qml \
+ assets/qml/SetupPanes/*.qml \
assets/qml/*.qml
TRANSLATIONS += \
diff --git a/assets/assets.qrc b/assets/assets.qrc
index dba0617e..dc5bae12 100644
--- a/assets/assets.qrc
+++ b/assets/assets.qrc
@@ -85,5 +85,8 @@
icons/scroll-top.svg
icons/scroll-up.svg
qml/Widgets/SimpleDial.qml
+ qml/SetupPanes/Network.qml
+ qml/SetupPanes/Serial.qml
+ qml/SetupPanes/Settings.qml
diff --git a/assets/qml/SetupPanes/Network.qml b/assets/qml/SetupPanes/Network.qml
new file mode 100644
index 00000000..e399edc5
--- /dev/null
+++ b/assets/qml/SetupPanes/Network.qml
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2020-2021 Alex Spataru
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+import QtQuick 2.12
+import QtQuick.Layouts 1.12
+import QtQuick.Controls 2.12
+
+Control {
+ id: root
+
+ //
+ // Access to properties
+ //
+ property alias port: _portText.text
+ property alias address: _ipText.text
+ property alias socketType: _typeCombo.currentIndex
+
+ //
+ // Layout
+ //
+ ColumnLayout {
+ anchors.fill: parent
+ anchors.margins: app.spacing / 2
+
+ GridLayout {
+ columns: 2
+ Layout.fillWidth: true
+ rowSpacing: app.spacing
+ columnSpacing: app.spacing
+
+ //
+ // Socket type
+ //
+ Label {
+ opacity: enabled ? 1 : 0.5
+ enabled: !Cpp_IO_Manager.connected
+ Behavior on opacity {NumberAnimation{}}
+ text: qsTr("Socket type") + ":"
+ } ComboBox {
+ id: _typeCombo
+ Layout.fillWidth: true
+ model: Cpp_IO_Network.socketTypes
+ currentIndex: Cpp_IO_Network.socketTypeIndex
+ onCurrentIndexChanged: {
+ if (currentIndex !== Cpp_IO_Network.socketTypeIndex)
+ Cpp_IO_Network.socketTypeIndex = currentIndex
+ }
+
+ opacity: enabled ? 1 : 0.5
+ enabled: !Cpp_IO_Manager.connected
+ Behavior on opacity {NumberAnimation{}}
+ }
+
+ //
+ // Address
+ //
+ Label {
+ opacity: enabled ? 1 : 0.5
+ enabled: !Cpp_IO_Manager.connected
+ Behavior on opacity {NumberAnimation{}}
+ text: qsTr("IP Address") + ":"
+ } TextField {
+ id: _ipText
+ Layout.fillWidth: true
+ placeholderText: Cpp_IO_Network.defaultHost
+ text: Cpp_IO_Network.host
+ onTextChanged: {
+ if (Cpp_IO_Network.host !== text)
+ Cpp_IO_Network.host = text
+ }
+
+ opacity: enabled ? 1 : 0.5
+ enabled: !Cpp_IO_Manager.connected
+ Behavior on opacity {NumberAnimation{}}
+ }
+
+ //
+ // Port
+ //
+ Label {
+ opacity: enabled ? 1 : 0.5
+ enabled: !Cpp_IO_Manager.connected
+ Behavior on opacity {NumberAnimation{}}
+ text: qsTr("Port") + ":"
+ } TextField {
+ id: _portText
+ Layout.fillWidth: true
+ text: Cpp_IO_Network.port
+ placeholderText: Cpp_IO_Network.defaultPort
+ onTextChanged: {
+ if (Cpp_IO_Network.port !== text)
+ Cpp_IO_Network.port = text
+ }
+
+ opacity: enabled ? 1 : 0.5
+ enabled: !Cpp_IO_Manager.connected
+ Behavior on opacity {NumberAnimation{}}
+ }
+ }
+
+ //
+ // Vertical spacer
+ //
+ Item {
+ Layout.fillHeight: true
+ }
+ }
+}
diff --git a/assets/qml/SetupPanes/Serial.qml b/assets/qml/SetupPanes/Serial.qml
new file mode 100644
index 00000000..cef26caa
--- /dev/null
+++ b/assets/qml/SetupPanes/Serial.qml
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2020-2021 Alex Spataru
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+import QtQuick 2.12
+import QtQuick.Layouts 1.12
+import QtQuick.Controls 2.12
+
+Control {
+ id: root
+
+ //
+ // Access to properties
+ //
+ property alias port: _portCombo.currentIndex
+ property alias baudRate: _baudCombo.currentIndex
+ property alias dataBits: _dataCombo.currentIndex
+ property alias parity: _parityCombo.currentIndex
+ property alias flowControl: _flowCombo.currentIndex
+ property alias stopBits: _stopBitsCombo.currentIndex
+
+ //
+ // Update listbox models when translation is changed
+ //
+ Connections {
+ target: Cpp_Misc_Translator
+ function onLanguageChanged() {
+ var oldParityIndex = _parityCombo.currentIndex
+ var oldFlowControlIndex = _flowCombo.currentIndex
+
+ _parityCombo.model = Cpp_IO_Serial.parityList
+ _flowCombo.model = Cpp_IO_Serial.flowControlList
+
+ _parityCombo.currentIndex = oldParityIndex
+ _flowCombo.currentIndex = oldFlowControlIndex
+ }
+ }
+
+ //
+ // Control layout
+ //
+ ColumnLayout {
+ anchors.fill: parent
+ anchors.margins: app.spacing / 2
+
+ //
+ // Controls
+ //
+ GridLayout {
+ columns: 2
+ Layout.fillWidth: true
+ rowSpacing: app.spacing
+ columnSpacing: app.spacing
+
+ //
+ // COM port selector
+ //
+ Label {
+ opacity: enabled ? 1 : 0.5
+ enabled: !Cpp_IO_Manager.connected
+ Behavior on opacity {NumberAnimation{}}
+ text: qsTr("COM Port") + ":"
+ } ComboBox {
+ id: _portCombo
+ Layout.fillWidth: true
+ model: Cpp_IO_Serial.portList
+ currentIndex: Cpp_IO_Serial.portIndex
+ onCurrentIndexChanged: {
+ if (currentIndex !== Cpp_IO_Serial.portIndex)
+ Cpp_IO_Serial.portIndex = currentIndex
+ }
+
+ opacity: enabled ? 1 : 0.5
+ enabled: !Cpp_IO_Manager.connected
+ Behavior on opacity {NumberAnimation{}}
+ }
+
+ //
+ // Baud rate selector
+ //
+ Label {
+ opacity: enabled ? 1 : 0.5
+ Behavior on opacity {NumberAnimation{}}
+ text: qsTr("Baud Rate") + ":"
+ } ComboBox {
+ id: _baudCombo
+ editable: true
+ currentIndex: 4
+ Layout.fillWidth: true
+ model: Cpp_IO_Serial.baudRateList
+
+ validator: IntValidator {
+ bottom: 1
+ }
+
+ onAccepted: {
+ if (find(editText) === -1)
+ Cpp_IO_Serial.appendBaudRate(editText)
+ }
+
+ onCurrentTextChanged: {
+ var value = currentText
+ Cpp_IO_Serial.baudRate = value
+ }
+ }
+
+ //
+ // Spacer
+ //
+ Item {
+ Layout.minimumHeight: app.spacing / 2
+ Layout.maximumHeight: app.spacing / 2
+ } Item {
+ Layout.minimumHeight: app.spacing / 2
+ Layout.maximumHeight: app.spacing / 2
+ }
+
+ //
+ // Data bits selector
+ //
+ Label {
+ text: qsTr("Data Bits") + ":"
+ } ComboBox {
+ id: _dataCombo
+ Layout.fillWidth: true
+ model: Cpp_IO_Serial.dataBitsList
+ currentIndex: Cpp_IO_Serial.dataBitsIndex
+ onCurrentIndexChanged: {
+ if (Cpp_IO_Serial.dataBitsIndex !== currentIndex)
+ Cpp_IO_Serial.dataBitsIndex = currentIndex
+ }
+ }
+
+ //
+ // Parity selector
+ //
+ Label {
+ text: qsTr("Parity") + ":"
+ } ComboBox {
+ id: _parityCombo
+ Layout.fillWidth: true
+ model: Cpp_IO_Serial.parityList
+ currentIndex: Cpp_IO_Serial.parityIndex
+ onCurrentIndexChanged: {
+ if (Cpp_IO_Serial.parityIndex !== currentIndex)
+ Cpp_IO_Serial.parityIndex = currentIndex
+ }
+ }
+
+ //
+ // Stop bits selector
+ //
+ Label {
+ text: qsTr("Stop Bits") + ":"
+ } ComboBox {
+ id: _stopBitsCombo
+ Layout.fillWidth: true
+ model: Cpp_IO_Serial.stopBitsList
+ currentIndex: Cpp_IO_Serial.stopBitsIndex
+ onCurrentIndexChanged: {
+ if (Cpp_IO_Serial.stopBitsIndex !== currentIndex)
+ Cpp_IO_Serial.stopBitsIndex = currentIndex
+ }
+ }
+
+ //
+ // Flow control selector
+ //
+ Label {
+ text: qsTr("Flow Control") + ":"
+ } ComboBox {
+ id: _flowCombo
+ Layout.fillWidth: true
+ model: Cpp_IO_Serial.flowControlList
+ currentIndex: Cpp_IO_Serial.flowControlIndex
+ onCurrentIndexChanged: {
+ if (Cpp_IO_Serial.flowControlIndex !== currentIndex)
+ Cpp_IO_Serial.flowControlIndex = currentIndex
+ }
+ }
+ }
+
+ //
+ // Vertical spacer
+ //
+ Item {
+ Layout.fillHeight: true
+ }
+ }
+}
+
+
diff --git a/assets/qml/SetupPanes/Settings.qml b/assets/qml/SetupPanes/Settings.qml
new file mode 100644
index 00000000..15c463aa
--- /dev/null
+++ b/assets/qml/SetupPanes/Settings.qml
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2020-2021 Alex Spataru
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+import QtQuick 2.12
+import QtQuick.Layouts 1.12
+import QtQuick.Controls 2.12
+
+Control {
+ id: root
+
+ //
+ // Access to properties
+ //
+ property alias endSequence: _endSequence.text
+ property alias language: _langCombo.currentIndex
+ property alias startSequence: _startSequence.text
+
+ //
+ // Layout
+ //
+ ColumnLayout {
+ anchors.fill: parent
+ anchors.margins: app.spacing / 2
+
+ //
+ // Controls
+ //
+ GridLayout {
+ columns: 2
+ Layout.fillWidth: true
+ rowSpacing: app.spacing
+ columnSpacing: app.spacing
+
+ //
+ // Language selector
+ //
+ Label {
+ text: qsTr("Language") + ":"
+ } ComboBox {
+ id: _langCombo
+ Layout.fillWidth: true
+ model: Cpp_Misc_Translator.availableLanguages
+ onCurrentIndexChanged: Cpp_Misc_Translator.setLanguage(currentIndex)
+ }
+
+ //
+ // Start sequence
+ //
+ Label {
+ text: qsTr("Start sequence") + ": "
+ } TextField {
+ id: _startSequence
+ Layout.fillWidth: true
+ placeholderText: "/*"
+ text: "/*"
+ onTextChanged: {
+ if (text !== Cpp_IO_Manager.startSequence)
+ Cpp_IO_Manager.startSequence = text
+ }
+ }
+
+ //
+ // End sequence
+ //
+ Label {
+ text: qsTr("End sequence") + ": "
+ } TextField {
+ id: _endSequence
+ Layout.fillWidth: true
+ placeholderText: "*/"
+ text: "*/"
+ onTextChanged: {
+ if (text !== Cpp_IO_Manager.finishSequence)
+ Cpp_IO_Manager.finishSequence = text
+ }
+ }
+ }
+
+ //
+ // Vertical spacer
+ //
+ Item {
+ Layout.fillHeight: true
+ }
+ }
+}
diff --git a/assets/qml/Windows/Console.qml b/assets/qml/Windows/Console.qml
index e086840b..c65b033b 100644
--- a/assets/qml/Windows/Console.qml
+++ b/assets/qml/Windows/Console.qml
@@ -48,7 +48,6 @@ Control {
// Clears console output
//
function clearConsole() {
- console.log("clear console")
Cpp_IO_Console.clear()
textEdit.clear()
}
diff --git a/assets/qml/Windows/Setup.qml b/assets/qml/Windows/Setup.qml
index 2dc44e49..f6f07902 100644
--- a/assets/qml/Windows/Setup.qml
+++ b/assets/qml/Windows/Setup.qml
@@ -28,6 +28,7 @@ import Qt.labs.settings 1.0
import QtGraphicalEffects 1.0
import "../Widgets" as Widgets
+import "../SetupPanes" as SetupPanes
Control {
id: root
@@ -39,35 +40,36 @@ Control {
// Save settings
//
Settings {
- category: "Setup"
- property alias dmAuto: commAuto.checked
- property alias dmManual: commManual.checked
- property alias dmParity: parity.currentIndex
- property alias dmCsvExport: csvLogging.checked
- property alias dmStopBits: stopBits.currentIndex
- property alias dmDataBits: dataBits.currentIndex
- property alias dmBaudValue: baudRate.currentIndex
- property alias dmFlowControl: flowControl.currentIndex
- property alias dmStartSequence: startSeqText.text
- property alias dmEndSequence: endSeqText.text
- property alias appLanguage: languageCombo.currentIndex
- }
+ //
+ // Misc settings
+ //
+ property alias auto: commAuto.checked
+ property alias manual: commManual.checked
+ property alias csvExport: csvLogging.checked
+ property alias tabIndex: tab.currentIndex
- //
- // Update listbox models when translation is changed
- //
- Connections {
- target: Cpp_Misc_Translator
- function onLanguageChanged() {
- var oldParityIndex = parity.currentIndex
- var oldFlowControlIndex = flowControl.currentIndex
+ //
+ // Serial settings
+ //
+ property alias baudRate: serial.baudRate
+ property alias stopBits: serial.stopBits
+ property alias parity: serial.parity
+ property alias flowControl: serial.flowControl
+ property alias dataBits: serial.dataBits
- parity.model = Cpp_IO_Serial.parityList
- flowControl.model = Cpp_IO_Serial.flowControlList
+ //
+ // Network settings
+ //
+ property alias address: network.address
+ property alias port: network.port
+ property alias socketType: network.socketType
- parity.currentIndex = oldParityIndex
- flowControl.currentIndex = oldFlowControlIndex
- }
+ //
+ // App settings
+ //
+ property alias language: settings.language
+ property alias endSequence: settings.endSequence
+ property alias startSequence: settings.startSequence
}
//
@@ -175,194 +177,55 @@ Control {
}
//
- // A lot of comboboxes
+ // Tab bar
//
- GridLayout {
- columns: 2
+ TabBar {
+ height: 24
+ id: tab
Layout.fillWidth: true
- rowSpacing: app.spacing
- columnSpacing: app.spacing
-
- //
- // COM port selector
- //
- Label {
- opacity: enabled ? 1 : 0.5
- enabled: !Cpp_IO_Manager.connected
- Behavior on opacity {NumberAnimation{}}
- text: qsTr("COM Port") + ":"
- } ComboBox {
- id: portSelector
- Layout.fillWidth: true
- model: Cpp_IO_Serial.portList
- currentIndex: Cpp_IO_Serial.portIndex
- onCurrentIndexChanged: {
- if (currentIndex !== Cpp_IO_Serial.portIndex)
- Cpp_IO_Serial.portIndex = currentIndex
- }
-
- opacity: enabled ? 1 : 0.5
- enabled: !Cpp_IO_Manager.connected
- Behavior on opacity {NumberAnimation{}}
+ onCurrentIndexChanged: {
+ if (currentIndex < 2)
+ Cpp_IO_Manager.dataSource = currentIndex
}
- //
- // Baud rate selector
- //
- Label {
- opacity: enabled ? 1 : 0.5
- Behavior on opacity {NumberAnimation{}}
- text: qsTr("Baud Rate") + ":"
- } ComboBox {
- id: baudRate
- editable: true
- currentIndex: 3
- Layout.fillWidth: true
- model: Cpp_IO_Serial.baudRateList
-
- validator: IntValidator {
- bottom: 1
- }
-
- onAccepted: {
- if (find(editText) === -1)
- Cpp_IO_Serial.appendBaudRate(editText)
- }
-
- onCurrentTextChanged: {
- var value = currentText
- Cpp_IO_Serial.baudRate = value
- }
+ TabButton {
+ text: qsTr("Serial")
+ height: tab.height + 3
+ width: implicitWidth + 2 * app.spacing
}
- //
- // Spacer
- //
- Item {
- Layout.minimumHeight: app.spacing / 2
- Layout.maximumHeight: app.spacing / 2
- } Item {
- Layout.minimumHeight: app.spacing / 2
- Layout.maximumHeight: app.spacing / 2
+ TabButton {
+ text: qsTr("Network")
+ height: tab.height + 3
+ width: implicitWidth + 2 * app.spacing
}
- //
- // Data bits selector
- //
- Label {
- text: qsTr("Data Bits") + ":"
- } ComboBox {
- id: dataBits
- Layout.fillWidth: true
- model: Cpp_IO_Serial.dataBitsList
- currentIndex: Cpp_IO_Serial.dataBitsIndex
- onCurrentIndexChanged: {
- if (Cpp_IO_Serial.dataBitsIndex !== currentIndex)
- Cpp_IO_Serial.dataBitsIndex = currentIndex
- }
+ TabButton {
+ text: qsTr("Settings")
+ height: tab.height + 3
+ width: implicitWidth + 2 * app.spacing
+ }
+ }
+
+ //
+ // Tab bar contents
+ //
+ StackLayout {
+ clip: true
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ currentIndex: tab.currentIndex
+
+ SetupPanes.Serial {
+ id: serial
}
- //
- // Parity selector
- //
- Label {
- text: qsTr("Parity") + ":"
- } ComboBox {
- id: parity
- Layout.fillWidth: true
- model: Cpp_IO_Serial.parityList
- currentIndex: Cpp_IO_Serial.parityIndex
- onCurrentIndexChanged: {
- if (Cpp_IO_Serial.parityIndex !== currentIndex)
- Cpp_IO_Serial.parityIndex = currentIndex
- }
+ SetupPanes.Network {
+ id: network
}
- //
- // Stop bits selector
- //
- Label {
- text: qsTr("Stop Bits") + ":"
- } ComboBox {
- id: stopBits
- Layout.fillWidth: true
- model: Cpp_IO_Serial.stopBitsList
- currentIndex: Cpp_IO_Serial.stopBitsIndex
- onCurrentIndexChanged: {
- if (Cpp_IO_Serial.stopBitsIndex !== currentIndex)
- Cpp_IO_Serial.stopBitsIndex = currentIndex
- }
- }
-
- //
- // Flow control selector
- //
- Label {
- text: qsTr("Flow Control") + ":"
- } ComboBox {
- id: flowControl
- Layout.fillWidth: true
- model: Cpp_IO_Serial.flowControlList
- currentIndex: Cpp_IO_Serial.flowControlIndex
- onCurrentIndexChanged: {
- if (Cpp_IO_Serial.flowControlIndex !== currentIndex)
- Cpp_IO_Serial.flowControlIndex = currentIndex
- }
- }
-
- //
- // Spacer
- //
- Item {
- Layout.minimumHeight: app.spacing / 2
- Layout.maximumHeight: app.spacing / 2
- } Item {
- Layout.minimumHeight: app.spacing / 2
- Layout.maximumHeight: app.spacing / 2
- }
-
- //
- // Language selector
- //
- Label {
- text: qsTr("Language") + ":"
- } ComboBox {
- id: languageCombo
- Layout.fillWidth: true
- model: Cpp_Misc_Translator.availableLanguages
- onCurrentIndexChanged: Cpp_Misc_Translator.setLanguage(currentIndex)
- }
-
- //
- // Start sequence
- //
- Label {
- text: qsTr("Start sequence") + ": "
- } TextField {
- id: startSeqText
- Layout.fillWidth: true
- placeholderText: "/*"
- text: "/*"
- onTextChanged: {
- if (text !== Cpp_IO_Manager.startSequence)
- Cpp_IO_Manager.startSequence = text
- }
- }
-
- //
- // End sequence
- //
- Label {
- text: qsTr("End sequence") + ": "
- } TextField {
- id: endSeqText
- Layout.fillWidth: true
- placeholderText: "*/"
- text: "*/"
- onTextChanged: {
- if (text !== Cpp_IO_Manager.finishSequence)
- Cpp_IO_Manager.finishSequence = text
- }
+ SetupPanes.Settings {
+ id: settings
}
}
@@ -370,8 +233,8 @@ Control {
// Spacer
//
Item {
- Layout.fillHeight: true
- Layout.minimumHeight: app.spacing * 2
+ Layout.minimumHeight: app.spacing / 2
+ Layout.maximumHeight: app.spacing / 2
}
//
@@ -445,8 +308,7 @@ Control {
// Spacer
//
Item {
- Layout.fillHeight: true
- Layout.minimumHeight: app.spacing * 2
+ height: app.spacing * 2
}
}
}
diff --git a/assets/qml/main.qml b/assets/qml/main.qml
index 901fffd1..a121ae90 100644
--- a/assets/qml/main.qml
+++ b/assets/qml/main.qml
@@ -234,7 +234,7 @@ ApplicationWindow {
target: Cpp_JSON_Generator
enabled: !app.firstValidPacket
function onFrameChanged() {
- if (Cpp_IO_Manager.connected || Cpp_CSV_Player.isOpen) {
+ if ((Cpp_IO_Manager.connected || Cpp_CSV_Player.isOpen) && Cpp_JSON_Generator.frameValid()) {
app.firstValidPacket = true
setup.hide()
toolbar.dataClicked()
diff --git a/src/IO/Console.cpp b/src/IO/Console.cpp
index 168e2d29..1f53f0e2 100644
--- a/src/IO/Console.cpp
+++ b/src/IO/Console.cpp
@@ -55,6 +55,7 @@ Console::Console()
auto dm = Manager::getInstance();
auto te = Misc::TimerEvents::getInstance();
connect(te, SIGNAL(timeout42Hz()), this, SLOT(displayData()));
+ connect(dm, &Manager::dataSent, this, &Console::onDataSent);
connect(dm, &Manager::dataReceived, this, &Console::onDataReceived);
// Log something to look like a pro
@@ -321,27 +322,7 @@ void Console::send(const QString &data)
}
// Write data to device
- auto bytes = Manager::getInstance()->writeData(bin);
-
- // Write success, notify UI & log bytes written
- if (bytes > 0)
- {
- // Get sent byte array
- auto sent = bin;
- sent.chop(bin.length() - bytes);
-
- // Display sent data on console (if allowed)
- if (echo())
- {
- m_isStartingLine = true;
- append(dataToString(bin), showTimestamp());
- m_isStartingLine = true;
- }
- }
-
- // Write error
- else
- LOG_WARNING() << Manager::getInstance()->device()->errorString();
+ Manager::getInstance()->writeData(bin);
}
/**
@@ -484,6 +465,17 @@ void Console::displayData()
m_dataBuffer.clear();
}
+/**
+ * Displays the given @a data in the console. @c QByteArray to ~@c QString conversion is
+ * done by the @c dataToString() function, which displays incoming data either in UTF-8
+ * or in hexadecimal mode.
+ */
+void Console::onDataSent(const QByteArray &data)
+{
+ if (echo())
+ append(dataToString(data) + "\n", showTimestamp());
+}
+
/**
* Adds the given @a data to the incoming data buffer, which is read later by the UI
* refresh functions (displayData())
diff --git a/src/IO/Console.h b/src/IO/Console.h
index 7134b50d..66bd7982 100644
--- a/src/IO/Console.h
+++ b/src/IO/Console.h
@@ -133,6 +133,7 @@ public slots:
private slots:
void displayData();
+ void onDataSent(const QByteArray &data);
void addToHistory(const QString &command);
void onDataReceived(const QByteArray &data);
diff --git a/src/IO/DataSources/Network.cpp b/src/IO/DataSources/Network.cpp
index 8fab12ba..24b3f020 100644
--- a/src/IO/DataSources/Network.cpp
+++ b/src/IO/DataSources/Network.cpp
@@ -21,25 +21,34 @@
*/
#include "Network.h"
+#include
using namespace IO::DataSources;
-
static Network *INSTANCE = nullptr;
+/**
+ * Constructor function
+ */
Network::Network()
{
- setPort(0);
setHost("");
+ setPort(defaultPort());
setSocketType(QAbstractSocket::TcpSocket);
connect(&m_tcpSocket, &QTcpSocket::errorOccurred, this, &Network::onErrorOccurred);
connect(&m_udpSocket, &QTcpSocket::errorOccurred, this, &Network::onErrorOccurred);
}
+/**
+ * Destructor function
+ */
Network::~Network()
{
disconnectDevice();
}
+/**
+ * Returns the only instance of this class
+ */
Network *Network::getInstance()
{
if (!INSTANCE)
@@ -48,26 +57,75 @@ Network *Network::getInstance()
return INSTANCE;
}
+/**
+ * Returns the host address
+ */
QString Network::host() const
{
return m_host;
}
+/**
+ * Returns the network port number
+ */
quint16 Network::port() const
{
return m_port;
}
-bool Network::configurationOk() const
+/**
+ * Returns the current socket type as an index of the list returned by the @c socketType
+ * function.
+ */
+int Network::socketTypeIndex() const
{
- return port() >= 0 && !QHostAddress(host()).isNull();
+ switch (socketType())
+ {
+ case QAbstractSocket::TcpSocket:
+ return 0;
+ break;
+ case QAbstractSocket::UdpSocket:
+ return 1;
+ break;
+ default:
+ return -1;
+ break;
+ }
}
+/**
+ * Returns @c true if the port is greater than 0 and the host address is valid.
+ */
+bool Network::configurationOk() const
+{
+ return true;
+ // return port() > 0 && !QHostAddress(host()).isNull();
+}
+
+/**
+ * Returns a list with the available socket types
+ */
+QStringList Network::socketTypes() const
+{
+ return QStringList { "TCP", "UDP" };
+}
+
+/**
+ * Returns the socket type. Valid return values are:
+ *
+ * @c QAbstractSocket::TcpSocket
+ * @c QAbstractSocket::UdpSocket
+ * @c QAbstractSocket::SctpSocket
+ * @c QAbstractSocket::UnknownSocketType
+ */
QAbstractSocket::SocketType Network::socketType() const
{
return m_socketType;
}
+/**
+ * Attempts to make a connection to the given host, port and TCP/UDP socket type.
+ */
QIODevice *Network::openNetworkPort()
{
// Disconnect all sockets
@@ -76,59 +134,122 @@ QIODevice *Network::openNetworkPort()
// Init socket pointer
QAbstractSocket *socket = nullptr;
+ // Get host & port
+ auto hostAddr = host();
+ auto portAddr = port();
+ if (hostAddr.isEmpty())
+ hostAddr = defaultHost();
+ if (portAddr <= 0)
+ portAddr = defaultPort();
+
// TCP connection, assign socket pointer & connect to host
if (socketType() == QAbstractSocket::TcpSocket)
{
socket = &m_tcpSocket;
- m_tcpSocket.connectToHost(host(), port());
+ m_tcpSocket.connectToHost(hostAddr, portAddr);
}
// UDP connection, assign socket pointer & connect to host
else if (socketType() == QAbstractSocket::UdpSocket)
{
socket = &m_udpSocket;
- m_udpSocket.connectToHost(host(), port());
+ m_udpSocket.connectToHost(hostAddr, portAddr);
}
// Convert socket to IO device pointer
return static_cast(socket);
}
+/**
+ * Instructs the module to communicate via a TCP socket.
+ */
void Network::setTcpSocket()
{
setSocketType(QAbstractSocket::TcpSocket);
}
+/**
+ * Instructs the module to communicate via an UDP socket.
+ */
void Network::setUdpSocket()
{
setSocketType(QAbstractSocket::UdpSocket);
}
+/**
+ * Disconnects the TCP/UDP sockets from the host
+ */
void Network::disconnectDevice()
{
m_tcpSocket.disconnectFromHost();
m_udpSocket.disconnectFromHost();
}
+/**
+ * Sets the @c port number
+ */
void Network::setPort(const quint16 port)
{
m_port = port;
emit portChanged();
}
+/**
+ * Sets the IPv4 or IPv6 address specified by the input string representation
+ */
void Network::setHost(const QString &host)
{
m_host = host;
emit hostChanged();
}
+/**
+ * Changes the current socket type given an index of the list returned by the
+ * @c socketType() function.
+ */
+void Network::setSocketTypeIndex(const int index)
+{
+ switch (index)
+ {
+ case 0:
+ setTcpSocket();
+ break;
+ case 1:
+ setUdpSocket();
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * Changes the socket type. Valid input values are:
+ *
+ * @c QAbstractSocket::TcpSocket
+ * @c QAbstractSocket::UdpSocket
+ * @c QAbstractSocket::SctpSocket
+ * @c QAbstractSocket::UnknownSocketType
+ */
void Network::setSocketType(const QAbstractSocket::SocketType type)
{
m_socketType = type;
emit socketTypeChanged();
}
+/**
+ * This function is called whenever a socket error occurs, it disconnects the socket
+ * from the host and displays the error in a message box.
+ */
void Network::onErrorOccurred(const QAbstractSocket::SocketError socketError)
{
- qDebug() << socketError;
+ QString error;
+ if (socketType() == QAbstractSocket::TcpSocket)
+ error = m_tcpSocket.errorString();
+ else if (socketType() == QAbstractSocket::UdpSocket)
+ error = m_udpSocket.errorString();
+ else
+ error = QString::number(socketError);
+
+ Misc::Utilities::showMessageBox(tr("Socket error"), error);
+ disconnectDevice();
}
diff --git a/src/IO/DataSources/Network.h b/src/IO/DataSources/Network.h
index 14727cee..f6ebea50 100644
--- a/src/IO/DataSources/Network.h
+++ b/src/IO/DataSources/Network.h
@@ -1,23 +1,10 @@
/*
- * Copyright (c) 2020-2021 Alex Spataru
+ * Copyright (C) MATUSICA S.A. de C.V. - All Rights Reserved
*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ * Proprietary and confidential.
*
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
+ * Written by Alex Spataru , February 2021
*/
#ifndef IO_DATA_SOURCES_NETWORK_H
@@ -49,6 +36,19 @@ class Network : public QObject
READ socketType
WRITE setSocketType
NOTIFY socketTypeChanged)
+ Q_PROPERTY(int socketTypeIndex
+ READ socketTypeIndex
+ WRITE setSocketTypeIndex
+ NOTIFY socketTypeChanged)
+ Q_PROPERTY(QStringList socketTypes
+ READ socketTypes
+ CONSTANT)
+ Q_PROPERTY(QString defaultHost
+ READ defaultHost
+ CONSTANT)
+ Q_PROPERTY(quint16 defaultPort
+ READ defaultPort
+ CONSTANT)
// clang-format on
signals:
@@ -61,9 +61,15 @@ public:
QString host() const;
quint16 port() const;
+ int socketTypeIndex() const;
bool configurationOk() const;
+ QStringList socketTypes() const;
QAbstractSocket::SocketType socketType() const;
+ static QString defaultHost() { return "127.0.0.1"; }
+
+ static quint16 defaultPort() { return 23; }
+
QIODevice *openNetworkPort();
public slots:
@@ -72,6 +78,7 @@ public slots:
void disconnectDevice();
void setPort(const quint16 port);
void setHost(const QString &host);
+ void setSocketTypeIndex(const int index);
void setSocketType(const QAbstractSocket::SocketType type);
private slots:
diff --git a/src/IO/Manager.cpp b/src/IO/Manager.cpp
index f4245da3..9c326d02 100644
--- a/src/IO/Manager.cpp
+++ b/src/IO/Manager.cpp
@@ -271,17 +271,23 @@ QStringList Manager::dataSourcesList() const
*/
qint64 Manager::writeData(const QByteArray &data)
{
- // Write data to device
- qint64 bytes = 0;
- if (readWrite())
- bytes = device()->write(data);
+ if (connected())
+ {
+ qint64 bytes = device()->write(data);
- // Flash UI lights (if any)
- if (bytes > 0)
- emit tx();
+ if (bytes > 0)
+ {
+ auto writtenData = data;
+ writtenData.chop(data.length() - bytes);
- // Return number of bytes written
- return bytes;
+ emit tx();
+ emit dataSent(writtenData);
+ }
+
+ return bytes;
+ }
+
+ return -1;
}
/**
@@ -392,6 +398,9 @@ void Manager::setDataSource(const DataSource source)
// Change data source
m_dataSource = source;
emit dataSourceChanged();
+
+ // Log changes
+ LOG_INFO() << "Data source set to" << source;
}
/**
diff --git a/src/IO/Manager.h b/src/IO/Manager.h
index f2f15211..9077501c 100644
--- a/src/IO/Manager.h
+++ b/src/IO/Manager.h
@@ -80,6 +80,7 @@ signals:
void finishSequenceChanged();
void watchdogIntervalChanged();
void frameValidationRegexChanged();
+ void dataSent(const QByteArray &data);
void dataReceived(const QByteArray &data);
void frameReceived(const QByteArray &frame);
diff --git a/src/JSON/Generator.h b/src/JSON/Generator.h
index 6737a8e5..06fba6e1 100644
--- a/src/JSON/Generator.h
+++ b/src/JSON/Generator.h
@@ -100,6 +100,14 @@ public:
QString jsonMapFilepath() const;
OperationMode operationMode() const;
+ Q_INVOKABLE bool frameValid()
+ {
+ if (frame())
+ return frame()->groupCount() > 0;
+
+ return false;
+ }
+
public slots:
void loadJsonMap();
void setOperationMode(const OperationMode mode);