SlsDetectorCamera.cpp 35.1 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//###########################################################################
// This file is part of LImA, a Library for Image Acquisition
//
// Copyright (C) : 2009-2011
// European Synchrotron Radiation Facility
// BP 220, Grenoble 38043
// FRANCE
//
// This is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// This software is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, see <http://www.gnu.org/licenses/>.
//###########################################################################

23
#include "SlsDetectorCamera.h"
24

25
#include <limits.h>
26
#include <algorithm>
27
#include <numeric>
28
#include <cmath>
29
30
#include <iostream>
#include <fstream>
31

32
33
34
35
using namespace std;
using namespace lima;
using namespace lima::SlsDetector;

36

37
Camera::AppInputData::AppInputData(string cfg_fname) 
38
	: config_file_name(cfg_fname)
39
{
40
	DEB_CONSTRUCTOR();
41
42
43
	parseConfigFile();
}

44
void Camera::AppInputData::parseConfigFile()
45
{
46
47
	DEB_MEMBER_FUNCT();

48
	ifstream config_file(config_file_name);
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
	while (config_file) {
		string s;
		config_file >> s;
		RegEx re;
		FullMatch full_match;
		MatchList match_list;
		MatchListIt lit, lend;

		re = "hostname";
		if (re.match(s, full_match)) {
			string host_name;
			config_file >> host_name;
			RegEx re("([A-Za-z0-9]+)\\+?");
			re.multiSearch(host_name, match_list);
			lend = match_list.end();
			for (lit = match_list.begin(); lit != lend; ++lit) {
				const FullMatch& full_match = *lit;
				const SingleMatch& single_match = full_match[1];
				host_name_list.push_back(single_match);
			}
69
			DEB_TRACE() << DEB_VAR1(host_name_list);
70
71
72
			continue;
		}

73
		re = "(([0-9]+):)?rx_tcpport";
74
		if (re.match(s, full_match)) {
75
76
77
78
79
80
81
82
			int id = 0;
			if (full_match[2].found()) {
				istringstream is(full_match[2]);
				is >> id;
				if (id < 0)
					THROW_HW_FATAL(InvalidValue) << 
						"Invalid detector id: " << id;
			}
83
84
85
86
87
88
89
90
			int rx_tcpport;
			config_file >> rx_tcpport;
			recv_port_map[id] = rx_tcpport;
			continue;
		}
	}
}

91
92
93
Camera::AcqThread::ExceptionCleanUp::ExceptionCleanUp(AcqThread& thread,
						      AutoMutex& l)
	: Thread::ExceptionCleanUp(thread), m_lock(l)
94
95
96
97
98
99
100
101
{
	DEB_CONSTRUCTOR();
}

Camera::AcqThread::ExceptionCleanUp::~ExceptionCleanUp()
{
	DEB_DESTRUCTOR();
	AcqThread *thread = static_cast<AcqThread *>(&m_thread);
102
	thread->cleanUp(m_lock);
103
104
}

105
Camera::AcqThread::AcqThread(Camera *cam)
106
	: m_cam(cam), m_cond(m_cam->m_cond), m_state(m_cam->m_state)
107
108
{
	DEB_CONSTRUCTOR();
109
110
}

111
void Camera::AcqThread::start(AutoMutex& l)
112
113
114
{
	DEB_MEMBER_FUNCT();

115
116
117
	if ((&l.mutex() != &m_cond.mutex()) || !l.locked())
		THROW_HW_ERROR(Error) << "Invalid AutoMutex";

118
	m_state = Starting;
119
	Thread::start();
120
121

	struct sched_param param;
122
	param.sched_priority = sched_get_priority_min(SCHED_RR);
123
124
	int ret = pthread_setschedparam(m_thread, SCHED_RR, &param);
	if (ret != 0)
125
		DEB_ERROR() << "Could not set AcqThread real-time priority!!";
126

127
	while (m_state == Starting)
128
129
130
		m_cond.wait();
}

131
void Camera::AcqThread::stop(AutoMutex& l, bool wait)
132
133
{
	DEB_MEMBER_FUNCT();
134
135
136
	if ((&l.mutex() != &m_cond.mutex()) || !l.locked())
		THROW_HW_ERROR(Error) << "Invalid AutoMutex";

137
138
	m_state = StopReq;
	m_cond.broadcast();
139
	while (wait && (m_state != Stopped) && (m_state != Idle))
140
141
142
143
144
145
146
147
		m_cond.wait();
}

