├── images ├── clear.png ├── connect.png ├── settings.png ├── disconnect.png └── application-exit.png ├── .gitignore ├── parserfactory.h ├── parserbinary.cpp ├── main.cpp ├── nodenames.h ├── honeymon.qrc ├── parserbinary.h ├── parser.h ├── console.h ├── parserfactory.cpp ├── logfile.h ├── parserascii.h ├── messagetab.h ├── console.cpp ├── temperaturestab.h ├── nodenames.cpp ├── unknowntab.h ├── messagemodel.h ├── logfile.cpp ├── unknown16model.h ├── tempmodel.h ├── commandmodel.h ├── demandmodel.h ├── unknown18model.h ├── setpointmodel.h ├── decodertab.h ├── prognownextmodel.h ├── honeymon.pro ├── parserascii.cpp ├── messagetab.cpp ├── mainwindow.h ├── messagemodel.cpp ├── decoder.h ├── unknown16model.cpp ├── temperaturestab.cpp ├── settingsdialog.h ├── demandmodel.cpp ├── prognownextmodel.cpp ├── tempmodel.cpp ├── setpointmodel.cpp ├── commandmodel.cpp ├── unknown18model.cpp ├── decodertab.cpp ├── unknowntab.cpp ├── settingsdialog.ui ├── mainwindow.ui ├── settingsdialog.cpp ├── mainwindow.cpp └── decoder.cpp /images/clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrosser/honeymon/HEAD/images/clear.png -------------------------------------------------------------------------------- /images/connect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrosser/honeymon/HEAD/images/connect.png -------------------------------------------------------------------------------- /images/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrosser/honeymon/HEAD/images/settings.png -------------------------------------------------------------------------------- /images/disconnect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrosser/honeymon/HEAD/images/disconnect.png -------------------------------------------------------------------------------- /images/application-exit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrosser/honeymon/HEAD/images/application-exit.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | moc_* 2 | *.o 3 | qrc_*.cpp 4 | ui_*.h 5 | *.pro.user 6 | *.swp 7 | honeymon 8 | honeymon.app 9 | Makefile 10 | -------------------------------------------------------------------------------- /parserfactory.h: -------------------------------------------------------------------------------- 1 | #ifndef PARSERFACTORY_H 2 | #define PARSERFACTORY_H 3 | 4 | #include "parser.h" 5 | 6 | class QString; 7 | 8 | Parser *ParserCreate(QString); 9 | 10 | #endif // PARSERFACTORY_H 11 | -------------------------------------------------------------------------------- /parserbinary.cpp: -------------------------------------------------------------------------------- 1 | #include "parserbinary.h" 2 | 3 | ParserBinary::ParserBinary() 4 | { 5 | } 6 | 7 | void ParserBinary::inputBytes(QByteArray in) 8 | { 9 | //pass input bytes straight to decoder 10 | emit outputBytes(in); 11 | } 12 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "mainwindow.h" 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | QApplication a(argc, argv); 8 | MainWindow w; 9 | w.show(); 10 | QObject::connect(&a, SIGNAL(aboutToQuit()), &w, SLOT(closing())); 11 | return a.exec(); 12 | } 13 | -------------------------------------------------------------------------------- /nodenames.h: -------------------------------------------------------------------------------- 1 | #ifndef NODENAMES_H 2 | #define NODENAMES_H 3 | 4 | #include 5 | #include 6 | 7 | class NodeNames 8 | { 9 | public: 10 | NodeNames(); 11 | QString idToName(quint32 id); 12 | 13 | private: 14 | QMap nameMap; 15 | }; 16 | 17 | #endif // NODENAMES_H 18 | -------------------------------------------------------------------------------- /honeymon.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | images/connect.png 4 | images/disconnect.png 5 | images/application-exit.png 6 | images/settings.png 7 | images/clear.png 8 | 9 | 10 | -------------------------------------------------------------------------------- /parserbinary.h: -------------------------------------------------------------------------------- 1 | #ifndef PARSERBINARY_H 2 | #define PARSERBINARY_H 3 | 4 | #include "parser.h" 5 | 6 | class ParserBinary : public Parser 7 | { 8 | Q_OBJECT 9 | 10 | public: 11 | ParserBinary(); 12 | 13 | public slots: 14 | void inputBytes(QByteArray in); 15 | 16 | }; 17 | 18 | #endif // PARSERBINARY_H 19 | -------------------------------------------------------------------------------- /parser.h: -------------------------------------------------------------------------------- 1 | #ifndef PARSER_H 2 | #define PARSER_H 3 | 4 | #include 5 | #include 6 | 7 | //base class for parsers 8 | 9 | class Parser : public QObject 10 | { 11 | Q_OBJECT; 12 | 13 | public slots: 14 | virtual void inputBytes(QByteArray in) = 0; 15 | 16 | signals: 17 | void outputBytes(QByteArray); 18 | }; 19 | 20 | #endif // PARSER_H 21 | -------------------------------------------------------------------------------- /console.h: -------------------------------------------------------------------------------- 1 | #ifndef CONSOLE_H 2 | #define CONSOLE_H 3 | 4 | #include 5 | 6 | class Console : public QPlainTextEdit 7 | { 8 | Q_OBJECT 9 | 10 | signals: 11 | void getData(const QByteArray &data); 12 | 13 | public: 14 | explicit Console(QWidget *parent = 0); 15 | 16 | void putData(const QByteArray &data); 17 | 18 | }; 19 | 20 | #endif // CONSOLE_H 21 | -------------------------------------------------------------------------------- /parserfactory.cpp: -------------------------------------------------------------------------------- 1 | #include "parser.h" 2 | #include "parserbinary.h" 3 | #include "parserascii.h" 4 | 5 | #include 6 | 7 | Parser *ParserCreate(QString type) 8 | { 9 | if(type.compare(QString("binary")) == 0) 10 | return new ParserBinary(); 11 | 12 | if(type.compare(QString("ascii")) == 0) 13 | return new ParserAscii(); 14 | 15 | return NULL; 16 | } 17 | -------------------------------------------------------------------------------- /logfile.h: -------------------------------------------------------------------------------- 1 | #ifndef LOGFILE_H 2 | #define LOGFILE_H 3 | 4 | #include 5 | 6 | class QTextStream; 7 | class QFile; 8 | 9 | class LogFile : public QObject 10 | { 11 | Q_OBJECT 12 | 13 | public: 14 | LogFile(); 15 | ~LogFile(); 16 | 17 | public slots: 18 | void add(QString); 19 | 20 | private: 21 | QFile *log; 22 | QTextStream *out; 23 | }; 24 | 25 | #endif // LOGFILE_H 26 | -------------------------------------------------------------------------------- /parserascii.h: -------------------------------------------------------------------------------- 1 | #ifndef PARSERASCII_H 2 | #define PARSERASCII_H 3 | 4 | #include "parser.h" 5 | 6 | class ParserAscii : public Parser 7 | { 8 | Q_OBJECT 9 | 10 | enum state_t { IDLE, HEAD, PAYLOAD1, PAYLOAD2 }; 11 | 12 | public: 13 | ParserAscii(); 14 | 15 | public slots: 16 | void inputBytes(QByteArray in); 17 | 18 | private: 19 | quint8 charToInt(char c); 20 | void decodeChar(char c); 21 | state_t state; 22 | QByteArray data; 23 | }; 24 | 25 | #endif // PARSERASCII_H 26 | -------------------------------------------------------------------------------- /messagetab.h: -------------------------------------------------------------------------------- 1 | #ifndef MESSAGETAB_H 2 | #define MESSAGETAB_H 3 | 4 | #include 5 | 6 | class QTableView; 7 | class QAbstractTableModel; 8 | 9 | class MessageTab : public QWidget 10 | { 11 | Q_OBJECT 12 | public: 13 | explicit MessageTab(QWidget *parent = 0); 14 | 15 | void setMessageCountersModel(QAbstractTableModel *); 16 | void setMessageLogModel(QAbstractTableModel *); 17 | 18 | private: 19 | QTableView *messageCountersTable; 20 | QTableView *messageLogTable; 21 | }; 22 | 23 | #endif // MESSAGETAB_H 24 | -------------------------------------------------------------------------------- /console.cpp: -------------------------------------------------------------------------------- 1 | #include "console.h" 2 | 3 | #include 4 | 5 | #include 6 | 7 | Console::Console(QWidget *parent) : 8 | QPlainTextEdit(parent) 9 | { 10 | document()->setMaximumBlockCount(100); 11 | QPalette p = palette(); 12 | p.setColor(QPalette::Base, Qt::black); 13 | p.setColor(QPalette::Text, Qt::green); 14 | setPalette(p); 15 | 16 | } 17 | 18 | void Console::putData(const QByteArray &data) 19 | { 20 | insertPlainText(QString(data)); 21 | 22 | QScrollBar *bar = verticalScrollBar(); 23 | bar->setValue(bar->maximum()); 24 | } 25 | -------------------------------------------------------------------------------- /temperaturestab.h: -------------------------------------------------------------------------------- 1 | #ifndef TEMPERATURESTAB_H 2 | #define TEMPERATURESTAB_H 3 | 4 | #include 5 | 6 | class QTableView; 7 | class QAbstractTableModel; 8 | 9 | class TemperaturesTab : public QWidget 10 | { 11 | Q_OBJECT 12 | public: 13 | explicit TemperaturesTab(QWidget *parent = 0); 14 | 15 | void setMeasuredTempsModel(QAbstractTableModel *); 16 | void setSetpointsModel(QAbstractTableModel *); 17 | void setDemandsModel(QAbstractTableModel *); 18 | void setProgNowNextModel(QAbstractTableModel *); 19 | 20 | private: 21 | QTableView *measuredTempsTable; 22 | QTableView *setpointsTable; 23 | QTableView *demandsTable; 24 | QTableView *nowNextTable; 25 | }; 26 | 27 | #endif // TEMPERATURESTAB_H 28 | -------------------------------------------------------------------------------- /nodenames.cpp: -------------------------------------------------------------------------------- 1 | #include "nodenames.h" 2 | 3 | NodeNames::NodeNames() 4 | { 5 | nameMap.insert(0x11c9c1, "Loft"); 6 | nameMap.insert(0x11c9c2, "Kitchen"); 7 | nameMap.insert(0x11c9cb, "Lounge"); 8 | nameMap.insert(0x11c9cd, "Hall"); 9 | nameMap.insert(0x11c9d0, "Cons. Tall"); 10 | nameMap.insert(0x11c9d6, "Conservatory"); 11 | nameMap.insert(0x126a8a, "Piano Rm"); 12 | nameMap.insert(0x126a8b, "Front Bed"); 13 | nameMap.insert(0x126a95, "Back Bed"); 14 | nameMap.insert(0x333d48, "Prog2"); 15 | nameMap.insert(0x334ab3, "Prog1"); 16 | } 17 | 18 | QString NodeNames::idToName(quint32 id) 19 | { 20 | if(nameMap.contains(id)) { 21 | return nameMap[id]; 22 | } else { 23 | return QString("%1") .arg(id, 6, 16, QChar('0')); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /unknowntab.h: -------------------------------------------------------------------------------- 1 | #ifndef UNKNOWNTAB_H 2 | #define UNKNOWNTAB_H 3 | 4 | #include 5 | 6 | class QTableView; 7 | class QAbstractTableModel; 8 | 9 | class UnknownTab : public QWidget 10 | { 11 | Q_OBJECT 12 | public: 13 | explicit UnknownTab(QWidget *parent = 0); 14 | 15 | void set1060Model(QAbstractTableModel *); 16 | void set1100Model(QAbstractTableModel *); 17 | void set0008Model(QAbstractTableModel *); 18 | void set0009Model(QAbstractTableModel *); 19 | void set1F09Model(QAbstractTableModel *); 20 | void set3B00Model(QAbstractTableModel *); 21 | 22 | private: 23 | QTableView *x1060Table; 24 | QTableView *x1100Table; 25 | QTableView *x0008Table; 26 | QTableView *x0009Table; 27 | QTableView *x1F09Table; 28 | QTableView *x3B00Table; 29 | }; 30 | 31 | #endif // UNKNOWNTAB_H 32 | -------------------------------------------------------------------------------- /messagemodel.h: -------------------------------------------------------------------------------- 1 | #ifndef MESSAGEMODEL_H 2 | #define MESSAGEMODEL_H 3 | 4 | #include 5 | 6 | #include 7 | 8 | class MessageModel : public QAbstractTableModel 9 | { 10 | Q_OBJECT 11 | public: 12 | MessageModel(QObject *parent); 13 | 14 | int rowCount(const QModelIndex &parent = QModelIndex()) const ; 15 | int columnCount(const QModelIndex &parent = QModelIndex()) const; 16 | QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; 17 | QVariant headerData(int section, Qt::Orientation orientation, int role) const; 18 | 19 | public slots: 20 | void newData(QByteArray in); 21 | 22 | private: 23 | 24 | quint32 numMessages; 25 | 26 | struct record_t { 27 | QTime time; 28 | QByteArray data; 29 | }; 30 | 31 | QList messageList; 32 | }; 33 | 34 | #endif // MESSAGEMODEL_H 35 | -------------------------------------------------------------------------------- /logfile.cpp: -------------------------------------------------------------------------------- 1 | #include "logfile.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | LogFile::LogFile() 10 | { 11 | out=NULL; 12 | 13 | log = new QFile("/var/tmp/cmzone.log"); 14 | 15 | if (log->open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) { 16 | out = new QTextStream(log); 17 | } else { 18 | //qDebug() << "Error opening log file '" << fileName << "'. All debug output redirected to console."; 19 | } 20 | } 21 | 22 | LogFile::~LogFile() 23 | { 24 | log->close(); 25 | } 26 | 27 | void LogFile::add(QString msg) 28 | { 29 | QString debugdate = QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss"); 30 | 31 | if(out) 32 | (*out) << debugdate << " " << msg << endl; 33 | else 34 | qDebug() << debugdate << " " << msg << endl; 35 | } 36 | -------------------------------------------------------------------------------- /unknown16model.h: -------------------------------------------------------------------------------- 1 | #ifndef UNKNOWN16MODEL_H 2 | #define UNKNOWN16MODEL_H 3 | 4 | #include 5 | 6 | class NodeNames; 7 | 8 | class Unknown16Model : public QAbstractTableModel 9 | { 10 | Q_OBJECT 11 | public: 12 | Unknown16Model(QObject *parent); 13 | 14 | int rowCount(const QModelIndex &parent = QModelIndex()) const ; 15 | int columnCount(const QModelIndex &parent = QModelIndex()) const; 16 | QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; 17 | QVariant headerData(int section, Qt::Orientation orientation, int role) const; 18 | void setNodeNameHelper(NodeNames *n); 19 | 20 | public slots: 21 | void newData(quint32 id0, QByteArray data); 22 | 23 | private: 24 | 25 | struct record_t { 26 | quint32 id1; 27 | QByteArray data; 28 | }; 29 | 30 | NodeNames *nn; 31 | QMap unknown16Map; 32 | }; 33 | 34 | #endif // UNKNOWN16MODEL_H 35 | -------------------------------------------------------------------------------- /tempmodel.h: -------------------------------------------------------------------------------- 1 | #ifndef TEMPMODEL_H 2 | #define TEMPMODEL_H 3 | 4 | #include 5 | 6 | class NodeNames; 7 | 8 | class TempModel : public QAbstractTableModel 9 | { 10 | Q_OBJECT 11 | public: 12 | TempModel(QObject *parent); 13 | 14 | int rowCount(const QModelIndex &parent = QModelIndex()) const ; 15 | int columnCount(const QModelIndex &parent = QModelIndex()) const; 16 | QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; 17 | QVariant headerData(int section, Qt::Orientation orientation, int role) const; 18 | void setNodeNameHelper(NodeNames *n); 19 | 20 | public slots: 21 | void newData(quint32 id0, quint32 id1, quint32 zone, float temp); 22 | 23 | private: 24 | 25 | struct record_t { 26 | quint32 id1; 27 | quint32 id2; 28 | quint32 zone; 29 | float temp; 30 | }; 31 | 32 | NodeNames *nn; 33 | QMap temperatureMap; 34 | }; 35 | 36 | #endif // TEMPMODEL_H 37 | -------------------------------------------------------------------------------- /commandmodel.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMANDMODEL_H 2 | #define COMMANDMODEL_H 3 | 4 | #include 5 | 6 | class NodeNames; 7 | 8 | class CommandModel : public QAbstractTableModel 9 | { 10 | Q_OBJECT 11 | public: 12 | CommandModel(QObject *parent); 13 | 14 | int rowCount(const QModelIndex &parent = QModelIndex()) const ; 15 | int columnCount(const QModelIndex &parent = QModelIndex()) const; 16 | QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; 17 | QVariant headerData(int section, Qt::Orientation orientation, int role) const; 18 | void setNodeNameHelper(NodeNames *n); 19 | 20 | public slots: 21 | void newData(quint32 id0, quint32 id1, quint32 data); 22 | 23 | private: 24 | 25 | struct record_t { 26 | quint32 id1; 27 | quint32 id2; 28 | quint32 command; 29 | quint32 count; 30 | }; 31 | 32 | NodeNames *nn; 33 | QMap commandMap; 34 | }; 35 | 36 | #endif // COMMANDMODEL_H 37 | -------------------------------------------------------------------------------- /demandmodel.h: -------------------------------------------------------------------------------- 1 | #ifndef DEMANDMODEL_H 2 | #define DEMANDMODEL_H 3 | 4 | #include 5 | 6 | class NodeNames; 7 | 8 | class DemandModel : public QAbstractTableModel 9 | { 10 | Q_OBJECT 11 | public: 12 | DemandModel(QObject *parent); 13 | 14 | int rowCount(const QModelIndex &parent = QModelIndex()) const ; 15 | int columnCount(const QModelIndex &parent = QModelIndex()) const; 16 | QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; 17 | QVariant headerData(int section, Qt::Orientation orientation, int role) const; 18 | void setNodeNameHelper(NodeNames *n); 19 | 20 | public slots: 21 | void newData(quint32 id0, quint32 id1, quint32 zone, quint32 demand); 22 | 23 | private: 24 | 25 | struct record_t { 26 | quint32 id1; 27 | quint32 id2; 28 | quint32 zone; 29 | quint32 demand; 30 | }; 31 | 32 | NodeNames *nn; 33 | QMap demandMap; 34 | }; 35 | 36 | #endif // DEMANDMODEL_H 37 | -------------------------------------------------------------------------------- /unknown18model.h: -------------------------------------------------------------------------------- 1 | #ifndef UNKNOWN18MODEL_H 2 | #define UNKNOWN18MODEL_H 3 | 4 | #include 5 | 6 | class NodeNames; 7 | 8 | class Unknown18Model : public QAbstractTableModel 9 | { 10 | Q_OBJECT 11 | public: 12 | Unknown18Model(QObject *parent); 13 | 14 | int rowCount(const QModelIndex &parent = QModelIndex()) const ; 15 | int columnCount(const QModelIndex &parent = QModelIndex()) const; 16 | QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; 17 | QVariant headerData(int section, Qt::Orientation orientation, int role) const; 18 | void setNodeNameHelper(NodeNames *n); 19 | 20 | public slots: 21 | void newData(quint32 id0, quint32 id1, QByteArray data); 22 | 23 | private: 24 | 25 | struct record_t { 26 | quint32 id1; 27 | quint32 id2; 28 | quint32 zone; 29 | QByteArray data; 30 | }; 31 | 32 | NodeNames *nn; 33 | QMap unknown18Map; 34 | }; 35 | 36 | #endif // UNKNOWN18MODEL_H 37 | -------------------------------------------------------------------------------- /setpointmodel.h: -------------------------------------------------------------------------------- 1 | #ifndef SETPOINTMODEL_H 2 | #define SETPOINTMODEL_H 3 | 4 | #include 5 | 6 | class NodeNames; 7 | 8 | class SetpointModel : public QAbstractTableModel 9 | { 10 | Q_OBJECT 11 | public: 12 | SetpointModel(QObject *parent); 13 | 14 | int rowCount(const QModelIndex &parent = QModelIndex()) const ; 15 | int columnCount(const QModelIndex &parent = QModelIndex()) const; 16 | QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; 17 | QVariant headerData(int section, Qt::Orientation orientation, int role) const; 18 | void setNodeNameHelper(NodeNames *n); 19 | 20 | public slots: 21 | void newData(quint32 id0, quint32 id1, quint32 zone, float setpoint); 22 | 23 | private: 24 | 25 | struct record_t { 26 | quint32 id1; 27 | quint32 id2; 28 | quint32 zone; 29 | float setpoint; 30 | }; 31 | 32 | NodeNames *nn; 33 | QMap temperatureMap; 34 | }; 35 | 36 | #endif // SETPOINTMODEL_H 37 | -------------------------------------------------------------------------------- /decodertab.h: -------------------------------------------------------------------------------- 1 | #ifndef DECODERTAB_H 2 | #define DECODERTAB_H 3 | 4 | #include 5 | 6 | class QLabel; 7 | 8 | class DecoderTab : public QWidget 9 | { 10 | Q_OBJECT 11 | public: 12 | explicit DecoderTab(QWidget *parent = 0); 13 | 14 | signals: 15 | 16 | public slots: 17 | void inputByteCount(quint32); 18 | void candidatePayloadCount(quint32); 19 | void overLengthMessageCount(quint32); 20 | void lengthOddCount(quint32); 21 | void manchesterInvalidCount(quint32); 22 | void checkSumErrorCount(quint32); 23 | void validMessageCount(quint32); 24 | void seventyCount(quint32); 25 | void collisionCount(quint32); 26 | 27 | private: 28 | QLabel *numInputBytesLabel; 29 | QLabel *numCandidateMessagesLabel; 30 | QLabel *numOverLengthMessagesLabel; 31 | QLabel *numLengthOddPayloadsLabel; 32 | QLabel *numManchesterInvalidLabel; 33 | QLabel *numCheckSumErrorsLabel; 34 | QLabel *numValidMessagesLabel; 35 | QLabel *numSeventyLabel; 36 | QLabel *numCollisionLabel; 37 | }; 38 | 39 | #endif // DECODERTAB_H 40 | -------------------------------------------------------------------------------- /prognownextmodel.h: -------------------------------------------------------------------------------- 1 | #ifndef PROGNOWNEXTMODEL_H 2 | #define PROGNOWNEXTMODEL_H 3 | 4 | #include 5 | 6 | class NodeNames; 7 | 8 | class ProgNowNextModel : public QAbstractTableModel 9 | { 10 | Q_OBJECT 11 | public: 12 | ProgNowNextModel(QObject *parent); 13 | 14 | int rowCount(const QModelIndex &parent = QModelIndex()) const ; 15 | int columnCount(const QModelIndex &parent = QModelIndex()) const; 16 | QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; 17 | QVariant headerData(int section, Qt::Orientation orientation, int role) const; 18 | void setNodeNameHelper(NodeNames *n); 19 | 20 | public slots: 21 | void newData(quint32 id1, quint32 zone, float tempNow, float tempNext, quint32 countDown); 22 | 23 | private: 24 | 25 | struct record_t { 26 | quint32 id1; 27 | quint32 zone; 28 | float tempNow; 29 | float tempNext; 30 | quint32 countDown; 31 | }; 32 | 33 | NodeNames *nn; 34 | QMap temperatureMap; 35 | }; 36 | 37 | #endif // SETPOINTMODEL_H 38 | -------------------------------------------------------------------------------- /honeymon.pro: -------------------------------------------------------------------------------- 1 | CONFIG += 2 | QT += widgets network serialport 3 | 4 | TARGET = honeymon 5 | TEMPLATE = app 6 | 7 | SOURCES += \ 8 | main.cpp \ 9 | mainwindow.cpp \ 10 | settingsdialog.cpp \ 11 | console.cpp \ 12 | decoder.cpp \ 13 | tempmodel.cpp \ 14 | demandmodel.cpp \ 15 | commandmodel.cpp \ 16 | nodenames.cpp \ 17 | logfile.cpp \ 18 | setpointmodel.cpp \ 19 | decodertab.cpp \ 20 | prognownextmodel.cpp \ 21 | unknown18model.cpp \ 22 | unknowntab.cpp \ 23 | unknown16model.cpp \ 24 | temperaturestab.cpp \ 25 | messagetab.cpp \ 26 | messagemodel.cpp \ 27 | parserbinary.cpp \ 28 | parserfactory.cpp \ 29 | parserascii.cpp 30 | 31 | HEADERS += \ 32 | mainwindow.h \ 33 | settingsdialog.h \ 34 | console.h \ 35 | decoder.h \ 36 | tempmodel.h \ 37 | demandmodel.h \ 38 | commandmodel.h \ 39 | nodenames.h \ 40 | logfile.h \ 41 | setpointmodel.h \ 42 | decodertab.h \ 43 | prognownextmodel.h \ 44 | unknown18model.h \ 45 | unknowntab.h \ 46 | unknown16model.h \ 47 | temperaturestab.h \ 48 | messagetab.h \ 49 | messagemodel.h \ 50 | parser.h \ 51 | parserbinary.h \ 52 | parserfactory.h \ 53 | parserascii.h 54 | 55 | FORMS += \ 56 | mainwindow.ui \ 57 | settingsdialog.ui 58 | 59 | RESOURCES += \ 60 | honeymon.qrc 61 | -------------------------------------------------------------------------------- /parserascii.cpp: -------------------------------------------------------------------------------- 1 | #include "parserascii.h" 2 | 3 | ParserAscii::ParserAscii() 4 | { 5 | state=IDLE; 6 | } 7 | 8 | //accept lines of text input messages of the form 9 | //53 A9 6A A9 AA 5A 55 96 A9 AA 9A AA 95 69 A9 A5 A9 99 AA AA A6 AA A6 96 6A A9 55 35 10 | void ParserAscii::inputBytes(QByteArray in) 11 | { 12 | for(int i=0; i= '0' && n <= '9') 20 | return (n-'0'); 21 | else 22 | 23 | if (n >= 'A' && n <= 'F') 24 | return (n-'A'+10); 25 | else 26 | return 0; 27 | } 28 | 29 | //reformat to binary equivalent 30 | void ParserAscii::decodeChar(char c) 31 | { 32 | static quint8 byte; 33 | 34 | //ignore any spaces 35 | if(c==' ') 36 | return; 37 | 38 | switch(state) 39 | { 40 | case IDLE: 41 | if(c=='5') state=HEAD; 42 | break; 43 | 44 | case HEAD: 45 | if(c=='3') state=PAYLOAD1; 46 | //prefix the message as it would have been 47 | //from the binary data 48 | data.append(0x33); 49 | data.append(0x55); 50 | data.append(0x53); 51 | break; 52 | 53 | case PAYLOAD1: 54 | //first character of payload 55 | byte = charToInt(c) * 16; 56 | state = PAYLOAD2; 57 | break; 58 | 59 | case PAYLOAD2: 60 | //second character of payload 61 | byte += charToInt(c); 62 | data.append(byte); 63 | 64 | //look for end of message 65 | if(byte==0x35) { 66 | emit outputBytes(data); 67 | data.clear(); 68 | state=IDLE; 69 | } else { 70 | state=PAYLOAD1; 71 | } 72 | break; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /messagetab.cpp: -------------------------------------------------------------------------------- 1 | #include "messagetab.h" 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | MessageTab::MessageTab(QWidget *parent) : 12 | QWidget(parent) 13 | { 14 | //overall grid layout 15 | QGridLayout *overallLayout = new QGridLayout(); 16 | 17 | //group box for message log 18 | QGroupBox *messageLogGroup = new QGroupBox("Message log"); 19 | QVBoxLayout *messageLogLayout = new QVBoxLayout(); 20 | messageLogTable = new QTableView(); 21 | messageLogTable->verticalHeader()->hide(); 22 | messageLogLayout->addWidget(messageLogTable); 23 | messageLogGroup->setLayout(messageLogLayout); 24 | overallLayout->addWidget(messageLogGroup, 0, 0, 1, 1); 25 | 26 | //group box for message counters 27 | QGroupBox *messageCountersGroup = new QGroupBox("Message counters"); 28 | QVBoxLayout *messageCountersLayout = new QVBoxLayout(); 29 | messageCountersTable = new QTableView(); 30 | messageCountersTable->verticalHeader()->hide(); 31 | messageCountersLayout->addWidget(messageCountersTable); 32 | messageCountersGroup->setLayout(messageCountersLayout); 33 | overallLayout->addWidget(messageCountersGroup, 0, 1, 1, 1); 34 | 35 | //set the layout for the whole tab 36 | this->setLayout(overallLayout); 37 | } 38 | 39 | void MessageTab::setMessageCountersModel(QAbstractTableModel *m) 40 | { 41 | messageCountersTable->setModel(m); 42 | connect(m, SIGNAL(layoutChanged()), messageCountersTable, SLOT(resizeColumnsToContents())); 43 | connect(m, SIGNAL(layoutChanged()), messageCountersTable, SLOT(resizeRowsToContents())); 44 | messageCountersTable->resizeColumnsToContents(); 45 | } 46 | 47 | void MessageTab::setMessageLogModel(QAbstractTableModel *m) 48 | { 49 | messageLogTable->setModel(m); 50 | connect(m, SIGNAL(layoutChanged()), messageLogTable, SLOT(resizeColumnsToContents())); 51 | connect(m, SIGNAL(layoutChanged()), messageLogTable, SLOT(resizeRowsToContents())); 52 | messageLogTable->resizeColumnsToContents(); 53 | } 54 | -------------------------------------------------------------------------------- /mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class Decoder; 10 | class NodeNames; 11 | class TempModel; 12 | class DemandModel; 13 | class CommandModel; 14 | class SetpointModel; 15 | class ProgNowNextModel; 16 | class X1060Model; 17 | class Unknown16Model; 18 | class Unknown18Model; 19 | class MessageModel; 20 | class Parser; 21 | 22 | #include "logfile.h" 23 | 24 | class QTableView; 25 | class QHBoxLayout; 26 | class QUdpSocket; 27 | 28 | namespace Ui { 29 | class MainWindow; 30 | } 31 | 32 | class Console; 33 | class SettingsDialog; 34 | 35 | class QSerialPort; 36 | 37 | class MainWindow : public QMainWindow 38 | { 39 | Q_OBJECT 40 | 41 | public: 42 | explicit MainWindow(QWidget *parent = 0); 43 | ~MainWindow(); 44 | public slots: 45 | void closing(); 46 | 47 | private slots: 48 | void openSerialPort(); 49 | void closeSerialPort(); 50 | void about(); 51 | void readData(); 52 | void message(QString); 53 | void readPendingDatagrams(); 54 | void setParser(QString); 55 | void setAsciiParser(); 56 | void setBinaryParser(); 57 | void writeInflux(const QString string); 58 | private: 59 | void initActionsConnections(); 60 | 61 | private: 62 | Ui::MainWindow *ui; 63 | Console *console; 64 | SettingsDialog *settings; 65 | QSerialPort *serial; 66 | QUdpSocket *udpSocket; 67 | QUdpSocket *influxSocket; 68 | 69 | QTabWidget *tabs; 70 | 71 | LogFile *logFile; 72 | 73 | NodeNames *nodeNames; 74 | Decoder *decoder; 75 | Parser *parser; 76 | 77 | TempModel *tempDistModel; 78 | SetpointModel *zoneSetpointModel; 79 | DemandModel *demandModel; 80 | CommandModel *commandModel; 81 | ProgNowNextModel *nowNextModel; 82 | MessageModel *messageModel; 83 | 84 | Unknown18Model *unknown1060Model; 85 | Unknown16Model *unknown1100Model; 86 | Unknown16Model *unknown0008Model; 87 | Unknown16Model *unknown0009Model; 88 | Unknown16Model *unknown1F09Model; 89 | Unknown16Model *unknown3B00Model; 90 | }; 91 | 92 | #endif // MAINWINDOW_H 93 | -------------------------------------------------------------------------------- /messagemodel.cpp: -------------------------------------------------------------------------------- 1 | #include "messagemodel.h" 2 | #include "nodenames.h" 3 | 4 | #include 5 | 6 | MessageModel::MessageModel(QObject *parent) : QAbstractTableModel(parent) 7 | { 8 | numMessages=0; 9 | } 10 | 11 | int MessageModel::rowCount(const QModelIndex &) const 12 | { 13 | return numMessages; 14 | } 15 | 16 | int MessageModel::columnCount(const QModelIndex &) const 17 | { 18 | return 2; 19 | } 20 | 21 | QVariant MessageModel::data(const QModelIndex &index, int role) const 22 | { 23 | if (role == Qt::DisplayRole) 24 | { 25 | //get the value to display 26 | QList::const_iterator i = messageList.constBegin(); 27 | int count=0; 28 | while (i != messageList.constEnd()) { 29 | if(count==index.row()) { 30 | switch(index.column()) { 31 | case 0: 32 | return i->time.toString(); 33 | break; 34 | case 1: 35 | { 36 | QString s; 37 | //print the hex data 38 | for(int j=0; jdata.size(); j++) 39 | s.append(QString("%1 ") .arg(i->data.at(j) & 0xFF, 2, 16, QChar('0'))); 40 | return s; 41 | break; 42 | } 43 | default: 44 | return QString("Unknown!"); 45 | break; 46 | } 47 | } 48 | 49 | ++i; 50 | ++count; 51 | } 52 | 53 | } 54 | if(role==Qt::FontRole) 55 | { 56 | if(index.column() == 1) { 57 | QFont f("Monospace"); 58 | f.setPointSize(8); 59 | f.setStyleHint(QFont::TypeWriter); 60 | return f; 61 | } else { 62 | QFont f; 63 | f.setPointSize(8); 64 | return f; 65 | } 66 | } 67 | return QVariant(); 68 | } 69 | 70 | QVariant MessageModel::headerData(int section, Qt::Orientation orientation, int role) const 71 | { 72 | if (role == Qt::DisplayRole) 73 | { 74 | if (orientation == Qt::Horizontal) { 75 | switch (section) 76 | { 77 | case 0: 78 | return QString("Time"); 79 | case 1: 80 | return QString("Message"); 81 | } 82 | } 83 | } 84 | if(role==Qt::FontRole) 85 | { 86 | QFont f; 87 | f.setPointSize(8); 88 | return f; 89 | } 90 | return QVariant(); 91 | } 92 | 93 | void MessageModel::newData(QByteArray data) 94 | { 95 | record_t r; 96 | r.time = QTime::currentTime(); 97 | r.data = data; 98 | 99 | messageList.append(r); 100 | numMessages++; 101 | 102 | //for simplicity, request that the whole view is updated 103 | QModelIndex topLeft = createIndex(0,0); 104 | QModelIndex bottomRight = (createIndex(messageList.size(), 3)); 105 | 106 | emit layoutChanged(); 107 | emit dataChanged(topLeft, bottomRight); 108 | 109 | } 110 | -------------------------------------------------------------------------------- /decoder.h: -------------------------------------------------------------------------------- 1 | #ifndef DECODER_H 2 | #define DECODER_H 3 | 4 | #include 5 | 6 | class NodeNames; 7 | 8 | class Decoder : public QObject 9 | { 10 | Q_OBJECT 11 | 12 | enum state_t { IDLE, HEAD1, HEAD2, PAYLOAD }; 13 | 14 | public: 15 | Decoder(); 16 | 17 | signals: 18 | //debugging to the console 19 | void consoleMessage(QString); 20 | 21 | //all valid messages 22 | void gotMessage(QByteArray); 23 | void gotCommand(quint32 id1, quint32 id2, quint32 command); 24 | 25 | //messages that we understand 26 | void zoneSetpointSetting(quint32 id1, quint32 id2, quint32 zone, float temp); 27 | void heatDemand(quint32 id1, quint32 id2, quint32 zone, quint32 demand); 28 | void zoneTempDistribution(quint32 id1, quint32 id2, quint32 zone, float temp); 29 | void programmerNowNext(quint32 id1, quint32 zone, float tempNow, float tempNext, quint32 countDown); 30 | void hr80parameters(quint32 id1, quint32 zone, quint32 flags, float tempMin, float tempMax); 31 | 32 | //things still to understand 33 | void unknown1060(quint32 id1, quint32 id2, QByteArray data); 34 | void unknown1100(quint32 id1, QByteArray data); 35 | void unknown0008(quint32 id1, QByteArray data); 36 | void unknown0009(quint32 id1, QByteArray data); 37 | void unknown1F09(quint32 id1, QByteArray data); 38 | void unknown3B00(quint32 id1, QByteArray data); 39 | 40 | //statistics 41 | void inputByteCount(quint32); 42 | void candidatePayloadCount(quint32); 43 | void overLengthMessageCount(quint32); 44 | void lengthOddCount(quint32); 45 | void manchesterInvalidCount(quint32); 46 | void checkSumErrorCount(quint32); 47 | void validMessageCount(quint32); 48 | void seventyCount(quint32); 49 | void collisionCount(quint32); 50 | 51 | void logMessage(QString); 52 | void influxData(QString); 53 | 54 | public slots: 55 | void inputBytes(QByteArray in); 56 | 57 | private: 58 | state_t state; 59 | NodeNames *nodenames; 60 | QByteArray *raw; 61 | void decodeChar(char c); 62 | void lengthCheck(); 63 | char manchesterLUT(char c); 64 | void manchesterDecode(); 65 | void checksum(QByteArray &); 66 | void writeLog(QByteArray &, quint32 command); 67 | void decodeHeader(QByteArray &); 68 | void decode2309(quint32 id1, quint32 id2, quint32 length, quint32 i, QByteArray &in); 69 | void decode3150(quint32 id1, quint32 id2, quint32 length, quint32 i, QByteArray &in); 70 | void decode30C9(quint32 id1, quint32 id2, quint32 length, quint32 i, QByteArray &in); 71 | void decode2249(quint32 id1, quint32 length, quint32 i, QByteArray &in); 72 | void decode1060(quint32 id1, quint32 id2, quint32 length, quint32 index, QByteArray &in); 73 | void decode1100(quint32 id1, quint32 length, quint32 i, QByteArray &in); 74 | void decode0008(quint32 id1, quint32 length, quint32 i, QByteArray &in); 75 | void decode0009(quint32 id1, quint32 length, quint32 i, QByteArray &in); 76 | void decode000A(quint32 id1, quint32 length, quint32 i, QByteArray &in); 77 | void decode1F09(quint32 id1, quint32 length, quint32 i, QByteArray &in); 78 | void decode3B00(quint32 id1, quint32 length, quint32 i, QByteArray &in); 79 | 80 | //statistics 81 | quint32 numInputBytes; 82 | quint32 numCandidatePayloads; 83 | quint32 numOverLengthMessages; 84 | quint32 numLengthOdd; 85 | quint32 numManchesterInvalid; 86 | quint32 numCheckSumErrors; 87 | quint32 numValidMessages; 88 | quint32 numSeventyBytes; 89 | quint32 numCollisions; 90 | }; 91 | 92 | #endif // DECODER_H 93 | -------------------------------------------------------------------------------- /unknown16model.cpp: -------------------------------------------------------------------------------- 1 | #include "unknown16model.h" 2 | #include "nodenames.h" 3 | 4 | #include 5 | 6 | Unknown16Model::Unknown16Model(QObject *parent) : QAbstractTableModel(parent) 7 | { 8 | } 9 | 10 | int Unknown16Model::rowCount(const QModelIndex & /*parent*/) const 11 | { 12 | return unknown16Map.count(); 13 | } 14 | 15 | int Unknown16Model::columnCount(const QModelIndex & /*parent*/) const 16 | { 17 | return 2; 18 | } 19 | 20 | QVariant Unknown16Model::data(const QModelIndex &index, int role) const 21 | { 22 | if (role == Qt::DisplayRole) 23 | { 24 | //get the value to display 25 | QMap::const_iterator i = unknown16Map.constBegin(); 26 | int count=0; 27 | while (i != unknown16Map.constEnd()) { 28 | if(count==index.row()) { 29 | switch(index.column()) { 30 | case 0: 31 | { 32 | quint32 id1=i.value().id1; 33 | if(nn) return nn->idToName(id1); 34 | return QString("%1") .arg(id1, 6, 16, QChar('0')); 35 | break; 36 | } 37 | case 1: 38 | { 39 | QString s; 40 | //print the hex data 41 | for(int j=0; j 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | TemperaturesTab::TemperaturesTab(QWidget *parent) : 12 | QWidget(parent) 13 | { 14 | //overall grid layout 15 | QGridLayout *overallLayout = new QGridLayout(); 16 | 17 | //group box for measured temperatures 18 | QGroupBox *measuredTempsGroup = new QGroupBox("Measured Temperatures 0x30c9"); 19 | QVBoxLayout *measuredTempsLayout = new QVBoxLayout(); 20 | measuredTempsTable = new QTableView(); 21 | measuredTempsTable->verticalHeader()->hide(); 22 | measuredTempsLayout->addWidget(measuredTempsTable); 23 | measuredTempsGroup->setLayout(measuredTempsLayout); 24 | overallLayout->addWidget(measuredTempsGroup, 0, 0, 1, 1); 25 | 26 | //group box for setpoints 27 | QGroupBox *setpointsGroup = new QGroupBox("Setpoints 0x2309"); 28 | QVBoxLayout *setpointsLayout = new QVBoxLayout(); 29 | setpointsTable = new QTableView(); 30 | setpointsTable->verticalHeader()->hide(); 31 | setpointsLayout->addWidget(setpointsTable); 32 | setpointsGroup->setLayout(setpointsLayout); 33 | overallLayout->addWidget(setpointsGroup, 0, 1, 1, 1); 34 | 35 | //group box for TRV demands 36 | QGroupBox *demandsGroup = new QGroupBox("Demand 0x3150"); 37 | QVBoxLayout *demandsLayout = new QVBoxLayout(); 38 | demandsTable = new QTableView(); 39 | demandsTable->verticalHeader()->hide(); 40 | demandsLayout->addWidget(demandsTable); 41 | demandsGroup->setLayout(demandsLayout); 42 | overallLayout->addWidget(demandsGroup, 0, 2, 2, 1); 43 | 44 | //group box for programmer now / next info 45 | QGroupBox *nowNextGroup = new QGroupBox("Programmer now/next 0x2249"); 46 | QVBoxLayout *nowNextLayout = new QVBoxLayout(); 47 | nowNextTable = new QTableView(); 48 | nowNextTable->verticalHeader()->hide(); 49 | nowNextLayout->addWidget(nowNextTable); 50 | nowNextGroup->setLayout(nowNextLayout); 51 | overallLayout->addWidget(nowNextGroup, 0, 3, 1, 1); 52 | 53 | //set the layout for the whole tab 54 | this->setLayout(overallLayout); 55 | } 56 | 57 | void TemperaturesTab::setMeasuredTempsModel(QAbstractTableModel *m) 58 | { 59 | measuredTempsTable->setModel(m); 60 | connect(m, SIGNAL(layoutChanged()), measuredTempsTable, SLOT(resizeColumnsToContents())); 61 | connect(m, SIGNAL(layoutChanged()), measuredTempsTable, SLOT(resizeRowsToContents())); 62 | measuredTempsTable->resizeColumnsToContents(); 63 | } 64 | 65 | void TemperaturesTab::setSetpointsModel(QAbstractTableModel *m) 66 | { 67 | setpointsTable->setModel(m); 68 | connect(m, SIGNAL(layoutChanged()), setpointsTable, SLOT(resizeColumnsToContents())); 69 | connect(m, SIGNAL(layoutChanged()), setpointsTable, SLOT(resizeRowsToContents())); 70 | setpointsTable->resizeColumnsToContents(); 71 | } 72 | 73 | void TemperaturesTab::setDemandsModel(QAbstractTableModel *m) 74 | { 75 | demandsTable->setModel(m); 76 | connect(m, SIGNAL(layoutChanged()), demandsTable, SLOT(resizeColumnsToContents())); 77 | connect(m, SIGNAL(layoutChanged()), demandsTable, SLOT(resizeRowsToContents())); 78 | demandsTable->resizeColumnsToContents(); 79 | } 80 | 81 | void TemperaturesTab::setProgNowNextModel(QAbstractTableModel *m) 82 | { 83 | nowNextTable->setModel(m); 84 | connect(m, SIGNAL(layoutChanged()), nowNextTable, SLOT(resizeColumnsToContents())); 85 | connect(m, SIGNAL(layoutChanged()), nowNextTable, SLOT(resizeRowsToContents())); 86 | nowNextTable->resizeColumnsToContents(); 87 | } 88 | -------------------------------------------------------------------------------- /settingsdialog.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2012 Denis Shienkov 4 | ** Copyright (C) 2012 Laszlo Papp 5 | ** Contact: http://www.qt-project.org/legal 6 | ** 7 | ** This file is part of the QtSerialPort module of the Qt Toolkit. 8 | ** 9 | ** $QT_BEGIN_LICENSE:LGPL$ 10 | ** Commercial License Usage 11 | ** Licensees holding valid commercial Qt licenses may use this file in 12 | ** accordance with the commercial license agreement provided with the 13 | ** Software or, alternatively, in accordance with the terms contained in 14 | ** a written agreement between you and Digia. For licensing terms and 15 | ** conditions see http://qt.digia.com/licensing. For further information 16 | ** use the contact form at http://qt.digia.com/contact-us. 17 | ** 18 | ** GNU Lesser General Public License Usage 19 | ** Alternatively, this file may be used under the terms of the GNU Lesser 20 | ** General Public License version 2.1 as published by the Free Software 21 | ** Foundation and appearing in the file LICENSE.LGPL included in the 22 | ** packaging of this file. Please review the following information to 23 | ** ensure the GNU Lesser General Public License version 2.1 requirements 24 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 25 | ** 26 | ** In addition, as a special exception, Digia gives you certain additional 27 | ** rights. These rights are described in the Digia Qt LGPL Exception 28 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 29 | ** 30 | ** GNU General Public License Usage 31 | ** Alternatively, this file may be used under the terms of the GNU 32 | ** General Public License version 3.0 as published by the Free Software 33 | ** Foundation and appearing in the file LICENSE.GPL included in the 34 | ** packaging of this file. Please review the following information to 35 | ** ensure the GNU General Public License version 3.0 requirements will be 36 | ** met: http://www.gnu.org/copyleft/gpl.html. 37 | ** 38 | ** 39 | ** $QT_END_LICENSE$ 40 | ** 41 | ****************************************************************************/ 42 | 43 | #ifndef SETTINGSDIALOG_H 44 | #define SETTINGSDIALOG_H 45 | 46 | #include 47 | #include 48 | 49 | QT_USE_NAMESPACE 50 | 51 | namespace Ui { 52 | class SettingsDialog; 53 | } 54 | 55 | class QIntValidator; 56 | 57 | 58 | class SettingsDialog : public QDialog 59 | { 60 | Q_OBJECT 61 | 62 | public: 63 | struct Settings { 64 | QString name; 65 | qint32 baudRate; 66 | QString stringBaudRate; 67 | QSerialPort::DataBits dataBits; 68 | QString stringDataBits; 69 | QSerialPort::Parity parity; 70 | QString stringParity; 71 | QSerialPort::StopBits stopBits; 72 | QString stringStopBits; 73 | QSerialPort::FlowControl flowControl; 74 | QString stringFlowControl; 75 | bool localEchoEnabled; 76 | }; 77 | 78 | explicit SettingsDialog(QWidget *parent = 0); 79 | ~SettingsDialog(); 80 | 81 | Settings settings() const; 82 | 83 | private slots: 84 | void showPortInfo(int idx); 85 | void apply(); 86 | void checkCustomBaudRatePolicy(int idx); 87 | 88 | private: 89 | void fillPortsParameters(); 90 | void fillPortsInfo(); 91 | void updateSettings(); 92 | 93 | private: 94 | Ui::SettingsDialog *ui; 95 | Settings currentSettings; 96 | QIntValidator *intValidator; 97 | }; 98 | 99 | #endif // SETTINGSDIALOG_H 100 | 101 | -------------------------------------------------------------------------------- /demandmodel.cpp: -------------------------------------------------------------------------------- 1 | #include "demandmodel.h" 2 | #include "nodenames.h" 3 | 4 | #include 5 | 6 | DemandModel::DemandModel(QObject *parent) : QAbstractTableModel(parent) 7 | { 8 | } 9 | 10 | int DemandModel::rowCount(const QModelIndex &) const 11 | { 12 | return demandMap.count(); 13 | } 14 | 15 | int DemandModel::columnCount(const QModelIndex &) const 16 | { 17 | return 4; 18 | } 19 | 20 | QVariant DemandModel::data(const QModelIndex &index, int role) const 21 | { 22 | if (role == Qt::DisplayRole) 23 | { 24 | //get the value to display 25 | QMap::const_iterator i = demandMap.constBegin(); 26 | int count=0; 27 | while (i != demandMap.constEnd()) { 28 | if(count==index.row()) { 29 | switch(index.column()) { 30 | case 0: 31 | { 32 | quint32 id1=i.value().id1; 33 | if(nn) return nn->idToName(id1); 34 | return QString("%1") .arg(id1, 6, 16, QChar('0')); 35 | break; 36 | } 37 | case 1: 38 | { 39 | quint32 id2=i.value().id2; 40 | if(nn) return nn->idToName(id2); 41 | return QString("%1") .arg(id2, 6, 16, QChar('0')); 42 | break; 43 | } 44 | case 2: 45 | return QString("%1") .arg(i.value().zone); 46 | break; 47 | case 3: 48 | return QString("%1") .arg(i.value().demand); 49 | break; 50 | default: 51 | return QString("Unknown!"); 52 | break; 53 | } 54 | } 55 | 56 | ++i; 57 | ++count; 58 | } 59 | 60 | } 61 | if(role==Qt::FontRole) 62 | { 63 | QFont f; 64 | f.setPointSize(8); 65 | return f; 66 | } 67 | return QVariant(); 68 | } 69 | 70 | QVariant DemandModel::headerData(int section, Qt::Orientation orientation, int role) const 71 | { 72 | if (role == Qt::DisplayRole) 73 | { 74 | if (orientation == Qt::Horizontal) { 75 | switch (section) 76 | { 77 | case 0: 78 | return QString("Valve"); 79 | break; 80 | case 1: 81 | return QString("Set By"); 82 | break; 83 | case 2: 84 | return QString("Zone"); 85 | break; 86 | case 3: 87 | return QString("Demand"); 88 | break; 89 | } 90 | } 91 | } 92 | if(role==Qt::FontRole) 93 | { 94 | QFont f; 95 | f.setPointSize(8); 96 | return f; 97 | } 98 | return QVariant(); 99 | } 100 | 101 | void DemandModel::newData(quint32 id1, quint32 id2, quint32 zone, quint32 demand) 102 | { 103 | QString key = QString("%1:%2") 104 | .arg(id1, 6, 16, QChar('0')) 105 | .arg(id2, 6, 16, QChar('0')); 106 | 107 | record_t r; 108 | r.id1 = id1; 109 | r.id2 = id2; 110 | r.zone = zone; 111 | r.demand = demand; 112 | 113 | demandMap.insert(key, r); 114 | 115 | //for simplicity, request that the whole view is updated 116 | QModelIndex topLeft = createIndex(0,0); 117 | QModelIndex bottomRight = (createIndex(demandMap.size(), 3)); 118 | 119 | emit layoutChanged(); 120 | emit dataChanged(topLeft, bottomRight); 121 | 122 | } 123 | 124 | void DemandModel::setNodeNameHelper(NodeNames *n) 125 | { 126 | nn=n; 127 | } 128 | -------------------------------------------------------------------------------- /prognownextmodel.cpp: -------------------------------------------------------------------------------- 1 | #include "prognownextmodel.h" 2 | #include "nodenames.h" 3 | 4 | #include 5 | 6 | ProgNowNextModel::ProgNowNextModel(QObject *parent) : QAbstractTableModel(parent) 7 | { 8 | nn=NULL; 9 | } 10 | 11 | int ProgNowNextModel::rowCount(const QModelIndex &) const 12 | { 13 | return temperatureMap.count(); 14 | } 15 | 16 | int ProgNowNextModel::columnCount(const QModelIndex &) const 17 | { 18 | return 5; 19 | } 20 | 21 | QVariant ProgNowNextModel::data(const QModelIndex &index, int role) const 22 | { 23 | if (role == Qt::DisplayRole) 24 | { 25 | //get the value to display 26 | QMap::const_iterator i = temperatureMap.constBegin(); 27 | int count=0; 28 | while (i != temperatureMap.constEnd()) { 29 | if(count==index.row()) { 30 | switch(index.column()) { 31 | case 0: 32 | { 33 | quint32 id1 = i.value().id1; 34 | if(nn) return nn->idToName(id1); 35 | return QString("%1") .arg(id1, 6, 16, QChar('0')); 36 | } 37 | break; 38 | case 1: 39 | return i.value().zone; 40 | break; 41 | case 2: 42 | return i.value().tempNow; 43 | break; 44 | case 3: 45 | return i.value().tempNext; 46 | break; 47 | case 4: 48 | return i.value().countDown; 49 | break; 50 | default: 51 | return QString("Unknown!"); 52 | break; 53 | } 54 | } 55 | 56 | ++i; 57 | ++count; 58 | } 59 | 60 | } 61 | if(role==Qt::FontRole) 62 | { 63 | QFont f; 64 | f.setPointSize(8); 65 | return f; 66 | } 67 | return QVariant(); 68 | } 69 | 70 | QVariant ProgNowNextModel::headerData(int section, Qt::Orientation orientation, int role) const 71 | { 72 | if (role == Qt::DisplayRole) 73 | { 74 | if (orientation == Qt::Horizontal) { 75 | switch (section) 76 | { 77 | case 0: 78 | return QString("Prog"); 79 | case 1: 80 | return QString("Zone"); 81 | case 2: 82 | return QString("Now"); 83 | case 3: 84 | return QString("Next"); 85 | case 4: 86 | return QString("Countdown"); 87 | } 88 | } 89 | } 90 | if(role==Qt::FontRole) 91 | { 92 | QFont f; 93 | f.setPointSize(8); 94 | return f; 95 | } 96 | return QVariant(); 97 | } 98 | 99 | void ProgNowNextModel::newData(quint32 id1, quint32 zone, float tempNow, float tempNext, quint32 countDown) 100 | { 101 | QString key = QString("%1:%2") 102 | .arg(id1, 6, 16, QChar('0')) 103 | .arg(zone); 104 | 105 | record_t r; 106 | r.id1 = id1; 107 | r.zone = zone; 108 | r.tempNow = tempNow; 109 | r.tempNext = tempNext; 110 | r.countDown = countDown; 111 | 112 | temperatureMap.insert(key, r); 113 | 114 | //for simplicity, request that the whole view is updated 115 | QModelIndex topLeft = createIndex(0,0); 116 | QModelIndex bottomRight = (createIndex(temperatureMap.size(), 4)); 117 | emit layoutChanged(); 118 | emit dataChanged(topLeft, bottomRight); 119 | } 120 | 121 | void ProgNowNextModel::setNodeNameHelper(NodeNames *n) 122 | { 123 | nn=n; 124 | } 125 | -------------------------------------------------------------------------------- /tempmodel.cpp: -------------------------------------------------------------------------------- 1 | #include "tempmodel.h" 2 | #include "nodenames.h" 3 | 4 | #include 5 | 6 | TempModel::TempModel(QObject *parent) : QAbstractTableModel(parent) 7 | { 8 | nn=NULL; 9 | } 10 | 11 | int TempModel::rowCount(const QModelIndex & /*parent*/) const 12 | { 13 | return temperatureMap.count(); 14 | } 15 | 16 | int TempModel::columnCount(const QModelIndex & /*parent*/) const 17 | { 18 | return 3; 19 | } 20 | 21 | QVariant TempModel::data(const QModelIndex &index, int role) const 22 | { 23 | if (role == Qt::DisplayRole) 24 | { 25 | //get the value to display 26 | QMap::const_iterator i = temperatureMap.constBegin(); 27 | int count=0; 28 | while (i != temperatureMap.constEnd()) { 29 | if(count==index.row()) { 30 | switch(index.column()) { 31 | case 0: 32 | { 33 | quint32 id1 = i.value().id1; 34 | if(nn) return nn->idToName(id1); 35 | return QString("%1") .arg(id1, 6, 16, QChar('0')); 36 | } 37 | break; 38 | //The second ID is always equal to the first for HR80, or zero for a programmer 39 | //Does not seem to be an interesting thing to display 40 | //case 1: 41 | // { 42 | // quint32 id2 = i.value().id2; 43 | // if(nn) return nn->idToName(id2); 44 | // return QString("%1") .arg(id2, 6, 16, QChar('0')); 45 | // } 46 | // break; 47 | case 1: 48 | return i.value().zone; 49 | break; 50 | case 2: 51 | return QString("%1") .arg(i.value().temp); 52 | break; 53 | default: 54 | return QString("Unknown!"); 55 | break; 56 | } 57 | } 58 | 59 | ++i; 60 | ++count; 61 | } 62 | 63 | } 64 | if(role==Qt::FontRole) 65 | { 66 | QFont f; 67 | f.setPointSize(8); 68 | return f; 69 | } 70 | return QVariant(); 71 | } 72 | 73 | QVariant TempModel::headerData(int section, Qt::Orientation orientation, int role) const 74 | { 75 | if (role == Qt::DisplayRole) 76 | { 77 | if (orientation == Qt::Horizontal) { 78 | switch (section) 79 | { 80 | case 0: 81 | return QString("Sensor"); 82 | case 1: 83 | return QString("Zone"); 84 | case 2: 85 | return QString("Temp"); 86 | } 87 | } 88 | } 89 | if(role==Qt::FontRole) 90 | { 91 | QFont f; 92 | f.setPointSize(8); 93 | return f; 94 | } 95 | return QVariant(); 96 | } 97 | 98 | void TempModel::newData(quint32 id1, quint32 id2, quint32 zone, float temp) 99 | { 100 | QString key = QString("%1:%2:%3") 101 | .arg(id1, 6, 16, QChar('0')) 102 | .arg(id2, 6, 16, QChar('0')) 103 | .arg(zone); 104 | 105 | record_t r; 106 | r.id1 = id1; 107 | r.id2 = id2; 108 | r.zone = zone; 109 | r.temp = temp; 110 | 111 | temperatureMap.insert(key, r); 112 | 113 | //for simplicity, request that the whole view is updated 114 | QModelIndex topLeft = createIndex(0,0); 115 | QModelIndex bottomRight = (createIndex(temperatureMap.size(), 4)); 116 | emit layoutChanged(); 117 | emit dataChanged(topLeft, bottomRight); 118 | } 119 | 120 | void TempModel::setNodeNameHelper(NodeNames *n) 121 | { 122 | nn=n; 123 | } 124 | -------------------------------------------------------------------------------- /setpointmodel.cpp: -------------------------------------------------------------------------------- 1 | #include "setpointmodel.h" 2 | #include "nodenames.h" 3 | 4 | #include 5 | 6 | SetpointModel::SetpointModel(QObject *parent) : QAbstractTableModel(parent) 7 | { 8 | nn=NULL; 9 | } 10 | 11 | int SetpointModel::rowCount(const QModelIndex & /*parent*/) const 12 | { 13 | return temperatureMap.count(); 14 | } 15 | 16 | int SetpointModel::columnCount(const QModelIndex & /*parent*/) const 17 | { 18 | return 4; 19 | } 20 | 21 | QVariant SetpointModel::data(const QModelIndex &index, int role) const 22 | { 23 | if (role == Qt::DisplayRole) 24 | { 25 | //get the value to display 26 | QMap::const_iterator i = temperatureMap.constBegin(); 27 | int count=0; 28 | while (i != temperatureMap.constEnd()) { 29 | if(count==index.row()) { 30 | switch(index.column()) { 31 | case 0: 32 | { 33 | quint32 id1 = i.value().id1; 34 | if(nn) return nn->idToName(id1); 35 | return QString("%1") .arg(id1, 6, 16, QChar('0')); 36 | } 37 | break; 38 | case 1: 39 | { 40 | quint32 id2 = i.value().id2; 41 | if(id2 == 0) return QString("-"); 42 | if(nn) return nn->idToName(id2); 43 | return QString("%1") .arg(id2, 6, 16, QChar('0')); 44 | } 45 | break; 46 | case 2: 47 | return i.value().zone; 48 | break; 49 | case 3: 50 | return QString("%1") .arg(i.value().setpoint); 51 | break; 52 | default: 53 | return QString("Unknown!"); 54 | break; 55 | } 56 | } 57 | 58 | ++i; 59 | ++count; 60 | } 61 | 62 | } 63 | if(role==Qt::FontRole) 64 | { 65 | QFont f; 66 | f.setPointSize(8); 67 | return f; 68 | } 69 | return QVariant(); 70 | } 71 | 72 | QVariant SetpointModel::headerData(int section, Qt::Orientation orientation, int role) const 73 | { 74 | if (role == Qt::DisplayRole) 75 | { 76 | if (orientation == Qt::Horizontal) { 77 | switch (section) 78 | { 79 | case 0: 80 | return QString("Valve"); 81 | case 1: 82 | return QString("Set By"); 83 | case 2: 84 | return QString("Zone"); 85 | case 3: 86 | return QString("Setpoint"); 87 | } 88 | } 89 | } 90 | if(role==Qt::FontRole) 91 | { 92 | QFont f; 93 | f.setPointSize(8); 94 | return f; 95 | } 96 | return QVariant(); 97 | } 98 | 99 | void SetpointModel::newData(quint32 id1, quint32 id2, quint32 zone, float setpoint) 100 | { 101 | QString key = QString("%1:%2:%3") 102 | .arg(id1, 6, 16, QChar('0')) 103 | .arg(id2, 6, 16, QChar('0')) 104 | .arg(zone); 105 | 106 | record_t r; 107 | r.id1 = id1; 108 | r.id2 = id2; 109 | r.zone = zone; 110 | r.setpoint = setpoint; 111 | 112 | temperatureMap.insert(key, r); 113 | 114 | //for simplicity, request that the whole view is updated 115 | QModelIndex topLeft = createIndex(0,0); 116 | QModelIndex bottomRight = (createIndex(temperatureMap.size(), 4)); 117 | emit layoutChanged(); 118 | emit dataChanged(topLeft, bottomRight); 119 | } 120 | 121 | void SetpointModel::setNodeNameHelper(NodeNames *n) 122 | { 123 | nn=n; 124 | } 125 | -------------------------------------------------------------------------------- /commandmodel.cpp: -------------------------------------------------------------------------------- 1 | #include "commandmodel.h" 2 | #include "nodenames.h" 3 | 4 | #include 5 | 6 | CommandModel::CommandModel(QObject *parent) : QAbstractTableModel(parent) 7 | { 8 | } 9 | 10 | int CommandModel::rowCount(const QModelIndex & /*parent*/) const 11 | { 12 | return commandMap.count(); 13 | } 14 | 15 | int CommandModel::columnCount(const QModelIndex & /*parent*/) const 16 | { 17 | return 4; 18 | } 19 | 20 | QVariant CommandModel::data(const QModelIndex &index, int role) const 21 | { 22 | if (role == Qt::DisplayRole) 23 | { 24 | //get the value to display 25 | QMap::const_iterator i = commandMap.constBegin(); 26 | int count=0; 27 | while (i != commandMap.constEnd()) { 28 | if(count==index.row()) { 29 | switch(index.column()) { 30 | case 0: 31 | { 32 | quint32 id1=i.value().id1; 33 | if(nn) return nn->idToName(id1); 34 | return QString("%1") .arg(id1, 6, 16, QChar('0')); 35 | break; 36 | } 37 | case 1: 38 | { 39 | quint32 id2=i.value().id2; 40 | if(id2 == 0) return QString("-"); 41 | if(nn) return nn->idToName(id2); 42 | return QString("%1") .arg(id2, 6, 16, QChar('0')); 43 | break; 44 | } 45 | case 2: 46 | return QString("%1") .arg(i.value().command, 4, 16, QChar('0')); 47 | break; 48 | case 3: 49 | return QString("%1") .arg(i.value().count); 50 | default: 51 | return QString("Unknown!"); 52 | break; 53 | } 54 | } 55 | 56 | ++i; 57 | ++count; 58 | } 59 | 60 | } 61 | if(role==Qt::FontRole) 62 | { 63 | QFont f; 64 | f.setPointSize(8); 65 | return f; 66 | } 67 | return QVariant(); 68 | } 69 | 70 | QVariant CommandModel::headerData(int section, Qt::Orientation orientation, int role) const 71 | { 72 | if (role == Qt::DisplayRole) 73 | { 74 | if (orientation == Qt::Horizontal) { 75 | switch (section) 76 | { 77 | case 0: 78 | return QString("ID1"); 79 | case 1: 80 | return QString("ID2"); 81 | case 2: 82 | return QString("Command"); 83 | case 3: 84 | return QString("Count"); 85 | } 86 | } 87 | } 88 | if(role==Qt::FontRole) 89 | { 90 | QFont f; 91 | f.setPointSize(8); 92 | return f; 93 | } 94 | return QVariant(); 95 | } 96 | 97 | void CommandModel::newData(quint32 id1, quint32 id2, quint32 command) 98 | { 99 | QString key = QString("%1:%2:%3") 100 | .arg(id1, 6, 16, QChar('0')) 101 | .arg(id2, 6, 16, QChar('0')) 102 | .arg(command, 4, 16, QChar('0')); 103 | 104 | record_t r; 105 | r.id1 = id1; 106 | r.id2 = id2; 107 | r.command = command; 108 | 109 | if(commandMap.contains(key)) 110 | r.count = commandMap[key].count + 1; 111 | else 112 | r.count = 1; 113 | 114 | commandMap.insert(key, r); 115 | 116 | //for simplicity, request that the whole view is updated 117 | QModelIndex topLeft = createIndex(0,0); 118 | QModelIndex bottomRight = (createIndex(commandMap.size(), 3)); 119 | 120 | emit layoutChanged(); 121 | emit dataChanged(topLeft, bottomRight); 122 | 123 | } 124 | 125 | void CommandModel::setNodeNameHelper(NodeNames *n) 126 | { 127 | nn=n; 128 | } 129 | -------------------------------------------------------------------------------- /unknown18model.cpp: -------------------------------------------------------------------------------- 1 | #include "unknown18model.h" 2 | #include "nodenames.h" 3 | 4 | #include 5 | 6 | Unknown18Model::Unknown18Model(QObject *parent) : QAbstractTableModel(parent) 7 | { 8 | } 9 | 10 | int Unknown18Model::rowCount(const QModelIndex &) const 11 | { 12 | return unknown18Map.count(); 13 | } 14 | 15 | int Unknown18Model::columnCount(const QModelIndex &) const 16 | { 17 | return 3; 18 | } 19 | 20 | QVariant Unknown18Model::data(const QModelIndex &index, int role) const 21 | { 22 | if (role == Qt::DisplayRole) 23 | { 24 | //get the value to display 25 | QMap::const_iterator i = unknown18Map.constBegin(); 26 | int count=0; 27 | while (i != unknown18Map.constEnd()) { 28 | if(count==index.row()) { 29 | switch(index.column()) { 30 | case 0: 31 | { 32 | quint32 id1=i.value().id1; 33 | if(nn) return nn->idToName(id1); 34 | return QString("%1") .arg(id1, 6, 16, QChar('0')); 35 | break; 36 | } 37 | case 1: 38 | { 39 | quint32 id2=i.value().id2; 40 | if(nn) return nn->idToName(id2); 41 | return QString("%1") .arg(id2, 6, 16, QChar('0')); 42 | break; 43 | } 44 | case 2: 45 | { 46 | QString s; 47 | //print the hex data 48 | for(int j=0; j 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | DecoderTab::DecoderTab(QWidget *parent) : 11 | QWidget(parent) 12 | { 13 | //group box for decoder statistics 14 | QGroupBox *decoderStatsGroup = new QGroupBox("Decoder Statistics"); 15 | 16 | //labels 17 | QLabel *inputBytesLabel = new QLabel("Number of input bytes"); 18 | QLabel *candidateMessagesLabel = new QLabel("Number of candidate payloads"); 19 | QLabel *overLengthMessagesLabel = new QLabel("Number of overlength messages"); 20 | QLabel *lengthOddPayloadsLabel = new QLabel("Number of odd length messages"); 21 | QLabel *manchesterInvalidLabel = new QLabel("Number of Manchester errors"); 22 | QLabel *checkSumErrorsLabel = new QLabel("Number of checksum errors"); 23 | QLabel *validMessagesLabel = new QLabel("Number of valid messages"); 24 | QLabel *seventyLabel = new QLabel("Number of messages containing 0x70"); 25 | QLabel *collisionsLabel = new QLabel("Number of message collisions"); 26 | 27 | //grid layout for stats labels and values 28 | QGridLayout *decoderStatsLayout = new QGridLayout(); 29 | decoderStatsLayout->addWidget(inputBytesLabel, 0, 0); 30 | decoderStatsLayout->addWidget(candidateMessagesLabel, 1, 0); 31 | decoderStatsLayout->addWidget(overLengthMessagesLabel, 2, 0); 32 | decoderStatsLayout->addWidget(lengthOddPayloadsLabel, 3, 0); 33 | decoderStatsLayout->addWidget(manchesterInvalidLabel, 4, 0); 34 | decoderStatsLayout->addWidget(checkSumErrorsLabel, 5, 0); 35 | decoderStatsLayout->addWidget(validMessagesLabel, 6, 0); 36 | decoderStatsLayout->addWidget(seventyLabel, 7, 0); 37 | decoderStatsLayout->addWidget(collisionsLabel, 8, 0); 38 | 39 | //values 40 | numInputBytesLabel = new QLabel("0"); 41 | numCandidateMessagesLabel = new QLabel("0"); 42 | numOverLengthMessagesLabel = new QLabel("0"); 43 | numLengthOddPayloadsLabel = new QLabel("0"); 44 | numManchesterInvalidLabel = new QLabel("0"); 45 | numCheckSumErrorsLabel = new QLabel("0"); 46 | numValidMessagesLabel = new QLabel("0"); 47 | numSeventyLabel = new QLabel("0"); 48 | numCollisionLabel = new QLabel("0"); 49 | 50 | decoderStatsLayout->addWidget(numInputBytesLabel, 0, 1); 51 | decoderStatsLayout->addWidget(numCandidateMessagesLabel, 1, 1); 52 | decoderStatsLayout->addWidget(numOverLengthMessagesLabel, 2, 1); 53 | decoderStatsLayout->addWidget(numLengthOddPayloadsLabel, 3, 1); 54 | decoderStatsLayout->addWidget(numManchesterInvalidLabel, 4, 1); 55 | decoderStatsLayout->addWidget(numCheckSumErrorsLabel, 5, 1); 56 | decoderStatsLayout->addWidget(numValidMessagesLabel, 6, 1); 57 | decoderStatsLayout->addWidget(numSeventyLabel, 7, 1); 58 | decoderStatsLayout->addWidget(numCollisionLabel, 8, 1); 59 | 60 | decoderStatsGroup->setLayout(decoderStatsLayout); 61 | 62 | //vertical layout down the tab 63 | QVBoxLayout *vlayout = new QVBoxLayout(); 64 | vlayout->addWidget(decoderStatsGroup); 65 | vlayout->addStretch(); 66 | 67 | //set the layout for the whole tab 68 | this->setLayout(vlayout); 69 | } 70 | 71 | void DecoderTab::inputByteCount(quint32 n) 72 | { 73 | numInputBytesLabel->setNum((int)n); 74 | } 75 | 76 | void DecoderTab::candidatePayloadCount(quint32 n) 77 | { 78 | numCandidateMessagesLabel->setNum((int)n); 79 | } 80 | 81 | void DecoderTab::overLengthMessageCount(quint32 n) 82 | { 83 | numOverLengthMessagesLabel->setNum((int)n); 84 | } 85 | 86 | void DecoderTab::lengthOddCount(quint32 n) 87 | { 88 | numLengthOddPayloadsLabel->setNum((int)n); 89 | } 90 | 91 | void DecoderTab::manchesterInvalidCount(quint32 n) 92 | { 93 | numManchesterInvalidLabel->setNum((int)n); 94 | } 95 | 96 | void DecoderTab::checkSumErrorCount(quint32 n) 97 | { 98 | numCheckSumErrorsLabel->setNum((int)n); 99 | } 100 | 101 | void DecoderTab::validMessageCount(quint32 n) 102 | { 103 | numValidMessagesLabel->setNum((int)n); 104 | } 105 | 106 | void DecoderTab::seventyCount(quint32 n) 107 | { 108 | numSeventyLabel->setNum((int)n); 109 | } 110 | 111 | void DecoderTab::collisionCount(quint32 n) 112 | { 113 | numCollisionLabel->setNum((int)n); 114 | } 115 | -------------------------------------------------------------------------------- /unknowntab.cpp: -------------------------------------------------------------------------------- 1 | #include "unknowntab.h" 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | UnknownTab::UnknownTab(QWidget *parent) : 12 | QWidget(parent) 13 | { 14 | //overall grid layout 15 | QGridLayout *overallLayout = new QGridLayout(); 16 | 17 | void unknown1060(quint32 id1, quint32 id2, quint32 one, quint32 two, quint32 three); 18 | void unknown1100(quint32 id1, QByteArray data); 19 | void unknown0008(quint32 id1, QByteArray data); 20 | void unknown0009(quint32 id1, QByteArray data); 21 | void unknown1F09(quint32 id1, QByteArray data); 22 | void unknown3B00(quint32 id1, QByteArray data); 23 | 24 | QGroupBox *x1060Group = new QGroupBox("0x1060"); 25 | QVBoxLayout *x1060Layout = new QVBoxLayout(); 26 | x1060Table = new QTableView(); 27 | x1060Table->verticalHeader()->hide(); 28 | x1060Layout->addWidget(x1060Table); 29 | x1060Group->setLayout(x1060Layout); 30 | overallLayout->addWidget(x1060Group, 0, 0, 1, 1); 31 | 32 | QGroupBox *x1100Group = new QGroupBox("0x1100"); 33 | QVBoxLayout *x1100Layout = new QVBoxLayout(); 34 | x1100Table = new QTableView(); 35 | x1100Table->verticalHeader()->hide(); 36 | x1100Layout->addWidget(x1100Table); 37 | x1100Group->setLayout(x1100Layout); 38 | overallLayout->addWidget(x1100Group, 0, 1, 1, 1); 39 | 40 | QGroupBox *x0008Group = new QGroupBox("0x0008"); 41 | QVBoxLayout *x0008Layout = new QVBoxLayout(); 42 | x0008Table = new QTableView(); 43 | x0008Table->verticalHeader()->hide(); 44 | x0008Layout->addWidget(x0008Table); 45 | x0008Group->setLayout(x0008Layout); 46 | overallLayout->addWidget(x0008Group, 0, 2, 1, 1); 47 | 48 | QGroupBox *x0009Group = new QGroupBox("0x0009"); 49 | QVBoxLayout *x0009Layout = new QVBoxLayout(); 50 | x0009Table = new QTableView(); 51 | x0009Table->verticalHeader()->hide(); 52 | x0009Layout->addWidget(x0009Table); 53 | x0009Group->setLayout(x0009Layout); 54 | overallLayout->addWidget(x0009Group, 1, 0, 1, 1); 55 | 56 | QGroupBox *x1F09Group = new QGroupBox("0x1F09"); 57 | QVBoxLayout *x1F09Layout = new QVBoxLayout(); 58 | x1F09Table = new QTableView(); 59 | x1F09Table->verticalHeader()->hide(); 60 | x1F09Layout->addWidget(x1F09Table); 61 | x1F09Group->setLayout(x1F09Layout); 62 | overallLayout->addWidget(x1F09Group, 1, 1, 1, 1); 63 | 64 | QGroupBox *x3B00Group = new QGroupBox("0x3B00"); 65 | QVBoxLayout *x3B00Layout = new QVBoxLayout(); 66 | x3B00Table = new QTableView(); 67 | x3B00Table->verticalHeader()->hide(); 68 | x3B00Layout->addWidget(x3B00Table); 69 | x3B00Group->setLayout(x3B00Layout); 70 | overallLayout->addWidget(x3B00Group, 1, 2, 1, 1); 71 | 72 | //set the layout for the whole tab 73 | this->setLayout(overallLayout); 74 | } 75 | 76 | void UnknownTab::set1060Model(QAbstractTableModel *m) 77 | { 78 | x1060Table->setModel(m); 79 | connect(m, SIGNAL(layoutChanged()), x1060Table, SLOT(resizeColumnsToContents())); 80 | connect(m, SIGNAL(layoutChanged()), x1060Table, SLOT(resizeRowsToContents())); 81 | x1060Table->resizeColumnsToContents(); 82 | } 83 | 84 | void UnknownTab::set1100Model(QAbstractTableModel *m) 85 | { 86 | x1100Table->setModel(m); 87 | connect(m, SIGNAL(layoutChanged()), x1100Table, SLOT(resizeColumnsToContents())); 88 | connect(m, SIGNAL(layoutChanged()), x1100Table, SLOT(resizeRowsToContents())); 89 | x1100Table->resizeColumnsToContents(); 90 | } 91 | 92 | void UnknownTab::set0008Model(QAbstractTableModel *m) 93 | { 94 | x0008Table->setModel(m); 95 | connect(m, SIGNAL(layoutChanged()), x0008Table, SLOT(resizeColumnsToContents())); 96 | connect(m, SIGNAL(layoutChanged()), x0008Table, SLOT(resizeRowsToContents())); 97 | x0008Table->resizeColumnsToContents(); 98 | } 99 | 100 | void UnknownTab::set0009Model(QAbstractTableModel *m) 101 | { 102 | x0009Table->setModel(m); 103 | connect(m, SIGNAL(layoutChanged()), x0009Table, SLOT(resizeColumnsToContents())); 104 | connect(m, SIGNAL(layoutChanged()), x0009Table, SLOT(resizeRowsToContents())); 105 | x0009Table->resizeColumnsToContents(); 106 | } 107 | 108 | void UnknownTab::set1F09Model(QAbstractTableModel *m) 109 | { 110 | x1F09Table->setModel(m); 111 | connect(m, SIGNAL(layoutChanged()), x1F09Table, SLOT(resizeColumnsToContents())); 112 | connect(m, SIGNAL(layoutChanged()), x1F09Table, SLOT(resizeRowsToContents())); 113 | x1F09Table->resizeColumnsToContents(); 114 | } 115 | 116 | void UnknownTab::set3B00Model(QAbstractTableModel *m) 117 | { 118 | x3B00Table->setModel(m); 119 | connect(m, SIGNAL(layoutChanged()), x3B00Table, SLOT(resizeColumnsToContents())); 120 | connect(m, SIGNAL(layoutChanged()), x3B00Table, SLOT(resizeRowsToContents())); 121 | x3B00Table->resizeColumnsToContents(); 122 | } 123 | -------------------------------------------------------------------------------- /settingsdialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | SettingsDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 281 10 | 262 11 | 12 | 13 | 14 | Settings 15 | 16 | 17 | 18 | 19 | 20 | Select Parameters 21 | 22 | 23 | 24 | 25 | 26 | BaudRate: 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | Data bits: 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | Parity: 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | Stop bits: 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | Flow control: 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | Select Serial Port 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | Description: 89 | 90 | 91 | 92 | 93 | 94 | 95 | Manufacturer: 96 | 97 | 98 | 99 | 100 | 101 | 102 | Location: 103 | 104 | 105 | 106 | 107 | 108 | 109 | Vendor ID: 110 | 111 | 112 | 113 | 114 | 115 | 116 | Product ID: 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | Qt::Horizontal 129 | 130 | 131 | 132 | 96 133 | 20 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | Apply 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | Additional options 151 | 152 | 153 | 154 | 155 | 156 | Local echo 157 | 158 | 159 | true 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | -------------------------------------------------------------------------------- /mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 300 11 | 12 | 13 | 14 | HoneyMon 15 | 16 | 17 | 18 | 19 | 20 | 0 21 | 0 22 | 400 23 | 25 24 | 25 | 26 | 27 | 28 | Calls 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | Tools 38 | 39 | 40 | 41 | 42 | 43 | 44 | Help 45 | 46 | 47 | 48 | 49 | 50 | 51 | Parser 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | TopToolBarArea 64 | 65 | 66 | false 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | toolBar 77 | 78 | 79 | TopToolBarArea 80 | 81 | 82 | false 83 | 84 | 85 | 86 | 87 | &About 88 | 89 | 90 | About program 91 | 92 | 93 | Alt+A 94 | 95 | 96 | 97 | 98 | About Qt 99 | 100 | 101 | 102 | 103 | 104 | :/images/connect.png:/images/connect.png 105 | 106 | 107 | C&onnect 108 | 109 | 110 | Connect to serial port 111 | 112 | 113 | Ctrl+O 114 | 115 | 116 | 117 | 118 | 119 | :/images/disconnect.png:/images/disconnect.png 120 | 121 | 122 | &Disconnect 123 | 124 | 125 | Disconnect from serial port 126 | 127 | 128 | Ctrl+D 129 | 130 | 131 | 132 | 133 | 134 | :/images/settings.png:/images/settings.png 135 | 136 | 137 | &Configure 138 | 139 | 140 | Configure serial port 141 | 142 | 143 | Alt+C 144 | 145 | 146 | 147 | 148 | 149 | :/images/clear.png:/images/clear.png 150 | 151 | 152 | C&lear 153 | 154 | 155 | Clear data 156 | 157 | 158 | Alt+L 159 | 160 | 161 | 162 | 163 | 164 | :/images/application-exit.png:/images/application-exit.png 165 | 166 | 167 | &Quit 168 | 169 | 170 | Ctrl+Q 171 | 172 | 173 | 174 | 175 | true 176 | 177 | 178 | Binary 179 | 180 | 181 | 182 | 183 | true 184 | 185 | 186 | Ascii 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | -------------------------------------------------------------------------------- /settingsdialog.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2012 Denis Shienkov 4 | ** Copyright (C) 2012 Laszlo Papp 5 | ** Contact: http://www.qt-project.org/legal 6 | ** 7 | ** This file is part of the QtSerialPort module of the Qt Toolkit. 8 | ** 9 | ** $QT_BEGIN_LICENSE:LGPL$ 10 | ** Commercial License Usage 11 | ** Licensees holding valid commercial Qt licenses may use this file in 12 | ** accordance with the commercial license agreement provided with the 13 | ** Software or, alternatively, in accordance with the terms contained in 14 | ** a written agreement between you and Digia. For licensing terms and 15 | ** conditions see http://qt.digia.com/licensing. For further information 16 | ** use the contact form at http://qt.digia.com/contact-us. 17 | ** 18 | ** GNU Lesser General Public License Usage 19 | ** Alternatively, this file may be used under the terms of the GNU Lesser 20 | ** General Public License version 2.1 as published by the Free Software 21 | ** Foundation and appearing in the file LICENSE.LGPL included in the 22 | ** packaging of this file. Please review the following information to 23 | ** ensure the GNU Lesser General Public License version 2.1 requirements 24 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 25 | ** 26 | ** In addition, as a special exception, Digia gives you certain additional 27 | ** rights. These rights are described in the Digia Qt LGPL Exception 28 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 29 | ** 30 | ** GNU General Public License Usage 31 | ** Alternatively, this file may be used under the terms of the GNU 32 | ** General Public License version 3.0 as published by the Free Software 33 | ** Foundation and appearing in the file LICENSE.GPL included in the 34 | ** packaging of this file. Please review the following information to 35 | ** ensure the GNU General Public License version 3.0 requirements will be 36 | ** met: http://www.gnu.org/copyleft/gpl.html. 37 | ** 38 | ** 39 | ** $QT_END_LICENSE$ 40 | ** 41 | ****************************************************************************/ 42 | 43 | #include "settingsdialog.h" 44 | #include "ui_settingsdialog.h" 45 | 46 | #include 47 | #include 48 | #include 49 | 50 | QT_USE_NAMESPACE 51 | 52 | SettingsDialog::SettingsDialog(QWidget *parent) : 53 | QDialog(parent), 54 | ui(new Ui::SettingsDialog) 55 | { 56 | ui->setupUi(this); 57 | 58 | intValidator = new QIntValidator(0, 4000000, this); 59 | 60 | ui->baudRateBox->setInsertPolicy(QComboBox::NoInsert); 61 | 62 | connect(ui->applyButton, SIGNAL(clicked()), 63 | this, SLOT(apply())); 64 | connect(ui->serialPortInfoListBox, SIGNAL(currentIndexChanged(int)), 65 | this, SLOT(showPortInfo(int))); 66 | connect(ui->baudRateBox, SIGNAL(currentIndexChanged(int)), 67 | this, SLOT(checkCustomBaudRatePolicy(int))); 68 | 69 | fillPortsParameters(); 70 | fillPortsInfo(); 71 | 72 | updateSettings(); 73 | } 74 | 75 | SettingsDialog::~SettingsDialog() 76 | { 77 | delete ui; 78 | } 79 | 80 | SettingsDialog::Settings SettingsDialog::settings() const 81 | { 82 | return currentSettings; 83 | } 84 | 85 | void SettingsDialog::showPortInfo(int idx) 86 | { 87 | if (idx != -1) { 88 | QStringList list = ui->serialPortInfoListBox->itemData(idx).toStringList(); 89 | ui->descriptionLabel->setText(tr("Description: %1").arg(list.at(1))); 90 | ui->manufacturerLabel->setText(tr("Manufacturer: %1").arg(list.at(2))); 91 | ui->locationLabel->setText(tr("Location: %1").arg(list.at(3))); 92 | ui->vidLabel->setText(tr("Vendor Identifier: %1").arg(list.at(4))); 93 | ui->pidLabel->setText(tr("Product Identifier: %1").arg(list.at(5))); 94 | } 95 | } 96 | 97 | void SettingsDialog::apply() 98 | { 99 | updateSettings(); 100 | hide(); 101 | } 102 | 103 | void SettingsDialog::checkCustomBaudRatePolicy(int idx) 104 | { 105 | bool isCustomBaudRate = !ui->baudRateBox->itemData(idx).isValid(); 106 | ui->baudRateBox->setEditable(isCustomBaudRate); 107 | if (isCustomBaudRate) { 108 | ui->baudRateBox->clearEditText(); 109 | QLineEdit *edit = ui->baudRateBox->lineEdit(); 110 | edit->setValidator(intValidator); 111 | } 112 | } 113 | 114 | void SettingsDialog::fillPortsParameters() 115 | { 116 | // fill baud rate (is not the entire list of available values, 117 | // desired values??, add your independently) 118 | ui->baudRateBox->addItem(QLatin1String("9600"), QSerialPort::Baud9600); 119 | ui->baudRateBox->addItem(QLatin1String("19200"), QSerialPort::Baud19200); 120 | ui->baudRateBox->addItem(QLatin1String("38400"), QSerialPort::Baud38400); 121 | ui->baudRateBox->addItem(QLatin1String("115200"), QSerialPort::Baud115200); 122 | ui->baudRateBox->addItem(QLatin1String("Custom")); 123 | 124 | // fill data bits 125 | ui->dataBitsBox->addItem(QLatin1String("5"), QSerialPort::Data5); 126 | ui->dataBitsBox->addItem(QLatin1String("6"), QSerialPort::Data6); 127 | ui->dataBitsBox->addItem(QLatin1String("7"), QSerialPort::Data7); 128 | ui->dataBitsBox->addItem(QLatin1String("8"), QSerialPort::Data8); 129 | ui->dataBitsBox->setCurrentIndex(3); 130 | 131 | // fill parity 132 | ui->parityBox->addItem(QLatin1String("None"), QSerialPort::NoParity); 133 | ui->parityBox->addItem(QLatin1String("Even"), QSerialPort::EvenParity); 134 | ui->parityBox->addItem(QLatin1String("Odd"), QSerialPort::OddParity); 135 | ui->parityBox->addItem(QLatin1String("Mark"), QSerialPort::MarkParity); 136 | ui->parityBox->addItem(QLatin1String("Space"), QSerialPort::SpaceParity); 137 | 138 | // fill stop bits 139 | ui->stopBitsBox->addItem(QLatin1String("1"), QSerialPort::OneStop); 140 | #ifdef Q_OS_WIN 141 | ui->stopBitsBox->addItem(QLatin1String("1.5"), QSerialPort::OneAndHalfStop); 142 | #endif 143 | ui->stopBitsBox->addItem(QLatin1String("2"), QSerialPort::TwoStop); 144 | 145 | // fill flow control 146 | ui->flowControlBox->addItem(QLatin1String("None"), QSerialPort::NoFlowControl); 147 | ui->flowControlBox->addItem(QLatin1String("RTS/CTS"), QSerialPort::HardwareControl); 148 | ui->flowControlBox->addItem(QLatin1String("XON/XOFF"), QSerialPort::SoftwareControl); 149 | } 150 | 151 | void SettingsDialog::fillPortsInfo() 152 | { 153 | ui->serialPortInfoListBox->clear(); 154 | foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) { 155 | QStringList list; 156 | list << info.portName() 157 | << info.description() 158 | << info.manufacturer() 159 | << info.systemLocation() 160 | << (info.vendorIdentifier() ? QString::number(info.vendorIdentifier(), 16) : QString()) 161 | << (info.productIdentifier() ? QString::number(info.productIdentifier(), 16) : QString()); 162 | 163 | ui->serialPortInfoListBox->addItem(list.first(), list); 164 | } 165 | } 166 | 167 | void SettingsDialog::updateSettings() 168 | { 169 | currentSettings.name = ui->serialPortInfoListBox->currentText(); 170 | 171 | // Baud Rate 172 | if (ui->baudRateBox->currentIndex() == 4) { 173 | // custom baud rate 174 | currentSettings.baudRate = ui->baudRateBox->currentText().toInt(); 175 | } else { 176 | // standard baud rate 177 | currentSettings.baudRate = static_cast( 178 | ui->baudRateBox->itemData(ui->baudRateBox->currentIndex()).toInt()); 179 | } 180 | currentSettings.stringBaudRate = QString::number(currentSettings.baudRate); 181 | 182 | // Data bits 183 | currentSettings.dataBits = static_cast( 184 | ui->dataBitsBox->itemData(ui->dataBitsBox->currentIndex()).toInt()); 185 | currentSettings.stringDataBits = ui->dataBitsBox->currentText(); 186 | 187 | // Parity 188 | currentSettings.parity = static_cast( 189 | ui->parityBox->itemData(ui->parityBox->currentIndex()).toInt()); 190 | currentSettings.stringParity = ui->parityBox->currentText(); 191 | 192 | // Stop bits 193 | currentSettings.stopBits = static_cast( 194 | ui->stopBitsBox->itemData(ui->stopBitsBox->currentIndex()).toInt()); 195 | currentSettings.stringStopBits = ui->stopBitsBox->currentText(); 196 | 197 | // Flow control 198 | currentSettings.flowControl = static_cast( 199 | ui->flowControlBox->itemData(ui->flowControlBox->currentIndex()).toInt()); 200 | currentSettings.stringFlowControl = ui->flowControlBox->currentText(); 201 | 202 | // Additional options 203 | currentSettings.localEchoEnabled = ui->localEchoCheckBox->isChecked(); 204 | } 205 | 206 | -------------------------------------------------------------------------------- /mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include "ui_mainwindow.h" 3 | #include "console.h" 4 | #include "settingsdialog.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "nodenames.h" 13 | #include "decoder.h" 14 | 15 | #include "tempmodel.h" 16 | #include "setpointmodel.h" 17 | #include "demandmodel.h" 18 | #include "commandmodel.h" 19 | #include "prognownextmodel.h" 20 | #include "unknown18model.h" 21 | #include "unknown16model.h" 22 | #include "messagemodel.h" 23 | 24 | #include "decodertab.h" 25 | #include "temperaturestab.h" 26 | #include "unknowntab.h" 27 | #include "messagetab.h" 28 | 29 | #include "parserfactory.h" 30 | 31 | MainWindow::MainWindow(QWidget *parent) : 32 | QMainWindow(parent), 33 | ui(new Ui::MainWindow) 34 | { 35 | ui->setupUi(this); 36 | console = new Console; 37 | console->setEnabled(false); 38 | 39 | tabs = new QTabWidget(); 40 | setCentralWidget(tabs); 41 | 42 | serial = new QSerialPort(this); 43 | settings = new SettingsDialog; 44 | 45 | ui->actionConnect->setEnabled(true); 46 | ui->actionDisconnect->setEnabled(false); 47 | ui->actionQuit->setEnabled(true); 48 | ui->actionConfigure->setEnabled(true); 49 | ui->actionAscii->setEnabled(true); 50 | ui->actionBinary->setEnabled(true); 51 | 52 | nodeNames = new NodeNames(); 53 | logFile = new LogFile(); 54 | 55 | decoder = new Decoder(); 56 | connect(decoder, SIGNAL(logMessage(QString)), logFile, SLOT(add(QString))); 57 | 58 | tempDistModel = new TempModel(this); 59 | tempDistModel->setNodeNameHelper(nodeNames); 60 | 61 | zoneSetpointModel = new SetpointModel(this); 62 | zoneSetpointModel->setNodeNameHelper(nodeNames); 63 | 64 | demandModel = new DemandModel(this); 65 | demandModel->setNodeNameHelper(nodeNames); 66 | 67 | commandModel = new CommandModel(this); 68 | commandModel->setNodeNameHelper(nodeNames); 69 | 70 | nowNextModel = new ProgNowNextModel(this); 71 | nowNextModel->setNodeNameHelper(nodeNames); 72 | 73 | unknown1060Model = new Unknown18Model(this); 74 | unknown1060Model->setNodeNameHelper(nodeNames); 75 | 76 | unknown1100Model = new Unknown16Model(this); 77 | unknown1100Model->setNodeNameHelper(nodeNames); 78 | 79 | unknown0008Model = new Unknown16Model(this); 80 | unknown0008Model->setNodeNameHelper(nodeNames); 81 | 82 | unknown0009Model = new Unknown16Model(this); 83 | unknown0009Model->setNodeNameHelper(nodeNames); 84 | 85 | unknown1F09Model = new Unknown16Model(this); 86 | unknown1F09Model->setNodeNameHelper(nodeNames); 87 | 88 | unknown3B00Model = new Unknown16Model(this); 89 | unknown3B00Model->setNodeNameHelper(nodeNames); 90 | 91 | messageModel = new MessageModel(this); 92 | 93 | MessageTab *messageTab = new MessageTab(); 94 | messageTab->setMessageCountersModel(commandModel); 95 | messageTab->setMessageLogModel(messageModel); 96 | tabs->addTab(messageTab, "Messages"); 97 | 98 | TemperaturesTab *temperaturesTab = new TemperaturesTab(); 99 | temperaturesTab->setMeasuredTempsModel(tempDistModel); 100 | temperaturesTab->setSetpointsModel(zoneSetpointModel); 101 | temperaturesTab->setDemandsModel(demandModel); 102 | temperaturesTab->setProgNowNextModel(nowNextModel); 103 | 104 | tabs->addTab(temperaturesTab, "Temperatures"); 105 | 106 | UnknownTab *unknownTab = new UnknownTab(); 107 | unknownTab->set0008Model(unknown0008Model); 108 | unknownTab->set0009Model(unknown0009Model); 109 | unknownTab->set1060Model(unknown1060Model); 110 | unknownTab->set1100Model(unknown1100Model); 111 | unknownTab->set1F09Model(unknown1F09Model); 112 | unknownTab->set3B00Model(unknown3B00Model); 113 | tabs->addTab(unknownTab, "Unknown messages"); 114 | 115 | DecoderTab *decoderTab = new DecoderTab(); 116 | tabs->addTab(decoderTab, "Decoder"); 117 | 118 | tabs->addTab(console, "Console"); 119 | 120 | initActionsConnections(); 121 | 122 | parser=NULL; 123 | setBinaryParser(); 124 | 125 | connect(serial, SIGNAL(readyRead()), this, SLOT(readData())); 126 | 127 | connect(decoder, SIGNAL(consoleMessage(QString)), this, SLOT(message(QString))); 128 | connect(decoder, SIGNAL(gotMessage(QByteArray)), messageModel, SLOT(newData(QByteArray))); 129 | 130 | //connect decoded messages to tables 131 | connect(decoder, SIGNAL(zoneTempDistribution(quint32,quint32,quint32,float)), tempDistModel, SLOT(newData(quint32,quint32,quint32,float))); 132 | connect(decoder, SIGNAL(zoneSetpointSetting(quint32,quint32,quint32,float)), zoneSetpointModel, SLOT(newData(quint32,quint32,quint32,float))); 133 | connect(decoder, SIGNAL(heatDemand(quint32,quint32,quint32,quint32)), demandModel, SLOT(newData(quint32, quint32, quint32, quint32))); 134 | connect(decoder, SIGNAL(gotCommand(quint32,quint32,quint32)), commandModel, SLOT(newData(quint32,quint32,quint32))); 135 | connect(decoder, SIGNAL(programmerNowNext(quint32,quint32,float,float,quint32)), nowNextModel, SLOT(newData(quint32, quint32, float, float, quint32))); 136 | 137 | //connect unknown messages to tables 138 | connect(decoder, SIGNAL(unknown1060(quint32,quint32,QByteArray)), unknown1060Model, SLOT(newData(quint32,quint32,QByteArray))); 139 | connect(decoder, SIGNAL(unknown1100(quint32,QByteArray)), unknown1100Model, SLOT(newData(quint32,QByteArray))); 140 | connect(decoder, SIGNAL(unknown0008(quint32,QByteArray)), unknown0008Model, SLOT(newData(quint32,QByteArray))); 141 | connect(decoder, SIGNAL(unknown0009(quint32,QByteArray)), unknown0009Model, SLOT(newData(quint32,QByteArray))); 142 | connect(decoder, SIGNAL(unknown1F09(quint32,QByteArray)), unknown1F09Model, SLOT(newData(quint32,QByteArray))); 143 | connect(decoder, SIGNAL(unknown3B00(quint32,QByteArray)), unknown3B00Model, SLOT(newData(quint32,QByteArray))); 144 | 145 | //connect decoder stats to decoder tab 146 | connect(decoder, SIGNAL(inputByteCount(quint32)), decoderTab, SLOT(inputByteCount(quint32))); 147 | connect(decoder, SIGNAL(candidatePayloadCount(quint32)), decoderTab, SLOT(candidatePayloadCount(quint32))); 148 | connect(decoder, SIGNAL(overLengthMessageCount(quint32)), decoderTab, SLOT(overLengthMessageCount(quint32))); 149 | connect(decoder, SIGNAL(lengthOddCount(quint32)), decoderTab, SLOT(lengthOddCount(quint32))); 150 | connect(decoder, SIGNAL(manchesterInvalidCount(quint32)), decoderTab, SLOT(manchesterInvalidCount(quint32))); 151 | connect(decoder, SIGNAL(validMessageCount(quint32)), decoderTab, SLOT(validMessageCount(quint32))); 152 | 153 | //connect decoded messages to influxdb 154 | connect(decoder, SIGNAL(influxData(QString)), this, SLOT(writeInflux(QString))); 155 | 156 | //receive broadcast traffic from RF receiver 157 | udpSocket = new QUdpSocket(this); 158 | udpSocket->bind(8888, QUdpSocket::ShareAddress); 159 | 160 | connect(udpSocket, SIGNAL(readyRead()), 161 | this, SLOT(readPendingDatagrams())); 162 | 163 | //send influx format data 164 | influxSocket = new QUdpSocket(this); 165 | } 166 | 167 | void MainWindow::writeInflux(const QString string) 168 | { 169 | influxSocket->writeDatagram(string.toLatin1(), QHostAddress::LocalHost , 8089); 170 | } 171 | 172 | 173 | void MainWindow::readPendingDatagrams() 174 | { 175 | while (udpSocket->hasPendingDatagrams()) { 176 | QByteArray datagram; 177 | datagram.resize(udpSocket->pendingDatagramSize()); 178 | QHostAddress sender; 179 | quint16 senderPort; 180 | 181 | udpSocket->readDatagram(datagram.data(), datagram.size(), 182 | &sender, &senderPort); 183 | 184 | if(parser) 185 | parser->inputBytes(datagram); 186 | } 187 | } 188 | 189 | MainWindow::~MainWindow() 190 | { 191 | delete settings; 192 | delete ui; 193 | } 194 | 195 | void MainWindow::openSerialPort() 196 | { 197 | SettingsDialog::Settings p = settings->settings(); 198 | serial->setPortName(p.name); 199 | if (serial->open(QIODevice::ReadWrite)) { 200 | if (serial->setBaudRate(p.baudRate) 201 | && serial->setDataBits(p.dataBits) 202 | && serial->setParity(p.parity) 203 | && serial->setStopBits(p.stopBits) 204 | && serial->setFlowControl(p.flowControl)) { 205 | 206 | console->setEnabled(true); 207 | ui->actionConnect->setEnabled(false); 208 | ui->actionDisconnect->setEnabled(true); 209 | ui->actionConfigure->setEnabled(false); 210 | ui->statusBar->showMessage(tr("Connected to %1 : %2, %3, %4, %5, %6") 211 | .arg(p.name).arg(p.stringBaudRate).arg(p.stringDataBits) 212 | .arg(p.stringParity).arg(p.stringStopBits).arg(p.stringFlowControl)); 213 | 214 | } else { 215 | serial->close(); 216 | QMessageBox::critical(this, tr("Error"), 217 | tr("Can't configure the serial port: %1,\n" 218 | "error code: %2") 219 | .arg(p.name).arg(serial->error())); 220 | 221 | ui->statusBar->showMessage(tr("Open error")); 222 | } 223 | } else { 224 | QMessageBox::critical(this, tr("Error"), 225 | tr("Can't opened the serial port: %1,\n" 226 | "error code: %2") 227 | .arg(p.name).arg(serial->error())); 228 | 229 | ui->statusBar->showMessage(tr("Configure error")); 230 | } 231 | } 232 | 233 | void MainWindow::closeSerialPort() 234 | { 235 | serial->close(); 236 | console->setEnabled(false); 237 | ui->actionConnect->setEnabled(true); 238 | ui->actionDisconnect->setEnabled(false); 239 | ui->actionConfigure->setEnabled(true); 240 | ui->statusBar->showMessage(tr("Disconnected")); 241 | } 242 | 243 | void MainWindow::closing() 244 | { 245 | this->closeSerialPort(); 246 | } 247 | 248 | void MainWindow::about() 249 | { 250 | QMessageBox::about(this, tr("CMZone/Evotouch montior"), 251 | tr("This program decodes some of the messages in a " 252 | "Honeywell CMZone/Evotouch heating control system and " 253 | "displays the key system state")); 254 | } 255 | 256 | void MainWindow::readData() 257 | { 258 | QByteArray data = serial->readAll(); 259 | 260 | if(parser) 261 | parser->inputBytes(data); 262 | } 263 | 264 | void MainWindow::message(QString s) 265 | { 266 | console->putData(s.toLatin1()); 267 | } 268 | 269 | void MainWindow::setParser(QString type) 270 | { 271 | if(parser) 272 | { 273 | parser->disconnect(); 274 | delete parser; 275 | parser=NULL; 276 | } 277 | 278 | qDebug() << "setting parser to " << type; 279 | parser=ParserCreate(type); 280 | connect(parser, SIGNAL(outputBytes(QByteArray)), decoder, SLOT(inputBytes(QByteArray))); 281 | } 282 | 283 | void MainWindow::setAsciiParser() 284 | { 285 | setParser(QString("ascii")); 286 | ui->actionAscii->setChecked(true); 287 | ui->actionBinary->setChecked(false); 288 | } 289 | 290 | void MainWindow::setBinaryParser() 291 | { 292 | setParser(QString("binary")); 293 | ui->actionAscii->setChecked(false); 294 | ui->actionBinary->setChecked(true); 295 | } 296 | 297 | void MainWindow::initActionsConnections() 298 | { 299 | connect(ui->actionConnect, SIGNAL(triggered()), this, SLOT(openSerialPort())); 300 | connect(ui->actionDisconnect, SIGNAL(triggered()), this, SLOT(closeSerialPort())); 301 | connect(ui->actionQuit, SIGNAL(triggered()), this, SLOT(close())); 302 | connect(ui->actionConfigure, SIGNAL(triggered()), settings, SLOT(show())); 303 | connect(ui->actionClear, SIGNAL(triggered()), console, SLOT(clear())); 304 | connect(ui->actionAbout, SIGNAL(triggered()), this, SLOT(about())); 305 | connect(ui->actionAboutQt, SIGNAL(triggered()), qApp, SLOT(aboutQt())); 306 | connect(ui->actionAscii, SIGNAL(triggered()), this, SLOT(setAsciiParser())); 307 | connect(ui->actionBinary, SIGNAL(triggered()), this, SLOT(setBinaryParser())); 308 | } 309 | -------------------------------------------------------------------------------- /decoder.cpp: -------------------------------------------------------------------------------- 1 | #include "decoder.h" 2 | #include "nodenames.h" 3 | 4 | Decoder::Decoder() 5 | { 6 | state = IDLE; 7 | raw = new QByteArray; 8 | nodenames = new NodeNames(); 9 | 10 | //initialise statistics 11 | numInputBytes = 0; 12 | numCandidatePayloads = 0; 13 | numOverLengthMessages = 0; 14 | numLengthOdd = 0; 15 | numManchesterInvalid = 0; 16 | numCheckSumErrors = 0; 17 | numValidMessages = 0; 18 | numCollisions = 0; 19 | numSeventyBytes = 0; 20 | } 21 | 22 | void Decoder::inputBytes(QByteArray in) 23 | { 24 | int size = in.size(); 25 | numInputBytes += size; 26 | 27 | emit inputByteCount(numInputBytes); 28 | 29 | for(int i=0; iappend(c); 40 | state = HEAD1; 41 | } 42 | break; 43 | 44 | case HEAD1: 45 | if (c=='U') { 46 | raw->append(c); 47 | state = HEAD2; 48 | } else { 49 | raw->clear(); 50 | state = IDLE; 51 | } 52 | break; 53 | 54 | case HEAD2: 55 | if (c=='S') { 56 | raw->append(c); 57 | state = PAYLOAD; 58 | } else { 59 | raw->clear(); 60 | state = IDLE; 61 | } 62 | break; 63 | 64 | case PAYLOAD: 65 | //why do i receive 0x70 characters? 66 | //these seem spurious yet messages are valid with them removed 67 | if(c == 0x70) { 68 | numSeventyBytes++; 69 | emit seventyCount(numSeventyBytes); 70 | break; 71 | } 72 | 73 | //if two messages collide, we find the 0x33 0x55 0x53 pattern 74 | //in the middle of an existing payload 75 | if(c == '3') { 76 | raw->clear(); 77 | raw->append(c); 78 | state = HEAD1; 79 | numCollisions++; 80 | emit collisionCount(numCollisions); 81 | break; 82 | } 83 | 84 | raw->append(c); 85 | if (c=='5') { 86 | numCandidatePayloads++; 87 | emit candidatePayloadCount(numCandidatePayloads); 88 | lengthCheck(); 89 | raw->clear(); 90 | state = IDLE; 91 | } 92 | break; 93 | 94 | default: 95 | raw->clear(); 96 | state = IDLE; 97 | } 98 | } 99 | 100 | void Decoder::lengthCheck() 101 | { 102 | if(raw->length() < 255) { 103 | manchesterDecode(); 104 | } else { 105 | numOverLengthMessages++; 106 | emit overLengthMessageCount(numOverLengthMessages); 107 | emit consoleMessage(QString("Message too long - %1\n") .arg(raw->length())); 108 | } 109 | } 110 | 111 | char Decoder::manchesterLUT(char c) 112 | { 113 | char val=-1; 114 | 115 | switch((unsigned char)c) 116 | { 117 | case 0xAA: val=0x00; break; 118 | case 0xA9: val=0x01; break; 119 | case 0xA6: val=0x02; break; 120 | case 0xA5: val=0x03; break; 121 | case 0x9A: val=0x04; break; 122 | case 0x99: val=0x05; break; 123 | case 0x96: val=0x06; break; 124 | case 0x95: val=0x07; break; 125 | case 0x6A: val=0x08; break; 126 | case 0x69: val=0x09; break; 127 | case 0x66: val=0x0A; break; 128 | case 0x65: val=0x0B; break; 129 | case 0x5A: val=0x0C; break; 130 | case 0x59: val=0x0D; break; 131 | case 0x56: val=0x0E; break; 132 | case 0x55: val=0x0F; break; 133 | } 134 | 135 | return val; 136 | } 137 | 138 | void Decoder::manchesterDecode() 139 | { 140 | QByteArray mdecoded; 141 | QString msg; 142 | 143 | msg.append("RAW "); 144 | for(int i=0; isize(); i++) { 145 | msg.append(QString("%1 ") .arg(raw->at(i) & 0xFF, 2, 16, QChar('0'))); 146 | } 147 | msg.append("\n"); 148 | emit consoleMessage(msg); 149 | 150 | msg.clear(); 151 | if(raw->length()%2 != 0) { 152 | numLengthOdd++; 153 | emit lengthOddCount(numLengthOdd); 154 | emit consoleMessage(QString("ERROR - packet length is not a multiple of 2\n")); 155 | return; 156 | } 157 | 158 | for(int i=3; isize()-1; i+=2) { 159 | char ms=manchesterLUT(raw->at(i)); 160 | if(ms==-1) { 161 | numManchesterInvalid++; 162 | emit manchesterInvalidCount(numManchesterInvalid); 163 | emit consoleMessage(QString("Manchester decoding failed at %1 (ms) - 0x%2\n") .arg(i).arg(raw->at(i) & 0xFF, 2, 16)); 164 | return; 165 | } 166 | 167 | char ls=manchesterLUT(raw->at(i+1)); 168 | if(ls==-1) { 169 | numManchesterInvalid++; 170 | emit manchesterInvalidCount(numManchesterInvalid); 171 | emit consoleMessage(QString("Manchester decoding failed at %1 (ls) - 0x%2\n") .arg(i).arg(raw->at(i+1) & 0xFF, 2, 16)); 172 | return; 173 | } 174 | 175 | char byte=(ms<<4) | ls; 176 | mdecoded.append(byte); 177 | } 178 | 179 | msg.append("DEC "); 180 | for(int i=0; iidToName(id1)) .arg(zone) .arg(temp)); 329 | 330 | } 331 | } 332 | 333 | void Decoder::decode3150(quint32 id1, quint32 id2, quint32 length, quint32 i, QByteArray &in) 334 | { 335 | //heat demand 336 | quint32 zone = (in.at(i) & 0xFF); 337 | quint32 demand = (in.at(i+1) & 0xFF); 338 | emit heatDemand(id1, id2, zone, demand); 339 | 340 | emit influxData(QString("demand,device=%1,zone=%2 value=%3") .arg(nodenames->idToName(id1)) .arg(zone) .arg(demand)); 341 | } 342 | 343 | void Decoder::decode30C9(quint32 id1, quint32 id2, quint32 length, quint32 i, QByteArray &in) 344 | { 345 | //zone temperature distribution 346 | //a number of 3 byte sections 347 | for(int n=i; nidToName(id1)) .arg(zone) .arg(temp)); 353 | 354 | } 355 | } 356 | 357 | void Decoder::decode2249(quint32 id1, quint32 length, quint32 i, QByteArray &in) 358 | { 359 | //programmer now/next setpoint 360 | //a number of 7 byte sections, one for each zome 361 | for(int n=i; n