Browse Source

Fixes #82, adds control channels in ModbusNG

Neal Wilson 7 years ago
parent
commit
d50b5179bc
3 changed files with 98 additions and 6 deletions
  1. 16
    2
      config/Windows/productionroaster.xml
  2. 31
    3
      src/modbus.w
  3. 51
    1
      src/typica.w

+ 16
- 2
config/Windows/productionroaster.xml View File

52
         var window = this;
52
         var window = this;
53
         var targetOffset = 0;
53
         var targetOffset = 0;
54
         var gtrans = 0;
54
         var gtrans = 0;
55
+		var translationdelay = new Timer;
56
+		translationdelay.interval = 0;
57
+		translationdelay.singleShot = true;
55
         var targetDetector = new ThresholdDetector;
58
         var targetDetector = new ThresholdDetector;
56
         window.targetcolumnname = "";
59
         window.targetcolumnname = "";
57
         var currentDetector = new ThresholdDetector;
60
         var currentDetector = new ThresholdDetector;
385
                             for(var j = 0; j < device.channelCount(); j++) {
388
                             for(var j = 0; j < device.channelCount(); j++) {
386
                                 channels.push(device.getChannel(j));
389
                                 channels.push(device.getChannel(j));
387
                                 columnNames.push(device.channelColumnName(j));
390
                                 columnNames.push(device.channelColumnName(j));
388
-                                channelType.push("T");
391
+                                channelType.push(device.channelType(j));
389
                                 if(device.isChannelHidden(j)) {
392
                                 if(device.isChannelHidden(j)) {
390
                                     channelVisibility.push(false);
393
                                     channelVisibility.push(false);
391
                                 } else {
394
                                 } else {
392
                                     channelVisibility.push(true);
395
                                     channelVisibility.push(true);
393
                                     var indicator = new TemperatureDisplay;
396
                                     var indicator = new TemperatureDisplay;
397
+									if(device.channelType(j) == "C") {
398
+										indicator.setDisplayUnits(Units.Unitless);
399
+										indicator.digitCount = 6;
400
+									}
394
                                     temperatureDisplays.push(indicator);
401
                                     temperatureDisplays.push(indicator);
395
                                     var decorator = new WidgetDecorator(indicator, device.channelIndicatorText(j), 2);
402
                                     var decorator = new WidgetDecorator(indicator, device.channelIndicatorText(j), 2);
396
                                     device.getChannel(j).newData.connect(indicator.setValue);
403
                                     device.getChannel(j).newData.connect(indicator.setValue);
592
 			{
599
 			{
593
 				var colname = driverReference.column;
600
 				var colname = driverReference.column;
594
 				window.targetcolumnname = colname;
601
 				window.targetcolumnname = colname;
602
+				if(driverReference.delay)
603
+				{
604
+					translationdelay.interval = Number(driverReference.delay) * 1000;
605
+				}
595
 				for(var j = 0; j < columnNames.length; j++)
606
 				for(var j = 0; j < columnNames.length; j++)
596
 				{
607
 				{
597
 					if(columnNames[j] == colname)
608
 					if(columnNames[j] == colname)
926
 			}
937
 			}
927
 			return retval;
938
 			return retval;
928
 		};
939
 		};
940
+		translationdelay.timeout.connect(function() {
941
+			offsets[offsetForChannel(translationChannel)].measurement.connect(currentDetector.newMeasurement);
942
+		});
929
         start.clicked.connect(function() {
943
         start.clicked.connect(function() {
930
 			start.enabled = false;
944
 			start.enabled = false;
931
 			hasTranslated = false;
945
 			hasTranslated = false;
956
             }
970
             }
957
 			if(translationChannel >= 0)
971
 			if(translationChannel >= 0)
958
 			{
972
 			{
959
-				offsets[offsetForChannel(translationChannel)].measurement.connect(currentDetector.newMeasurement);
973
+				translationdelay.start();
960
 			}
974
 			}
961
 			if(typeof(externtrans) != 'undefined') {
975
 			if(typeof(externtrans) != 'undefined') {
962
 				externtrans.display(0);
976
 				externtrans.display(0);

+ 31
- 3
src/modbus.w View File

188
     QComboBox *unit = new QComboBox;
188
     QComboBox *unit = new QComboBox;
189
     unit->addItem("Celsius", "C");
189
     unit->addItem("Celsius", "C");
190
     unit->addItem("Fahrenheit", "F");
190
     unit->addItem("Fahrenheit", "F");
191
+    unit->addItem("Control", "Control");
191
     unit->setCurrentIndex(1);
192
     unit->setCurrentIndex(1);
192
     layout->addRow(tr("Unit"), unit);
193
     layout->addRow(tr("Unit"), unit);
193
     QLineEdit *column = new QLineEdit;
194
     QLineEdit *column = new QLineEdit;
299
         case 1:
300
         case 1:
300
             updateAttribute("unit", "F");
301
             updateAttribute("unit", "F");
301
             break;
302
             break;
303
+        case 2:
304
+	        updateAttribute("unit", "Control");
305
+	        break;
302
     }
306
     }
303
 }
307
 }
304
 
308
 
367
         Q_INVOKABLE QString channelColumnName(int);
371
         Q_INVOKABLE QString channelColumnName(int);
368
         Q_INVOKABLE QString channelIndicatorText(int);
372
         Q_INVOKABLE QString channelIndicatorText(int);
369
         Q_INVOKABLE bool isChannelHidden(int);
373
         Q_INVOKABLE bool isChannelHidden(int);
374
+        Q_INVOKABLE QString channelType(int);
370
     private slots:
375
     private slots:
371
         void sendNextMessage();
376
         void sendNextMessage();
372
         void timeout();
377
         void timeout();
385
         QList<QString> channelNames;
390
         QList<QString> channelNames;
386
         QList<QString> channelLabels;
391
         QList<QString> channelLabels;
387
         QList<bool> hiddenStates;
392
         QList<bool> hiddenStates;
393
+        QList<QString> channelTypeList;
388
 };
394
 };
389
 
395
 
390
 @ One of the things that the old Modbus code got right was in allowing the
396
 @ One of the things that the old Modbus code got right was in allowing the
419
     connect(messageDelayTimer, SIGNAL(timeout()), this, SLOT(sendNextMessage()));
425
     connect(messageDelayTimer, SIGNAL(timeout()), this, SLOT(sendNextMessage()));
420
     connect(commTimeout, SIGNAL(timeout()), this, SLOT(timeout()));
426
     connect(commTimeout, SIGNAL(timeout()), this, SLOT(timeout()));
421
     connect(port, SIGNAL(readyRead()), this, SLOT(dataAvailable()));
427
     connect(port, SIGNAL(readyRead()), this, SLOT(dataAvailable()));
422
-    port->open(QIODevice::ReadWrite);
428
+    if(!port->open(QIODevice::ReadWrite))
429
+    {
430
+	    qDebug() << "Failed to open serial port";
431
+    }
423
     for(int i = 0; i < model->rowCount(index); i++)
432
     for(int i = 0; i < model->rowCount(index); i++)
424
     {
433
     {
425
         QModelIndex channelIndex = model->index(i, 0, index);
434
         QModelIndex channelIndex = model->index(i, 0, index);
472
         if(channelAttributes.value("unit").toString() == "C")
481
         if(channelAttributes.value("unit").toString() == "C")
473
         {
482
         {
474
             scanItem.unit = Units::Celsius;
483
             scanItem.unit = Units::Celsius;
484
+            channelTypeList.append("T");
475
         }
485
         }
476
-        else
486
+        else if(channelAttributes.value("unit").toString() == "F")
477
         {
487
         {
478
             scanItem.unit = Units::Fahrenheit;
488
             scanItem.unit = Units::Fahrenheit;
489
+            channelTypeList.append("T");
490
+        }
491
+        else
492
+        {
493
+	        scanItem.unit = Units::Unitless;
494
+	        channelTypeList.append("C");
479
         }
495
         }
480
         scanList.append(scanItem);
496
         scanList.append(scanItem);
481
         channels.append(new Channel);
497
         channels.append(new Channel);
577
         QTime time = QTime::currentTime();
593
         QTime time = QTime::currentTime();
578
         for(int i = 0; i < scanList.size(); i++)
594
         for(int i = 0; i < scanList.size(); i++)
579
         {
595
         {
580
-            channels.at(i)->input(Measurement(scanList.at(i).lastValue, time, Units::Fahrenheit));
596
+	        if(scanList.at(scanPosition).unit == Units::Unitless)
597
+	        {
598
+		        channels.at(i)->input(Measurement(scanList.at(i).lastValue, time, Units::Unitless));
599
+	        }
600
+	        else
601
+	        {
602
+	            channels.at(i)->input(Measurement(scanList.at(i).lastValue, time, Units::Fahrenheit));
603
+            }
581
         }
604
         }
582
     }
605
     }
583
     responseBuffer.clear();
606
     responseBuffer.clear();
633
     return hiddenStates.at(channel);
656
     return hiddenStates.at(channel);
634
 }
657
 }