void Camera::AcqThread::threadFunction()
{
	DEB_MEMBER_FUNCT();

	AutoMutex l = m_cam->lock();
148

149
150
151
152
	// cleanup is executed with lock, once state goes to Stopped
	// thread will be deleted in getEffectiveState without releasing lock
	ExceptionCleanUp cleanup(*this, l);

153
	GlobalCPUAffinityMgr& affinity_mgr = m_cam->m_global_cpu_affinity_mgr;
154
155
	{
		AutoMutexUnlock u(l);
156
157
		affinity_mgr.startAcq();
		startAcq();
158
159
	}
	m_state = Running;
160
	DEB_TRACE() << DEB_VAR1(m_state);
161
162
	m_cond.broadcast();

163
	SeqFilter seq_filter;
164
	bool had_frames = false;
165
	bool cont_acq = true;
166
	bool acq_end = false;
167
	do {
168
169
170
		while ((m_state != StopReq) && m_frame_queue.empty()) {
			if (!m_cond.wait(m_cam->m_new_frame_timeout)) {
				AutoMutexUnlock u(l);
171
172
173
174
175
176
177
				try {
					m_cam->checkLostPackets();
				} catch (Exception& e) {
					string name = ("Camera::AcqThread: "
						       "checkLostPackets");
					m_cam->reportException(e, name);
				}
178
179
			}
		}
180
		if (!m_frame_queue.empty()) {
181
			FrameType frame = m_frame_queue.front();
182
			m_frame_queue.pop();
183
184
185
186
187
188
			DEB_TRACE() << DEB_VAR1(frame);
			seq_filter.addVal(frame);
			SeqFilter::Range frames = seq_filter.getSeqRange();
			if (frames.nb > 0) {
				int f = frames.first;
				do {
189
190
					m_cam->m_buffer.waitLimaFrame(f, l);
					AutoMutexUnlock u(l);
191
					DEB_TRACE() << DEB_VAR1(f);
192
193
194
					Status status = newFrameReady(f);
					cont_acq = status.first;
					acq_end = status.second;
195
					had_frames = true;
196
				} while ((++f != frames.end()) && cont_acq);
197
198
			}
		}
199
	} while ((m_state != StopReq) && cont_acq);
200
	AcqState prev_state = m_state;
201

202
203
204
205
206
	if (acq_end && m_cam->m_skip_frame_freq) {
		AutoMutexUnlock u(l);
		m_cam->waitLastSkippedFrame();
	}
		
207
	m_state = Stopping;
208
	DEB_TRACE() << DEB_VAR2(prev_state, m_state);
209
210
	{
		AutoMutexUnlock u(l);
211
		stopAcq();
212

213
214
215
216
217
		IntList bfl;
		m_cam->getSortedBadFrameList(bfl);
		DEB_ALWAYS() << "bad_frames=" << bfl.size() << ": "
			     << PrettyIntList(bfl);

218
219
220
		Stats stats;
		m_cam->getStats(stats);
		DEB_ALWAYS() << DEB_VAR1(stats);
221

222
		FrameMap& m = m_cam->m_frame_map;
223
224
225
226
		if (m.getNbItems() > 1) {
			XYStat::LinRegress delay_stat = m.calcDelayStat();
			DEB_ALWAYS() << DEB_VAR1(delay_stat);
		}
227

228
		if (had_frames) {
229
230
			affinity_mgr.recvFinished();
			affinity_mgr.waitLimaFinished();
231
		} else {
232
			affinity_mgr.cleanUp();
233
		}
234
	}
235

236
	m_state = Stopped;
237
	DEB_TRACE() << DEB_VAR1(m_state);
238
239
240
	m_cond.broadcast();
}

241
242
243
244
245
246
247
248
249
void Camera::AcqThread::queueFinishedFrame(FrameType frame)
{
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(frame);
	AutoMutex l = m_cam->lock();
	m_frame_queue.push(frame);
	m_cond.broadcast();
}

250
void Camera::AcqThread::cleanUp(AutoMutex& l)
251
252
253
254
255
256
{
	DEB_MEMBER_FUNCT();

	if ((m_state == Stopped) || (m_state == Idle))
		return;

257
	AcqState prev_state = m_state;
258
259
260
261
262
263
264
265
	if ((m_state == Running) || (m_state == StopReq)) {
		m_state = Stopping;
		AutoMutexUnlock u(l);
		stopAcq();
	}

	{
		AutoMutexUnlock u(l);
266
267
268
		ostringstream err_msg;
		err_msg << "AcqThread: exception thrown: "
			<< "m_state=" << prev_state;
269
270
		Event::Code err_code = Event::CamFault;
		Event *event = new Event(Hardware, Event::Error, Event::Camera, 
271
					 err_code, err_msg.str());
272
273
274
275
276
277
278
279
280
281
282
		DEB_EVENT(*event) << DEB_VAR1(*event);
		m_cam->reportEvent(event);
	}

	m_state = Stopped;
	m_cond.broadcast();
}

