|
@@ -0,0 +1,484 @@
|
|
1
|
+@** Phidgets 1048.
|
|
2
|
+
|
|
3
|
+\noindent Phidgets, Inc. has provided one of their four channel temperature
|
|
4
|
+sensor devices so that support could be added to \pn{}. This was originally
|
|
5
|
+planned for version 1.7, however early support was rushed in for the 1.6.3
|
|
6
|
+release. As a result, this support is not full featured, but it should still be
|
|
7
|
+adequate for the most common uses.
|
|
8
|
+
|
|
9
|
+Two configuration widgets are required. The first is for the device as a whole.
|
|
10
|
+
|
|
11
|
+@<Class declarations@>=
|
|
12
|
+class PhidgetsTemperatureSensorConfWidget : public BasicDeviceConfigurationWidget
|
|
13
|
+{
|
|
14
|
+ Q_OBJECT
|
|
15
|
+ public:
|
|
16
|
+ Q_INVOKABLE PhidgetsTemperatureSensorConfWidget(DeviceTreeModel *model,
|
|
17
|
+ const QModelIndex &index);
|
|
18
|
+ private slots:
|
|
19
|
+ void addChannel();
|
|
20
|
+ void updateRate(int ms);
|
|
21
|
+};
|
|
22
|
+
|
|
23
|
+@ This widget allows specification of a device wide sample rate and allows
|
|
24
|
+adding channels for the device to monitor. The device specifications indicate
|
|
25
|
+temperature updates happen up to 25 times per second, but this is generally
|
|
26
|
+excessive for \pn{} so a default rate is set to a multiple of this close to
|
|
27
|
+3 updates per second. There are other options for collecting measurements from
|
|
28
|
+this device and I have not yet had time to experiment with all of the options
|
|
29
|
+to determine the best approach suitable for coffee roasting applications.
|
|
30
|
+
|
|
31
|
+@<Phidgets implementation@>=
|
|
32
|
+PhidgetsTemperatureSensorConfWidget::PhidgetsTemperatureSensorConfWidget(DeviceTreeModel *model,
|
|
33
|
+ const QModelIndex &index)
|
|
34
|
+ : BasicDeviceConfigurationWidget(model, index)
|
|
35
|
+{
|
|
36
|
+ QFormLayout *layout = new QFormLayout;
|
|
37
|
+ QPushButton *addChannelButton = new QPushButton(tr("Add Channel"));
|
|
38
|
+ QSpinBox *sampleRate = new QSpinBox;
|
|
39
|
+ sampleRate->setMinimum(40);
|
|
40
|
+ sampleRate->setMaximum(600);
|
|
41
|
+ sampleRate->setSingleStep(40);
|
|
42
|
+ sampleRate->setValue(360);
|
|
43
|
+
|
|
44
|
+ @<Get device configuration data for current node@>@;
|
|
45
|
+ for(int i = 0; i < configData.size(); i++)
|
|
46
|
+ {
|
|
47
|
+ node = configData.at(i).toElement();
|
|
48
|
+ if(node.attribute("name") == "sampleRate")
|
|
49
|
+ {
|
|
50
|
+ sampleRate->setValue(node.attribute("value").toInt());
|
|
51
|
+ }
|
|
52
|
+ }
|
|
53
|
+ updateRate(sampleRate->value());
|
|
54
|
+
|
|
55
|
+ connect(sampleRate, SIGNAL(valueChanged(int)), this, SLOT(updateRate(int)));
|
|
56
|
+ connect(addChannelButton, SIGNAL(clicked()), this, SLOT(addChannel()));
|
|
57
|
+
|
|
58
|
+ layout->addRow(addChannelButton);
|
|
59
|
+ layout->addRow(tr("Sample rate:"), sampleRate);
|
|
60
|
+ setLayout(layout);
|
|
61
|
+}
|
|
62
|
+
|
|
63
|
+@ Adding another channel is handled in the usual way, with the channel
|
|
64
|
+configured in a separate widget.
|
|
65
|
+
|
|
66
|
+@<Phidgets implementation@>=
|
|
67
|
+void PhidgetsTemperatureSensorConfWidget::addChannel()
|
|
68
|
+{
|
|
69
|
+ insertChildNode(tr("Channel"), "phidgets1048channel");
|
|
70
|
+}
|
|
71
|
+
|
|
72
|
+@ Changes to the sample rate are saved as an attribute of the node as usual.
|
|
73
|
+
|
|
74
|
+@<Phidgets implementation@>=
|
|
75
|
+void PhidgetsTemperatureSensorConfWidget::updateRate(int ms)
|
|
76
|
+{
|
|
77
|
+ updateAttribute("sampleRate", QString("%1").arg(ms));
|
|
78
|
+}
|
|
79
|
+
|
|
80
|
+@ The other required configuration widget is for a single channel.
|
|
81
|
+
|
|
82
|
+@<Class declarations@>=
|
|
83
|
+class PhidgetTemperatureSensorChannelConfWidget : public BasicDeviceConfigurationWidget
|
|
84
|
+{
|
|
85
|
+ Q_OBJECT
|
|
86
|
+ public:
|
|
87
|
+ Q_INVOKABLE PhidgetTemperatureSensorChannelConfWidget(DeviceTreeModel *model,
|
|
88
|
+ const QModelIndex &index);
|
|
89
|
+ private slots:
|
|
90
|
+ void updateColumnName(const QString &value);
|
|
91
|
+ void updateHidden(bool hidden);
|
|
92
|
+ void updateTC(int index);
|
|
93
|
+ void updateChannel(int channel);
|
|
94
|
+ private:
|
|
95
|
+ QComboBox *tcType;
|
|
96
|
+};
|
|
97
|
+
|
|
98
|
+@ For each channel it is necessary to specify which channel of the device
|
|
99
|
+measurements will come in on. The thermocouple type should be set to match the
|
|
100
|
+type of the thermocouple attached to that channel. The column name and if the
|
|
101
|
+channel is hidden has the same meaning as in channels on other devices.
|
|
102
|
+
|
|
103
|
+@<Phidgets implementation@>=
|
|
104
|
+PhidgetTemperatureSensorChannelConfWidget::PhidgetTemperatureSensorChannelConfWidget(
|
|
105
|
+ DeviceTreeModel *model, const QModelIndex &index)
|
|
106
|
+ : BasicDeviceConfigurationWidget(model, index),
|
|
107
|
+ tcType(new QComboBox)
|
|
108
|
+{
|
|
109
|
+ QFormLayout *layout = new QFormLayout;
|
|
110
|
+ QLineEdit *columnName = new QLineEdit;
|
|
111
|
+ layout->addRow(tr("Column Name:"), columnName);
|
|
112
|
+ QCheckBox *hideSeries = new QCheckBox("Hide this channel");
|
|
113
|
+ layout->addRow(hideSeries);
|
|
114
|
+ layout->addRow(tr("Thermocouple Type:"), tcType);
|
|
115
|
+ tcType->addItem("Type K", "1");
|
|
116
|
+ tcType->addItem("Type J", "2");
|
|
117
|
+ tcType->addItem("Type E", "3");
|
|
118
|
+ tcType->addItem("Type T", "4");
|
|
119
|
+ QSpinBox *channel = new QSpinBox;
|
|
120
|
+ layout->addRow(tr("Channel:"), channel);
|
|
121
|
+ channel->setMinimum(0);
|
|
122
|
+ channel->setMaximum(3);
|
|
123
|
+ setLayout(layout);
|
|
124
|
+ @<Get device configuration data for current node@>@;
|
|
125
|
+ for(int i = 0; i < configData.size(); i++)
|
|
126
|
+ {
|
|
127
|
+ node = configData.at(i).toElement();
|
|
128
|
+ if(node.attribute("name") == "columnname")
|
|
129
|
+ {
|
|
130
|
+ columnName->setText(node.attribute("value"));
|
|
131
|
+ }
|
|
132
|
+ else if(node.attribute("name") == "hidden")
|
|
133
|
+ {
|
|
134
|
+ hideSeries->setChecked(node.attribute("value") == "true");
|
|
135
|
+ }
|
|
136
|
+ else if(node.attribute("name") == "tctype")
|
|
137
|
+ {
|
|
138
|
+ tcType->setCurrentIndex(tcType->findData(node.attribute("value")));
|
|
139
|
+ }
|
|
140
|
+ else if(node.attribute("name") == "channel")
|
|
141
|
+ {
|
|
142
|
+ channel->setValue(node.attribute("value").toInt());
|
|
143
|
+ }
|
|
144
|
+ }
|
|
145
|
+ updateColumnName(columnName->text());
|
|
146
|
+ updateHidden(hideSeries->isChecked());
|
|
147
|
+ updateTC(tcType->currentIndex());
|
|
148
|
+ updateChannel(channel->value());
|
|
149
|
+ connect(columnName, SIGNAL(textEdited(QString)), this, SLOT(updateColumnName(QString)));
|
|
150
|
+ connect(hideSeries, SIGNAL(toggled(bool)), this, SLOT(updateHidden(bool)));
|
|
151
|
+ connect(tcType, SIGNAL(currentIndexChanged(int)), this, SLOT(updateTC(int)));
|
|
152
|
+ connect(channel, SIGNAL(valueChanged(int)), this, SLOT(updateChannel(int)));
|
|
153
|
+}
|
|
154
|
+
|
|
155
|
+@ Channel configuration settings are persisted as they are made.
|
|
156
|
+
|
|
157
|
+@<Phidgets implementation@>=
|
|
158
|
+void PhidgetTemperatureSensorChannelConfWidget::updateColumnName(const QString &value)
|
|
159
|
+{
|
|
160
|
+ updateAttribute("columnname", value);
|
|
161
|
+}
|
|
162
|
+
|
|
163
|
+void PhidgetTemperatureSensorChannelConfWidget::updateHidden(bool hidden)
|
|
164
|
+{
|
|
165
|
+ updateAttribute("hidden", hidden ? "true" : "false");
|
|
166
|
+}
|
|
167
|
+
|
|
168
|
+void PhidgetTemperatureSensorChannelConfWidget::updateTC(int index)
|
|
169
|
+{
|
|
170
|
+ updateAttribute("tctype", tcType->itemData(index).toString());
|
|
171
|
+}
|
|
172
|
+
|
|
173
|
+void PhidgetTemperatureSensorChannelConfWidget::updateChannel(int channel)
|
|
174
|
+{
|
|
175
|
+ updateAttribute("channel", QString("%1").arg(channel));
|
|
176
|
+}
|
|
177
|
+
|
|
178
|
+@ The configuration widgets need to be registered so they can be instantiated as
|
|
179
|
+appropriate.
|
|
180
|
+
|
|
181
|
+@<Register device configuration widgets@>=
|
|
182
|
+app.registerDeviceConfigurationWidget("phidgets1048",
|
|
183
|
+ PhidgetsTemperatureSensorConfWidget::staticMetaObject);
|
|
184
|
+app.registerDeviceConfigurationWidget("phidgets1048channel",
|
|
185
|
+ PhidgetTemperatureSensorChannelConfWidget::staticMetaObject);
|
|
186
|
+
|
|
187
|
+@ A |NodeInserter| for the device node is also required, but this should only
|
|
188
|
+be provided if the required library is installed.
|
|
189
|
+
|
|
190
|
+@<Register top level device configuration nodes@>=
|
|
191
|
+QLibrary phidgetsCheck("phidget21");
|
|
192
|
+if(phidgetsCheck.load())
|
|
193
|
+{
|
|
194
|
+ inserter = new NodeInserter(tr("Phidgets 1048"), tr("Phidgets 1048"),
|
|
195
|
+ "phidgets1048", NULL);
|
|
196
|
+ topLevelNodeInserters.append(inserter);
|
|
197
|
+ phidgetsCheck.unload();
|
|
198
|
+}
|
|
199
|
+else
|
|
200
|
+{
|
|
201
|
+ phidgetsCheck.setFileName("Phidget21.framework/phidget21");
|
|
202
|
+ if(phidgetsCheck.load())
|
|
203
|
+ {
|
|
204
|
+ inserter = new NodeInserter(tr("Phidgets 1048"), tr("Phidgets 1048"),
|
|
205
|
+ "phidgets1048", NULL);
|
|
206
|
+ topLevelNodeInserters.append(inserter);
|
|
207
|
+ phidgetsCheck.unload();
|
|
208
|
+ }
|
|
209
|
+}
|
|
210
|
+
|
|
211
|
+@ As usual, a class representing the device is provided.
|
|
212
|
+
|
|
213
|
+@<Class declarations@>=
|
|
214
|
+class PhidgetsTemperatureSensor : public QObject
|
|
215
|
+{
|
|
216
|
+ Q_OBJECT
|
|
217
|
+ public:
|
|
218
|
+ Q_INVOKABLE PhidgetsTemperatureSensor(const QModelIndex &deviceIndex);
|
|
219
|
+ Q_INVOKABLE int channelCount();
|
|
220
|
+ Channel* getChannel(int channel);
|
|
221
|
+ Q_INVOKABLE bool isChannelHidden(int channel);
|
|
222
|
+ Q_INVOKABLE QString channelColumnName(int channel);
|
|
223
|
+ Q_INVOKABLE QString channelIndicatorText(int channel);
|
|
224
|
+ public slots:
|
|
225
|
+ void start();
|
|
226
|
+ void stop();
|
|
227
|
+ private slots:
|
|
228
|
+ void getMeasurements();
|
|
229
|
+ private:
|
|
230
|
+ QList<int> channelIndices;
|
|
231
|
+ QList<int> tctypes;
|
|
232
|
+ QList<Channel*> channelList;
|
|
233
|
+ QMap<int, Channel*> channelMap;
|
|
234
|
+ QList<bool> hiddenState;
|
|
235
|
+ QList<QString> columnNames;
|
|
236
|
+ QList<QString> indicatorTexts;
|
|
237
|
+ QLibrary driver;
|
|
238
|
+ QTimer sampleTimer;
|
|
239
|
+ void *device;
|
|
240
|
+ @<Phidgets 1048 function pointers@>@;
|
|
241
|
+};
|
|
242
|
+
|
|
243
|
+@ The constructor uses the configuration data to set up the interface used for
|
|
244
|
+integration with the logging view.
|
|
245
|
+
|
|
246
|
+@<Phidgets implementation@>=
|
|
247
|
+PhidgetsTemperatureSensor::PhidgetsTemperatureSensor(const QModelIndex &index)
|
|
248
|
+ : QObject(NULL), driver("phidget21"), device(NULL)
|
|
249
|
+{
|
|
250
|
+ DeviceTreeModel *model = (DeviceTreeModel *)(index.model());
|
|
251
|
+ QDomElement deviceReferenceElement =
|
|
252
|
+ model->referenceElement(model->data(index, Qt::UserRole).toString());
|
|
253
|
+ QDomNodeList deviceConfigData = deviceReferenceElement.elementsByTagName("attribute");
|
|
254
|
+ QDomElement node;
|
|
255
|
+ for(int i = 0; i < deviceConfigData.size(); i++)
|
|
256
|
+ {
|
|
257
|
+ node = deviceConfigData.at(i).toElement();
|
|
258
|
+ if(node.attribute("name") == "sampleRate")
|
|
259
|
+ {
|
|
260
|
+ sampleTimer.setInterval(node.attribute("value").toInt());
|
|
261
|
+ }
|
|
262
|
+ }
|
|
263
|
+ if(model->hasChildren(index))
|
|
264
|
+ {
|
|
265
|
+ for(int i = 0; i < model->rowCount(index); i++)
|
|
266
|
+ {
|
|
267
|
+ QModelIndex channelIndex = model->index(i, 0, index);
|
|
268
|
+ QDomElement channelReference = model->referenceElement(model->data(channelIndex, 32).toString());
|
|
269
|
+ QDomElement channelReferenceElement = model->referenceElement(model->data(channelIndex, Qt::UserRole).toString());
|
|
270
|
+ QDomNodeList channelConfigData = channelReferenceElement.elementsByTagName("attribute");
|
|
271
|
+ for(int j = 0; j < channelConfigData.size(); j++)
|
|
272
|
+ {
|
|
273
|
+ node = channelConfigData.at(j).toElement();
|
|
274
|
+ if(node.attribute("name") == "channel")
|
|
275
|
+ {
|
|
276
|
+ int channelID = node.attribute("value").toInt();
|
|
277
|
+ channelIndices.append(channelID);
|
|
278
|
+ Channel* channel = new Channel;
|
|
279
|
+ channelList.append(channel);
|
|
280
|
+ channelMap.insert(channelID, channel);
|
|
281
|
+ }
|
|
282
|
+ else if(node.attribute("name") == "hidden")
|
|
283
|
+ {
|
|
284
|
+ hiddenState.append(node.attribute("value") == "true");
|
|
285
|
+ }
|
|
286
|
+ else if(node.attribute("name") == "columnname")
|
|
287
|
+ {
|
|
288
|
+ columnNames.append(node.attribute("value"));
|
|
289
|
+ }
|
|
290
|
+ else if(node.attribute("name") == "tctype")
|
|
291
|
+ {
|
|
292
|
+ tctypes.append(node.attribute("value").toInt());
|
|
293
|
+ }
|
|
294
|
+ }
|
|
295
|
+ indicatorTexts.append(model->data(channelIndex, Qt::DisplayRole).toString());
|
|
296
|
+ }
|
|
297
|
+ }
|
|
298
|
+}
|
|
299
|
+
|
|
300
|
+@ There is a distinction between logical and physical channels. Physical
|
|
301
|
+channels are specified as a configuration attribute and are used for
|
|
302
|
+communication with hardware. Logical channels are determined by the order of
|
|
303
|
+nodes in the configuration and are used for integrating device support with the
|
|
304
|
+rest of the program.
|
|
305
|
+
|
|
306
|
+@<Phidgets implementation@>=
|
|
307
|
+int PhidgetsTemperatureSensor::channelCount()
|
|
308
|
+{
|
|
309
|
+ return channelList.length();
|
|
310
|
+}
|
|
311
|
+
|
|
312
|
+Channel* PhidgetsTemperatureSensor::getChannel(int channel)
|
|
313
|
+{
|
|
314
|
+ return channelList.at(channel);
|
|
315
|
+}
|
|
316
|
+
|
|
317
|
+@ Some information is available about each channel.
|
|
318
|
+
|
|
319
|
+@<Phidgets implementation@>=
|
|
320
|
+bool PhidgetsTemperatureSensor::isChannelHidden(int channel)
|
|
321
|
+{
|
|
322
|
+ return hiddenState.at(channel);
|
|
323
|
+}
|
|
324
|
+
|
|
325
|
+QString PhidgetsTemperatureSensor::channelColumnName(int channel)
|
|
326
|
+{
|
|
327
|
+ if(channel >= 0 && channel < columnNames.length())
|
|
328
|
+ {
|
|
329
|
+ return columnNames.at(channel);
|
|
330
|
+ }
|
|
331
|
+ return QString();
|
|
332
|
+}
|
|
333
|
+
|
|
334
|
+QString PhidgetsTemperatureSensor::channelIndicatorText(int channel)
|
|
335
|
+{
|
|
336
|
+ if(channel >= 0 && channel < indicatorTexts.length())
|
|
337
|
+ {
|
|
338
|
+ return indicatorTexts.at(channel);
|
|
339
|
+ }
|
|
340
|
+ return QString();
|
|
341
|
+}
|
|
342
|
+
|
|
343
|
+@ To avoid introducing dependencies on a library that is only needed for
|
|
344
|
+hardware that may not exist, the phidget21 library is only loaded at runtime
|
|
345
|
+if it is needed. Some function pointers and associated types are, therefore,
|
|
346
|
+required. This approach also means the associated header does not need to
|
|
347
|
+exist at compile time.
|
|
348
|
+
|
|
349
|
+@<Phidgets 1048 function pointers@>=
|
|
350
|
+typedef int (*PhidgetHandleOnly)(void *);
|
|
351
|
+typedef int (*PhidgetHandleInt)(void *, int);
|
|
352
|
+typedef int (*PhidgetHandleIntInt)(void *, int, int);
|
|
353
|
+typedef int (*PhidgetHandleIntDoubleOut)(void *, int, double*);
|
|
354
|
+PhidgetHandleOnly createDevice;
|
|
355
|
+PhidgetHandleInt openDevice;
|
|
356
|
+PhidgetHandleInt waitForOpen;
|
|
357
|
+PhidgetHandleIntInt setTCType;
|
|
358
|
+PhidgetHandleIntDoubleOut getTemperature;
|
|
359
|
+PhidgetHandleOnly closeDevice;
|
|
360
|
+PhidgetHandleOnly deleteDevice;
|
|
361
|
+
|
|
362
|
+@ Library loading is deferred until we are ready to open a device.
|
|
363
|
+
|
|
364
|
+@<Phidgets implementation@>=
|
|
365
|
+void PhidgetsTemperatureSensor::start()
|
|
366
|
+{
|
|
367
|
+ if(!driver.load())
|
|
368
|
+ {
|
|
369
|
+ driver.setFileName("Phidget21.framework/phidget21");
|
|
370
|
+ if(!driver.load())
|
|
371
|
+ {
|
|
372
|
+ QMessageBox::critical(NULL, tr("Typica: Driver not found"),
|
|
373
|
+ tr("Failed to find phidget21. Please install it."));
|
|
374
|
+ return;
|
|
375
|
+ }
|
|
376
|
+ }
|
|
377
|
+ if((createDevice = (PhidgetHandleOnly) driver.resolve("CPhidgetTemperatureSensor_create")) == 0 || @|
|
|
378
|
+ (openDevice = (PhidgetHandleInt) driver.resolve("CPhidget_open")) == 0 || @|
|
|
379
|
+ (waitForOpen = (PhidgetHandleInt) driver.resolve("CPhidget_waitForAttachment")) == 0 || @|
|
|
380
|
+ (setTCType = (PhidgetHandleIntInt) driver.resolve("CPhidgetTemperatureSensor_setThermocoupleType")) == 0 || @|
|
|
381
|
+ (getTemperature = (PhidgetHandleIntDoubleOut) driver.resolve("CPhidgetTemperatureSensor_getTemperature")) == 0 || @|
|
|
382
|
+ (closeDevice = (PhidgetHandleOnly) driver.resolve("CPhidget_close")) == 0 || @|
|
|
383
|
+ (deleteDevice = (PhidgetHandleOnly) driver.resolve("CPhidget_delete")) == 0)
|
|
384
|
+ {
|
|
385
|
+ QMessageBox::critical(NULL, tr("Typica: Link error"),
|
|
386
|
+ tr("Failed to link a required symbol in phidget21."));
|
|
387
|
+ return;
|
|
388
|
+ }
|
|
389
|
+ createDevice(&device);
|
|
390
|
+ openDevice(device, -1);
|
|
391
|
+ int error;
|
|
392
|
+ if(error = waitForOpen(device, 10000))
|
|
393
|
+ {
|
|
394
|
+ closeDevice(device);
|
|
395
|
+ deleteDevice(device);
|
|
396
|
+ QMessageBox::critical(NULL, tr("Typica: Failed to Open Device"),
|
|
397
|
+ tr("CPhidget_waitForAttachment returns error %n", 0, error));
|
|
398
|
+ return;
|
|
399
|
+ }
|
|
400
|
+ for(int i = 0; i < channelIndices.length(); i++)
|
|
401
|
+ {
|
|
402
|
+ setTCType(device, channelIndices.at(i), tctypes.at(i));
|
|
403
|
+ }
|
|
404
|
+ connect(&sampleTimer, SIGNAL(timeout()), this, SLOT(getMeasurements()));
|
|
405
|
+ sampleTimer.start();
|
|
406
|
+}
|
|
407
|
+
|
|
408
|
+@ Once the device is started, we periodically request measurements and pass
|
|
409
|
+them to the appropriate |Channel|.
|
|
410
|
+
|
|
411
|
+@<Phidgets implementation@>=
|
|
412
|
+void PhidgetsTemperatureSensor::getMeasurements()
|
|
413
|
+{
|
|
414
|
+ double value = 0.0;
|
|
415
|
+ QTime time = QTime::currentTime();
|
|
416
|
+ foreach(int i, channelIndices)
|
|
417
|
+ {
|
|
418
|
+ getTemperature(device, i, &value);
|
|
419
|
+ Measurement measure(value * 9.0 / 5.0 + 32.0, time);
|
|
420
|
+ channelMap[i]->input(measure);
|
|
421
|
+ }
|
|
422
|
+}
|
|
423
|
+
|
|
424
|
+@ Some clean up is needed in the |stop()| method.
|
|
425
|
+
|
|
426
|
+@<Phidgets implementation@>=
|
|
427
|
+void PhidgetsTemperatureSensor::stop()
|
|
428
|
+{
|
|
429
|
+ sampleTimer.stop();
|
|
430
|
+ closeDevice(device);
|
|
431
|
+ deleteDevice(device);
|
|
432
|
+ driver.unload();
|
|
433
|
+}
|
|
434
|
+
|
|
435
|
+@ The implementation currently goes into typica.cpp.
|
|
436
|
+
|
|
437
|
+@<Class implementations@>=
|
|
438
|
+@<Phidgets implementation@>@;
|
|
439
|
+
|
|
440
|
+@ The |PhidgetsTemperatureSensor| needs to be available from the host
|
|
441
|
+environment. This detail is likely to change in the future.
|
|
442
|
+
|
|
443
|
+@<Set up the scripting engine@>=
|
|
444
|
+constructor = engine->newFunction(constructPhidgetsTemperatureSensor);
|
|
445
|
+value = engine->newQMetaObject(&PhidgetsTemperatureSensor::staticMetaObject, constructor);
|
|
446
|
+engine->globalObject().setProperty("PhidgetsTemperatureSensor", value);
|
|
447
|
+
|
|
448
|
+@ Two function prototypes are needed.
|
|
449
|
+
|
|
450
|
+@<Function prototypes for scripting@>=
|
|
451
|
+QScriptValue constructPhidgetsTemperatureSensor(QScriptContext *context, QScriptEngine *engine);
|
|
452
|
+QScriptValue Phidgets_getChannel(QScriptContext *context, QScriptEngine *engine);
|
|
453
|
+
|
|
454
|
+@ The script constructor is trivial.
|
|
455
|
+
|
|
456
|
+@<Functions for scripting@>=
|
|
457
|
+QScriptValue constructPhidgetsTemperatureSensor(QScriptContext *context, QScriptEngine *engine)
|
|
458
|
+{
|
|
459
|
+ if(context->argumentCount() != 1)
|
|
460
|
+ {
|
|
461
|
+ context->throwError("Incorrect number of arguments passed to "@|
|
|
462
|
+ "PhidgetsTemperatureSensor constructor. This takes "@|
|
|
463
|
+ "a QModelIndex.");
|
|
464
|
+ }
|
|
465
|
+ QScriptValue object = engine->newQObject(new PhidgetsTemperatureSensor(argument<QModelIndex>(0, context)), QScriptEngine::ScriptOwnership);
|
|
466
|
+ setQObjectProperties(object, engine);
|
|
467
|
+ object.setProperty("getChannel", engine->newFunction(Phidgets_getChannel));
|
|
468
|
+ return object;
|
|
469
|
+}
|
|
470
|
+
|
|
471
|
+@ As usual, a wrapper is needed for getting channels.
|
|
472
|
+
|
|
473
|
+@<Functions for scripting@>=
|
|
474
|
+QScriptValue Phidgets_getChannel(QScriptContext *context, QScriptEngine *engine)
|
|
475
|
+{
|
|
476
|
+ PhidgetsTemperatureSensor *self = getself<PhidgetsTemperatureSensor *>(context);
|
|
477
|
+ QScriptValue object;
|
|
478
|
+ if(self)
|
|
479
|
+ {
|
|
480
|
+ object = engine->newQObject(self->getChannel(argument<int>(0, context)));
|
|
481
|
+ setChannelProperties(object, engine);
|
|
482
|
+ }
|
|
483
|
+ return object;
|
|
484
|
+}
|