5#include <QtStateMachine/QAbstractState>
10 obj[
"timestamp"] =
timestamp.toString(Qt::ISODateWithMs);
12 obj[
"reason"] =
static_cast<int>(
reason);
23 case Entered: reasonStr =
"ENTER";
break;
24 case Exited: reasonStr =
"EXIT";
break;
25 case Timeout: reasonStr =
"TIMEOUT";
break;
26 case Error: reasonStr =
"ERROR";
break;
27 case Signal: reasonStr =
"SIGNAL";
break;
28 case Event: reasonStr =
"EVENT";
break;
29 default: reasonStr =
"?";
break;
32 QString result = QStringLiteral(
"[%1] %2 %3")
33 .arg(timestamp.toString(
"HH:mm:ss.zzz"), reasonStr, stateName);
34 if (!details.isEmpty()) {
35 result += QStringLiteral(
" (%1)").arg(details);
49 if (_enabled == enabled) {
57 const auto states = _machine->findChildren<QAbstractState*>();
58 for (QAbstractState* state : states) {
59 _connectToState(state);
63 for (
const auto& conn : _connections) {
70void StateHistoryRecorder::_connectToState(QAbstractState* state)
72 auto enterConn = connect(state, &QAbstractState::entered,
73 this, &StateHistoryRecorder::_onStateEntered);
74 auto exitConn = connect(state, &QAbstractState::exited,
75 this, &StateHistoryRecorder::_onStateExited);
76 _connections.append(enterConn);
77 _connections.append(exitConn);
85 while (_history.size() > _maxEntries) {
86 _history.removeFirst();
97 if (n >= _history.size()) {
100 return _history.mid(_history.size() - n);
105 QList<HistoryEntry> result;
106 for (
const auto& entry : _history) {
107 if (entry.stateName == stateName) {
108 result.append(entry);
117 lines << QStringLiteral(
"=== State History: %1 ===").arg(_machine->objectName());
118 lines << QStringLiteral(
"Entries: %1 / %2").arg(_history.size()).arg(_maxEntries);
121 for (
const auto& entry : _history) {
122 lines << entry.toString();
125 return lines.join(
'\n');
131 for (
const auto& entry : _history) {
132 array.append(entry.toJson());
140 for (
const QString& line : lines) {
141 if (!line.isEmpty()) {
142 qCDebug(QGCStateMachineLog) << line;
148 const QString& details)
150 if (!_enabled)
return;
153 entry.
timestamp = QDateTime::currentDateTime();
161void StateHistoryRecorder::_addEntry(
const HistoryEntry& entry)
163 _history.append(entry);
166 while (_history.size() > _maxEntries) {
167 _history.removeFirst();
171void StateHistoryRecorder::_onStateEntered()
173 if (!_enabled)
return;
175 auto* state = qobject_cast<QAbstractState*>(sender());
179 entry.timestamp = QDateTime::currentDateTime();
180 entry.stateName = state->objectName();
186void StateHistoryRecorder::_onStateExited()
188 if (!_enabled)
return;
190 auto* state = qobject_cast<QAbstractState*>(sender());
194 entry.timestamp = QDateTime::currentDateTime();
195 entry.stateName = state->objectName();
QGroundControl specific state machine with enhanced error handling.
void setMaxEntries(int max)
Set the maximum number of entries to keep (circular buffer)
QString dumpHistory() const
Get a human-readable dump of the history.
void addEntry(const QString &stateName, TransitionReason reason, const QString &details=QString())
Manually add an entry (for custom transition types)
QList< HistoryEntry > entriesForState(const QString &stateName) const
Get entries for a specific state.
QJsonArray toJson() const
Export history as JSON array.
StateHistoryRecorder(QGCStateMachine *machine, int maxEntries=1000)
void clear()
Clear all recorded history.
void setEnabled(bool enabled)
Enable or disable recording.
QList< HistoryEntry > lastEntries(int n) const
Get the last N entries.
TransitionReason
Reason for a state transition.
@ Timeout
Transition due to timeout.
@ Error
Transition due to error.
@ Signal
Transition triggered by signal.
@ Event
Transition triggered by event.
@ Entered
State was entered.
@ Exited
State was exited.
void logHistory() const
Log history to debug output.
A recorded state transition entry.
QJsonObject toJson() const