void Camera::AcqThread::startAcq()
{
	DEB_MEMBER_FUNCT();
283
	sls::Detector *det = m_cam->m_det;
284
	DEB_TRACE() << "calling startReceiver";
285
	det->startReceiver();
286
287
	DEB_TRACE() << "calling Model::startAcq";
	m_cam->m_model->startAcq();
288
289
	DEB_TRACE() << "calling startDetector";
	det->startDetector();
290
291
292
293
294
}

void Camera::AcqThread::stopAcq()
{
	DEB_MEMBER_FUNCT();
295
	sls::Detector *det = m_cam->m_det;
296
297
298
299
	DetStatus det_status = m_cam->getDetStatus();
	bool xfer_active = m_cam->m_model->isXferActive();
	DEB_ALWAYS() << DEB_VAR2(det_status, xfer_active);
	if ((det_status == Defs::Running) || xfer_active) {
300
301
		DEB_TRACE() << "calling stopDetector";
		det->stopDetector();
302
		Timestamp t0 = Timestamp::now();
303
		while (m_cam->m_model->isAcqActive())
304
305
306
307
308
309
			Sleep(m_cam->m_abort_sleep_time);
		double milli_sec = (Timestamp::now() - t0) * 1e3;
		DEB_TRACE() << "Abort -> Idle: " << DEB_VAR1(milli_sec);
	}
	DEB_TRACE() << "calling stopReceiver";
	det->stopReceiver();
310
311
	DEB_TRACE() << "calling Model::stopAcq";
	m_cam->m_model->stopAcq();
312
313
}

314
Camera::AcqThread::Status Camera::AcqThread::newFrameReady(FrameType frame)
315
316
317
318
{
	DEB_MEMBER_FUNCT();
	HwFrameInfoType frame_info;
	frame_info.acq_frame_nb = frame;
319
	StdBufferCbMgr *cb_mgr = m_cam->m_buffer.getBufferCbMgr(LimaBuffer);
320
	bool cont_acq = cb_mgr->newFrameReady(frame_info);
321
322
323
	bool acq_end = (frame == m_cam->m_lima_nb_frames - 1);
	cont_acq &= !acq_end;
	return Status(cont_acq, acq_end);
324
325
}

326
327
328
Camera::Camera(string config_fname, int det_id) 
	: m_det_id(det_id),
	  m_model(NULL),
329
	  m_frame_map(this),
Alejandro Homs Puron's avatar
Alejandro Homs Puron committed
330
331
332
	  m_lima_nb_frames(1),
	  m_det_nb_frames(1),
	  m_skip_frame_freq(0),
333
	  m_last_skipped_frame_timeout(0.5),
334
	  m_lat_time(0),
335
	  m_buffer(this),
336
	  m_pixel_depth(PixelDepth16), 
337
	  m_image_type(Bpp16), 
338
	  m_raw_mode(false),
339
	  m_state(Idle),
340
	  m_new_frame_timeout(0.5),
341
	  m_abort_sleep_time(0.1),
342
	  m_tol_lost_packets(true),
343
	  m_time_ranges_cb(NULL),
344
	  m_global_cpu_affinity_mgr(this)
345
{
346
347
	DEB_CONSTRUCTOR();

348
	CPUAffinity::getNbSystemCPUs();
349

350
351
	m_input_data = new AppInputData(config_fname);

352
353
354
	bool remove_shmem = false;
	if (remove_shmem)
		removeSharedMem();
355
356
	createReceivers();

357
358
	DEB_TRACE() << "Creating the sls::Detector object";
	m_det = new sls::Detector(m_det_id);
359
	DEB_TRACE() << "Reading configuration file";
360
	const char *fname = m_input_data->config_file_name.c_str();
361
	EXC_CHECK(m_det->loadConfig(fname));
362

363
364
365
	EXC_CHECK(m_det->setRxSilentMode(1));
	EXC_CHECK(m_det->setRxFrameDiscardPolicy(
				  slsDetectorDefs::DISCARD_PARTIAL_FRAMES));
366
	setReceiverFifoDepth(4);
367

368
369
370
	sls::Result<int> dr_res;
	EXC_CHECK(dr_res = m_det->getDynamicRange());
	m_pixel_depth = PixelDepth(dr_res.squash(-1));
371

372
	setTrigMode(Defs::Auto);
373
374
375
	setNbFrames(1);
	setExpTime(0.99);
	setFramePeriod(1.0);
376
377
}

378
Camera::~Camera()
379
{
380
	DEB_DESTRUCTOR();
381

382
383
384
	if (m_time_ranges_cb)
		unregisterTimeRangesChangedCallback(*m_time_ranges_cb);

385
386
387
	if (!m_model)
		return;

388
	stopAcq();
389
390
391
	m_model->m_cam = NULL;
}

