QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
StatusTextHandler.cc
Go to the documentation of this file.
1#include "StatusTextHandler.h"
2#include "MAVLinkLib.h"
4
5#include <QtCore/QTimer>
6#include <QtCore/QDateTime>
7
8QGC_LOGGING_CATEGORY(StatusTextHandlerLog, "MAVLink.StatusTextHandler")
9
10StatusText::StatusText(MAV_COMPONENT componentid, MAV_SEVERITY severity, const QString &text)
11 : m_compId(componentid)
12 , m_severity(severity)
13 , m_text(text)
14{
15 // qCDebug(StatusTextHandlerLog) << Q_FUNC_INFO << this;
16}
17
19{
20 switch (m_severity) {
21 case MAV_SEVERITY_EMERGENCY:
22 case MAV_SEVERITY_ALERT:
23 case MAV_SEVERITY_CRITICAL:
24 case MAV_SEVERITY_ERROR:
25 return true;
26
27 default:
28 return false;
29 }
30}
31
33 : QObject(parent)
34 , m_chunkedStatusTextTimer(new QTimer(this))
35{
36 // qCDebug(StatusTextHandlerLog) << Q_FUNC_INFO << this;
37
38 m_chunkedStatusTextTimer->setSingleShot(true);
39 m_chunkedStatusTextTimer->setInterval(1000);
40 (void) connect(m_chunkedStatusTextTimer, &QTimer::timeout, this, &StatusTextHandler::_chunkedStatusTextTimeout);
41}
42
44{
46
47 // qCDebug(StatusTextHandlerLog) << Q_FUNC_INFO << this;
48}
49
51{
52 // Warning: There is a bug in mavlink which causes mavlink_msg_statustext_get_text to work incorrect.
53 // It ends up copying crap off the end of the buffer, so don't use it for now.
54
55 mavlink_statustext_t statusText;
56 mavlink_msg_statustext_decode(&message, &statusText);
57
58 char buffer[MAVLINK_MSG_STATUSTEXT_FIELD_TEXT_LEN + 1];
59 memcpy(buffer, statusText.text, MAVLINK_MSG_STATUSTEXT_FIELD_TEXT_LEN);
60 buffer[MAVLINK_MSG_STATUSTEXT_FIELD_TEXT_LEN] = '\0';
61
62 return QString(buffer);
63}
64
66{
67 QString result;
68 for (const StatusText *message: messages()) {
69 (void) result.prepend(message->getFormattedText());
70 }
71
72 return result;
73}
74
76{
77 qDeleteAll(m_messages);
78 m_messages.clear();
79
80 if (m_criticalMessageCount != 0) {
81 m_criticalMessageCount = 0;
83 }
84}
85
86void StatusTextHandler::handleHTMLEscapedTextMessage(MAV_COMPONENT compId, MAV_SEVERITY severity, const QString &text, const QString &description)
87{
88 QString htmlText(text);
89
90 (void) htmlText.replace("\n", "<br/>");
91
92 // TODO: handle text + description separately in the UI
93 if (!description.isEmpty()) {
94 QString htmlDescription(description);
95 (void) htmlDescription.replace("\n", "<br/>");
96 (void) htmlText.append(QStringLiteral("<br/><small><small>"));
97 (void) htmlText.append(htmlDescription);
98 (void) htmlText.append(QStringLiteral("</small></small>"));
99 }
100
101 if (m_activeComponent == MAV_COMPONENT::MAV_COMPONENT_ENUM_END) {
102 m_activeComponent = compId;
103 }
104
105 if (compId != m_activeComponent) {
106 m_multiComp = true;
107 }
108
109 // Color the output depending on the message severity. We have 3 distinct cases:
110 // 1: If we have an ERROR or worse, make it bigger, bolder, and highlight it red.
111 // 2: If we have a warning or notice, just make it bold and color it orange.
112 // 3: Otherwise color it the standard color, white.
113 QString style;
114 switch (severity) {
115 case MAV_SEVERITY_EMERGENCY:
116 case MAV_SEVERITY_ALERT:
117 case MAV_SEVERITY_CRITICAL:
118 case MAV_SEVERITY_ERROR:
119 style = QStringLiteral("<#E>");
120 break;
121
122 case MAV_SEVERITY_NOTICE:
123 case MAV_SEVERITY_WARNING:
124 style = QStringLiteral("<#I>");
125 break;
126
127 default:
128 style = QStringLiteral("<#N>");
129 break;
130 }
131
132 QString severityText;
133 switch (severity) {
134 case MAV_SEVERITY_EMERGENCY:
135 severityText = tr("EMERGENCY");
136 break;
137
138 case MAV_SEVERITY_ALERT:
139 severityText = tr("ALERT");
140 break;
141
142 case MAV_SEVERITY_CRITICAL:
143 severityText = tr("Critical");
144 break;
145
146 case MAV_SEVERITY_ERROR:
147 severityText = tr("Error");
148 break;
149
150 case MAV_SEVERITY_WARNING:
151 severityText = tr("Warning");
152 break;
153
154 case MAV_SEVERITY_NOTICE:
155 severityText = tr("Notice");
156 break;
157
158 case MAV_SEVERITY_INFO:
159 severityText = tr("Info");
160 break;
161
162 case MAV_SEVERITY_DEBUG:
163 severityText = tr("Debug");
164 break;
165
166 default:
167 qCWarning(StatusTextHandlerLog) << Q_FUNC_INFO << "Invalid MAV_SEVERITY";
168 break;
169 }
170
171 QString compString;
172 if (m_multiComp) {
173 compString = QString("COMP:%1").arg(compId);
174 }
175
176 const QString dateString = QDateTime::currentDateTime().toString("hh:mm:ss.zzz");
177
178 const QString formatText = QString("<font style=\"%1\">[%2 %3] %4: %5</font><br/>").arg(style, dateString, compString, severityText, htmlText);
179
180 StatusText* const message = new StatusText(compId, severity, text);
181 message->setFormatedText(formatText);
182
183 emit newFormattedMessage(formatText);
184
185 (void) m_messages.append(message);
186
187 if (message->severityIsError()) {
188 m_criticalMessageCount++;
190 emit newErrorMessage(message->getText());
191 }
192}
193
195{
196 if (message.msgid != MAVLINK_MSG_ID_STATUSTEXT) {
197 return;
198 }
199
200 _handleStatusText(message);
201}
202
203void StatusTextHandler::_handleStatusText(const mavlink_message_t &message)
204{
205 mavlink_statustext_t statustext;
206 mavlink_msg_statustext_decode(&message, &statustext);
207
208 const QString messageText = getMessageText(message);
209 const bool includesNullTerminator = messageText.length() < MAVLINK_MSG_STATUSTEXT_FIELD_TEXT_LEN;
210
211 const MAV_COMPONENT compId = static_cast<MAV_COMPONENT>(message.compid);
212 if (m_chunkedStatusTextInfoMap.contains(compId) && (m_chunkedStatusTextInfoMap.value(compId).chunkId != statustext.id)) {
213 // We have an incomplete chunked status still pending
214 (void) m_chunkedStatusTextInfoMap.value(compId).rgMessageChunks.append(QString());
215 _chunkedStatusTextCompleted(compId);
216 }
217
218 if (statustext.id == 0) {
219 // Non-chunked status text. We still use common chunked text output mechanism.
220 ChunkedStatusTextInfo_t chunkedInfo;
221 chunkedInfo.chunkId = 0;
222 chunkedInfo.severity = static_cast<MAV_SEVERITY>(statustext.severity);
223 (void) chunkedInfo.rgMessageChunks.append(messageText);
224 (void) m_chunkedStatusTextInfoMap.insert(compId, chunkedInfo);
225 } else {
226 if (m_chunkedStatusTextInfoMap.contains(compId)) {
227 // A chunk sequence is in progress
228 QStringList& chunks = m_chunkedStatusTextInfoMap[compId].rgMessageChunks;
229 if (statustext.chunk_seq > chunks.size()) {
230 // We are missing some chunks in between, fill them in as missing
231 for (size_t i = chunks.size(); i < statustext.chunk_seq; i++) {
232 (void) chunks.append(QString());
233 }
234 }
235
236 (void) chunks.append(messageText);
237 } else {
238 // Starting a new chunk sequence
239 ChunkedStatusTextInfo_t chunkedInfo;
240 chunkedInfo.chunkId = statustext.id;
241 chunkedInfo.severity = static_cast<MAV_SEVERITY>(statustext.severity);
242 (void) chunkedInfo.rgMessageChunks.append(messageText);
243 (void) m_chunkedStatusTextInfoMap.insert(compId, chunkedInfo);
244 }
245
246 m_chunkedStatusTextTimer->start();
247 }
248
249 if ((statustext.id == 0) || includesNullTerminator) {
250 m_chunkedStatusTextTimer->stop();
251 _chunkedStatusTextCompleted(compId);
252 }
253}
254
255void StatusTextHandler::_chunkedStatusTextTimeout()
256{
257 for (auto compId : m_chunkedStatusTextInfoMap.keys()) {
258 auto& chunkedInfo = m_chunkedStatusTextInfoMap[compId];
259 (void) chunkedInfo.rgMessageChunks.append(QString());
260 _chunkedStatusTextCompleted(compId);
261 }
262}
263
264void StatusTextHandler::_chunkedStatusTextCompleted(MAV_COMPONENT compId)
265{
266 const ChunkedStatusTextInfo_t& chunkedInfo = m_chunkedStatusTextInfoMap.value(compId);
267 const MAV_SEVERITY severity = chunkedInfo.severity;
268
269 QString messageText;
270 for (const QString& chunk : std::as_const(chunkedInfo.rgMessageChunks)) {
271 if (chunk.isEmpty()) {
272 (void) messageText.append(tr(" ... ", "Indicates missing chunk from chunked STATUS_TEXT"));
273 } else {
274 (void) messageText.append(chunk);
275 }
276 }
277
278 (void) m_chunkedStatusTextInfoMap.remove(compId);
279
280 emit textMessageReceived(compId, severity, messageText, "");
281}
struct __mavlink_message mavlink_message_t
#define QGC_LOGGING_CATEGORY(name, categoryStr)
std::array< MsgOutKey, 4 > keys
Definition UBXPlan.cc:13
void criticalMessageCountChanged()
StatusTextHandler(QObject *parent=nullptr)
void handleHTMLEscapedTextMessage(MAV_COMPONENT componentid, MAV_SEVERITY severity, const QString &text, const QString &description)
const QList< StatusText * > & messages() const
void newErrorMessage(QString message)
static QString getMessageText(const mavlink_message_t &message)
void mavlinkMessageReceived(const mavlink_message_t &message)
void textMessageReceived(MAV_COMPONENT componentid, MAV_SEVERITY severity, QString text, QString description)
void newFormattedMessage(QString message)
QString formattedMessages() const
bool severityIsError() const
void setFormatedText(const QString &formatedText)
QString getText() const