diff --git a/README.md b/README.md index b8ad999..bca6baf 100644 --- a/README.md +++ b/README.md @@ -55,9 +55,13 @@ https://www.wemos.cc/en/latest/ch340_driver.html The Arduino SW understands the following commands: -* "D11\n", "D21\n" or "D61\n" Activate Relais connected to pin D1, D2 or D6 -* "D10\n", "D20\n" or "D60\n" Deactivate Relais connected to pin D1, D2 or D6 -* "D1T\n", "D2T\n" or "D6T\n" Trigger Relais connected to pin D1, D2 or D6 for 500ms +* "R11\n", "R21\n", "R31\n", "R41\n", "R51\n" Activates Relais connected to pin D1, D2, D6, D7 and D8 +* "R10\n", "R20\n", "R30\n", "R40\n", "R50\n" Deactivates Relais connected to pin D1, D2, D6, D7 and D8 +* "R1T\n", "R2T\n", "R3T\n", "R4T\n", "R5T\n" Trigger Relais connected to pin D1, D2, D6, D7 and D8 for 500ms + +The Arduino board sends the status of Relais, when it was triggered with the button with the same command. + +The Arduino board sends every second a watchdog signal "WD\n". ## Installation @@ -85,6 +89,15 @@ Github Sponsors: [:heart: Sponsor](https://github.com/sponsors/alexmucde) +## Changes + +v0.0.3: + +* Support up to 5 Relais +* Changed communication protocol with Arduino board +* Added Watchdog +* Fixed startup problem with Arduino Flash Mode + ## Copyright Alexander Wenzel diff --git a/dialog.cpp b/dialog.cpp index 6f38837..4ee758b 100644 --- a/dialog.cpp +++ b/dialog.cpp @@ -30,22 +30,26 @@ Dialog::Dialog(QWidget *parent) { ui->setupUi(this); + // clear settings on_pushButtonDefaultSettings_clicked(); + // set window title with version information setWindowTitle(QString("DLTRelais %1").arg(DLT_RELAIS_VERSION)); + // disable stop button at startup ui->pushButtonStop->setDisabled(true); + // connect status slots connect(&dltRelais, SIGNAL(status(QString)), this, SLOT(statusRelais(QString))); connect(&dltMiniServer, SIGNAL(status(QString)), this, SLOT(statusDlt(QString))); - /* load global settings */ + // load global settings from registry QSettings settings; QString filename = settings.value("autoload/filename").toString(); bool autoload = settings.value("autoload/checked").toBool(); bool autostart = settings.value("autostart/checked").toBool(); - /* autoload settings */ + // autoload settings, when activated in global settings if(autoload) { dltRelais.readSettings(filename); @@ -53,7 +57,7 @@ Dialog::Dialog(QWidget *parent) restoreSettings(); } - /* autostart */ + // autostart, when activated in global settings if(autostart) { on_pushButtonStart_clicked(); @@ -62,6 +66,8 @@ Dialog::Dialog(QWidget *parent) Dialog::~Dialog() { + + // disconnect status slots disconnect(&dltRelais, SIGNAL(status(QString)), this, SLOT(statusRelais(QString))); disconnect(&dltMiniServer, SIGNAL(status(QString)), this, SLOT(statusDlt(QString))); @@ -70,7 +76,7 @@ Dialog::~Dialog() void Dialog::restoreSettings() { - /* DLTRelais */ + // update names of Relais ui->lineEditRelaisName1->setText(dltRelais.getRelaisName(1)); ui->lineEditRelaisName2->setText(dltRelais.getRelaisName(2)); ui->lineEditRelaisName3->setText(dltRelais.getRelaisName(3)); @@ -85,11 +91,15 @@ void Dialog::updateSettings() void Dialog::on_pushButtonStart_clicked() { + // start communication updateSettings(); + // start Relais and DLT communication dltRelais.start(); dltMiniServer.start(); + // disable settings and start button + // enable stop button ui->pushButtonStart->setDisabled(true); ui->pushButtonStop->setDisabled(false); ui->pushButtonDefaultSettings->setDisabled(true); @@ -99,9 +109,14 @@ void Dialog::on_pushButtonStart_clicked() void Dialog::on_pushButtonStop_clicked() { + // stop communication + + // stop Relais and DLT communication dltRelais.stop(); dltMiniServer.stop(); + // enable settings and start button + // disable stop button ui->pushButtonStart->setDisabled(false); ui->pushButtonStop->setDisabled(true); ui->pushButtonDefaultSettings->setDisabled(false); @@ -111,6 +126,9 @@ void Dialog::on_pushButtonStop_clicked() void Dialog::statusRelais(QString text) { + // status from Relais + + // Relais status changed on Arduino board if(text=="R10\r\n") { ui->checkBoxRelais1->setChecked(false); @@ -165,6 +183,8 @@ void Dialog::statusRelais(QString text) ui->checkBoxRelais5->setChecked(true); return; } + + // status of Relais communication changed else if(text == "" || text == "stopped") { QPalette palette; @@ -190,8 +210,10 @@ void Dialog::statusRelais(QString text) void Dialog::statusDlt(QString text) { + // status from DLT Mini Server ui->lineEditStatusDLT->setText(text); + // status of DLT communication changed if(text == "" || text == "stopped") { QPalette palette; @@ -218,6 +240,9 @@ void Dialog::statusDlt(QString text) } } +// The following functions are called, when the Relais Checkboxes are triggered or the Trigger +// button is pressed + void Dialog::on_checkBoxRelais1_clicked(bool checked) { if(checked) @@ -322,8 +347,10 @@ void Dialog::on_checkBoxRelais5_clicked(bool checked) dltMiniServer.sendValue2(dltRelais.getRelaisName(5),"Off"); } } + void Dialog::on_pushButtonDefaultSettings_clicked() { + // Reset settings to default dltRelais.clearSettings(); dltMiniServer.clearSettings(); @@ -332,14 +359,18 @@ void Dialog::on_pushButtonDefaultSettings_clicked() void Dialog::on_pushButtonLoadSettings_clicked() { + // Load settings from XML file + QString fileName = QFileDialog::getOpenFileName(this, tr("Open Settings"), "", tr("DLTRelais Settings (*.xml);;All files (*.*)")); if(fileName.isEmpty()) { + // No file was selected or cancel was pressed return; } + // read the settings from XML file dltRelais.readSettings(fileName); dltMiniServer.readSettings(fileName); @@ -348,6 +379,8 @@ void Dialog::on_pushButtonLoadSettings_clicked() void Dialog::on_pushButtonSaveSettings_clicked() { + // Save settings into XML file + updateSettings(); QString fileName = QFileDialog::getSaveFileName(this, @@ -355,15 +388,23 @@ void Dialog::on_pushButtonSaveSettings_clicked() if(fileName.isEmpty()) { + // No file was selected or cancel was pressed return; } + // read the settings from XML file QFile file(fileName); if (!file.open(QFile::WriteOnly | QFile::Text)) - return; + { + // Cannot open the file for writing + return; + } QXmlStreamWriter xml(&file); xml.setAutoFormatting(true); + + // FIXME: Cannot read data from XML file, which contains a start document + // So currently do not call StartDocument //xml.writeStartDocument(); xml.writeStartElement("DLTRelaisSettings"); @@ -371,6 +412,8 @@ void Dialog::on_pushButtonSaveSettings_clicked() dltMiniServer.writeSettings(xml); xml.writeEndElement(); // DLTRelaisSettings + // FIXME: Cannot read data from XML file, which contains a end document + // So currently do not call EndDocument //xml.writeEndDocument(); file.close(); @@ -378,10 +421,10 @@ void Dialog::on_pushButtonSaveSettings_clicked() void Dialog::on_pushButtonSettings_clicked() { + // Open settings dialog SettingsDialog dlg(this); dlg.restoreSettings(&dltRelais, &dltMiniServer); - if(dlg.exec()==QDialog::Accepted) { dlg.backupSettings(&dltRelais, &dltMiniServer); @@ -391,6 +434,7 @@ void Dialog::on_pushButtonSettings_clicked() void Dialog::on_pushButtonInfo_clicked() { + // Open information window QMessageBox msgBox(this); msgBox.setWindowTitle("Info DLTRelais"); diff --git a/dialog.h b/dialog.h index 4f2950e..ad733cb 100644 --- a/dialog.h +++ b/dialog.h @@ -38,39 +38,40 @@ class Dialog : public QDialog private slots: + // Relais control void on_checkBoxRelais1_clicked(bool checked); void on_pushButtonRelais1Trigger_clicked(); void on_checkBoxRelais2_clicked(bool checked); void on_pushButtonRelais2Trigger_clicked(); void on_checkBoxRelais3_clicked(bool checked); void on_pushButtonRelais3Trigger_clicked(); + void on_checkBoxRelais4_clicked(bool checked); + void on_pushButtonRelais4Trigger_clicked(); + void on_checkBoxRelais5_clicked(bool checked); + void on_pushButtonRelais5Trigger_clicked(); + // Status of Relais and DLT connection void statusRelais(QString text); void statusDlt(QString text); + // Settings and Info void on_pushButtonSettings_clicked(); void on_pushButtonDefaultSettings_clicked(); void on_pushButtonLoadSettings_clicked(); void on_pushButtonSaveSettings_clicked(); void on_pushButtonInfo_clicked(); + // Start and stop communication void on_pushButtonStart_clicked(); void on_pushButtonStop_clicked(); - void on_pushButtonRelais4Trigger_clicked(); - - void on_pushButtonRelais5Trigger_clicked(); - - void on_checkBoxRelais4_clicked(bool checked); - - void on_checkBoxRelais5_clicked(bool checked); - private: Ui::Dialog *ui; DLTRelais dltRelais; DLTMiniServer dltMiniServer; + // Settings void restoreSettings(); void updateSettings(); }; diff --git a/dltrelais.cpp b/dltrelais.cpp index c0c6d01..405cd5a 100644 --- a/dltrelais.cpp +++ b/dltrelais.cpp @@ -29,6 +29,9 @@ DLTRelais::~DLTRelais() void DLTRelais::start() { + // start communication + + // set serial port parameters serialPort.setBaudRate(QSerialPort::Baud115200); serialPort.setDataBits(QSerialPort::Data8); serialPort.setParity(QSerialPort::NoParity); @@ -36,19 +39,29 @@ void DLTRelais::start() serialPort.setFlowControl(QSerialPort::NoFlowControl); serialPort.setPortName(interface); + // open serial port if(serialPort.open(QIODevice::ReadWrite)==true) { + // open with success + + // prevent flash mode of Wemos D1 mini serialPort.setDataTerminalReady(false); - status(QString("started")); + + // connect slot to receive data from serial port connect(&serialPort, SIGNAL(readyRead()), this, SLOT(readyRead())); + + status(QString("started")); qDebug() << "DLTRelais: started" << interface; } else { + // open failed + qDebug() << "DLTRelais: Failed to open interface" << interface; status(QString("error")); } + // connect slot watchdog timer and start watchdog timer connect(&timer, SIGNAL(timeout()), this, SLOT(timeout())); timer.start(3000); watchDogCounter = 0; @@ -57,79 +70,108 @@ void DLTRelais::start() void DLTRelais::stop() { + // stop communication + status(QString("stopped")); + qDebug() << "DLTRelais: stopped" << interface; + // close serial port, if it is open if(serialPort.isOpen()) { serialPort.close(); + + // disconnect slot to receive data from serial port disconnect(&serialPort, SIGNAL(readyRead()), this, SLOT(readyRead())); } + // stop watchdog timer timer.stop(); disconnect(&timer, SIGNAL(timeout()), this, SLOT(timeout())); - status(QString("stopped")); - qDebug() << "DLTRelais: stopped" << interface; } void DLTRelais::readyRead() { + // data on serial port was received + + // loop as long as data is available while(serialPort.bytesAvailable()) { char data[256]; + + // read one line form serial port qint64 size = serialPort.readLine(data,sizeof(data)); if(size>0) + { + // line is not empty qDebug() << "DLTRelais: readLine" << data; - - if(QString(data) == "WD\r\n") - { - watchDogCounter++; - } - else - { - status(QString(data)); + if(QString(data) == "WD\r\n") + { + // watchdog message received + watchDogCounter++; + } + else + { + // all other messages forward to status signal + status(QString(data)); + } } } } void DLTRelais::timeout() { + // watchdog timeout + + // check if watchdog was triggered between last call if(watchDogCounter==watchDogCounterLast) { - qDebug() << "DLTRelais: Watchdog expired try reconnect" ; + // no watchdog was received + qDebug() << "DLTRelais: Watchdog expired try to reconnect" ; + // if serial port is open close serial port if(serialPort.isOpen()) { serialPort.close(); disconnect(&serialPort, SIGNAL(readyRead()), this, SLOT(readyRead())); } + // try to reopen serial port if(serialPort.open(QIODevice::ReadWrite)==true) { + // retry was succesful + + // prevent flash mode of Wemos D1 mini serialPort.setDataTerminalReady(false); + + // connect slot to receive data from serial port connect(&serialPort, SIGNAL(readyRead()), this, SLOT(readyRead())); + status(QString("started")); qDebug() << "DLTRelais: started" << interface; } else { + // retry failed + qDebug() << "DLTRelais: Failed to open interface" << interface; status(QString("error")); } + watchDogCounterLast = watchDogCounter; } - watchDogCounterLast = watchDogCounter; } void DLTRelais::clearSettings() { + // clear settings for(int num=0;num<5;num++) relaisName[num] = QString("Relais%1").arg(num+1); } void DLTRelais::writeSettings(QXmlStreamWriter &xml) { - /* Write project settings */ + // Write project settings to XML file xml.writeStartElement("DLTRelais"); xml.writeTextElement("relaisName1",relaisName[0]); xml.writeTextElement("relaisName2",relaisName[1]); @@ -142,6 +184,7 @@ void DLTRelais::writeSettings(QXmlStreamWriter &xml) void DLTRelais::readSettings(const QString &filename) { + // read settings from XML file bool isDLTRelais = false; QFile file(filename); @@ -208,6 +251,9 @@ void DLTRelais::readSettings(const QString &filename) void DLTRelais::trigger(int num) { + // trigger a Relais for 500ms + qDebug() << "DLTRelais: trigger" << num; + if(num==1) serialPort.write("R1T\n"); else if(num==2) @@ -218,12 +264,13 @@ void DLTRelais::trigger(int num) serialPort.write("R4T\n"); else if(num==5) serialPort.write("R5T\n"); - - qDebug() << "DLTRelais: trigger" << num; } void DLTRelais::on(int num) { + // set Relais to on + qDebug() << "DLTRelais: on" << num; + if(num==1) serialPort.write("R11\n"); else if(num==2) @@ -234,12 +281,13 @@ void DLTRelais::on(int num) serialPort.write("R41\n"); else if(num==5) serialPort.write("R51\n"); - - qDebug() << "DLTRelais: on" << num; } void DLTRelais::off(int num) { + // set Relais to off + qDebug() << "DLTRelais: off" << num; + if(num==1) serialPort.write("R10\n"); else if(num==2) @@ -250,6 +298,4 @@ void DLTRelais::off(int num) serialPort.write("R40\n"); else if(num==5) serialPort.write("R50\n"); - - qDebug() << "DLTRelais: off" << num; } diff --git a/dltrelais.h b/dltrelais.h index 20b24fe..03e73d1 100644 --- a/dltrelais.h +++ b/dltrelais.h @@ -28,43 +28,51 @@ class DLTRelais : public QObject explicit DLTRelais(QObject *parent = nullptr); ~DLTRelais(); + // Start and stop connection void start(); void stop(); + // Trigger Relais void trigger(int num); void on(int num); void off(int num); + // Interface name QString getInterface() { return interface; } void setInterface(QString interface) { this->interface = interface; } + // Relais names QString getRelaisName(int num) { if(num>0 && num<6) return relaisName[num-1]; else return QString(); } void setRelaisName(int num,const QString &name) { if(num>0 && num<6) this->relaisName[num-1] = name; } + // Settings void clearSettings(); void writeSettings(QXmlStreamWriter &xml); void readSettings(const QString &filename); signals: + // Called when status changed void status(QString text); private slots: + // Serial data available void readyRead(); + // Watchdog Timeout void timeout(); private: + // Temporary variables QSerialPort serialPort; + QTimer timer; + unsigned int watchDogCounter,watchDogCounterLast; + // Settings QString interface; QString relaisName[5]; - - unsigned int watchDogCounter,watchDogCounterLast; - - QTimer timer; }; #endif // DLT_RELAIS_H