Browse Source

Fixes #82, adds control channels in ModbusNG

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

+ 31
- 3
src/modbus.w View File

@@ -188,6 +188,7 @@ ModbusNGInputConfWidget::ModbusNGInputConfWidget(DeviceTreeModel *model, const Q
188 188
     QComboBox *unit = new QComboBox;
189 189
     unit->addItem("Celsius", "C");
190 190
     unit->addItem("Fahrenheit", "F");
191
+    unit->addItem("Control", "Control");
191 192
     unit->setCurrentIndex(1);
192 193
     layout->addRow(tr("Unit"), unit);
193 194
     QLineEdit *column = new QLineEdit;
@@ -299,6 +300,9 @@ void ModbusNGInputConfWidget::updateUnit(int value)
299 300
         case 1:
300 301
             updateAttribute("unit", "F");
301 302
             break;
303
+        case 2:
304
+	        updateAttribute("unit", "Control");
305
+	        break;
302 306
     }
303 307
 }
304 308
 
@@ -367,6 +371,7 @@ class ModbusNG : public QObject
367 371
         Q_INVOKABLE QString channelColumnName(int);
368 372
         Q_INVOKABLE QString channelIndicatorText(int);
369 373
         Q_INVOKABLE bool isChannelHidden(int);
374
+        Q_INVOKABLE QString channelType(int);
370 375
     private slots:
371 376
         void sendNextMessage();
372 377
         void timeout();
@@ -385,6 +390,7 @@ class ModbusNG : public QObject
385 390
         QList<QString> channelNames;
386 391
         QList<QString> channelLabels;
387 392
         QList<bool> hiddenStates;
393
+        QList<QString> channelTypeList;
388 394
 };
389 395
 
390 396
 @ One of the things that the old Modbus code got right was in allowing the
@@ -419,7 +425,10 @@ ModbusNG::ModbusNG(DeviceTreeModel *model, const QModelIndex &index) :
419 425
     connect(messageDelayTimer, SIGNAL(timeout()), this, SLOT(sendNextMessage()));
420 426
     connect(commTimeout, SIGNAL(timeout()), this, SLOT(timeout()));
421 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 432
     for(int i = 0; i < model->rowCount(index); i++)
424 433
     {
425 434
         QModelIndex channelIndex = model->index(i, 0, index);
@@ -472,10 +481,17 @@ ModbusNG::ModbusNG(DeviceTreeModel *model, const QModelIndex &index) :
472 481
         if(channelAttributes.value("unit").toString() == "C")
473 482
         {
474 483
             scanItem.unit = Units::Celsius;
484
+            channelTypeList.append("T");
475 485
         }
476
-        else
486
+        else if(channelAttributes.value("unit").toString() == "F")
477 487
         {
478 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 496
         scanList.append(scanItem);
481 497
         channels.append(new Channel);
@@ -577,7 +593,14 @@ void ModbusNG::dataAvailable()
577 593
         QTime time = QTime::currentTime();
578 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 606
     responseBuffer.clear();
@@ -633,6 +656,11 @@ bool ModbusNG::isChannelHidden(int channel)
633 656
     return hiddenStates.at(channel);
634 657
 }
635 658
 
659
+QString ModbusNG::channelType(int channel)
660
+{
661
+	return channelTypeList.at(channel);
662
+}
663
+
636 664
 @ This class must be exposed to the host environment.
637 665
 
638 666
 @<Function prototypes for scripting@>=

+ 51
- 1
src/typica.w View File

@@ -840,6 +840,41 @@ void setQLayoutItemProperties(QScriptValue, QScriptEngine *)
840 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 878
 @* Scripting QWidget.
844 879
 
845 880
 \noindent The first interesting class in this hierarchy is |QWidget|. This is
@@ -19917,9 +19952,11 @@ class TranslationConfWidget : public BasicDeviceConfigurationWidget
19917 19952
     @[private slots@]:@/
19918 19953
         void updateMatchingColumn(const QString &column);
19919 19954
         void updateTemperature();
19955
+        void updateDelay();
19920 19956
     private:@/
19921 19957
         QDoubleSpinBox *temperatureValue;
19922 19958
         QComboBox *unitSelector;
19959
+        QSpinBox *delaySelector;
19923 19960
 };
19924 19961
 
19925 19962
 @ The constructor sets up our user interface.
@@ -19927,7 +19964,8 @@ class TranslationConfWidget : public BasicDeviceConfigurationWidget
19927 19964
 @<TranslationConfWidget implementation@>=
19928 19965
 TranslationConfWidget::TranslationConfWidget(DeviceTreeModel *model, const QModelIndex &index)
19929 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 19970
     unitSelector->addItem("Fahrenheit");
19933 19971
     unitSelector->addItem("Celsius");
@@ -19938,6 +19976,7 @@ TranslationConfWidget::TranslationConfWidget(DeviceTreeModel *model, const QMode
19938 19976
     layout->addRow(tr("Column to match:"), column);
19939 19977
     layout->addRow(tr("Unit:"), unitSelector);
19940 19978
     layout->addRow(tr("Value:"), temperatureValue);
19979
+    layout->addRow(tr("Start of batch safety delay:"), delaySelector);
19941 19980
     @<Get device configuration data for current node@>@;
19942 19981
     for(int i = 0; i < configData.size(); i++)
19943 19982
     {
@@ -19954,12 +19993,18 @@ TranslationConfWidget::TranslationConfWidget(DeviceTreeModel *model, const QMode
19954 19993
         {
19955 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 20001
     updateMatchingColumn(column->text());
19959 20002
     updateTemperature();
20003
+    updateDelay();
19960 20004
     connect(column, SIGNAL(textEdited(QString)), this, SLOT(updateMatchingColumn(QString)));
19961 20005
     connect(unitSelector, SIGNAL(currentIndexChanged(QString)), this, SLOT(updateTemperature()));
19962 20006
     connect(temperatureValue, SIGNAL(valueChanged(double)), this, SLOT(updateTemperature()));
20007
+    connect(delaySelector, SIGNAL(valueChanged(int)), this, SLOT(updateDelay()));
19963 20008
     setLayout(layout);
19964 20009
 }
19965 20010
 
@@ -19987,6 +20032,11 @@ void TranslationConfWidget::updateMatchingColumn(const QString &column)
19987 20032
     updateAttribute("column", column);
19988 20033
 }
19989 20034
 
20035
+void TranslationConfWidget::updateDelay()
20036
+{
20037
+	updateAttribute("delay", QString("%1").arg(delaySelector->value()));
20038
+}
20039
+
19990 20040
 @ This is registered with the configuration system.
19991 20041
 
19992 20042
 @<Register device configuration widgets@>=

Loading…
Cancel
Save