635
 
658
 
659
+QString ModbusNG::channelType(int channel)
660
+{
661
+	return channelTypeList.at(channel);
662
+}
663
+
636
 @ This class must be exposed to the host environment.
664
 @ This class must be exposed to the host environment.
637
 
665
 
638
 @<Function prototypes for scripting@>=
666
 @<Function prototypes for scripting@>=

+ 51
- 1
src/typica.w View File

840
     /* Nothing needs to be done here. */
840
     /* Nothing needs to be done here. */
841
 }
841
 }
842
 
842
 
843
+@* Timers.
844
+
845
+\noindent Some features in Typica require access to functionality similar to
846
+what |QTimer| provides from the host environment. This includes allowing
847
+script devices to periodically poll connected hardware and allowing a safety
848
+delay on profile translation.
849
+
850
+<@Function prototypes for scripting@>=
851
+void setQTimerProperties(QScriptValue value, QScriptEngine *engine);
852
+QScriptValue constructQTimer(QScriptContext *context, QScriptEngine *engine);
853
+
854
+@ The host environment is informed of the constructor.
855
+
856
+@<Set up the scripting engine@>=
857
+constructor = engine->newFunction(constructQTimer);
858
+value = engine->newQMetaObject(&QTimer::staticMetaObject, constructor);
859
+engine->globalObject().setProperty("Timer", value);
860
+
861
+@ Everything that we are interested in here is a signal, slot, or property so
862
+there is little else to do.
863
+
864
+@<Functions for scripting@>=
865
+void setQTimerProperties(QScriptValue value, QScriptEngine *engine)
866
+{
867
+	setQObjectProperties(value, engine);
868
+}
869
+
870
+QScriptValue constructQTimer(QScriptContext *, QScriptEngine *engine)
871
+{
872
+	QScriptValue object = engine->newQObject(new QTimer);
873
+	setQTimerProperties(object, engine);
874
+	return object;
875
+}
876
+
877
+
843
 @* Scripting QWidget.