392
Type Camera::getType()
393
394
{
	DEB_MEMBER_FUNCT();
395
396
397
398
399
400
	slsDetectorDefs::detectorType sls_type;
	const char *err_msg = "Detector types are different";
	EXC_CHECK(sls_type = m_det->getDetectorType().tsquash(err_msg));
	Type det_type;
	switch (sls_type) {
	case slsDetectorDefs::GENERIC:
401
		det_type = GenericDet;
402
403
		break;
	case slsDetectorDefs::EIGER:
404
		det_type = EigerDet;
405
406
		break;
	case slsDetectorDefs::JUNGFRAU:
407
		det_type = JungfrauDet;
408
409
410
		break;
	default:
		det_type = UnknownDet;
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
	}
	DEB_RETURN() << DEB_VAR1(det_type);
	return det_type;
}

void Camera::setModel(Model *model)
{
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR2(model, m_model);
	
	if (model && (model->getType() != getType()))
		THROW_HW_ERROR(InvalidValue) << DEB_VAR2(getType(), 
							 model->getType());
	if (m_model == model)
		return;
	if (m_model)
		m_model->m_cam = NULL;
	m_model = model;
429
430
431
	if (!m_model)
		return;

432
433
434
435
436
437
	int nb_udp_ifaces;
	m_model->getNbUDPInterfaces(nb_udp_ifaces);
	DEB_ALWAYS() << "Using " << m_model->getName()
		     << " with " << getNbDetModules() << "x" << nb_udp_ifaces
		     << " UDP interfaces";

438
439
440
	int nb_items = m_model->getNbFrameMapItems();
	m_frame_map.setNbItems(nb_items);
	m_model->updateFrameMapItems(&m_frame_map);
441

442
	setPixelDepth(m_pixel_depth);
443
444
}

445
446
447
void Camera::removeSharedMem()
{
	DEB_MEMBER_FUNCT();
448
449
	ostringstream cmd;
	cmd << "sls_detector_get " << m_det_id << "-free";
450
451
452
453
	string cmd_str = cmd.str();
	int ret = system(cmd_str.c_str());
	if (ret != 0)
		THROW_HW_ERROR(Error) << "Error executing " << DEB_VAR1(cmd_str);
454
455
}

456
void Camera::createReceivers()
457
{
458
459
	DEB_MEMBER_FUNCT();

460
	DEB_TRACE() << "Receivers:";
461
462
463
464
465
	const RecvPortMap& recv_port_map = m_input_data->recv_port_map;
	RecvPortMap::const_iterator mit, mend = recv_port_map.end();
	int idx = 0;
	for (mit = recv_port_map.begin(); mit != mend; ++mit, ++idx) {
		unsigned int id = mit->first;
466
467
468
		if (id >= m_input_data->host_name_list.size())
			THROW_HW_FATAL(InvalidValue) << DEB_VAR1(id) 
						     << "too high";
469
470
		const string& host_name = m_input_data->host_name_list[id];
		int rx_port = mit->second;
471
		DEB_TRACE() << "  " << host_name << ": " << DEB_VAR1(rx_port);
472

473
		AutoPtr<Receiver> recv_obj = new Receiver(this, idx, rx_port);
474
475
476
477
		m_recv_list.push_back(recv_obj);
	}
}

478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
string Camera::execCmd(const string& s, bool put, int idx)
{
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << "s=\"" << s << "\", " << DEB_VAR2(put, idx);

	string prog_name = string("sls_detector_") + (put ? "put" : "get");
	ostringstream os;
	os << prog_name << " ";
	if (idx >= 0)
		os << idx << ':';
	os << s;
	SystemCmdPipe cmd(os.str(), prog_name, false);
	cmd.setPipe(SystemCmdPipe::StdOut, SystemCmdPipe::DoPipe);
	cmd.setPipe(SystemCmdPipe::StdErr, SystemCmdPipe::DoPipe);
	StringList out, err;
	int ret = cmd.execute(out, err);
	DEB_TRACE() << DEB_VAR3(ret, out, err);
	string err_str = accumulate(err.begin(), err.end(), string());
	if ((ret != 0) || (err_str.find("ERROR") != string::npos))
		THROW_HW_ERROR(Error) << prog_name << "(" << ret << "): "
				      << err_str;
	else if (!err_str.empty())
		cerr << err_str;
	string out_str = accumulate(out.begin(), out.end(), string());
	DEB_RETURN() << DEB_VAR1(out_str);
	return out_str;
}

506
void Camera::putCmd(const string& s, int idx)
507
{
508
	DEB_MEMBER_FUNCT();
509
	execCmd(s, true, idx);
510
511
}

