| 
				
			 | 
			
			
				
				@@ -0,0 +1,695 @@ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				1
			 | 
			
			
				
				+@** Script Driven Devices. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				2
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				3
			 | 
			
			
				
				+\noindent There are many data acquisition products that are reasonable to use 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				4
			 | 
			
			
				
				+with \pn which are not natively supported due to lack of available hardware 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				5
			 | 
			
			
				
				+for testing, lack of time or money to develop that support, or lack of 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				6
			 | 
			
			
				
				+documentation. It has also become relatively simple for hardware tinkerers to 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				7
			 | 
			
			
				
				+develop new devices matching this description as well. Vendors in this space 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				8
			 | 
			
			
				
				+tend to give inadequate consideration to interoperability and with some devices 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				9
			 | 
			
			
				
				+the communications protocol used changes significantly between firmware 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				10
			 | 
			
			
				
				+revisions. There are simply far too many devices like this to support 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				11
			 | 
			
			
				
				+everything. At the same time there are people with these devices who are 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				12
			 | 
			
			
				
				+capable of programming the basic communications handling but have difficulty 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				13
			 | 
			
			
				
				+with integrating that with \pn. By providing an in-program environment that 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				14
			 | 
			
			
				
				+handles much of the boilerplate and allowing people to write scripts 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				15
			 | 
			
			
				
				+implementing these protocols without the need to modify core \pn code or 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				16
			 | 
			
			
				
				+recompile the program, these people may find it easier to make their existing 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				17
			 | 
			
			
				
				+hardware work. Such scripts can also serve as prototypes for native support. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				18
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				19
			 | 
			
			
				
				+Configuration widgets for these devices allow key value pairs to be specified 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				20
			 | 
			
			
				
				+both at the device level and on a per-channel basis. This is intentionally kept 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				21
			 | 
			
			
				
				+generic as it is impossible to know what configurable details may be required. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				22
			 | 
			
			
				
				+Common configurations will have a device node representing a single logical 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				23
			 | 
			
			
				
				+device, usually a single physical device but this is not in any way enforced, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				24
			 | 
			
			
				
				+and one child node per channel. These details are made available to the device 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				25
			 | 
			
			
				
				+script and are used to integrate with the logging view. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				26
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				27
			 | 
			
			
				
				+Some of the naming conventions used here are legacy of the initial conception 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				28
			 | 
			
			
				
				+of this feature and should be changed before release if there is time to do so. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				29
			 | 
			
			
				
				+While initial support will be focused on devices that present as a serial port, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				30
			 | 
			
			
				
				+there is no reason this could not be extended to cover devices that are 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				31
			 | 
			
			
				
				+interfaced through USB HID, Bluetooth, COM, output piped from an external 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				32
			 | 
			
			
				
				+console program, devices interfaced through arbitrary libraries, or any other 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				33
			 | 
			
			
				
				+class of device not directly supported in the core code should there be an 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				34
			 | 
			
			
				
				+interest in any of these. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				35
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				36
			 | 
			
			
				
				+@<Class declarations@>= 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				37
			 | 
			
			
				
				+class UnsupportedSerialDeviceConfWidget : public BasicDeviceConfigurationWidget 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				38
			 | 
			
			
				
				+{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				39
			 | 
			
			
				
				+	Q_OBJECT 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				40
			 | 
			
			
				
				+	public: 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				41
			 | 
			
			
				
				+		Q_INVOKABLE UnsupportedSerialDeviceConfWidget(DeviceTreeModel *model, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				42
			 | 
			
			
				
				+		                                              const QModelIndex &index); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				43
			 | 
			
			
				
				+	private slots: 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				44
			 | 
			
			
				
				+		void updateConfiguration(); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				45
			 | 
			
			
				
				+		void saveScript(); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				46
			 | 
			
			
				
				+		void addChannel(); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				47
			 | 
			
			
				
				+	private: 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				48
			 | 
			
			
				
				+		SaltModel *deviceSettingsModel; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				49
			 | 
			
			
				
				+		QTextEdit *scriptEditor; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				50
			 | 
			
			
				
				+}; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				51
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				52
			 | 
			
			
				
				+@ The device configuration widget consists of two tabs. One tab provides a 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				53
			 | 
			
			
				
				+button for adding channels and an area for entering device specific 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				54
			 | 
			
			
				
				+configuration details. The other provides an area for entering the device 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				55
			 | 
			
			
				
				+script. This may be extended later to provide better editing, testing, and 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				56
			 | 
			
			
				
				+debugging support, but the initial concern is simply having a working feature. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				57
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				58
			 | 
			
			
				
				+@<UnsupportedSerialDeviceConfWidget implementation@>= 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				59
			 | 
			
			
				
				+UnsupportedSerialDeviceConfWidget::UnsupportedSerialDeviceConfWidget(DeviceTreeModel *model, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				60
			 | 
			
			
				
				+                                                                     const QModelIndex &index) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				61
			 | 
			
			
				
				+	: BasicDeviceConfigurationWidget(model, index), 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				62
			 | 
			
			
				
				+	deviceSettingsModel(new SaltModel(2)), 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				63
			 | 
			
			
				
				+	scriptEditor(new QTextEdit) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				64
			 | 
			
			
				
				+{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				65
			 | 
			
			
				
				+	scriptEditor->setTabStopWidth(20); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				66
			 | 
			
			
				
				+	QVBoxLayout *dummyLayout = new QVBoxLayout; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				67
			 | 
			
			
				
				+	QTabWidget *central = new QTabWidget; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				68
			 | 
			
			
				
				+	QWidget *deviceConfigurationWidget = new QWidget; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				69
			 | 
			
			
				
				+	QVBoxLayout *deviceConfigurationLayout = new QVBoxLayout; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				70
			 | 
			
			
				
				+	QPushButton *addChannelButton = new QPushButton(tr("Add Channel")); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				71
			 | 
			
			
				
				+	deviceConfigurationLayout->addWidget(addChannelButton); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				72
			 | 
			
			
				
				+	connect(addChannelButton, SIGNAL(clicked()), this, SLOT(addChannel())); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				73
			 | 
			
			
				
				+	QLabel *deviceSettingsLabel = new QLabel(tr("Device Settings:")); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				74
			 | 
			
			
				
				+	deviceConfigurationLayout->addWidget(deviceSettingsLabel); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				75
			 | 
			
			
				
				+	QTableView *deviceSettingsView = new QTableView; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				76
			 | 
			
			
				
				+	deviceSettingsModel->setHeaderData(0, Qt::Horizontal, tr("Key")); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				77
			 | 
			
			
				
				+	deviceSettingsModel->setHeaderData(1, Qt::Horizontal, tr("Value")); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				78
			 | 
			
			
				
				+	deviceSettingsView->setModel(deviceSettingsModel); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				79
			 | 
			
			
				
				+	deviceConfigurationLayout->addWidget(deviceSettingsView); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				80
			 | 
			
			
				
				+	 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				81
			 | 
			
			
				
				+	deviceConfigurationWidget->setLayout(deviceConfigurationLayout); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				82
			 | 
			
			
				
				+	central->addTab(deviceConfigurationWidget, tr("Configuration")); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				83
			 | 
			
			
				
				+	central->addTab(scriptEditor, tr("Script")); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				84
			 | 
			
			
				
				+	dummyLayout->addWidget(central); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				85
			 | 
			
			
				
				+	 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				86
			 | 
			
			
				
				+	@<Get device configuration data for current node@>@; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				87
			 | 
			
			
				
				+	for(int i = 0; i < configData.size(); i++) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				88
			 | 
			
			
				
				+	{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				89
			 | 
			
			
				
				+		node = configData.at(i).toElement(); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				90
			 | 
			
			
				
				+		if(node.attribute("name") == "keys" || node.attribute("name") == "values") 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				91
			 | 
			
			
				
				+		{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				92
			 | 
			
			
				
				+			int column = 0; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				93
			 | 
			
			
				
				+			if(node.attribute("name") == "values") 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				94
			 | 
			
			
				
				+			{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				95
			 | 
			
			
				
				+				column = 1; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				96
			 | 
			
			
				
				+			} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				97
			 | 
			
			
				
				+			QString data = node.attribute("value"); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				98
			 | 
			
			
				
				+			if(data.length() > 3) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				99
			 | 
			
			
				
				+			{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				100
			 | 
			
			
				
				+				data.chop(2); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				101
			 | 
			
			
				
				+				data = data.remove(0, 2); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				102
			 | 
			
			
				
				+			} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				103
			 | 
			
			
				
				+			QStringList keyList = data.split(", "); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				104
			 | 
			
			
				
				+			for(int j = 0; j < keyList.size(); j++) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				105
			 | 
			
			
				
				+			{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				106
			 | 
			
			
				
				+				deviceSettingsModel->setData(deviceSettingsModel->index(j, column), 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				107
			 | 
			
			
				
				+				                             QVariant(keyList.at(j)), 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				108
			 | 
			
			
				
				+				                             Qt::EditRole); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				109
			 | 
			
			
				
				+			} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				110
			 | 
			
			
				
				+		} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				111
			 | 
			
			
				
				+		else if(node.attribute("name") == "script") 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				112
			 | 
			
			
				
				+		{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				113
			 | 
			
			
				
				+			scriptEditor->setPlainText(node.attribute("value")); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				114
			 | 
			
			
				
				+		} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				115
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				116
			 | 
			
			
				
				+	 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				117
			 | 
			
			
				
				+	connect(deviceSettingsModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)), 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				118
			 | 
			
			
				
				+	        this, SLOT(updateConfiguration())); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				119
			 | 
			
			
				
				+	connect(scriptEditor, SIGNAL(textChanged()), this, SLOT(saveScript())); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				120
			 | 
			
			
				
				+	setLayout(dummyLayout); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				121
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				122
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				123
			 | 
			
			
				
				+@ Device configuration data is entered through an ordinary |QTableView| with a 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				124
			 | 
			
			
				
				+|SaltModel| backing. The original use case for that model does not apply here, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				125
			 | 
			
			
				
				+but that model does ensure that additional blank rows are added as needed so 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				126
			 | 
			
			
				
				+that arbitrarily many key value pairs can be entered. When data changes in the 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				127
			 | 
			
			
				
				+model we write the full content of the model out. Note that commas may not be 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				128
			 | 
			
			
				
				+used in keys or values. For keys in which lists make sense, a different 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				129
			 | 
			
			
				
				+delimiter must be chosen. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				130
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				131
			 | 
			
			
				
				+@<UnsupportedSerialDeviceConfWidget implementation@>= 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				132
			 | 
			
			
				
				+void UnsupportedSerialDeviceConfWidget::updateConfiguration() 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				133
			 | 
			
			
				
				+{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				134
			 | 
			
			
				
				+	updateAttribute("keys", deviceSettingsModel->arrayLiteral(0, Qt::DisplayRole)); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				135
			 | 
			
			
				
				+	updateAttribute("values", deviceSettingsModel->arrayLiteral(1, Qt::DisplayRole)); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				136
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				137
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				138
			 | 
			
			
				
				+@ Every time the script text is changed, the new version of the script is 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				139
			 | 
			
			
				
				+saved. My expectation is that scripts will either be small or that they will be 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				140
			 | 
			
			
				
				+pasted in from outside of \pn so that this decision will not cause usability 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				141
			 | 
			
			
				
				+issues, however if I am wrong about this there may be a need to handle this 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				142
			 | 
			
			
				
				+more intelligently. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				143
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				144
			 | 
			
			
				
				+@<UnsupportedSerialDeviceConfWidget implementation@>= 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				145
			 | 
			
			
				
				+void UnsupportedSerialDeviceConfWidget::saveScript() 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				146
			 | 
			
			
				
				+{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				147
			 | 
			
			
				
				+	updateAttribute("script", scriptEditor->toPlainText()); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				148
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				149
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				150
			 | 
			
			
				
				+@ Typica requires channel nodes to simplify integration with other existing 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				151
			 | 
			
			
				
				+device code. Providing a new node type allows arbitrary attributes to be 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				152
			 | 
			
			
				
				+configured on a per-channel basis without resorting to strange conventions in 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				153
			 | 
			
			
				
				+the device configuration. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				154
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				155
			 | 
			
			
				
				+@<UnsupportedSerialDeviceConfWidget implementation@>= 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				156
			 | 
			
			
				
				+void UnsupportedSerialDeviceConfWidget::addChannel() 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				157
			 | 
			
			
				
				+{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				158
			 | 
			
			
				
				+	insertChildNode(tr("Channel"), "unsupporteddevicechannel"); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				159
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				160
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				161
			 | 
			
			
				
				+@ Channel configuration for unsupported devices is like unsupported device 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				162
			 | 
			
			
				
				+configuration in that arbitrary key value pairs may be entered for use by the 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				163
			 | 
			
			
				
				+device script. Conventions common to all other channel node types are also 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				164
			 | 
			
			
				
				+present here. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				165
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				166
			 | 
			
			
				
				+@<Class declarations@>= 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				167
			 | 
			
			
				
				+class UnsupportedDeviceChannelConfWidget : public BasicDeviceConfigurationWidget 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				168
			 | 
			
			
				
				+{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				169
			 | 
			
			
				
				+	Q_OBJECT 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				170
			 | 
			
			
				
				+	public: 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				171
			 | 
			
			
				
				+		Q_INVOKABLE UnsupportedDeviceChannelConfWidget(DeviceTreeModel *model, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				172
			 | 
			
			
				
				+		                                               const QModelIndex &index); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				173
			 | 
			
			
				
				+	private slots: 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				174
			 | 
			
			
				
				+		void updateColumnName(const QString &value); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				175
			 | 
			
			
				
				+		void updateHidden(bool hidden); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				176
			 | 
			
			
				
				+		void updateConfiguration(); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				177
			 | 
			
			
				
				+	private: 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				178
			 | 
			
			
				
				+		SaltModel *channelSettingsModel; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				179
			 | 
			
			
				
				+}; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				180
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				181
			 | 
			
			
				
				+@ The constructor is typical for for channel node configuraion widgets. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				182
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				183
			 | 
			
			
				
				+@<UnsupportedSerialDeviceConfWidget implementation@>= 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				184
			 | 
			
			
				
				+UnsupportedDeviceChannelConfWidget::UnsupportedDeviceChannelConfWidget(DeviceTreeModel *model, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				185
			 | 
			
			
				
				+                                                                       const QModelIndex &index) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				186
			 | 
			
			
				
				+	: BasicDeviceConfigurationWidget(model, index), 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				187
			 | 
			
			
				
				+	channelSettingsModel(new SaltModel(2)) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				188
			 | 
			
			
				
				+{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				189
			 | 
			
			
				
				+	QFormLayout *layout = new QFormLayout; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				190
			 | 
			
			
				
				+	QLineEdit *columnName = new QLineEdit; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				191
			 | 
			
			
				
				+	layout->addRow(tr("Column Name:"), columnName); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				192
			 | 
			
			
				
				+	QCheckBox *hideSeries = new QCheckBox("Hide this channel"); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				193
			 | 
			
			
				
				+	layout->addRow(hideSeries); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				194
			 | 
			
			
				
				+	QTableView *channelSettings = new QTableView; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				195
			 | 
			
			
				
				+	channelSettingsModel->setHeaderData(0, Qt::Horizontal, "Key"); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				196
			 | 
			
			
				
				+	channelSettingsModel->setHeaderData(1, Qt::Horizontal, "Value"); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				197
			 | 
			
			
				
				+	channelSettings->setModel(channelSettingsModel); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				198
			 | 
			
			
				
				+	layout->addRow(channelSettings); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				199
			 | 
			
			
				
				+	setLayout(layout); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				200
			 | 
			
			
				
				+	@<Get device configuration data for current node@>@; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				201
			 | 
			
			
				
				+	for(int i = 0; i < configData.size(); i++) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				202
			 | 
			
			
				
				+	{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				203
			 | 
			
			
				
				+		node = configData.at(i).toElement(); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				204
			 | 
			
			
				
				+		if(node.attribute("name") == "columnname") 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				205
			 | 
			
			
				
				+		{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				206
			 | 
			
			
				
				+			columnName->setText(node.attribute("value")); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				207
			 | 
			
			
				
				+		} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				208
			 | 
			
			
				
				+		else if(node.attribute("name") == "hidden") 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				209
			 | 
			
			
				
				+		{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				210
			 | 
			
			
				
				+			hideSeries->setChecked(node.attribute("value") == "true"); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				211
			 | 
			
			
				
				+		} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				212
			 | 
			
			
				
				+		else if(node.attribute("name") == "keys" || node.attribute("name") == "values") 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				213
			 | 
			
			
				
				+		{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				214
			 | 
			
			
				
				+			int column = 0; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				215
			 | 
			
			
				
				+			if(node.attribute("name") == "values") 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				216
			 | 
			
			
				
				+			{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				217
			 | 
			
			
				
				+				column = 1; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				218
			 | 
			
			
				
				+			} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				219
			 | 
			
			
				
				+			QString data = node.attribute("value"); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				220
			 | 
			
			
				
				+			if(data.length() > 3) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				221
			 | 
			
			
				
				+			{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				222
			 | 
			
			
				
				+				data.chop(2); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				223
			 | 
			
			
				
				+				data = data.remove(0, 2); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				224
			 | 
			
			
				
				+			} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				225
			 | 
			
			
				
				+			QStringList keyList = data.split(", "); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				226
			 | 
			
			
				
				+			for(int j = 0; j < keyList.size(); j++) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				227
			 | 
			
			
				
				+			{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				228
			 | 
			
			
				
				+				channelSettingsModel->setData(channelSettingsModel->index(j, column), 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				229
			 | 
			
			
				
				+				                              QVariant(keyList.at(j)), 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				230
			 | 
			
			
				
				+				                              Qt::EditRole); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				231
			 | 
			
			
				
				+			} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				232
			 | 
			
			
				
				+		} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				233
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				234
			 | 
			
			
				
				+	connect(columnName, SIGNAL(textEdited(QString)), this, SLOT(updateColumnName(QString))); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				235
			 | 
			
			
				
				+	connect(hideSeries, SIGNAL(toggled(bool)), this, SLOT(updateHidden(bool))); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				236
			 | 
			
			
				
				+	connect(channelSettingsModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)), 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				237
			 | 
			
			
				
				+	        this, SLOT(updateConfiguration())); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				238
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				239
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				240
			 | 
			
			
				
				+@ Arbitrary channel configuration data is handled in the same way as device 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				241
			 | 
			
			
				
				+level settings while the column name and hidden status is handled in the same 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				242
			 | 
			
			
				
				+way as they are in other channel nodes. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				243
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				244
			 | 
			
			
				
				+@<UnsupportedSerialDeviceConfWidget implementation@>= 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				245
			 | 
			
			
				
				+void UnsupportedDeviceChannelConfWidget::updateColumnName(const QString &value) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				246
			 | 
			
			
				
				+{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				247
			 | 
			
			
				
				+	updateAttribute("columnname", value); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				248
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				249
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				250
			 | 
			
			
				
				+void UnsupportedDeviceChannelConfWidget::updateHidden(bool hidden) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				251
			 | 
			
			
				
				+{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				252
			 | 
			
			
				
				+	updateAttribute("hidden", hidden ? "true" : "false"); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				253
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				254
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				255
			 | 
			
			
				
				+void UnsupportedDeviceChannelConfWidget::updateConfiguration() 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				256
			 | 
			
			
				
				+{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				257
			 | 
			
			
				
				+	updateAttribute("keys", channelSettingsModel->arrayLiteral(0, Qt::DisplayRole)); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				258
			 | 
			
			
				
				+	updateAttribute("values", channelSettingsModel->arrayLiteral(1, Qt::DisplayRole)); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				259
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				260
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				261
			 | 
			
			
				
				+@ The configuration widgets need to be registered so they can be instantiated 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				262
			 | 
			
			
				
				+as appropriate. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				263
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				264
			 | 
			
			
				
				+@<Register device configuration widgets@>= 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				265
			 | 
			
			
				
				+app.registerDeviceConfigurationWidget("unsupporteddevicechannel", 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				266
			 | 
			
			
				
				+	UnsupportedDeviceChannelConfWidget::staticMetaObject); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				267
			 | 
			
			
				
				+app.registerDeviceConfigurationWidget("unsupporteddevice", 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				268
			 | 
			
			
				
				+	UnsupportedSerialDeviceConfWidget::staticMetaObject); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				269
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				270
			 | 
			
			
				
				+@ A |NodeInserter| for the device node is also provided. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				271
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				272
			 | 
			
			
				
				+@<Register top level device configuration nodes@>= 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				273
			 | 
			
			
				
				+inserter = new NodeInserter(tr("Other Device"), tr("Other Device"), 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				274
			 | 
			
			
				
				+	"unsupporteddevice", NULL); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				275
			 | 
			
			
				
				+topLevelNodeInserters.append(inserter); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				276
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				277
			 | 
			
			
				
				+@ A device abstraction is not strictly required for this feature, however 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				278
			 | 
			
			
				
				+having one greatly simplifies integrating this feature. At some point I would 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				279
			 | 
			
			
				
				+like to revise other device abstraction classes so that a huge amount of 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				280
			 | 
			
			
				
				+boilerplate associated with these can be removed from configuration documents. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				281
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				282
			 | 
			
			
				
				+This device abstraction includes features in a few particular categories. First 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				283
			 | 
			
			
				
				+there are methods that are required for integrating the device with the logging 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				284
			 | 
			
			
				
				+view. The logging view instantiates the device abstraction, passing in the 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				285
			 | 
			
			
				
				+configuration data required to properly set up the device. It then is able to 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				286
			 | 
			
			
				
				+query information about the measurement channels that have been configured for 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				287
			 | 
			
			
				
				+this device and can set up all of the relevant indicators. Some device classes 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				288
			 | 
			
			
				
				+may be able to produce annotations, so this class can be treated exactly the 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				289
			 | 
			
			
				
				+same as any other annotation source. Another requested feature includes the 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				290
			 | 
			
			
				
				+ability of a device to trigger the start and end of batches, so signals are 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				291
			 | 
			
			
				
				+provided for this capability. Finally, there are methods associated with 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				292
			 | 
			
			
				
				+starting and stopping the device. The |start()| method will be called when the 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				293
			 | 
			
			
				
				+logging view has finished making all of the signal connections. The |stop()| 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				294
			 | 
			
			
				
				+method will be called when the logging view is closed, giving script code the 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				295
			 | 
			
			
				
				+chance to cleanly release any resources that must be held for device 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				296
			 | 
			
			
				
				+communications. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				297
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				298
			 | 
			
			
				
				+@<Class declarations@>= 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				299
			 | 
			
			
				
				+class JavaScriptDevice : public QObject 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				300
			 | 
			
			
				
				+{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				301
			 | 
			
			
				
				+	Q_OBJECT 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				302
			 | 
			
			
				
				+	public: 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				303
			 | 
			
			
				
				+		Q_INVOKABLE JavaScriptDevice(const QModelIndex &deviceIndex, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				304
			 | 
			
			
				
				+		                             QScriptEngine *engine); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				305
			 | 
			
			
				
				+		Q_INVOKABLE int channelCount(); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				306
			 | 
			
			
				
				+		Channel* getChannel(int channel); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				307
			 | 
			
			
				
				+		Q_INVOKABLE bool isChannelHidden(int channel); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				308
			 | 
			
			
				
				+		Q_INVOKABLE Units::Unit expectedChannelUnit(int channel); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				309
			 | 
			
			
				
				+		Q_INVOKABLE QString channelColumnName(int channel); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				310
			 | 
			
			
				
				+		Q_INVOKABLE QString channelIndicatorText(int channel); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				311
			 | 
			
			
				
				+	public slots: 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				312
			 | 
			
			
				
				+		void setTemperatureColumn(int tcol); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				313
			 | 
			
			
				
				+		void setAnnotationColumn(int ncol); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				314
			 | 
			
			
				
				+		void start(); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				315
			 | 
			
			
				
				+		void stop(); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				316
			 | 
			
			
				
				+	signals: 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				317
			 | 
			
			
				
				+		void annotation(QString note, int tcol, int ncol); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				318
			 | 
			
			
				
				+		void triggerStartBatch(); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				319
			 | 
			
			
				
				+		void triggerStopBatch(); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				320
			 | 
			
			
				
				+		void deviceStopRequested(); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				321
			 | 
			
			
				
				+	private: 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				322
			 | 
			
			
				
				+		QVariantMap deviceSettings; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				323
			 | 
			
			
				
				+		QString deviceScript; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				324
			 | 
			
			
				
				+		QList<Channel *> channelList; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				325
			 | 
			
			
				
				+		QList<bool> hiddenState; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				326
			 | 
			
			
				
				+		QList<Units::Unit> channelUnits; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				327
			 | 
			
			
				
				+		QList<QString> columnNames; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				328
			 | 
			
			
				
				+		QList<QString> indicatorTexts; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				329
			 | 
			
			
				
				+		QList<QVariantMap> channelSettings; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				330
			 | 
			
			
				
				+		int annotationTemperatureColumn; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				331
			 | 
			
			
				
				+		int annotationNoteColumn; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				332
			 | 
			
			
				
				+		QScriptEngine *scriptengine; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				333
			 | 
			
			
				
				+}; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				334
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				335
			 | 
			
			
				
				+@ The |JavaScriptDevice| instance provides two interfaces. Its invokable 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				336
			 | 
			
			
				
				+methods provide the information needed to integrate script driven devices with 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				337
			 | 
			
			
				
				+a generic logging view. Additional information is also exposed through the host 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				338
			 | 
			
			
				
				+environment running the device script. This means that the class requires 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				339
			 | 
			
			
				
				+knowledge of the host environment, which it obtains through a script function 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				340
			 | 
			
			
				
				+similar to what is done for window creation. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				341
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				342
			 | 
			
			
				
				+The name of the function is generic so this may be easily extended later to 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				343
			 | 
			
			
				
				+create all device abstraction instances. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				344
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				345
			 | 
			
			
				
				+@<Function prototypes for scripting@>= 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				346
			 | 
			
			
				
				+QScriptValue createDevice(QScriptContext *context, QScriptEngine *engine); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				347
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				348
			 | 
			
			
				
				+@ That method is made available to the scripting engine. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				349
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				350
			 | 
			
			
				
				+@<Set up the scripting engine@>= 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				351
			 | 
			
			
				
				+engine->globalObject().setProperty("createDevice", 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				352
			 | 
			
			
				
				+                                   engine->newFunction(createDevice)); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				353
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				354
			 | 
			
			
				
				+@ This function currently creates a |JavaScriptDevice| from a device 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				355
			 | 
			
			
				
				+configuration node which must be passed through as an argument. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				356
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				357
			 | 
			
			
				
				+@<Functions for scripting@>= 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				358
			 | 
			
			
				
				+QScriptValue createDevice(QScriptContext *context, QScriptEngine *engine)@/ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				359
			 | 
			
			
				
				+{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				360
			 | 
			
			
				
				+	QModelIndex deviceIndex = argument<QModelIndex>(0, context); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				361
			 | 
			
			
				
				+	JavaScriptDevice *device = new JavaScriptDevice(deviceIndex, engine); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				362
			 | 
			
			
				
				+	QScriptValue object = engine->newQObject(device); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				363
			 | 
			
			
				
				+	setQObjectProperties(object, engine); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				364
			 | 
			
			
				
				+	object.setProperty("getChannel", engine->newFunction(JavaScriptDevice_getChannel)); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				365
			 | 
			
			
				
				+	return object; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				366
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				367
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				368
			 | 
			
			
				
				+@ The |start()| method is responsible for preparing the host environment and 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				369
			 | 
			
			
				
				+executing the device script. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				370
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				371
			 | 
			
			
				
				+@<JavaScriptDevice implementation@>= 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				372
			 | 
			
			
				
				+void JavaScriptDevice::start() 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				373
			 | 
			
			
				
				+{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				374
			 | 
			
			
				
				+	QScriptValue object = scriptengine->newQObject(this); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				375
			 | 
			
			
				
				+	@<Expose device settings as object property@>@; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				376
			 | 
			
			
				
				+	@<Expose channels and channel settings to device script@>@; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				377
			 | 
			
			
				
				+	QScriptContext *context = scriptengine->currentContext(); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				378
			 | 
			
			
				
				+	QScriptValue oldThis = context->thisObject(); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				379
			 | 
			
			
				
				+	context->setThisObject(object); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				380
			 | 
			
			
				
				+	QScriptValue result = scriptengine->evaluate(deviceScript); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				381
			 | 
			
			
				
				+	QScriptEngine *engine = scriptengine; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				382
			 | 
			
			
				
				+	@<Report scripting errors@>@; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				383
			 | 
			
			
				
				+	context->setThisObject(oldThis); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				384
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				385
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				386
			 | 
			
			
				
				+@ Device settings are only needed from the device script itself. As such, these 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				387
			 | 
			
			
				
				+are presented under a settings property available from the |this| object when 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				388
			 | 
			
			
				
				+the script is run. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				389
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				390
			 | 
			
			
				
				+@<Expose device settings as object property@>= 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				391
			 | 
			
			
				
				+QScriptValue settingsObject = scriptengine->newObject(); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				392
			 | 
			
			
				
				+QVariantMap::const_iterator i = deviceSettings.constBegin(); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				393
			 | 
			
			
				
				+while(i != deviceSettings.constEnd()) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				394
			 | 
			
			
				
				+{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				395
			 | 
			
			
				
				+	settingsObject.setProperty(i.key(), i.value().toString()); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				396
			 | 
			
			
				
				+	i++; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				397
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				398
			 | 
			
			
				
				+object.setProperty("settings", settingsObject); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				399
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				400
			 | 
			
			
				
				+@ While channels are available to the device script through the same 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				401
			 | 
			
			
				
				+|getChannel()| interface used outside of the device script for integration 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				402
			 | 
			
			
				
				+purposes, it is more convenient to have an array of channels with channel 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				403
			 | 
			
			
				
				+specific settings as properties of the channel. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				404
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				405
			 | 
			
			
				
				+@<Expose channels and channel settings to device script@>= 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				406
			 | 
			
			
				
				+QScriptValue channelsArray = scriptengine->newArray(channelCount()); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				407
			 | 
			
			
				
				+for(int i = 0; i < channelCount(); i++) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				408
			 | 
			
			
				
				+{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				409
			 | 
			
			
				
				+	QScriptValue channelObject = scriptengine->newQObject(getChannel(i)); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				410
			 | 
			
			
				
				+	QScriptValue channelSettingsObject = scriptengine->newObject(); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				411
			 | 
			
			
				
				+	QVariantMap::const_iterator j = channelSettings.at(i).constBegin(); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				412
			 | 
			
			
				
				+	while(j != channelSettings.at(i).constEnd()) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				413
			 | 
			
			
				
				+	{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				414
			 | 
			
			
				
				+		channelSettingsObject.setProperty(j.key(), j.value().toString()); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				415
			 | 
			
			
				
				+		j++; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				416
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				417
			 | 
			
			
				
				+	channelObject.setProperty("settings", channelSettingsObject); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				418
			 | 
			
			
				
				+	channelsArray.setProperty(i, channelObject); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				419
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				420
			 | 
			
			
				
				+object.setProperty("channels", channelsArray); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				421
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				422
			 | 
			
			
				
				+@ Currently we require wrapper functions to work with channels in the host 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				423
			 | 
			
			
				
				+environment. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				424
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				425
			 | 
			
			
				
				+@<Function prototypes for scripting@>= 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				426
			 | 
			
			
				
				+QScriptValue JavaScriptDevice_getChannel(QScriptContext *context, QScriptEngine *engine); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				427
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				428
			 | 
			
			
				
				+@ The implementation is trivial. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				429
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				430
			 | 
			
			
				
				+@<Functions for scripting@>= 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				431
			 | 
			
			
				
				+QScriptValue JavaScriptDevice_getChannel(QScriptContext *context, QScriptEngine *engine) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				432
			 | 
			
			
				
				+{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				433
			 | 
			
			
				
				+	JavaScriptDevice *self = getself<JavaScriptDevice *>(context); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				434
			 | 
			
			
				
				+	QScriptValue object; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				435
			 | 
			
			
				
				+	if(self) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				436
			 | 
			
			
				
				+	{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				437
			 | 
			
			
				
				+		object = engine->newQObject(self->getChannel(argument<int>(0, context))); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				438
			 | 
			
			
				
				+		setChannelProperties(object, engine); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				439
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				440
			 | 
			
			
				
				+	return object; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				441
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				442
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				443
			 | 
			
			
				
				+@ The |stop()| method just fires off a signal that the script can hook into for 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				444
			 | 
			
			
				
				+any required cleanup. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				445
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				446
			 | 
			
			
				
				+@<JavaScriptDevice implementation@>= 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				447
			 | 
			
			
				
				+void JavaScriptDevice::stop() 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				448
			 | 
			
			
				
				+{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				449
			 | 
			
			
				
				+	emit deviceStopRequested(); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				450
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				451
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				452
			 | 
			
			
				
				+@ The constructor is responsible for all boilerplate initialization required 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				453
			 | 
			
			
				
				+for integrating script defined devices with the logging view. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				454
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				455
			 | 
			
			
				
				+Note: At present expected units are assumed to be Fahrenheit. The configuration 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				456
			 | 
			
			
				
				+widget must be updated to allow at least for control measurements and 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				457
			 | 
			
			
				
				+eventually support for runtime defined units should also be added. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				458
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				459
			 | 
			
			
				
				+@<JavaScriptDevice implementation@>= 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				460
			 | 
			
			
				
				+JavaScriptDevice::JavaScriptDevice(const QModelIndex &index, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				461
			 | 
			
			
				
				+                                   QScriptEngine *engine) : 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				462
			 | 
			
			
				
				+	QObject(NULL), scriptengine(engine) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				463
			 | 
			
			
				
				+{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				464
			 | 
			
			
				
				+	DeviceTreeModel *model = (DeviceTreeModel *)(index.model()); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				465
			 | 
			
			
				
				+	QDomElement deviceReferenceElement = 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				466
			 | 
			
			
				
				+		model->referenceElement(model->data(index, Qt::UserRole).toString()); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				467
			 | 
			
			
				
				+	QDomNodeList deviceConfigData = deviceReferenceElement.elementsByTagName("attribute"); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				468
			 | 
			
			
				
				+	QDomElement node; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				469
			 | 
			
			
				
				+	QStringList deviceKeys; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				470
			 | 
			
			
				
				+	QStringList deviceValues; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				471
			 | 
			
			
				
				+	for(int i = 0; i < deviceConfigData.size(); i++) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				472
			 | 
			
			
				
				+	{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				473
			 | 
			
			
				
				+		node = deviceConfigData.at(i).toElement(); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				474
			 | 
			
			
				
				+		if(node.attribute("name") == "keys") 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				475
			 | 
			
			
				
				+		{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				476
			 | 
			
			
				
				+			QString data = node.attribute("value"); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				477
			 | 
			
			
				
				+			if(data.length() > 3) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				478
			 | 
			
			
				
				+			{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				479
			 | 
			
			
				
				+				data.chop(2); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				480
			 | 
			
			
				
				+				data = data.remove(0, 2); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				481
			 | 
			
			
				
				+			} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				482
			 | 
			
			
				
				+			deviceKeys = data.split(", "); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				483
			 | 
			
			
				
				+		} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				484
			 | 
			
			
				
				+		else if(node.attribute("name") == "values") 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				485
			 | 
			
			
				
				+		{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				486
			 | 
			
			
				
				+			QString data = node.attribute("value"); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				487
			 | 
			
			
				
				+			if(data.length() > 3) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				488
			 | 
			
			
				
				+			{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				489
			 | 
			
			
				
				+				data.chop(2); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				490
			 | 
			
			
				
				+				data = data.remove(0, 2); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				491
			 | 
			
			
				
				+			} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				492
			 | 
			
			
				
				+			deviceValues = data.split(", "); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				493
			 | 
			
			
				
				+		} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				494
			 | 
			
			
				
				+		else if(node.attribute("name") == "script") 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				495
			 | 
			
			
				
				+		{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				496
			 | 
			
			
				
				+			deviceScript = node.attribute("value"); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				497
			 | 
			
			
				
				+		} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				498
			 | 
			
			
				
				+		deviceSettings.insert(node.attribute("name"), node.attribute("value")); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				499
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				500
			 | 
			
			
				
				+	for(int i = 0; i < qMin(deviceKeys.length(), deviceValues.length()); i++) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				501
			 | 
			
			
				
				+	{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				502
			 | 
			
			
				
				+		deviceSettings.insert(deviceKeys[i], deviceValues[i]); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				503
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				504
			 | 
			
			
				
				+	if(model->hasChildren(index)) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				505
			 | 
			
			
				
				+	{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				506
			 | 
			
			
				
				+		for(int i = 0; i < model->rowCount(index); i++) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				507
			 | 
			
			
				
				+		{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				508
			 | 
			
			
				
				+			QModelIndex channelIndex = model->index(i, 0, index); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				509
			 | 
			
			
				
				+			QDomElement channelReference = model->referenceElement(model->data(channelIndex, 32).toString()); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				510
			 | 
			
			
				
				+			channelList.append(new Channel); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				511
			 | 
			
			
				
				+			QDomElement channelReferenceElement = 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				512
			 | 
			
			
				
				+				model->referenceElement(model->data(channelIndex, Qt::UserRole).toString()); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				513
			 | 
			
			
				
				+			QDomNodeList channelConfigData = 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				514
			 | 
			
			
				
				+				channelReferenceElement.elementsByTagName("attribute"); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				515
			 | 
			
			
				
				+			QStringList channelKeys; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				516
			 | 
			
			
				
				+			QStringList channelValues; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				517
			 | 
			
			
				
				+			for(int j = 0; j < channelConfigData.size(); j++) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				518
			 | 
			
			
				
				+			{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				519
			 | 
			
			
				
				+				node = channelConfigData.at(j).toElement(); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				520
			 | 
			
			
				
				+				if(node.attribute("name") == "keys") 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				521
			 | 
			
			
				
				+				{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				522
			 | 
			
			
				
				+					QString data = node.attribute("value"); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				523
			 | 
			
			
				
				+					if(data.length() > 3) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				524
			 | 
			
			
				
				+					{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				525
			 | 
			
			
				
				+						data.chop(2); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				526
			 | 
			
			
				
				+						data = data.remove(0, 2); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				527
			 | 
			
			
				
				+					} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				528
			 | 
			
			
				
				+					channelKeys = data.split(", "); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				529
			 | 
			
			
				
				+				} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				530
			 | 
			
			
				
				+				else if(node.attribute("name") == "values") 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				531
			 | 
			
			
				
				+				{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				532
			 | 
			
			
				
				+					QString data = node.attribute("value"); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				533
			 | 
			
			
				
				+					if(data.length() > 3) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				534
			 | 
			
			
				
				+					{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				535
			 | 
			
			
				
				+						data.chop(2); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				536
			 | 
			
			
				
				+						data = data.remove(0, 2); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				537
			 | 
			
			
				
				+					} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				538
			 | 
			
			
				
				+					channelValues = data.split(", "); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				539
			 | 
			
			
				
				+				} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				540
			 | 
			
			
				
				+				else if(node.attribute("name") == "hidden") 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				541
			 | 
			
			
				
				+				{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				542
			 | 
			
			
				
				+					hiddenState.append(node.attribute("value") == "true"); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				543
			 | 
			
			
				
				+				} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				544
			 | 
			
			
				
				+				else if(node.attribute("name") == "columnname") 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				545
			 | 
			
			
				
				+				{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				546
			 | 
			
			
				
				+					columnNames.append(node.attribute("value")); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				547
			 | 
			
			
				
				+				} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				548
			 | 
			
			
				
				+			} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				549
			 | 
			
			
				
				+			QVariantMap cs; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				550
			 | 
			
			
				
				+			for(int j = 0; j < qMin(channelKeys.length(), channelValues.length()); j++) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				551
			 | 
			
			
				
				+			{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				552
			 | 
			
			
				
				+				cs.insert(channelKeys[j], channelValues[j]); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				553
			 | 
			
			
				
				+			} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				554
			 | 
			
			
				
				+			channelSettings.append(cs); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				555
			 | 
			
			
				
				+			indicatorTexts.append(model->data(channelIndex, Qt::DisplayRole).toString()); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				556
			 | 
			
			
				
				+			channelUnits.append(Units::Fahrenheit); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				557
			 | 
			
			
				
				+		} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				558
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				559
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				560
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				561
			 | 
			
			
				
				+@ Several methods are available to query information about the configured 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				562
			 | 
			
			
				
				+channels. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				563
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				564
			 | 
			
			
				
				+@<JavaScriptDevice implementation@>= 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				565
			 | 
			
			
				
				+int JavaScriptDevice::channelCount() 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				566
			 | 
			
			
				
				+{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				567
			 | 
			
			
				
				+	return channelList.length(); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				568
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				569
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				570
			 | 
			
			
				
				+Channel* JavaScriptDevice::getChannel(int channel) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				571
			 | 
			
			
				
				+{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				572
			 | 
			
			
				
				+	return channelList.at(channel); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				573
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				574
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				575
			 | 
			
			
				
				+bool JavaScriptDevice::isChannelHidden(int channel) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				576
			 | 
			
			
				
				+{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				577
			 | 
			
			
				
				+	return hiddenState.at(channel); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				578
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				579
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				580
			 | 
			
			
				
				+Units::Unit JavaScriptDevice::expectedChannelUnit(int channel) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				581
			 | 
			
			
				
				+{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				582
			 | 
			
			
				
				+	return channelUnits.at(channel); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				583
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				584
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				585
			 | 
			
			
				
				+QString JavaScriptDevice::channelColumnName(int channel) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				586
			 | 
			
			
				
				+{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				587
			 | 
			
			
				
				+	if(channel >= 0 && channel < columnNames.length()) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				588
			 | 
			
			
				
				+	{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				589
			 | 
			
			
				
				+		return columnNames.at(channel); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				590
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				591
			 | 
			
			
				
				+	return QString(); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				592
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				593
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				594
			 | 
			
			
				
				+QString JavaScriptDevice::channelIndicatorText(int channel) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				595
			 | 
			
			
				
				+{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				596
			 | 
			
			
				
				+	return indicatorTexts.at(channel); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				597
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				598
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				599
			 | 
			
			
				
				+@ Two slots are provided for controlling the placement of annotations. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				600
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				601
			 | 
			
			
				
				+@<JavaScriptDevice implementation@>= 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				602
			 | 
			
			
				
				+void JavaScriptDevice::setTemperatureColumn(int tcol) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				603
			 | 
			
			
				
				+{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				604
			 | 
			
			
				
				+	annotationTemperatureColumn = tcol; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				605
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				606
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				607
			 | 
			
			
				
				+void JavaScriptDevice::setAnnotationColumn(int ncol) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				608
			 | 
			
			
				
				+{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				609
			 | 
			
			
				
				+	annotationNoteColumn = ncol; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				610
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				611
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				612
			 | 
			
			
				
				+@ Device scripts must be able to produce measurements on a channel. To do this, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				613
			 | 
			
			
				
				+a function is provided for obtaining a timestamp. The returned timestamp should 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				614
			 | 
			
			
				
				+not be examined as future changes may break assumptions about the content of 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				615
			 | 
			
			
				
				+the timestamp. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				616
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				617
			 | 
			
			
				
				+@<Function prototypes for scripting@>= 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				618
			 | 
			
			
				
				+QScriptValue getMeasurementTimestamp(QScriptContext *context, QScriptEngine *engine); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				619
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				620
			 | 
			
			
				
				+@ That method is made available to the scripting engine. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				621
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				622
			 | 
			
			
				
				+@<Set up the scripting engine@>= 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				623
			 | 
			
			
				
				+engine->globalObject().setProperty("getMeasurementTimestamp", 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				624
			 | 
			
			
				
				+                                   engine->newFunction(getMeasurementTimestamp)); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				625
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				626
			 | 
			
			
				
				+@ At present this simply obtains the current system time. It is planned to 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				627
			 | 
			
			
				
				+switch to a better quality clock in the future, but this should be done for 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				628
			 | 
			
			
				
				+everything that uses |Measurement| objects at once. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				629
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				630
			 | 
			
			
				
				+@<Functions for scripting@>= 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				631
			 | 
			
			
				
				+QScriptValue getMeasurementTimestamp(QScriptContext *, QScriptEngine *engine)@/ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				632
			 | 
			
			
				
				+{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				633
			 | 
			
			
				
				+	return engine->toScriptValue<QTime>(QTime::currentTime()); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				634
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				635
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				636
			 | 
			
			
				
				+@ At present, implementations are not broken out to a separate file. This 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				637
			 | 
			
			
				
				+should be changed at some point. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				638
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				639
			 | 
			
			
				
				+@<Class implementations@>= 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				640
			 | 
			
			
				
				+@<UnsupportedSerialDeviceConfWidget implementation@> 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				641
			 | 
			
			
				
				+@<JavaScriptDevice implementation@> 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				642
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				643
			 | 
			
			
				
				+@* Serial Ports. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				644
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				645
			 | 
			
			
				
				+\noindent The first use case for script driven devices was connecting to 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				646
			 | 
			
			
				
				+devices which present themselves as a serial port. This covers a broad range 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				647
			 | 
			
			
				
				+of data acquisition products. To provide this support, |QextSerialPort|, which 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				648
			 | 
			
			
				
				+was already used to support some other hardware options, is directly exposed to 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				649
			 | 
			
			
				
				+the host environment. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				650
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				651
			 | 
			
			
				
				+@<Function prototypes for scripting@>= 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				652
			 | 
			
			
				
				+QScriptValue constructSerialPort(QScriptContext *context, QScriptEngine *engine); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				653
			 | 
			
			
				
				+void setSerialPortProperties(QScriptValue value, QScriptEngine *engine); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				654
			 | 
			
			
				
				+QScriptValue SerialPort_flush(QScriptContext *context, QScriptEngine *engine); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				655
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				656
			 | 
			
			
				
				+@ Our constructor is passed to the scripting engine. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				657
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				658
			 | 
			
			
				
				+@<Set up the scripting engine@>= 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				659
			 | 
			
			
				
				+constructor = engine->newFunction(constructSerialPort); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				660
			 | 
			
			
				
				+value = engine->newQMetaObject(&QextSerialPort::staticMetaObject, constructor); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				661
			 | 
			
			
				
				+engine->globalObject().setProperty("SerialPort", value); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				662
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				663
			 | 
			
			
				
				+@ At present we only support event driven communications and are not passing 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				664
			 | 
			
			
				
				+any port settings through the constructor. Such functionality may be added in 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				665
			 | 
			
			
				
				+the future, but it is not strictly necessary. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				666
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				667
			 | 
			
			
				
				+@<Functions for scripting@>= 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				668
			 | 
			
			
				
				+QScriptValue constructSerialPort(QScriptContext *, QScriptEngine *engine) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				669
			 | 
			
			
				
				+{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				670
			 | 
			
			
				
				+	QScriptValue object = engine->newQObject(new QextSerialPort()); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				671
			 | 
			
			
				
				+	setSerialPortProperties(object, engine); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				672
			 | 
			
			
				
				+	return object; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				673
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				674
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				675
			 | 
			
			
				
				+@ Some properties of |QIODevice| are brought in as usual for similar subclasses 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				676
			 | 
			
			
				
				+but we also add a wrapper around the |flush()| method. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				677
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				678
			 | 
			
			
				
				+@<Functions for scripting@>= 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				679
			 | 
			
			
				
				+void setSerialPortProperties(QScriptValue value, QScriptEngine *engine) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				680
			 | 
			
			
				
				+{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				681
			 | 
			
			
				
				+	setQIODeviceProperties(value, engine); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				682
			 | 
			
			
				
				+	value.setProperty("flush", engine->newFunction(SerialPort_flush)); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				683
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				684
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				685
			 | 
			
			
				
				+@ The wrapper around |flush()| is trivial. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				686
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				687
			 | 
			
			
				
				+@<Functions for scripting@>= 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				688
			 | 
			
			
				
				+QScriptValue SerialPort_flush(QScriptContext *context, QScriptEngine *) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				689
			 | 
			
			
				
				+{ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				690
			 | 
			
			
				
				+	QextSerialPort *self = getself<QextSerialPort *>(context); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				691
			 | 
			
			
				
				+	self->flush(); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				692
			 | 
			
			
				
				+	return QScriptValue(); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				693
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				694
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				695
			 | 
			
			
				
				+ 
			 |