878
 @* Scripting QWidget.
844
 
879
 
845
 \noindent The first interesting class in this hierarchy is |QWidget|. This is
880
 \noindent The first interesting class in this hierarchy is |QWidget|. This is
19917
     @[private slots@]:@/
19952
     @[private slots@]:@/
19918
         void updateMatchingColumn(const QString &column);
19953
         void updateMatchingColumn(const QString &column);
19919
         void updateTemperature();
19954
         void updateTemperature();
19955
+        void updateDelay();
19920
     private:@/
19956
     private:@/
19921
         QDoubleSpinBox *temperatureValue;
19957
         QDoubleSpinBox *temperatureValue;
19922
         QComboBox *unitSelector;
19958
         QComboBox *unitSelector;
19959
+        QSpinBox *delaySelector;
19923
 };
19960
 };
19924
 
19961
 
19925
 @ The constructor sets up our user interface.
19962
 @ The constructor sets up our user interface.
19927
 @<TranslationConfWidget implementation@>=
19964
 @<TranslationConfWidget implementation@>=
19928
 TranslationConfWidget::TranslationConfWidget(DeviceTreeModel *model, const QModelIndex &index)
19965
 TranslationConfWidget::TranslationConfWidget(DeviceTreeModel *model, const QModelIndex &index)