512
string Camera::getCmd(const string& s, int idx)
513
{
514
	DEB_MEMBER_FUNCT();
515
516
517
518
	string r = execCmd(s, false, idx);
	string::size_type p = s.find(':');
	string raw_s = s.substr((p == string::npos) ? 0 : (p + 1));
	DEB_TRACE() << DEB_VAR2(s, raw_s);
519
520
521
522
523
524
525
526
	bool multi_line = ((s == "list") || (s == "versions"));
	if (!multi_line) {
		if (r.find(raw_s + ' ') != 0)
			THROW_HW_ERROR(Error) << "Invalid response: " << r;
		string::size_type e = raw_s.size() + 1;
		p = r.find('\n', e);
		r = r.substr(e, (p == string::npos) ? p : (p - e));
	}
527
	DEB_RETURN() << DEB_VAR1(r);
528
	return r;
529
530
}

531
532
533
534
void Camera::setTrigMode(TrigMode trig_mode)
{
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(trig_mode);
535
	waitAcqState(Idle);
536
537
538
	TrigMode cam_trig_mode = trig_mode;
	if (trig_mode == Defs::SoftTriggerExposure)
		cam_trig_mode = Defs::TriggerExposure;
539
540
541
	typedef slsDetectorDefs::timingMode TimingMode;
	TimingMode mode = static_cast<TimingMode>(cam_trig_mode);
	EXC_CHECK(m_det->setTimingMode(mode));
542
	m_trig_mode = trig_mode;
Alejandro Homs Puron's avatar
Alejandro Homs Puron committed
543
	setNbFrames(m_lima_nb_frames);
544
545
546
547
548
549
550
551
552
}

void Camera::getTrigMode(TrigMode& trig_mode)
{
	DEB_MEMBER_FUNCT();
	trig_mode = m_trig_mode;
	DEB_RETURN() << DEB_VAR1(trig_mode);
}

553
void Camera::setNbFrames(FrameType nb_frames)
554
{
555
	DEB_MEMBER_FUNCT();
556
	DEB_PARAM() << DEB_VAR1(nb_frames);
557
558
559
560
561
562
563

	// Lima frame numbers are (signed) int
	const FrameType MaxFrames = INT_MAX;
	if (nb_frames >= MaxFrames)
		THROW_HW_ERROR(InvalidValue) << "too high " 
					     <<	DEB_VAR2(nb_frames, MaxFrames);

564
	waitAcqState(Idle);
Alejandro Homs Puron's avatar
Alejandro Homs Puron committed
565
566
567
	FrameType det_nb_frames = nb_frames;
	if (m_skip_frame_freq)
		det_nb_frames += nb_frames / m_skip_frame_freq;
568
	bool trig_exp = (m_trig_mode == Defs::TriggerExposure);
Alejandro Homs Puron's avatar
Alejandro Homs Puron committed
569
570
	int cam_frames = trig_exp ? 1 : det_nb_frames;
	int cam_triggers = trig_exp ? det_nb_frames : 1;
571
572
	EXC_CHECK(m_det->setNumberOfFrames(cam_frames));
	EXC_CHECK(m_det->setNumberOfTriggers(cam_triggers));
Alejandro Homs Puron's avatar
Alejandro Homs Puron committed
573
574
	m_lima_nb_frames = nb_frames;
	m_det_nb_frames = det_nb_frames;
575
}
576

577
void Camera::getNbFrames(FrameType& nb_frames)
578
579
{
	DEB_MEMBER_FUNCT();
Alejandro Homs Puron's avatar
Alejandro Homs Puron committed
580
	nb_frames = m_lima_nb_frames;
581
	DEB_RETURN() << DEB_VAR1(nb_frames);
582
}
583

Alejandro Homs Puron's avatar
Alejandro Homs Puron committed
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
void Camera::setSkipFrameFreq(FrameType skip_frame_freq)
{
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(skip_frame_freq);
	m_skip_frame_freq = skip_frame_freq;
	setNbFrames(m_lima_nb_frames);
}

void Camera::getSkipFrameFreq(FrameType& skip_frame_freq)
{
	DEB_MEMBER_FUNCT();
	skip_frame_freq = m_skip_frame_freq;
	DEB_RETURN() << DEB_VAR1(skip_frame_freq);
}

599
600
601
void Camera::setExpTime(double exp_time)
{
	DEB_MEMBER_FUNCT();
602
	DEB_PARAM() << DEB_VAR1(exp_time);
603
	waitAcqState(Idle);
604
	EXC_CHECK(m_det->setExptime(NSec(exp_time)));
605
606
	m_exp_time = exp_time;
}
607

608
609
610
611
void Camera::getExpTime(double& exp_time)
{ 
	DEB_MEMBER_FUNCT();
	exp_time = m_exp_time;
612
	DEB_RETURN() << DEB_VAR1(exp_time);
613
}
614

615
616
617
618
619
620
621
622
623
624
625
626
627
628
void Camera::setLatTime(double lat_time)
{
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(lat_time);
	m_lat_time = lat_time;
}

void Camera::getLatTime(double& lat_time)
{ 
	DEB_MEMBER_FUNCT();
	lat_time = m_lat_time;
	DEB_RETURN() << DEB_VAR1(lat_time);
}

