Commit 0064bb76 authored by Gus Grubba's avatar Gus Grubba

Merge pull request #2733 from dogmaphobic/wifibridgeStatus

Adding (optional) link status data to the WiFi Bridge panel.
parents 7c360bc9 0af5efd4
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
import QtQuick 2.5 import QtQuick 2.5
import QtQuick.Controls 1.2 import QtQuick.Controls 1.2
import QtQuick.Dialogs 1.2 import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.2
import QGroundControl 1.0 import QGroundControl 1.0
import QGroundControl.FactSystem 1.0 import QGroundControl.FactSystem 1.0
...@@ -42,12 +43,70 @@ QGCView { ...@@ -42,12 +43,70 @@ QGCView {
property int _firstColumn: ScreenTools.defaultFontPixelWidth * 20 property int _firstColumn: ScreenTools.defaultFontPixelWidth * 20
property int _secondColumn: ScreenTools.defaultFontPixelWidth * 12 property int _secondColumn: ScreenTools.defaultFontPixelWidth * 12
readonly property string dialogTitle: "controller WiFi Bridge" readonly property string dialogTitle: "controller WiFi Bridge"
property int stStatus: XMLHttpRequest.UNSENT
property int stErrorCount: 0
property bool stEnabled: false
property bool stResetCounters: false
ESP8266ComponentController { ESP8266ComponentController {
id: controller id: controller
factPanel: panel factPanel: panel
} }
Timer {
id: timer
}
function thisThingHasNoNumberLocaleSupport(n) {
return n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",").replace(",,", ",")
}
function updateStatus() {
timer.stop()
var req = new XMLHttpRequest;
var url = "http://192.168.4.1/status.json"
if(stResetCounters) {
url = url + "?r=1"
stResetCounters = false
}
req.open("GET", url);
req.onreadystatechange = function() {
stStatus = req.readyState;
if (stStatus === XMLHttpRequest.DONE) {
var objectArray = JSON.parse(req.responseText);
if (objectArray.errors !== undefined) {
console.log("Error fetching WiFi Bridge Status: " + objectArray.errors[0].message)
stErrorCount = stErrorCount + 1
if(stErrorCount < 2 && stEnabled)
timer.start()
} else {
if(stEnabled) {
//-- This should work but it doesn't
// var n = 34523453.345
// n.toLocaleString()
// "34,523,453.345"
vpackets.text = thisThingHasNoNumberLocaleSupport(objectArray["vpackets"])
vsent.text = thisThingHasNoNumberLocaleSupport(objectArray["vsent"])
vlost.text = thisThingHasNoNumberLocaleSupport(objectArray["vlost"])
gpackets.text = thisThingHasNoNumberLocaleSupport(objectArray["gpackets"])
gsent.text = thisThingHasNoNumberLocaleSupport(objectArray["gsent"])
glost.text = thisThingHasNoNumberLocaleSupport(objectArray["glost"])
stErrorCount = 0
wifiStatus.visible = true
timer.start()
}
}
}
}
req.send()
}
Component.onCompleted: {
timer.interval = 1000
timer.repeat = true
timer.triggered.connect(updateStatus)
}
property Fact wifiChannel: controller.getParameterFact(controller.componentID, "WIFI_CHANNEL") property Fact wifiChannel: controller.getParameterFact(controller.componentID, "WIFI_CHANNEL")
property Fact hostPort: controller.getParameterFact(controller.componentID, "WIFI_UDP_HPORT") property Fact hostPort: controller.getParameterFact(controller.componentID, "WIFI_UDP_HPORT")
property Fact clientPort: controller.getParameterFact(controller.componentID, "WIFI_UDP_CPORT") property Fact clientPort: controller.getParameterFact(controller.componentID, "WIFI_UDP_CPORT")
...@@ -76,97 +135,228 @@ QGCView { ...@@ -76,97 +135,228 @@ QGCView {
Rectangle { Rectangle {
width: parent.width width: parent.width
height: wifiCol.height + (ScreenTools.defaultFontPixelHeight * 2) height: wifiStatus.visible ? Math.max(wifiCol.height, wifiStatus.height) + (ScreenTools.defaultFontPixelHeight * 2) : wifiCol.height + (ScreenTools.defaultFontPixelHeight * 2)
color: palette.windowShade color: palette.windowShade
Column { Row {
id: wifiCol
anchors.margins: ScreenTools.defaultFontPixelHeight / 2
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left spacing: ScreenTools.defaultFontPixelWidth
spacing: ScreenTools.defaultFontPixelHeight / 2 Rectangle {
Row { height: parent.height
spacing: ScreenTools.defaultFontPixelWidth width: 1
QGCLabel { color: palette.window
text: "WiFi Channel" }
width: _firstColumn Column {
anchors.baseline: channelField.baseline id: wifiCol
anchors.verticalCenter: parent.verticalCenter
spacing: ScreenTools.defaultFontPixelHeight / 2
Row {
spacing: ScreenTools.defaultFontPixelWidth
QGCLabel {
text: "WiFi Channel"
width: _firstColumn
anchors.baseline: channelField.baseline
}
QGCComboBox {
id: channelField
width: _secondColumn
model: controller.wifiChannels
currentIndex: wifiChannel ? wifiChannel.value - 1 : 0
onActivated: {
wifiChannel.value = index + 1
}
}
} }
QGCComboBox { Row {
id: channelField spacing: ScreenTools.defaultFontPixelWidth
width: _secondColumn QGCLabel {
model: controller.wifiChannels text: "WiFi SSID"
currentIndex: wifiChannel ? wifiChannel.value - 1 : 0 width: _firstColumn
onActivated: { anchors.baseline: ssidField.baseline
wifiChannel.value = index + 1 }
QGCTextField {
id: ssidField
width: _secondColumn
text: controller.wifiSSID
maximumLength: 16
onEditingFinished: {
controller.wifiSSID = text
}
} }
} }
} Row {
Row { spacing: ScreenTools.defaultFontPixelWidth
spacing: ScreenTools.defaultFontPixelWidth QGCLabel {
QGCLabel { text: "WiFi Password"
text: "WiFi SSID" width: _firstColumn
width: _firstColumn anchors.baseline: passwordField.baseline
anchors.baseline: ssidField.baseline }
QGCTextField {
id: passwordField
width: _secondColumn
text: controller.wifiPassword
maximumLength: 16
onEditingFinished: {
controller.wifiPassword = text
}
} }
QGCTextField { }
id: ssidField Row {
width: _secondColumn spacing: ScreenTools.defaultFontPixelWidth
text: controller.wifiSSID QGCLabel {
maximumLength: 16 text: "UART Baud Rate"
onEditingFinished: { width: _firstColumn
controller.wifiSSID = text anchors.baseline: baudField.baseline
}
QGCComboBox {
id: baudField
width: _secondColumn
model: controller.baudRates
currentIndex: controller.baudIndex
onActivated: {
controller.baudIndex = index
}
} }
} }
Row {
spacing: ScreenTools.defaultFontPixelWidth
QGCLabel {
text: "QGC UDP Port"
width: _firstColumn
anchors.baseline: qgcportField.baseline
}
QGCTextField {
id: qgcportField
width: _secondColumn
text: hostPort ? hostPort.valueString : ""
validator: IntValidator {bottom: 1024; top: 65535;}
inputMethodHints: Qt.ImhDigitsOnly
onEditingFinished: {
hostPort.value = text
}
}
}
}
Rectangle {
height: parent.height
width: 1
color: palette.text
visible: wifiStatus.visible
} }
Row { Column {
spacing: ScreenTools.defaultFontPixelWidth id: wifiStatus
anchors.margins: ScreenTools.defaultFontPixelHeight / 2
spacing: ScreenTools.defaultFontPixelHeight / 2
visible: false
QGCLabel { QGCLabel {
text: "WiFi Password" text: "Bridge/Vehicle Link"
width: _firstColumn font.weight: Font.DemiBold
anchors.baseline: passwordField.baseline }
Row {
spacing: ScreenTools.defaultFontPixelWidth
QGCLabel {
text: "Messages Received"
width: _firstColumn
} }
QGCTextField { QGCLabel {
id: passwordField id: vpackets
width: _secondColumn
text: controller.wifiPassword
maximumLength: 16
onEditingFinished: {
controller.wifiPassword = text
} }
} }
} Row {
Row { spacing: ScreenTools.defaultFontPixelWidth
spacing: ScreenTools.defaultFontPixelWidth QGCLabel {
text: "Messages Lost"
width: _firstColumn
}
QGCLabel {
id: vlost
}
}
Row {
spacing: ScreenTools.defaultFontPixelWidth
QGCLabel {
text: "Messages Sent"
width: _firstColumn
}
QGCLabel {
id: vsent
}
}
Rectangle {
height: 1
width: parent.width
color: palette.text
}
QGCLabel { QGCLabel {
text: "UART Baud Rate" text: "Bridge/QGC Link"
width: _firstColumn font.weight: Font.DemiBold
anchors.baseline: baudField.baseline
} }
QGCComboBox { Row {
id: baudField spacing: ScreenTools.defaultFontPixelWidth
width: _secondColumn QGCLabel {
model: controller.baudRates text: "Messages Received"
currentIndex: controller.baudIndex width: _firstColumn
onActivated: { }
controller.baudIndex = index QGCLabel {
id: gpackets
} }
} }
} Row {
Row { spacing: ScreenTools.defaultFontPixelWidth
spacing: ScreenTools.defaultFontPixelWidth QGCLabel {
text: "Messages Lost"
width: _firstColumn
}
QGCLabel {
id: glost
}
}
Row {
spacing: ScreenTools.defaultFontPixelWidth
QGCLabel {
text: "Messages Sent"
width: _firstColumn
}
QGCLabel {
id: gsent
}
}
Rectangle {
height: 1
width: parent.width
color: palette.text
}
QGCLabel { QGCLabel {
text: "QGC UDP Port" text: "QGC/Bridge Link"
width: _firstColumn font.weight: Font.DemiBold
anchors.baseline: qgcportField.baseline }
Row {
spacing: ScreenTools.defaultFontPixelWidth
QGCLabel {
text: "Messages Received"
width: _firstColumn
}
QGCLabel {
text: controller.vehicle ? thisThingHasNoNumberLocaleSupport(controller.vehicle.messagesReceived) : 0
}
}
Row {
spacing: ScreenTools.defaultFontPixelWidth
QGCLabel {
text: "Messages Lost"
width: _firstColumn
}
QGCLabel {
text: controller.vehicle ? thisThingHasNoNumberLocaleSupport(controller.vehicle.messagesLost) : 0
}
} }
QGCTextField { Row {
id: qgcportField spacing: ScreenTools.defaultFontPixelWidth
width: _secondColumn QGCLabel {
text: hostPort ? hostPort.valueString : "" text: "Messages Sent"
validator: IntValidator {bottom: 1024; top: 65535;} width: _firstColumn
inputMethodHints: Qt.ImhDigitsOnly }
onEditingFinished: { QGCLabel {
hostPort.value = text text: controller.vehicle ? thisThingHasNoNumberLocaleSupport(controller.vehicle.messagesSent) : 0
} }
} }
} }
...@@ -204,6 +394,31 @@ QGCView { ...@@ -204,6 +394,31 @@ QGCView {
} }
} }
} }
QGCButton {
text: stEnabled ? "Hide Status" : "Show Status"
width: ScreenTools.defaultFontPixelWidth * 16
onClicked: {
stEnabled = !stEnabled
if(stEnabled)
updateStatus()
else {
wifiStatus.visible = false
timer.stop()
}
}
}
QGCButton {
text: "Reset Counters"
visible: stEnabled
enabled: stEnabled
width: ScreenTools.defaultFontPixelWidth * 16
onClicked: {
stResetCounters = true;
updateStatus()
if(controller.vehicle)
controller.vehicle.resetCounters()
}
}
} }
} }
} }
......
...@@ -58,9 +58,10 @@ public: ...@@ -58,9 +58,10 @@ public:
Q_PROPERTY(QStringList baudRates READ baudRates CONSTANT) Q_PROPERTY(QStringList baudRates READ baudRates CONSTANT)
Q_PROPERTY(int baudIndex READ baudIndex WRITE setBaudIndex NOTIFY baudIndexChanged) Q_PROPERTY(int baudIndex READ baudIndex WRITE setBaudIndex NOTIFY baudIndexChanged)
Q_PROPERTY(bool busy READ busy NOTIFY busyChanged) Q_PROPERTY(bool busy READ busy NOTIFY busyChanged)
Q_PROPERTY(Vehicle* vehicle READ vehicle CONSTANT)
Q_INVOKABLE void restoreDefaults(); Q_INVOKABLE void restoreDefaults();
Q_INVOKABLE void reboot(); Q_INVOKABLE void reboot ();
int componentID () { return MAV_COMP_ID_UDP_BRIDGE; } int componentID () { return MAV_COMP_ID_UDP_BRIDGE; }
QString version (); QString version ();
...@@ -70,6 +71,7 @@ public: ...@@ -70,6 +71,7 @@ public:
QStringList baudRates () { return _baudRates; } QStringList baudRates () { return _baudRates; }
int baudIndex (); int baudIndex ();
bool busy () { return _waitType != WAIT_FOR_NOTHING; } bool busy () { return _waitType != WAIT_FOR_NOTHING; }
Vehicle* vehicle () { return _vehicle; }
void setWifiSSID (QString id); void setWifiSSID (QString id);
void setWifiPassword (QString pwd); void setWifiPassword (QString pwd);
......
...@@ -111,6 +111,12 @@ Vehicle::Vehicle(LinkInterface* link, ...@@ -111,6 +111,12 @@ Vehicle::Vehicle(LinkInterface* link,
, _joystickManager(joystickManager) , _joystickManager(joystickManager)
, _flowImageIndex(0) , _flowImageIndex(0)
, _allLinksInactiveSent(false) , _allLinksInactiveSent(false)
, _messagesReceived(0)
, _messagesSent(0)
, _messagesLost(0)
, _messageSeq(0)
, _compID(0)
, _heardFrom(false)
{ {
_addLink(link); _addLink(link);
...@@ -215,6 +221,16 @@ Vehicle::~Vehicle() ...@@ -215,6 +221,16 @@ Vehicle::~Vehicle()
} }
void
Vehicle::resetCounters()
{
_messagesReceived = 0;
_messagesSent = 0;
_messagesLost = 0;
_messageSeq = 0;
_heardFrom = false;
}
void Vehicle::_mavlinkMessageReceived(LinkInterface* link, mavlink_message_t message) void Vehicle::_mavlinkMessageReceived(LinkInterface* link, mavlink_message_t message)
{ {
if (message.sysid != _id && message.sysid != 0) { if (message.sysid != _id && message.sysid != 0) {
...@@ -225,6 +241,32 @@ void Vehicle::_mavlinkMessageReceived(LinkInterface* link, mavlink_message_t mes ...@@ -225,6 +241,32 @@ void Vehicle::_mavlinkMessageReceived(LinkInterface* link, mavlink_message_t mes
_addLink(link); _addLink(link);
} }
//-- Check link status
_messagesReceived++;
emit messagesReceivedChanged();
if(!_heardFrom) {
if(message.msgid == MAVLINK_MSG_ID_HEARTBEAT) {
_heardFrom = true;
_compID = message.compid;
_messageSeq = message.seq + 1;
}
} else {
if(_compID == message.compid) {
uint16_t seq_received = (uint16_t)message.seq;
uint16_t packet_lost_count = 0;
//-- Account for overflow during packet loss
if(seq_received < _messageSeq) {
packet_lost_count = (seq_received + 255) - _messageSeq;
} else {
packet_lost_count = seq_received - _messageSeq;
}
_messageSeq = message.seq + 1;
_messagesLost += packet_lost_count;
if(packet_lost_count)
emit messagesLostChanged();
}
}
// Give the plugin a change to adjust the message contents // Give the plugin a change to adjust the message contents
_firmwarePlugin->adjustMavlinkMessage(this, &message); _firmwarePlugin->adjustMavlinkMessage(this, &message);
...@@ -471,6 +513,8 @@ void Vehicle::_sendMessageOnLink(LinkInterface* link, mavlink_message_t message) ...@@ -471,6 +513,8 @@ void Vehicle::_sendMessageOnLink(LinkInterface* link, mavlink_message_t message)
int len = mavlink_msg_to_send_buffer(buffer, &message); int len = mavlink_msg_to_send_buffer(buffer, &message);
link->writeBytes((const char*)buffer, len); link->writeBytes((const char*)buffer, len);
_messagesSent++;
emit messagesSentChanged();
} }
void Vehicle::_sendMessage(mavlink_message_t message) void Vehicle::_sendMessage(mavlink_message_t message)
...@@ -1269,8 +1313,8 @@ void Vehicle::_connectionLostTimeout(void) ...@@ -1269,8 +1313,8 @@ void Vehicle::_connectionLostTimeout(void)
{ {
if (_connectionLostEnabled && !_connectionLost) { if (_connectionLostEnabled && !_connectionLost) {
_connectionLost = true; _connectionLost = true;
_heardFrom = false;
emit connectionLostChanged(true); emit connectionLostChanged(true);
_say(QString("connection lost to vehicle %1").arg(id()), GAudioOutput::AUDIO_SEVERITY_NOTICE); _say(QString("connection lost to vehicle %1").arg(id()), GAudioOutput::AUDIO_SEVERITY_NOTICE);
} }
} }
...@@ -1278,11 +1322,9 @@ void Vehicle::_connectionLostTimeout(void) ...@@ -1278,11 +1322,9 @@ void Vehicle::_connectionLostTimeout(void)
void Vehicle::_connectionActive(void) void Vehicle::_connectionActive(void)
{ {
_connectionLostTimer.start(); _connectionLostTimer.start();
if (_connectionLost) { if (_connectionLost) {
_connectionLost = false; _connectionLost = false;
emit connectionLostChanged(false); emit connectionLostChanged(false);
_say(QString("connection regained to vehicle %1").arg(id()), GAudioOutput::AUDIO_SEVERITY_NOTICE); _say(QString("connection regained to vehicle %1").arg(id()), GAudioOutput::AUDIO_SEVERITY_NOTICE);
} }
} }
......
...@@ -119,6 +119,12 @@ public: ...@@ -119,6 +119,12 @@ public:
Q_PROPERTY(bool genericFirmware READ genericFirmware CONSTANT) Q_PROPERTY(bool genericFirmware READ genericFirmware CONSTANT)
Q_PROPERTY(bool connectionLost READ connectionLost NOTIFY connectionLostChanged) Q_PROPERTY(bool connectionLost READ connectionLost NOTIFY connectionLostChanged)
Q_PROPERTY(bool connectionLostEnabled READ connectionLostEnabled WRITE setConnectionLostEnabled NOTIFY connectionLostEnabledChanged) Q_PROPERTY(bool connectionLostEnabled READ connectionLostEnabled WRITE setConnectionLostEnabled NOTIFY connectionLostEnabledChanged)
Q_PROPERTY(uint messagesReceived READ messagesReceived NOTIFY messagesReceivedChanged)
Q_PROPERTY(uint messagesSent READ messagesSent NOTIFY messagesSentChanged)
Q_PROPERTY(uint messagesLost READ messagesLost NOTIFY messagesLostChanged)
/// Resets link status counters
Q_INVOKABLE void resetCounters ();
/// Returns the number of buttons which are reserved for firmware use in the MANUAL_CONTROL mavlink /// Returns the number of buttons which are reserved for firmware use in the MANUAL_CONTROL mavlink
/// message. For example PX4 Flight Stack reserves the first 8 buttons to simulate rc switches. /// message. For example PX4 Flight Stack reserves the first 8 buttons to simulate rc switches.
...@@ -275,6 +281,9 @@ public: ...@@ -275,6 +281,9 @@ public:
bool genericFirmware () { return !px4Firmware() && !apmFirmware(); } bool genericFirmware () { return !px4Firmware() && !apmFirmware(); }
bool connectionLost () const { return _connectionLost; } bool connectionLost () const { return _connectionLost; }
bool connectionLostEnabled() const { return _connectionLostEnabled; } bool connectionLostEnabled() const { return _connectionLostEnabled; }
uint messagesReceived () { return _messagesReceived; }
uint messagesSent () { return _messagesSent; }
uint messagesLost () { return _messagesLost; }
void setConnectionLostEnabled(bool connectionLostEnabled); void setConnectionLostEnabled(bool connectionLostEnabled);
...@@ -305,6 +314,10 @@ signals: ...@@ -305,6 +314,10 @@ signals:
void connectionLostChanged(bool connectionLost); void connectionLostChanged(bool connectionLost);
void connectionLostEnabledChanged(bool connectionLostEnabled); void connectionLostEnabledChanged(bool connectionLostEnabled);
void messagesReceivedChanged ();
void messagesSentChanged ();
void messagesLostChanged ();
/// Used internally to move sendMessage call to main thread /// Used internally to move sendMessage call to main thread
void _sendMessageOnThread(mavlink_message_t message); void _sendMessageOnThread(mavlink_message_t message);
void _sendMessageOnLinkOnThread(LinkInterface* link, mavlink_message_t message); void _sendMessageOnLinkOnThread(LinkInterface* link, mavlink_message_t message);
...@@ -506,6 +519,13 @@ private: ...@@ -506,6 +519,13 @@ private:
bool _allLinksInactiveSent; ///< true: allLinkInactive signal already sent one time bool _allLinksInactiveSent; ///< true: allLinkInactive signal already sent one time
uint _messagesReceived;
uint _messagesSent;
uint _messagesLost;
uint8_t _messageSeq;
uint8_t _compID;
bool _heardFrom;
// Settings keys // Settings keys
static const char* _settingsGroup; static const char* _settingsGroup;
static const char* _joystickModeSettingsKey; static const char* _joystickModeSettingsKey;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment