DielectricsRemoteMatlabReq.cpp 9.67 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
 * Nomad Instrument Control Software
 *
 * Copyright 2011 Institut Laue-Langevin
 *
 * Licensed under the EUPL, Version 1.1 only (the "License");
 * You may not use this work except in compliance with the Licence.
 * You may obtain a copy of the Licence at:
 *
 * http://joinup.ec.europa.eu/software/page/eupl
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the Licence is distributed on an "AS IS" basis,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the Licence for the specific language governing permissions and
 * limitations under the Licence.
 */

#include "DielectricsRemoteMatlabReq.h"
20
#include "Spectrums.h"
21
22
23
24
25
26
#include <InstrumentManager/InstrumentManager.h>
#include <boost/lexical_cast.hpp>
#include <fstream>
#include <iostream>
#include <common/base/ServerProperties.h>
#include "controllers/common/family/Families.h"
27
#include "FrequencyRequestMessages.pb.h"
28
29
30
31
32
33
34
35
36
37
38
39

namespace dielectrics {

using namespace std;
using namespace common;
using namespace boost;
using namespace cameo;

const std::string RemoteMatlabReq::TYPE = "dielectrics_remote_matlab";
const std::string RemoteMatlabReq::MATLAB_APPLICATION = "dielectrics-matlab";
const std::string RemoteMatlabReq::MATLAB_STOP_APPLICATION = "dielectrics-matlab-stop";
const std::string RemoteMatlabReq::RESPONDER_NAME = "dielectrics_controller";
40
const std::string RemoteMatlabReq::PUBLISHER_NAME = "dielectrics_pub";
41
42
43
44
45
46
47

const std::string RemoteMatlabReq::RUN_SPECTRUMS_TEST = "Run Spectrums Test";
const std::string RemoteMatlabReq::RUN_SPECTRUMS = "Run Spectrums";
const std::string RemoteMatlabReq::RUN_SPECTRUMS_TIME = "Run Spectrums Time";
const std::string RemoteMatlabReq::RUN_SINGLE_FREQUENCY = "Run Single Frequency";

RemoteMatlabReq::RemoteMatlabReq(const std::string& name) :
48
	ExperimentController(name), controller::Start(this), controller::Raz(this), Test(this) {
49

50
51
	setFamily(family::ACQUISITION);

52
53
	serverEndpoint.init(this, SAVE, "cameo_server");
	initialized.init(this, NOSAVE, "initialized");
54
	applicationState.init(this, NOSAVE, "matlab_state");
55

56
57
	values.init(this, NOSAVE, "values");

58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
	requestTypeValues.init(this, NOSAVE, "request_type_values");

	requestTypeValues.resize(4);
	requestTypeValues.set(0, RUN_SPECTRUMS_TEST);
	requestTypeValues.set(1, RUN_SPECTRUMS);
	requestTypeValues.set(2, RUN_SPECTRUMS_TIME);
	requestTypeValues.set(3, RUN_SINGLE_FREQUENCY);

	requestType.init(this, NOSAVE, "request_type", "Request");
	requestType.setEnumeratedLabels(requestTypeValues);
	requestType.setEnumeratedValues(requestTypeValues);

	requestType = requestTypeValues.get(0);

	fr.init(this, NOSAVE, "fr");
	frMin.init(this, NOSAVE, "frMin");
	frMax.init(this, NOSAVE, "frMax");
	nMax.init(this, NOSAVE, "nMax");
	time.init(this, NOSAVE, "time");
	comment.init(this, NOSAVE, "comment");

79
80
81
82
	actualN.init(this, NOSAVE, "N");
	actualTime.init(this, NOSAVE, "actual_time");
	actualRun.init(this, NOSAVE, "actual_run");

83
84
85
86
87
88
89
90
91
	fr = 0;
	frMin = 1E1;
	frMax = 1E6;
	nMax = 5;
	time = 0;
	comment = "a comment";
}

RemoteMatlabReq::RemoteMatlabReq(const RemoteMatlabReq& controller) :
92
	ExperimentController(controller), controller::Start(this), controller::Raz(this), Test(this) {
93
94
95
}

RemoteMatlabReq::~RemoteMatlabReq() {
96
97
	raz();
}
98

99
void RemoteMatlabReq::postConfiguration() {
100

101
102
103
104
105
106
107
108
109
	if (m_server.get() == 0) {
		// Create a new server if it is not already created.
		if (serverEndpoint() == "") {
			m_server.reset(new Server(application::This::getServer().getEndpoint()));
		}
		else {
			m_server.reset(new Server(serverEndpoint()));
		}
	}
110

111
112
113
114
	// Do not initialise if the controller is disabled.
	if (isEnabled()) {
		initialized = initApplication();
	}
115
116
}

117
118
119
120
121
122
123
124
125
126
127
void RemoteMatlabReq::setEnabled(bool all, bool postconf) {

	ExperimentController::setEnabled(all);

	// Enable the spectrums controller.
	for (vector<Spectrums *>::const_iterator c = m_spectrumsControllers.begin(); c != m_spectrumsControllers.end(); ++c) {
		(*c)->setEnabled(false, false);
	}
}

void RemoteMatlabReq::setDisabled(bool all) {
128

129
130
	raz();
	ExperimentController::setDisabled(all);
131

132
133
134
	// Disable the spectrums controller.
	for (vector<Spectrums *>::const_iterator c = m_spectrumsControllers.begin(); c != m_spectrumsControllers.end(); ++c) {
		(*c)->setDisabled(false);
135
	}
136
}
137

138
139
void RemoteMatlabReq::addSpectrumsController(Spectrums * controller) {
	m_spectrumsControllers.push_back(controller);
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
}

bool RemoteMatlabReq::initApplication() {

	// Do not initialize if it is already done
	if (initialized()) {
		return true;
	}

	try {
		// Start the Matlab server
		if (!m_server->isAvailable(10000)) {
			cout << "Matlab server is not available" << endl;
			return false;
		}

		cout << "Matlab server is connected to " << getName() << endl;

		m_matlabApplication = m_server->connect(MATLAB_APPLICATION);
159
160
161

		cout << "connected application" << endl;

162
163
164
165
166
167
168
169
170
171
172
173
174
175
		if (m_matlabApplication->exists()) {
			// The application exists from a previous server session
			m_matlabApplication->stop();
			application::State state = m_matlabApplication->waitFor();
			cout << "Terminated matlab application " << state << endl;
		}

		m_matlabApplication = m_server->start(MATLAB_APPLICATION);

		if (!m_matlabApplication->exists()) {
			cout << "No matlab application" << endl;
			return false;
		}

176
177
178
179
180
181
		applicationState = m_matlabApplication->waitFor(application::STARTING);

		// First delete the requester if it exists.
		m_requester.reset(0);

		// Create a new requester.
182
183
184
185
186
187
188
		m_requester = application::Requester::create(*m_matlabApplication, RESPONDER_NAME);

		if (m_requester.get() == 0) {
			cout << "requester error" << endl;
			return false;
		}

189
190
191
192
193
194
		// Create a new subscriber.
		m_subscriber = application::Subscriber::create(*m_matlabApplication, PUBLISHER_NAME);

		// Start the subscriber loop
		m_subscriberThread.reset(new thread(bind(&RemoteMatlabReq::subscriberLoop, this)));

195
196
197
		// Application initialized.
		initialized = true;

198
199
		applicationState = m_matlabApplication->waitFor(application::RUNNING);

200
201
202
203
204
205
206
207
208
209
210
211
212
213
		cout << "Matlab application initialized" << endl;

		return true;

	} catch (const std::exception & e) {
		// Currently an exception can occur during isAvailable.
		cout << "Unexpected exception during matlab connection: " << e.what() << endl;
	}

	return false;
}

void RemoteMatlabReq::start() {

214
215
216
217
218
	if (!initApplication()) {
		return;
	}

	commandStatus.setRunning();
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255

	// Serialize the request.
	proto::RunSpectrumsRequest request;

	request.set_fr(fr());
	request.set_frmin(frMin());
	request.set_frmax(frMax());
	request.set_nmax(nMax());
	request.set_time(time());
	request.set_comment(comment());

	if (requestType() == RUN_SPECTRUMS) {
		request.set_type(proto::RunSpectrumsRequest_Type_RUN);
	}
	else if (requestType() == RUN_SPECTRUMS_TIME) {
		request.set_type(proto::RunSpectrumsRequest_Type_RUN_TIME);
	}
	else if (requestType() == RUN_SINGLE_FREQUENCY) {
		request.set_type(proto::RunSpectrumsRequest_Type_RUN_SINGLE);
	}
	else if (requestType() == RUN_SPECTRUMS_TEST) {
		request.set_type(proto::RunSpectrumsRequest_Type_TEST);
	}

	// Send the message.
	m_requester->sendBinary(request.SerializeAsString());

	cout << getName() << " sent run request " << requestType() << endl;

	// Wait for the response synchronously.
	// Note that responses can be processed asynchronously if the server is able to.
	string data;
	m_requester->receiveBinary(data);

	proto::FrequencyResponse response;
	response.ParseFromString(data);

256
	cout << "received response " << response.responseid() << endl;
257
258
259
260
261
262
263
264
265
266

	delete [] values.get();
	int32* newArray = new int32[response.values_size()];

	for (int i = 0; i < response.values_size(); ++i) {
		newArray[i] = response.values(i);
	}

	values.set(newArray);
	values.setSize(response.values_size());
267
268

	sleep(1);
269
270

	commandStatus.setIdle();
271
272
273
274
}

void RemoteMatlabReq::raz() {

275
276
277
278
279
280
281
282
	// Reset if the controller was initialized.
	if (initialized()) {

		// Stop the subscriber
		m_subscriber->cancel();

		// The subscriber thread terminates
		m_subscriberThread->join();
283

284
285
286
287
288
289
		// First stop the application.
		stopApplication();

		// Restart the application.
		initialized = false;
	}
290
291
}

292
293
294
295
296
297
298
299
void RemoteMatlabReq::test() {

	for (int i = 0; i < 100; ++i) {
		raz();
		initApplication();
	}
}

300
301
302
303
304
305
306
307
308
309
310
311
void RemoteMatlabReq::stopRun() {

	auto_ptr<cameo::application::Instance> matlabStopApplication = m_server->start(MATLAB_STOP_APPLICATION);
	application::State state = matlabStopApplication->waitFor();
}

void RemoteMatlabReq::stopApplication() {

	if (!initialized()) {
		return;
	}

312
313
314
315
316
	// Exit immediately if the server is not available.
	if (!m_server->isAvailable(10000)) {
		return;
	}

317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
	// Serialize the request.
	proto::RunSpectrumsRequest request;

	request.set_fr(0);
	request.set_frmin(0);
	request.set_frmax(0);
	request.set_nmax(0);
	request.set_time(0);
	request.set_comment("");

	request.set_type(proto::RunSpectrumsRequest_Type_STOP);

	// Send the message.
	m_requester->sendBinary(request.SerializeAsString());

	cout << getName() << " sent stop request" << endl;

	// Wait for the response synchronously.
	// Note that responses can be processed asynchronously if the server is able to.
	string data;
	m_requester->receiveBinary(data);

	proto::FrequencyResponse response;
	response.ParseFromString(data);

	cout << "received response " << response.responseid() << endl;

	// Stop the remote application.
	m_matlabApplication->stop();

	// Wait for the termination
348
	applicationState = m_matlabApplication->waitFor();
349

350
	cout << "Matlab application terminated with state " << application::toString(applicationState()) << endl;
351
352
}

353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
void RemoteMatlabReq::subscriberLoop() {

	// Loop on events
	string data;
	while (m_subscriber->receiveBinary(data)) {

		// Parse the status.
		proto::RunSpectrumsStatus status;
		status.ParseFromString(data);

		// No need to read the type.
		actualN = status.n();
		actualTime = status.time();
		actualRun = status.run();
	}
}

370
}