629
630
631
void Camera::setFramePeriod(double frame_period)
{
	DEB_MEMBER_FUNCT();
632
	DEB_PARAM() << DEB_VAR1(frame_period);
633
634
635

	if (m_model) {
		TimeRanges time_ranges;
636
		double e = 1e-6;
637
		m_model->getTimeRanges(time_ranges);
638
639
640
641
642
643
		if ((frame_period < time_ranges.min_frame_period - e) ||
		    (frame_period > time_ranges.max_frame_period + e))
			THROW_HW_ERROR(InvalidValue) 
				<< DEB_VAR3(frame_period,
					    time_ranges.min_frame_period, 
					    time_ranges.max_frame_period);
644
645
	}

646
	waitAcqState(Idle);
647
	EXC_CHECK(m_det->setPeriod(NSec(frame_period)));
648
649
	m_frame_period = frame_period;
}
650

651
652
653
654
void Camera::getFramePeriod(double& frame_period)
{
	DEB_MEMBER_FUNCT();
	frame_period = m_frame_period;
655
	DEB_RETURN() << DEB_VAR1(frame_period);
656
}
657

658
659
660
void Camera::updateImageSize()
{
	DEB_MEMBER_FUNCT();
661
662
663
	RecvList::iterator it, end = m_recv_list.end();
	for (it = m_recv_list.begin(); it != end; ++it)
		(*it)->setGapPixelsEnable(!m_raw_mode);
664
665
666
667
668
669
670
	m_model->updateImageSize();
	FrameDim frame_dim;
	getFrameDim(frame_dim, m_raw_mode);
	DEB_TRACE() << "MaxImageSizeChanged: " << DEB_VAR1(frame_dim);
	maxImageSizeChanged(frame_dim.getSize(), frame_dim.getImageType());
}

671
672
673
674
675
void Camera::updateTimeRanges()
{
	DEB_MEMBER_FUNCT();
	TimeRanges time_ranges;
	m_model->getTimeRanges(time_ranges);
676
677
	m_exp_time = max(m_exp_time, time_ranges.min_exp_time);
	m_frame_period = max(m_frame_period, time_ranges.min_frame_period);
678
679
680
681
682
683
684
	DEB_TRACE() << "TimeRangesChanged: " 
		    << DEB_VAR6(time_ranges.min_exp_time, 
				time_ranges.max_exp_time,
				time_ranges.min_lat_time,
				time_ranges.max_lat_time,
				time_ranges.min_frame_period,
				time_ranges.max_frame_period);
685
686
	if (m_time_ranges_cb)
		m_time_ranges_cb->timeRangesChanged(time_ranges);
687
688
}

689
690
691
692
693
694
void Camera::updateCPUAffinity(bool recv_restarted)
{
	DEB_MEMBER_FUNCT();

	// receiver threads are restarted after DR change
	if (recv_restarted)
695
		m_global_cpu_affinity_mgr.updateRecvRestart();
696

697
698
699
	// apply the corresponding GlobalCPUAffinity
	GlobalCPUAffinity global_affinity = m_cpu_affinity_map[m_pixel_depth];
	m_global_cpu_affinity_mgr.applyAndSet(global_affinity);
700
701
}

702
void Camera::setRecvCPUAffinity(const RecvCPUAffinityList& recv_affinity_list)
703
704
{
	DEB_MEMBER_FUNCT();
705
	unsigned int nb_aff = recv_affinity_list.size();
706
	DEB_PARAM() << DEB_VAR1(nb_aff);
707
	RecvCPUAffinityList::const_iterator ait = recv_affinity_list.begin();
708
	RecvList::iterator rit = m_recv_list.begin();
709
710
	for (unsigned int i = 0; i < nb_aff; ++i, ++ait, ++rit)
		(*rit)->setCPUAffinity(*ait);
711
712
}

713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
void Camera::setModuleActive(int mod_idx, bool  active)
{
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR2(mod_idx, active);

	if ((mod_idx < 0) || (mod_idx >= getNbDetModules()))
		THROW_HW_ERROR(InvalidValue) << DEB_VAR1(mod_idx);

	Positions pos = Idx2Pos(mod_idx);
	EXC_CHECK(m_det->setActive(active, pos));
}

void Camera::getModuleActive(int mod_idx, bool& active)
{
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(mod_idx);

	if ((mod_idx < 0) || (mod_idx >= getNbDetModules()))
		THROW_HW_ERROR(InvalidValue) << DEB_VAR1(mod_idx);

	Positions pos = Idx2Pos(mod_idx);
	EXC_CHECK(active = m_det->getActive(pos).front());
	DEB_RETURN() << DEB_VAR1(active);
}