19929
 : BasicDeviceConfigurationWidget(model, index),
19966
 : BasicDeviceConfigurationWidget(model, index),
19930
-    temperatureValue(new QDoubleSpinBox), unitSelector(new QComboBox)
19967
+    temperatureValue(new QDoubleSpinBox), unitSelector(new QComboBox),
19968
+    delaySelector(new QSpinBox)
19931
 {
19969
 {
19932
     unitSelector->addItem("Fahrenheit");
19970
     unitSelector->addItem("Fahrenheit");
19933
     unitSelector->addItem("Celsius");
19971
     unitSelector->addItem("Celsius");
19938
     layout->addRow(tr("Column to match:"), column);
19976
     layout->addRow(tr("Column to match:"), column);
19939
     layout->addRow(tr("Unit:"), unitSelector);
19977
     layout->addRow(tr("Unit:"), unitSelector);
19940
     layout->addRow(tr("Value:"), temperatureValue);
19978
     layout->addRow(tr("Value:"), temperatureValue);
19979
+    layout->addRow(tr("Start of batch safety delay:"), delaySelector);
19941
     @<Get device configuration data for current node@>@;
19980
     @<Get device configuration data for current node@>@;
19942
     for(int i = 0; i < configData.size(); i++)
19981
     for(int i = 0; i < configData.size(); i++)
19943
     {
19982
     {
19954
         {
19993
         {
19955
             temperatureValue->setValue(node.attribute("value").toDouble());
19994
             temperatureValue->setValue(node.attribute("value").toDouble());
19956
         }
19995
         }
19996
+        else if(node.attribute("name") == "delay")
19997
+        {
19998
+	        delaySelector->setValue(node.attribute("value").toInt());
19999
+        }
19957
     }
20000
     }
19958
     updateMatchingColumn(column->text());
20001
     updateMatchingColumn(column->text());
19959
     updateTemperature();
20002
     updateTemperature();
20003
+    updateDelay();
19960
     connect(column, SIGNAL(textEdited(QString)), this, SLOT(updateMatchingColumn(QString)));
20004
     connect(column, SIGNAL(textEdited(QString)), this, SLOT(updateMatchingColumn(QString)));
19961
     connect(unitSelector, SIGNAL(currentIndexChanged(QString)), this, SLOT(updateTemperature()));
20005
     connect(unitSelector, SIGNAL(currentIndexChanged(QString)), this, SLOT(updateTemperature()));
19962
     connect(temperatureValue, SIGNAL(valueChanged(double)), this, SLOT(updateTemperature()));
20006
     connect(temperatureValue, SIGNAL(valueChanged(double)), this, SLOT(updateTemperature()));
20007
+    connect(delaySelector, SIGNAL(valueChanged(int)), this, SLOT(updateDelay()));
19963
     setLayout(layout);
20008
     setLayout(layout);
19964
 }
20009
 }
19965
 
20010
 
19987
     updateAttribute("column", column);
20032
     updateAttribute("column", column);
19988
 }
20033
 }
19989
 
20034
 
20035
+void TranslationConfWidget::updateDelay()
20036
+{
20037
+	updateAttribute("delay", QString("%1").arg(delaySelector->value()));
20038
+}
20039
+
19990
 @ This is registered with the configuration system.
20040
 @ This is registered with the configuration system.
19991
 
20041
 
19992
 @<Register device configuration widgets@>=
20042
 @<Register device configuration widgets@>=

Loading…
Cancel
Save