Generate XML tags for every serial port connection event.

This commit is contained in:
sawinglogz 2020-06-12 16:44:07 -04:00
parent 3210ecd1ba
commit 1630051dd1
2 changed files with 149 additions and 58 deletions

View File

@ -418,10 +418,6 @@ QList<SerialPortInfo> DeviceConnectionManager::getAvailablePorts()
} }
// TODO: Once we start recording/replaying connections, we'll need to include a version number, so that
// if we ever have to change the download code, the older replays will still work as expected.
// MARK: - // MARK: -
// MARK: Serial port info // MARK: Serial port info
@ -526,30 +522,63 @@ bool SerialPortInfo::operator==(const SerialPortInfo & other) const
// MARK: - // MARK: -
// MARK: Serial port connection // MARK: Serial port connection
// TODO: log these to XML // TODO: log these to XML stream
class SetValueEvent class SerialPortEvent
{ {
public: public:
SetValueEvent(const QString & name, int value) SerialPortEvent(const QString & tag)
: m_tag(tag)
{ {
set(name, value);
} }
void set(const QString & name, int value) void set(const QString & name, const QString & value)
{ {
m_values[name] = value; m_values[name] = value;
m_keys.append(name); m_keys.append(name);
} }
void set(const QString & name, qint64 value)
{
set(name, QString::number(value));
}
void checkResult(bool ok, QSerialPort::SerialPortError error)
{
if (ok && error == QSerialPort::NoError) return;
set("error", error);
if (ok) set("ok", ok); // we don't expect to see this, but we should know if it happens
}
void checkResult(qint64 len, QSerialPort::SerialPortError error)
{
if (len < 0 || error != QSerialPort::NoError) {
set("error", error);
}
}
void checkError(QSerialPort::SerialPortError error) {
if (error != QSerialPort::NoError) {
set("error", error);
}
}
inline bool ok() const { return m_values.contains("error") == false; } inline bool ok() const { return m_values.contains("error") == false; }
operator QString() const; operator QString() const;
protected: protected:
QHash<QString,int> m_values; const QString m_tag;
QHash<QString,QString> m_values;
QList<QString> m_keys; QList<QString> m_keys;
friend QXmlStreamWriter & operator<<(QXmlStreamWriter & xml, const SetValueEvent & event); QString m_data;
friend QXmlStreamWriter & operator<<(QXmlStreamWriter & xml, const SerialPortEvent & event);
}; };
SetValueEvent::operator QString() const class SetValueEvent : public SerialPortEvent
{
public:
SetValueEvent(const QString & name, int value)
: SerialPortEvent("set")
{
set(name, value);
}
};
SerialPortEvent::operator QString() const
{ {
QString out; QString out;
QXmlStreamWriter xml(&out); QXmlStreamWriter xml(&out);
@ -557,16 +586,36 @@ SetValueEvent::operator QString() const
return out; return out;
} }
QXmlStreamWriter & operator<<(QXmlStreamWriter & xml, const SetValueEvent & event) QXmlStreamWriter & operator<<(QXmlStreamWriter & xml, const SerialPortEvent & event)
{ {
xml.writeStartElement("set"); xml.writeStartElement(event.m_tag);
for (auto key : event.m_keys) { for (auto key : event.m_keys) {
xml.writeAttribute(key, QString::number(event.m_values[key])); xml.writeAttribute(key, event.m_values[key]);
}
if (!event.m_data.isEmpty()) {
xml.writeCharacters(event.m_data);
} }
xml.writeEndElement(); xml.writeEndElement();
return xml; return xml;
} }
class DataTransferEvent : public SerialPortEvent
{
public:
DataTransferEvent(const QString & tag)
: SerialPortEvent(tag)
{
}
void setData(const char* data, qint64 length)
{
QStringList bytes;
for (qint64 i = 0; i < length; i++) {
bytes.append(QString("%1").arg((unsigned char) data[i], 2, 16, QChar('0')).toUpper());
}
m_data = bytes.join(QChar(' '));
}
};
SerialPort::SerialPort() SerialPort::SerialPort()
{ {
@ -580,14 +629,23 @@ SerialPort::~SerialPort()
void SerialPort::setPortName(const QString &name) void SerialPort::setPortName(const QString &name)
{ {
qDebug() << "<setPortName>"; Q_ASSERT(m_portName.isEmpty());
return m_port.setPortName(name); m_portName = name;
} }
// TODO: This will eventually be open(), the constructor will be given the name, and the mode will always be ReadWrite
bool SerialPort::open(QIODevice::OpenMode mode) bool SerialPort::open(QIODevice::OpenMode mode)
{ {
qDebug() << "<open>"; Q_ASSERT(mode == QSerialPort::ReadWrite);
return m_port.open(mode); SerialPortEvent event("openConnection");
event.set("type", "serial");
event.set("port", m_portName);
m_port.setPortName(m_portName);
event.checkResult(m_port.open(mode), m_port.error());
qDebug().noquote() << event;
return event.ok();
} }
bool SerialPort::setBaudRate(qint32 baudRate, QSerialPort::Directions directions) bool SerialPort::setBaudRate(qint32 baudRate, QSerialPort::Directions directions)
@ -595,26 +653,17 @@ bool SerialPort::setBaudRate(qint32 baudRate, QSerialPort::Directions directions
SetValueEvent event("baudRate", baudRate); SetValueEvent event("baudRate", baudRate);
event.set("directions", directions); event.set("directions", directions);
bool ok = m_port.setBaudRate(baudRate, directions); event.checkResult(m_port.setBaudRate(baudRate, directions), m_port.error());
if (!ok) {
QSerialPort::SerialPortError error = m_port.error();
event.set("error", error);
}
qDebug().noquote() << event; qDebug().noquote() << event;
return event.ok(); return event.ok();
} }
// TODO: <set time="FOO" name="baudrate" value="19200"/>
bool SerialPort::setDataBits(QSerialPort::DataBits dataBits) bool SerialPort::setDataBits(QSerialPort::DataBits dataBits)
{ {
SetValueEvent event("setDataBits", dataBits); SetValueEvent event("setDataBits", dataBits);
bool ok = m_port.setDataBits(dataBits); event.checkResult(m_port.setDataBits(dataBits), m_port.error());
if (!ok) {
QSerialPort::SerialPortError error = m_port.error();
event.set("error", error);
}
qDebug().noquote() << event; qDebug().noquote() << event;
return event.ok(); return event.ok();
@ -624,11 +673,7 @@ bool SerialPort::setParity(QSerialPort::Parity parity)
{ {
SetValueEvent event("setParity", parity); SetValueEvent event("setParity", parity);
bool ok = m_port.setParity(parity); event.checkResult(m_port.setParity(parity), m_port.error());
if (!ok) {
QSerialPort::SerialPortError error = m_port.error();
event.set("error", error);
}
qDebug().noquote() << event; qDebug().noquote() << event;
return event.ok(); return event.ok();
@ -638,11 +683,7 @@ bool SerialPort::setStopBits(QSerialPort::StopBits stopBits)
{ {
SetValueEvent event("setStopBits", stopBits); SetValueEvent event("setStopBits", stopBits);
bool ok = m_port.setStopBits(stopBits); event.checkResult(m_port.setStopBits(stopBits), m_port.error());
if (!ok) {
QSerialPort::SerialPortError error = m_port.error();
event.set("error", error);
}
qDebug().noquote() << event; qDebug().noquote() << event;
return event.ok(); return event.ok();
@ -652,11 +693,7 @@ bool SerialPort::setFlowControl(QSerialPort::FlowControl flowControl)
{ {
SetValueEvent event("setFlowControl", flowControl); SetValueEvent event("setFlowControl", flowControl);
bool ok = m_port.setFlowControl(flowControl); event.checkResult(m_port.setFlowControl(flowControl), m_port.error());
if (!ok) {
QSerialPort::SerialPortError error = m_port.error();
event.set("error", error);
}
qDebug().noquote() << event; qDebug().noquote() << event;
return event.ok(); return event.ok();
@ -664,43 +701,96 @@ bool SerialPort::setFlowControl(QSerialPort::FlowControl flowControl)
bool SerialPort::clear(QSerialPort::Directions directions) bool SerialPort::clear(QSerialPort::Directions directions)
{ {
qDebug() << "<clear>"; SerialPortEvent event("clear");
return m_port.clear(directions); event.set("directions", directions);
event.checkResult(m_port.clear(directions), m_port.error());
qDebug().noquote() << event;
return event.ok();
} }
qint64 SerialPort::bytesAvailable() const qint64 SerialPort::bytesAvailable() const
{ {
qDebug() << "<bytesAvailable>"; SerialPortEvent event("get");
return m_port.bytesAvailable();
qint64 result = m_port.bytesAvailable();
event.set("bytesAvailable", result);
event.checkResult(result, m_port.error());
qDebug().noquote() << event;
return result;
} }
qint64 SerialPort::read(char *data, qint64 maxSize) qint64 SerialPort::read(char *data, qint64 maxSize)
{ {
qDebug() << "<rx>"; DataTransferEvent event("rx");
return m_port.read(data, maxSize);
qint64 len = m_port.read(data, maxSize);
if (len > 0) {
event.setData(data, len);
}
event.set("len", len);
if (len != maxSize) {
event.set("req", maxSize);
}
event.checkResult(len, m_port.error());
qDebug().noquote() << event;
return len;
} }
qint64 SerialPort::write(const char *data, qint64 maxSize) qint64 SerialPort::write(const char *data, qint64 maxSize)
{ {
qDebug() << "<tx>"; DataTransferEvent event("tx");
return m_port.write(data, maxSize);
event.setData(data, maxSize);
qint64 len = m_port.write(data, maxSize);
event.set("len", len);
if (len != maxSize) {
event.set("req", maxSize);
}
event.checkResult(len, m_port.error());
qDebug().noquote() << event;
return len;
} }
bool SerialPort::flush() bool SerialPort::flush()
{ {
qDebug() << "<flush>"; SerialPortEvent event("flush");
return m_port.flush();
event.checkResult(m_port.flush(), m_port.error());
qDebug().noquote() << event;
return event.ok();
} }
void SerialPort::close() void SerialPort::close()
{ {
qDebug() << "<close>"; SerialPortEvent event("closeConnection");
return m_port.close(); event.set("type", "serial");
event.set("port", m_portName);
// TODO: the separate connection stream will have an enclosing "connection" tag with these
// attributes. The main device connection manager stream will log this openConnection/
// closeConnection pair. We'll also need to include a loader ID and stream version number
// in the "connection" tag, so that if we ever have to change a loader's download code,
// the older replays will still work as expected.
m_port.close();
event.checkError(m_port.error());
qDebug().noquote() << event;
} }
void SerialPort::onReadyRead() void SerialPort::onReadyRead()
{ {
qDebug() << "<readyRead>"; SerialPortEvent event("readyRead");
// TODO: Most of the playback API reponds to the caller. How do we replay port-driven events?
qDebug().noquote() << event;
emit readyRead(); emit readyRead();
} }

View File

@ -58,6 +58,7 @@ class SerialPort : public QObject
private: private:
QSerialPort m_port; QSerialPort m_port;
QString m_portName;
private slots: private slots:
void onReadyRead(); void onReadyRead();