738
739
740
741
742
void Camera::setPixelDepth(PixelDepth pixel_depth)
{
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(pixel_depth);

743
	if (getAcqState() != Idle)
744
745
		THROW_HW_FATAL(Error) << "Camera is not idle";

746
	waitAcqState(Idle);
747
748
749
750
751
752
753
754
755
756
757
	switch (pixel_depth) {
	case PixelDepth4:
	case PixelDepth8:
		m_image_type = Bpp8;	break;
	case PixelDepth16:
		m_image_type = Bpp16;	break;
	case PixelDepth32:
		m_image_type = Bpp32;	break;
	default:
		THROW_HW_ERROR(InvalidValue) << DEB_VAR1(pixel_depth);
	}
758
	EXC_CHECK(m_det->setDynamicRange(pixel_depth));
759
760
	m_pixel_depth = pixel_depth;

761
	if (m_model) {
762
		updateImageSize();
763
		updateTimeRanges();
764
		updateCPUAffinity(true);
765
	}
766
767
768
769
770
771
772
773
774
}

void Camera::getPixelDepth(PixelDepth& pixel_depth)
{
	DEB_MEMBER_FUNCT();
	pixel_depth = m_pixel_depth; 
	DEB_RETURN() << DEB_VAR1(pixel_depth);
}

775
void Camera::setRawMode(bool raw_mode)
776
777
{
	DEB_MEMBER_FUNCT();
778
	DEB_PARAM() << DEB_VAR1(raw_mode);
779

780
	if (raw_mode == m_raw_mode)
781
		return;
782
	m_raw_mode = raw_mode;
783

784
	updateImageSize();
785
786
}

787
void Camera::getRawMode(bool& raw_mode)
788
789
{
	DEB_MEMBER_FUNCT();
790
791
	raw_mode = m_raw_mode; 
	DEB_RETURN() << DEB_VAR1(raw_mode);
792
793
}

794
AcqState Camera::getAcqState()
795
796
797
{
	DEB_MEMBER_FUNCT();
	AutoMutex l = lock();
798
	AcqState state = getEffectiveState();
799
800
	DEB_RETURN() << DEB_VAR1(state);
	return state;
801
802
}

803
AcqState Camera::getEffectiveState()
804
805
806
807
808
809
810
811
{
	if (m_state == Stopped) {
		m_acq_thread = NULL;
		m_state = Idle;
	}
	return m_state;
}

812
void Camera::waitAcqState(AcqState state)
813
814
{
	DEB_MEMBER_FUNCT();
815
	DEB_PARAM() << DEB_VAR1(state);
816
817
818
819
820
	AutoMutex l = lock();
	while (getEffectiveState() != state)
		m_cond.wait();
}

821
AcqState Camera::waitNotAcqState(AcqState state)
822
823
{
	DEB_MEMBER_FUNCT();
824
	DEB_PARAM() << DEB_VAR1(state);
825
826
827
	AutoMutex l = lock();
	while (getEffectiveState() == state)
		m_cond.wait();
828
829
830
	state = getEffectiveState();
	DEB_RETURN() << DEB_VAR1(state);
	return state;
831
832
}

833
834
835
836
void Camera::prepareAcq()
{
	DEB_MEMBER_FUNCT();

837
	StdBufferCbMgr *cb_mgr = m_buffer.getBufferCbMgr(AcqBuffer);
838
	if (!cb_mgr)
839
		THROW_HW_ERROR(Error) << "No Acq BufferCbMgr defined";
840
	else if (!m_buffer.getBufferCbMgr(LimaBuffer))
841
		THROW_HW_ERROR(Error) << "No Lima BufferCbMgr defined";
842
	if (!m_model)
843
		THROW_HW_ERROR(Error) << "No Model defined";
844

845
846
	m_buffer.prepareAcq();

847
848
	waitNotAcqState(Stopping);
	if (getAcqState() != Idle)
849
850
		THROW_HW_ERROR(Error) << "Camera is not idle";

Alejandro Homs Puron's avatar
Alejandro Homs Puron committed
851
	bool need_period = !m_lima_nb_frames || (m_lima_nb_frames > 1);
852
853
854
	need_period &= ((m_trig_mode == Defs::Auto) || 
			(m_trig_mode == Defs::BurstTrigger));
	if (need_period && (m_lat_time > 0))
855
856
		setFramePeriod(m_exp_time + m_lat_time);

857
	int nb_buffers;
858
	cb_mgr->getNbBuffers(nb_buffers);
859

860
861
	{
		AutoMutex l = lock();
862
		m_frame_map.setBufferSize(nb_buffers);
863
		m_frame_map.clear();
864
		m_prev_ifa.clear();
865
866
867
		RecvList::iterator it, end = m_recv_list.end();
		for (it = m_recv_list.begin(); it != end; ++it)
			(*it)->prepareAcq();
868
869
870

		m_missing_last_skipped_frame.clear();
		if (m_skip_frame_freq)
871
			for (int i = 0; i < getNbRecvs(); ++i)
872
				m_missing_last_skipped_frame.insert(i);
873
874

		m_next_ready_ts = Timestamp();
875
	}
876

877
	m_model->prepareAcq();
878
	m_global_cpu_affinity_mgr.prepareAcq();
879
	m_model->getReconstruction()->prepare();
880

881
	resetFramesCaught();
882
883
	EXC_CHECK(m_det->setFileWrite(0));
	EXC_CHECK(m_det->setNextFrameNumber(1));
884
885
}

886
void Camera::startAcq()
887
{
888
	DEB_MEMBER_FUNCT();
889

890
891
892
	AutoMutex l = lock();
	if (m_acq_thread)
		THROW_HW_ERROR(Error) << "Must call prepareAcq first";
893

894
	StdBufferCbMgr *cb_mgr = m_buffer.getBufferCbMgr(LimaBuffer);
895
	cb_mgr->setStartTimestamp(Timestamp::now());
896
897

	m_acq_thread = new AcqThread(this);
898
	m_acq_thread->start(l);
899
900
}

901
void Camera::stopAcq()
902
{
903
904
	DEB_MEMBER_FUNCT();

905
906
907
	Reconstruction *r = m_model ? m_model->getReconstruction() : NULL;
	if (r)
		r->cleanUp();
908
	m_global_cpu_affinity_mgr.stopAcq();
909

910
911
	AutoMutex l = lock();
	if (getEffectiveState() != Running)
912
913
		return;

914
	m_acq_thread->stop(l, true);
915
916
	if (getEffectiveState() != Idle)
		THROW_HW_ERROR(Error) << "Camera not Idle";
917
918
}

919
920
921
922
923
924
925
926
927
928
929
void Camera::triggerFrame()
{
	DEB_MEMBER_FUNCT();

	if (m_trig_mode != Defs::SoftTriggerExposure)
		THROW_HW_ERROR(InvalidValue) << "Wrong trigger mode";

	AutoMutex l = lock();
	if (getEffectiveState() != Running)
		THROW_HW_ERROR(Error) << "Camera not Running";

930
	EXC_CHECK(m_det->sendSoftwareTrigger());
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
	m_next_ready_ts = Timestamp::now();
	m_next_ready_ts += m_exp_time;
}

Camera::DetStatus Camera::getDetTrigStatus()
{
	DEB_MEMBER_FUNCT();

	if (m_trig_mode != Defs::SoftTriggerExposure)
		THROW_HW_ERROR(InvalidValue) << "Wrong trigger mode";

	Timestamp t = Timestamp::now();

	AutoMutex l = lock();
	bool ready = !m_next_ready_ts.isSet() || (m_next_ready_ts < t);
	DetStatus trig_status = ready ? Defs::Waiting : Defs::Running;
	DEB_RETURN() << DEB_VAR1(trig_status);
	return trig_status;
949
950
}

951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
DetFrameImagePackets Camera::readRecvPackets()
{
	DEB_MEMBER_FUNCT();

	FrameType frame = m_model->m_next_frame++;

	DetFrameImagePackets det_frame_packets{frame, {}};
	DetImagePackets& det_packets = det_frame_packets.second;
	FramePacketMap::iterator it = m_frame_packet_map.find(frame);
	if (it != m_frame_packet_map.end()) {
		det_packets = std::move(det_packets);
		m_frame_packet_map.erase(it);
	}

	int nb_recvs = getNbRecvs();
	for (int i = 0; i < nb_recvs; ++i) {
		while (det_packets.find(i) == det_packets.end()) {
			Receiver::ImagePackets *image_packets;
			image_packets = m_recv_list[i]->readImagePackets();
			if (!image_packets)
				break;
			typedef DetImagePackets::value_type MapEntry;
			FrameType f = image_packets->frame;
			if (f == frame)  {
				det_packets.emplace(MapEntry(i, image_packets));
				break;
			} else {
				DetImagePackets& other = m_frame_packet_map[f];
				other.emplace(MapEntry(i, image_packets));
			}
		}
	}

	FrameType& m_last_frame = m_model->m_last_frame;
	if ((int(m_last_frame) == -1) || (frame > m_last_frame))
		m_last_frame = frame;

	return det_frame_packets;
}

991
992
993
994
995
996
997
998
void Camera::publishFrame(FrameType frame)
{
	DEB_MEMBER_FUNCT();
	FrameMap::Item *mi = m_frame_map.getItem(0);
	Model::FinishInfo finfo = mi->frameFinished(frame, true, true);
	m_model->processFinishInfo(finfo);
}

999
1000
void Camera::assemblePackets(DetFrameImagePackets&& det_frame_packets)
{