FrelonCamera.cpp 40.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
//###########################################################################
// 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/>.
//###########################################################################
22
#include "FrelonCamera.h"
23
#include "lima/MiscUtils.h"
24
#include <sstream>
25

26
using namespace lima;
27
28
29
using namespace lima::Frelon;
using namespace std;

30
const double Camera::ResetLinkWaitTime = 5;
31
const double Camera::UpdateCcdStatusTime = 0.1;
32
33
const double Camera::MaxIdleWaitTime = 2.5;
const double Camera::MaxBusyRetryTime = 0.2;	// 16 Mpixel image Aurora Xfer
34

35
36
37
38
39
40
41
42
43
44
45
46
47
48
Camera::DeadTimeChangedCallback::DeadTimeChangedCallback()
	: m_cam(NULL)
{
	DEB_CONSTRUCTOR();
}

Camera::DeadTimeChangedCallback::~DeadTimeChangedCallback()
{
	DEB_DESTRUCTOR();

	if (m_cam)
		m_cam->unregisterDeadTimeChangedCallback(*this);
}

ahoms's avatar
ahoms committed
49

50
Camera::Camera(Espia::SerialLine& espia_ser_line)
51
	: m_ser_line(espia_ser_line), m_timing_ctrl(m_model, m_ser_line),
52
	  m_mis_cb_act(false), m_dead_time(0), m_dead_time_cb(NULL)
53
{
54
55
	DEB_CONSTRUCTOR();

56
57
58
59
60
61
	sync();
}

Camera::~Camera()
{
	DEB_DESTRUCTOR();
62
63
64

	if (m_dead_time_cb)
		unregisterDeadTimeChangedCallback(*m_dead_time_cb);
65
66
67
68
69
70
}

void Camera::sync()
{
	DEB_MEMBER_FUNCT();

ahoms's avatar
ahoms committed
71
	Espia::Dev& dev = getEspiaDev();
72
73
74
75
76
77
78
79
80
	int chan_up_led;
	dev.getChanUpLed(chan_up_led);
	if (!chan_up_led) {
		DEB_WARNING() << "Aurora link down. Forcing a link reset!";
		dev.resetLink();
		DEB_TRACE() << "Sleeping additional "
			    << DEB_VAR1(Frelon::Camera::ResetLinkWaitTime);
		Sleep(ResetLinkWaitTime);
	}
ahoms's avatar
ahoms committed
81

82
	DEB_TRACE() << "Synchronizing with the camera";
83

84
	m_model.reset();
85
	m_chan_roi_offset = 0;
86
	m_started = false;
87
88

	try {
89
		syncRegs();
90
91
	} catch (Exception e) {
		string err_msg = e.getErrMsg();
92
		DEB_TRACE() << "Error in sync: " << DEB_VAR1(err_msg);
93
94
95
96
97
98
99
100
101
		string timeout_msg = Espia::StrError(SCDXIPCI_ERR_TIMEOUT);
		bool timeout = (err_msg.find(timeout_msg) != string::npos);
		if (!timeout)
			throw;

		THROW_HW_ERROR(Error) << "Serial connection timeout: "
					 "is camera ON and connected?";
	}

102
	string ver;
103
	m_model.getFirmware().getVersionStr(ver);
104
105
	DEB_ALWAYS() << "Found Frelon " << m_model.getName() 
		     << " #" << m_model.getSerialNb() << ", FW:" << ver;
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
}

void Camera::syncRegs()
{
	DEB_MEMBER_FUNCT();

	m_ser_line.clearCache();

	string ver;
	getVersionStr(ver);
	m_model.setVersionStr(ver);

	int complex_ser_nb;
	getComplexSerialNb(complex_ser_nb);
	m_model.setComplexSerialNb(complex_ser_nb);
121

122
123
	if (m_model.hasGoodHTD())
		syncRegsGoodHTD();
124
125
126
	else 
		syncRegsBadHTD();

127

ahoms's avatar
ahoms committed
128
129
130
131
	double exp_time;
	getExpTime(exp_time);
	m_trig_mode = (exp_time == 0) ? ExtGate : IntTrig;

132
133
134
135
136
137
	// A sequencer cmd will send the CCD status byte to the Espia
	m_nb_frames = 1;
	writeRegister(NbFrames, m_nb_frames);
	DEB_TRACE() << "Sleeping " << UpdateCcdStatusTime << " s to allow "
		    << "CCD status byte get updated";
	Sleep(UpdateCcdStatusTime);
138
139

	getRoiBinOffset(m_roi_bin_offset);
140
	deadTimeChanged();
141
142
}

143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
void Camera::syncRegsGoodHTD()
{
	DEB_MEMBER_FUNCT();

	Status status;
	bool use_ser_line, read_spb2;
	use_ser_line = read_spb2 = true;
	getStatus(status, use_ser_line, read_spb2);
	if (status != Wait)
		DEB_WARNING() << "Camera not IDLE: " 
			      << DEB_VAR1(DEB_HEX(status));
	int retry = 0;
	do {
		setExtSyncEnable(ExtSyncNone);
		sendCmd(Stop);
158
159
		bool ok = waitIdleStatus(status, use_ser_line, read_spb2);
		if (ok) {
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
			if (retry > 0)
				DEB_TRACE() << "Succeeded after " << retry 
					    << " retries";
			break;
		} else if (retry == 0) {
			DEB_WARNING() << "Tyring a hard reset ...";
			sendCmd(Reset);
		}
	} while (++retry < 2);
					  
	if (status != Wait)
		THROW_HW_ERROR(Error) << "Wrong camera BUSY status: "
				      << DEB_VAR1(DEB_HEX(status));
}

175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210

void Camera::syncRegsBadHTD()
{
	DEB_MEMBER_FUNCT();

	Status status;
	getStatus(status);
	if ((status != 0) && (status != Wait)) {
		DEB_WARNING() << "Camera not IDLE: " 
			      << DEB_VAR1(DEB_HEX(status));
		double exp_time;
		getExpTime(exp_time);
		if (exp_time > 0) {
			DEB_TRACE() << "Sending software STOP ...";
			sendCmd(Stop);
		}

		if (waitIdleStatus(status))
			DEB_TRACE() << "Succeeded";
		else
			DEB_WARNING() << "Camera still not IDLE: " 
				      << DEB_VAR1(DEB_HEX(status));
	}
					  
	Espia::Dev& dev = getEspiaDev();
	DEB_TRACE() << "Forcing Aurora link reset on old firmware!";
	dev.resetLink();
	DEB_TRACE() << "Sleeping additional "
		    << DEB_VAR1(Frelon::Camera::ResetLinkWaitTime);
	Sleep(ResetLinkWaitTime);

	if (m_model.hasHTDCmd())
		setExtSyncEnable(ExtSyncBoth);
}


211
212
213
214
215
SerialLine& Camera::getSerialLine()
{
	return m_ser_line;
}

216
217
Espia::Dev& Camera::getEspiaDev()
{
218
	Espia::SerialLine& ser_line = m_ser_line.getEspiaSerialLine();
219
220
221
222
	Espia::Dev& dev = ser_line.getDev();
	return dev;
}

223
224
void Camera::sendCmd(Cmd cmd)
{
225
226
	DEB_MEMBER_FUNCT();
	const string& cmd_str = CmdStrMap[cmd];
227
	DEB_PARAM() << DEB_VAR2(cmd, cmd_str);
228
229
230
	if (cmd_str.empty())
		THROW_HW_ERROR(InvalidValue) << "Invalid " 
					     << DEB_VAR1(cmd);
231

232
	string resp;
233
	m_ser_line.sendFmtCmd(cmd_str, resp);
234
235
236
237
}

void Camera::writeRegister(Reg reg, int val)
{
238
	DEB_MEMBER_FUNCT();
239
240

	Timestamp t0 = Timestamp::now();
241
242
243
244
	int retry;
	bool end, prev_busy = false;
	for (retry = 0, end = false; !end; retry++) {
		bool fail, busy;
245
246
247
248
		try {
			m_ser_line.writeRegister(reg, val);
			if (retry > 0)
				DEB_WARNING() << "Succeeded after " << retry 
249
					      << " retrie(s)";
250
251
252
253
			return;
		} catch (Exception e) {
			string err_msg = e.getErrMsg();
			DEB_TRACE() << "Error in write: " << DEB_VAR1(err_msg);
254
255
256
257
258
259
260

			static const string fail_msg = "Frelon Error: FAI";
			fail = (err_msg.find(fail_msg) != string::npos);
			static const string busy_msg = "Frelon Error: BSY";
			busy = (err_msg.find(busy_msg) != string::npos);

			if (!fail && !busy)
261
262
263
				throw;
		}

264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
		if ((prev_busy != busy) && (retry > 0)) {
			DEB_WARNING() << "Write error type changed after " 
				      << retry << " retrie(s)! Restarting ...";
			retry = 0;
			t0 = Timestamp::now();
		}
		prev_busy = busy;

		if (busy)
			end = ((Timestamp::now() - t0) >= MaxBusyRetryTime);
		else
			end = (retry > 0);
		if (!end)
			DEB_TRACE() << "Retrying ...";
	}

	if (prev_busy)
		THROW_HW_ERROR(Error) << "Frelon Camera still busy after "
				      << MaxBusyRetryTime << " sec";
	else
		THROW_HW_ERROR(Error) << "Frelon Camera still failing after "
				      << retry << " retrie(s)";
286
287
288
289
}

void Camera::readRegister(Reg reg, int& val)
{
290
	DEB_MEMBER_FUNCT();
291
	m_ser_line.readRegister(reg, val);
292
293
}

294
295
296
297
298
299
void Camera::readFloatRegister(Reg reg, double& val)
{
	DEB_MEMBER_FUNCT();
	m_ser_line.readFloatRegister(reg, val);
}

300
301
void Camera::hardReset()
{
302
	DEB_MEMBER_FUNCT();
303

304
	DEB_TRACE() << "Reseting the camera";
305
	sendCmd(Reset);
306
307

	sync();
308
309
}

310
void Camera::getVersionStr(string& ver)
311
{
312
	DEB_MEMBER_FUNCT();
313
314
	string cmd = RegStrMap[Version] + "?";
	m_ser_line.sendFmtCmd(cmd, ver);
315
	DEB_RETURN() << DEB_VAR1(ver);
316
}
ahoms's avatar
ahoms committed
317
318
319

void Camera::getComplexSerialNb(int& complex_ser_nb)
{
320
	DEB_MEMBER_FUNCT();
ahoms's avatar
ahoms committed
321
	readRegister(CompSerNb, complex_ser_nb);
322
	DEB_RETURN() << DEB_VAR1(DEB_HEX(complex_ser_nb));
ahoms's avatar
ahoms committed
323
324
}

325
Model& Camera::getModel()
326
{
327
	return m_model;
ahoms's avatar
ahoms committed
328
329
}

330
331
332
333
334
TimingCtrl& Camera::getTimingCtrl()
{
	return m_timing_ctrl;
}

335
336
337
338
339
340
341
342
343
344
345
346
int Camera::getModesAvail()
{
	DEB_MEMBER_FUNCT();

	int modes_avail;
	if (m_model.hasModesAvail())
		readRegister(CcdModesAvail, modes_avail);
	else if (m_model.getChipType() == Kodak)
		modes_avail = KodakModesAvail;
	else
		modes_avail = AtmelModesAvail;
		
347
	DEB_RETURN() << DEB_VAR1(DEB_HEX(modes_avail));
348
349
350
351
352
353
	return modes_avail;
}

string Camera::getInputChanModeName(FrameTransferMode ftm, 
				    InputChan input_chan)
{
354
	DEB_STATIC_FUNCT();
355
356

	ostringstream os;
357
	os << FTMNameMap[ftm] << "-";
358
359
360
361
362
	string sep;
	for (int chan = 1; chan <= 4; chan++) {
		int chan_bit = 1 << (chan - 1);
		if ((input_chan & chan_bit) != 0) {
			os << sep << chan;
363
			sep = "&";
364
365
366
367
368
369
370
		}
	}
	string mode_name = os.str();
	DEB_RETURN() << DEB_VAR1(mode_name);
	return mode_name;
}

ahoms's avatar
ahoms committed
371
372
void Camera::setChanMode(int chan_mode)
{
373
374
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(chan_mode);
375
376
377
378
379
380
381
382
383
384
385
386
387
388

	int mode_bit = 1 << (chan_mode - 1);
	bool valid_mode = ((getModesAvail() & mode_bit) != 0);
	if (!valid_mode) {
		FrameTransferMode ftm;
		InputChan input_chan;
		calcFTMInputChan(chan_mode, ftm, input_chan);
		string mode_name = getInputChanModeName(ftm, input_chan);

		THROW_HW_ERROR(InvalidValue) 
			<< "Channel mode " << mode_name 
			<< " [" << DEB_VAR1(chan_mode) << "] "
			<< "not supported in " << m_model.getName();
	}
ahoms's avatar
ahoms committed
389
	writeRegister(ChanMode, chan_mode);
390
	deadTimeChanged();
ahoms's avatar
ahoms committed
391
392
393
394
}

void Camera::getChanMode(int& chan_mode)
{
395
	DEB_MEMBER_FUNCT();
ahoms's avatar
ahoms committed
396
	readRegister(ChanMode, chan_mode);
397
	DEB_RETURN() << DEB_VAR1(chan_mode);
ahoms's avatar
ahoms committed
398
399
}

400
void Camera::calcBaseChanMode(FrameTransferMode ftm, int& base_chan_mode)
ahoms's avatar
ahoms committed
401
{
402
	DEB_MEMBER_FUNCT();
ahoms's avatar
ahoms committed
403
	base_chan_mode = FTMChanRangeMap[ftm].first;
404
	DEB_RETURN() << DEB_VAR1(base_chan_mode);
ahoms's avatar
ahoms committed
405
406
}

407
408
void Camera::calcChanMode(FrameTransferMode ftm, InputChan input_chan,
			  int& chan_mode)
ahoms's avatar
ahoms committed
409
{
410
	DEB_MEMBER_FUNCT();
411
	DEB_PARAM() << DEB_VAR2(FTMNameMap[ftm], DEB_HEX(input_chan));
412

413
	calcBaseChanMode(ftm, chan_mode);
ahoms's avatar
ahoms committed
414
415
416
417
	const InputChanList& chan_list = FTMInputChanListMap[ftm];
	InputChanList::const_iterator it;
	it = find(chan_list.begin(), chan_list.end(), input_chan);
	if (it == chan_list.end())
418
419
		THROW_HW_ERROR(InvalidValue) << "Invalid " 
					     << DEB_VAR1(input_chan);
ahoms's avatar
ahoms committed
420
	chan_mode += it - chan_list.begin();
421
422

	DEB_RETURN() << DEB_VAR1(chan_mode);
ahoms's avatar
ahoms committed
423
424
}

425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
void Camera::calcFTMInputChan(int chan_mode, FrameTransferMode& ftm, 
			      InputChan& input_chan)
{
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(chan_mode);

	bool ftm_found = false;
	FTMChanRangeMapType::const_iterator it, end = FTMChanRangeMap.end();
	for (it = FTMChanRangeMap.begin(); it != end; ++it) {
		ftm = it->first;
		const ChanRange& range = it->second;
		if ((chan_mode >= range.first) && (chan_mode < range.second)) {
			ftm_found = true;
			break;
		}
	}
	if (!ftm_found)
		THROW_HW_ERROR(Error) << "Invalid " << DEB_VAR1(chan_mode);

	int base_chan_mode;
	calcBaseChanMode(ftm, base_chan_mode);
	input_chan = FTMInputChanListMap[ftm][chan_mode - base_chan_mode];
447
	DEB_RETURN() << DEB_VAR2(FTMNameMap[ftm], DEB_HEX(input_chan));
448
449
}

450
bool Camera::getDefInputChan(FrameTransferMode ftm, InputChan& input_chan)
451
452
{
	DEB_MEMBER_FUNCT();
453
	DEB_PARAM() << DEB_VAR1(FTMNameMap[ftm]);
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472

	int modes_avail = getModesAvail();

	bool valid_mode = false;
	InputChanList::const_iterator it, end = DefInputChanList.end();
	for (it = DefInputChanList.begin(); it != end; ++it) {
		input_chan = *it;
		int chan_mode;
		try {
			calcChanMode(ftm, input_chan, chan_mode);
		} catch (...) {
			continue;
		}
		int mode_bit = 1 << (chan_mode - 1);
		valid_mode = ((modes_avail & mode_bit) != 0);
		if (valid_mode)
			break;
	}

473
474
475
476
477
478
479
480
481
482
	if (!valid_mode) {
		DEB_WARNING() << "Could not find default input_chan for " 
			      << FTMNameMap[ftm] << ": " 
			      << DEB_VAR1(DEB_HEX(modes_avail));
		DEB_RETURN() << DEB_VAR1(valid_mode);
	} else {
		DEB_RETURN() << DEB_VAR2(valid_mode, DEB_HEX(input_chan)) 
			     << " [" << getInputChanModeName(ftm, input_chan) 
			     << "]";
	}
483

484
	return valid_mode;
485
486
}

ahoms's avatar
ahoms committed
487
488
void Camera::setInputChan(InputChan input_chan)
{
489
490
491
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(DEB_HEX(input_chan));

ahoms's avatar
ahoms committed
492
493
494
	FrameTransferMode ftm;
	getFrameTransferMode(ftm);
	int chan_mode;
495
	calcChanMode(ftm, input_chan, chan_mode);
ahoms's avatar
ahoms committed
496
497
498
499
500
	setChanMode(chan_mode);
}

void Camera::getInputChan(InputChan& input_chan)
{
501
502
	DEB_MEMBER_FUNCT();

ahoms's avatar
ahoms committed
503
	FrameTransferMode ftm;
504
	int chan_mode;
ahoms's avatar
ahoms committed
505
	getChanMode(chan_mode);
506
	calcFTMInputChan(chan_mode, ftm, input_chan);
507
508

	DEB_RETURN() << DEB_VAR1(DEB_HEX(input_chan));
ahoms's avatar
ahoms committed
509
510
511
512
}

void Camera::setFrameTransferMode(FrameTransferMode ftm)
{
513
	DEB_MEMBER_FUNCT();
514
	DEB_PARAM() << DEB_VAR1(FTMNameMap[ftm]);
515
	
ahoms's avatar
ahoms committed
516
517
518
519
520
521
522
	FrameTransferMode prev_ftm;
	getFrameTransferMode(prev_ftm);
	if (ftm == prev_ftm) {
		DEB_TRACE() << "Nothing to do";
		return;
	}

523
524
	InputChan input_chan;
	getInputChan(input_chan);
ahoms's avatar
ahoms committed
525
	int chan_mode;
526
527
528
529
530
	try {
		calcChanMode(ftm, input_chan, chan_mode);
		setChanMode(chan_mode);
	} catch (...) {
		DEB_TRACE() << DEB_VAR1(DEB_HEX(input_chan)) 
531
			    << " not available in " << FTMNameMap[ftm];
532
		DEB_TRACE() << "  Trying default input channel";
533
534
535
		if (!getDefInputChan(ftm, input_chan))
			THROW_HW_ERROR(Error) << "No input channel found for "
					      << FTMNameMap[ftm];
536
537
538
		calcChanMode(ftm, input_chan, chan_mode);
		setChanMode(chan_mode);
	}
ahoms's avatar
ahoms committed
539
540
541
542
543
544
545
546

	if (!m_mis_cb_act) 
		return;

	FrameDim frame_dim;
	getFrameDim(frame_dim);
	DEB_TRACE() << "MaxImageSizeChanged: " << DEB_VAR1(frame_dim);
	maxImageSizeChanged(frame_dim.getSize(), frame_dim.getImageType());
ahoms's avatar
ahoms committed
547
548
549
550
}

void Camera::getFrameTransferMode(FrameTransferMode& ftm)
{
551
552
	DEB_MEMBER_FUNCT();

ahoms's avatar
ahoms committed
553
554
555
556
557
558
559
	int chan_mode;
	getChanMode(chan_mode);

	FTMChanRangeMapType::const_iterator it, end = FTMChanRangeMap.end();
	for (it = FTMChanRangeMap.begin(); it != end; ++it) {
		ftm = it->first;
		const ChanRange& range = it->second;
560
		if ((chan_mode >= range.first) && (chan_mode < range.second)) {
561
			DEB_RETURN() << DEB_VAR1(FTMNameMap[ftm]);
ahoms's avatar
ahoms committed
562
			return;
563
		}
ahoms's avatar
ahoms committed
564
565
	}

566
	THROW_HW_ERROR(Error) << "Invalid " << DEB_VAR1(chan_mode);
ahoms's avatar
ahoms committed
567
568
}

569
570
571
572
573
574
575
576
577
578
void Camera::getMaxFrameDim(FrameDim& max_frame_dim)
{
	DEB_MEMBER_FUNCT();

	ChipType chip_type = m_model.getChipType();
	max_frame_dim = ChipMaxFrameDimMap[chip_type];

	DEB_RETURN() << DEB_VAR1(max_frame_dim);
}

ahoms's avatar
ahoms committed
579
580
void Camera::getFrameDim(FrameDim& frame_dim)
{
581
582
	DEB_MEMBER_FUNCT();

583
	getMaxFrameDim(frame_dim);
ahoms's avatar
ahoms committed
584
585
	FrameTransferMode ftm;
	getFrameTransferMode(ftm);
586
	if ((ftm == FTM) && !m_model.isHama())
ahoms's avatar
ahoms committed
587
		frame_dim /= Point(1, 2);
588
589

	DEB_RETURN() << DEB_VAR1(frame_dim);
ahoms's avatar
ahoms committed
590
591
592
593
}

void Camera::setFlipMode(int flip_mode)
{
594
595
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(flip_mode);
596
	writeRegister(FlipMode, flip_mode);
ahoms's avatar
ahoms committed
597
598
599
600
}

void Camera::getFlipMode(int& flip_mode)
{
601
	DEB_MEMBER_FUNCT();
602
	readRegister(FlipMode, flip_mode);
603
	DEB_RETURN() << DEB_VAR1(flip_mode);
ahoms's avatar
ahoms committed
604
605
}

606
void Camera::checkFlip(Flip& flip)
ahoms's avatar
ahoms committed
607
{
608
609
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(flip);
610
611
612
613
614
615
616
617
618
	DEB_TRACE() << "All standard flip modes are supported";
	DEB_RETURN() << DEB_VAR1(flip);
}

void Camera::setFlip(const Flip& flip)
{
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(flip);
	int flip_mode = (flip.x << 1) | (flip.y << 0);
ahoms's avatar
ahoms committed
619
620
621
	setFlipMode(flip_mode);
}

622
void Camera::getFlip(Flip& flip)
ahoms's avatar
ahoms committed
623
{
624
625
	DEB_MEMBER_FUNCT();

ahoms's avatar
ahoms committed
626
627
628
629
	int flip_mode;
	getFlipMode(flip_mode);
	flip.x = (flip_mode >> 1) & 1;
	flip.y = (flip_mode >> 0) & 1;
630
631

	DEB_RETURN() << DEB_VAR1(flip);
ahoms's avatar
ahoms committed
632
633
}

634
635
void Camera::checkBin(Bin& bin)
{
636
637
638
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(bin);
	
639
640
641
	int bin_x = min(bin.getX(), int(MaxBinX));
	int bin_y = min(bin.getY(), int(MaxBinY));
	bin = Bin(bin_x, bin_y);
642
643

	DEB_RETURN() << DEB_VAR1(bin);
644
645
}

ahoms's avatar
ahoms committed
646
647
void Camera::setBin(const Bin& bin)
{
648
649
650
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(bin);
	
651
	if ((bin.getX() > MaxBinX) || (bin.getY() > MaxBinY))
652
		THROW_HW_ERROR(InvalidValue) << "Invalid " << DEB_VAR1(bin)
653
654
					     << ". Max. HW binning is " 
					     << Bin(MaxBinX, MaxBinY);
655

ahoms's avatar
ahoms committed
656
657
	Bin curr_bin;
	getBin(curr_bin);
658
659
	DEB_TRACE() << DEB_VAR1(curr_bin);
	if (bin == curr_bin) 
ahoms's avatar
ahoms committed
660
661
		return;

662
	DEB_TRACE() << "Reseting Roi";
663
664
665
	Roi roi;
	setRoi(roi);

ahoms's avatar
ahoms committed
666
667
	writeRegister(BinHorz, bin.getX());
	writeRegister(BinVert, bin.getY());
668
669

	resetRoiBinOffset();
670
671

	deadTimeChanged();
ahoms's avatar
ahoms committed
672
673
674
675
}

void Camera::getBin(Bin& bin)
{
676
	DEB_MEMBER_FUNCT();
ahoms's avatar
ahoms committed
677
678
679
680
	int bin_x, bin_y;
	readRegister(BinHorz, bin_x);
	readRegister(BinVert, bin_y);
	bin = Bin(bin_x, bin_y);
681
	DEB_RETURN() << DEB_VAR1(bin);
ahoms's avatar
ahoms committed
682
683
684
685
}

void Camera::setRoiMode(RoiMode roi_mode)
{
686
687
688
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(roi_mode);

ahoms's avatar
ahoms committed
689
	bool roi_hw   = (roi_mode == Slow) || (roi_mode == Fast);
690
	bool roi_fast = (roi_mode == Fast);
ahoms's avatar
ahoms committed
691
	bool roi_kin  = (roi_mode == Kinetic);
692
	DEB_TRACE() << DEB_VAR3(roi_hw, roi_fast, roi_kin);
ahoms's avatar
ahoms committed
693
694
695
696

	writeRegister(RoiEnable,  roi_hw);
	writeRegister(RoiFast,    roi_fast);
	writeRegister(RoiKinetic, roi_kin);
697
698
699

	if (roi_mode == None)
		resetRoiBinOffset();
700
701

	deadTimeChanged();
ahoms's avatar
ahoms committed
702
703
704
705
}

void Camera::getRoiMode(RoiMode& roi_mode)
{
706
707
	DEB_MEMBER_FUNCT();

ahoms's avatar
ahoms committed
708
709
710
711
	int roi_hw, roi_fast, roi_kin;
	readRegister(RoiEnable,  roi_hw);
	readRegister(RoiFast,    roi_fast);
	readRegister(RoiKinetic, roi_kin);
712
	DEB_TRACE() << DEB_VAR3(roi_hw, roi_fast, roi_kin);
ahoms's avatar
ahoms committed
713

714
	if (roi_kin)
ahoms's avatar
ahoms committed
715
716
717
718
719
720
721
		roi_mode = Kinetic;
	else if (roi_fast && roi_hw)
		roi_mode = Fast;
	else if (roi_hw)
		roi_mode = Slow;
	else
		roi_mode = None;
722
723

	DEB_RETURN() << DEB_VAR1(roi_mode);
ahoms's avatar
ahoms committed
724
725
}

726
Flip Camera::getMirror()
ahoms's avatar
ahoms committed
727
{
728
	DEB_MEMBER_FUNCT();
729

730
731
	InputChan curr;
	getInputChan(curr);
732
	Flip mirror;
733
734
	mirror.x = isChanActive(curr, Chan12) || isChanActive(curr, Chan34);
	mirror.y = isChanActive(curr, Chan13) || isChanActive(curr, Chan24);
735

736
	DEB_RETURN() << DEB_VAR1(mirror);
737
	return mirror;
ahoms's avatar
ahoms committed
738
739
}

740
Point Camera::getNbChan()
ahoms's avatar
ahoms committed
741
{
742
	DEB_MEMBER_FUNCT();
743
	Point nb_chan = Point(getMirror()) + 1;
744
	DEB_RETURN() << DEB_VAR1(nb_chan);
745
	return nb_chan;
ahoms's avatar
ahoms committed
746
747
}

748
Size Camera::getCcdSize()
ahoms's avatar
ahoms committed
749
{
750
	DEB_MEMBER_FUNCT();
ahoms's avatar
ahoms committed
751
752
	FrameDim frame_dim;
	getFrameDim(frame_dim);
753
	Size ccd_size = frame_dim.getSize();
754
	DEB_RETURN() << DEB_VAR1(ccd_size);
755
	return ccd_size;
ahoms's avatar
ahoms committed
756
757
}

758
Size Camera::getChanSize()
ahoms's avatar
ahoms committed
759
{
760
	DEB_MEMBER_FUNCT();
761
	Size chan_size = getCcdSize() / getNbChan();
762
	DEB_RETURN() << DEB_VAR1(chan_size);
763
764
765
766
767
768
	return chan_size;
}

Flip Camera::getRoiInsideMirror()
{
	DEB_MEMBER_FUNCT();
769
770
	Flip roi_inside_mirror(m_chan_roi_offset.x > 0, 
			       m_chan_roi_offset.y > 0);
771
772
	DEB_RETURN() << DEB_VAR1(roi_inside_mirror);
	return roi_inside_mirror;
ahoms's avatar
ahoms committed
773
774
}

775
void Camera::xformChanCoords(const Point& point, Point& xform_point, 
ahoms's avatar
ahoms committed
776
777
			     Corner& ref_corner)
{
778
779
780
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(point);

781
782
	Flip chan_flip;
	getFlip(chan_flip);
783
784
	Flip mirror = getMirror();
	Size chan_size = getChanSize();
ahoms's avatar
ahoms committed
785

786
787
788
789
790
	InputChan curr;
	getInputChan(curr);
	bool right  = !isChanActive(curr, Chan1) && !isChanActive(curr, Chan3);
	bool bottom = !isChanActive(curr, Chan1) && !isChanActive(curr, Chan2);
	Flip readout_flip(right, bottom);
791
	DEB_TRACE() << DEB_VAR2(chan_flip, readout_flip);
792

793
794
	Flip effect_flip = chan_flip & readout_flip;
	DEB_TRACE() << "After flip: " << DEB_VAR1(effect_flip);
ahoms's avatar
ahoms committed
795
796

	if (mirror.x)
797
		effect_flip.x = (point.x >= chan_size.getWidth());
ahoms's avatar
ahoms committed
798
	if (mirror.y)
799
800
		effect_flip.y = (point.y >= chan_size.getHeight());
	DEB_TRACE() << "After mirror: " << DEB_VAR1(effect_flip);
ahoms's avatar
ahoms committed
801

802
	ref_corner = effect_flip.getRefCorner();
ahoms's avatar
ahoms committed
803

804
805
806
	Size ccd_size = getCcdSize();
	xform_point = ccd_size.getCornerCoords(point, ref_corner);
	DEB_RETURN() << DEB_VAR2(xform_point, ref_corner);
ahoms's avatar
ahoms committed
807
808
}

809
810
void Camera::calcImageRoi(const Roi& chan_roi, const Flip& roi_inside_mirror,
			  Roi& image_roi, Point& roi_bin_offset)
ahoms's avatar
ahoms committed
811
{
812
	DEB_MEMBER_FUNCT();
813
	DEB_PARAM() << DEB_VAR2(chan_roi, roi_inside_mirror);
814

815
816
	Point image_tl, chan_tl = chan_roi.getTopLeft();
	Point image_br, chan_br = chan_roi.getBottomRight();
ahoms's avatar
ahoms committed
817
	Corner c_tl, c_br;
818
819
820
821
	xformChanCoords(chan_tl, image_tl, c_tl);
	xformChanCoords(chan_br, image_br, c_br);
	Roi unbinned_roi(image_tl, image_br);
	DEB_TRACE() << "Before mirror shift " << DEB_VAR1(unbinned_roi);
822

ahoms's avatar
ahoms committed
823
824
	Bin bin;
	getBin(bin);
825
826
827
828
829
830
	Size bin_size = Point(bin);
	Point mirr_shift = roi_inside_mirror * (bin_size - 1);
	DEB_TRACE() << DEB_VAR1(mirr_shift);

	image_tl = unbinned_roi.getTopLeft() + mirr_shift;
	unbinned_roi.setTopLeft(image_tl);
831
	DEB_TRACE() << "After mirror shift " << DEB_VAR1(unbinned_roi);
832

ahoms's avatar
ahoms committed
833
	image_roi = unbinned_roi.getBinned(bin);
834

835
836
837
838
839
840
841
	image_tl %= bin_size;
	c_tl = roi_inside_mirror.getRefCorner();
	DEB_TRACE() << DEB_VAR2(image_tl, c_tl);

	roi_bin_offset = bin_size.getCornerCoords(image_tl, c_tl) % bin_size;

	DEB_RETURN() << DEB_VAR2(image_roi, roi_bin_offset);
ahoms's avatar
ahoms committed
842
843
}

844
void Camera::calcFinalRoi(const Roi& image_roi, const Point& chan_roi_offset,
845
			  Roi& final_roi)
ahoms's avatar
ahoms committed
846
{
847
	DEB_MEMBER_FUNCT();
848
	DEB_PARAM() << DEB_VAR2(image_roi, chan_roi_offset);
849

850
	Point tl = image_roi.getTopLeft() + chan_roi_offset;
851
	Point nb_chan = getNbChan();
ahoms's avatar
ahoms committed
852
853
	Size size = image_roi.getSize() * nb_chan;
	final_roi = Roi(tl, size);
854
855

	DEB_RETURN() << DEB_VAR1(final_roi);
ahoms's avatar
ahoms committed
856
857
}

858
859
void Camera::calcChanRoi(const Roi& image_roi, Roi& chan_roi,
			 Flip& roi_inside_mirror)
ahoms's avatar
ahoms committed
860
{
861
862
863
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(image_roi);

ahoms's avatar
ahoms committed
864
865
866
	Bin bin;
	getBin(bin);
	Roi unbinned_roi = image_roi.getUnbinned(bin);
867
868
	DEB_TRACE() << DEB_VAR1(unbinned_roi);

869
870
871
872
873
874
875
	Point image_tl = unbinned_roi.getTopLeft();
	image_tl += m_roi_bin_offset;
	unbinned_roi.setTopLeft(image_tl);
	DEB_TRACE() << "shifted: " << DEB_VAR2(m_roi_bin_offset, unbinned_roi);

	Point image_br = unbinned_roi.getBottomRight();
	Point chan_tl, chan_br;
ahoms's avatar
ahoms committed
876
	Corner c_tl, c_br;
877
878
	xformChanCoords(image_tl, chan_tl, c_tl);
	xformChanCoords(image_br, chan_br, c_br);
ahoms's avatar
ahoms committed
879
880

	chan_roi.setCorners(chan_tl, chan_br);
881
882
	DEB_TRACE() << "xformChanCoords: " << DEB_VAR3(chan_roi, c_tl, c_br);

ahoms's avatar
ahoms committed
883
884
885
886
887
	chan_tl = chan_roi.getTopLeft();
	chan_br = chan_roi.getBottomRight();

	bool two_xchan = (c_tl.getX() != c_br.getX());
	bool two_ychan = (c_tl.getY() != c_br.getY());
888
889
	DEB_TRACE() << DEB_VAR2(two_xchan, two_ychan);

890
	Size chan_size = getChanSize();
ahoms's avatar
ahoms committed
891
892
893
894
895
896
	if (two_xchan)
		chan_br.x = chan_size.getWidth() - 1;
	if (two_ychan)
		chan_br.y = chan_size.getHeight() - 1;

	chan_roi.setCorners(chan_tl, chan_br);
897

898
899
900
	roi_inside_mirror = getMirror();
	roi_inside_mirror.x &= (image_tl.x > chan_br.x);
	roi_inside_mirror.y &= (image_tl.y > chan_br.y);
901
902

	DEB_RETURN() << DEB_VAR2(chan_roi, roi_inside_mirror);
ahoms's avatar
ahoms committed
903
904
}

905
906
void Camera::calcChanRoiOffset(const Roi& req_roi, const Roi& image_roi,
			       Point& chan_roi_offset)
ahoms's avatar
ahoms committed
907
{
908
909
910
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR2(req_roi, image_roi);

ahoms's avatar
ahoms committed
911
912
	Point virt_tl = image_roi.getTopLeft();

913
	Size image_size, ccd_size = getCcdSize();
914
915
916
917
	Bin bin;
	getBin(bin);
	ccd_size /= bin;

ahoms's avatar
ahoms committed
918
	image_size = image_roi.getSize();
919
	Point image_br = image_roi.getBottomRight();
ahoms's avatar
ahoms committed
920

921
	Point mirror_tl = ccd_size - (image_br + 1) - image_size;
ahoms's avatar
ahoms committed
922
	Point req_tl = req_roi.getTopLeft();
923
	if (req_tl.x > image_br.x)
ahoms's avatar
ahoms committed
924
		virt_tl.x = mirror_tl.x;
925
	if (req_tl.y > image_br.y)
ahoms's avatar
ahoms committed
926
927
		virt_tl.y = mirror_tl.y;

928
929
	chan_roi_offset = virt_tl - image_roi.getTopLeft();
	DEB_RETURN() << DEB_VAR1(chan_roi_offset);
ahoms's avatar
ahoms committed
930
931
932
933
}

void Camera::checkRoiMode(const Roi& roi)
{
934
935
936
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(roi);

ahoms's avatar
ahoms committed
937
938
939
940
941
942
943
944
945
	RoiMode roi_mode;
	getRoiMode(roi_mode);
	if (!roi.isActive())
		roi_mode = None;
	else if (roi_mode == None)
		roi_mode = Slow;
	setRoiMode(roi_mode);
}

946
void Camera::checkRoi(const Roi& set_roi, Roi& hw_roi)
ahoms's avatar
ahoms committed
947
{
948
949
950
951
952
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(set_roi);

	if (set_roi.isActive()) {
		Roi chan_roi;
953
954
		Point chan_roi_offset;
		processSetRoi(set_roi, hw_roi, chan_roi, chan_roi_offset);
955
	} else 
956
		hw_roi = set_roi;
ahoms's avatar
ahoms committed
957

958
	DEB_RETURN() << DEB_VAR1(hw_roi);
ahoms's avatar
ahoms committed
959
960
}

961
void Camera::processSetRoi(const Roi& set_roi, Roi& hw_roi, 
962
			   Roi& chan_roi, Point& chan_roi_offset)
ahoms's avatar
ahoms committed
963
{
964
965
966
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(set_roi);

967
968
	Roi aligned_roi = set_roi;
	aligned_roi.alignCornersTo(Point(32, 1), Ceil);
969
970
	Flip roi_inside_mirror;
	calcChanRoi(aligned_roi, chan_roi, roi_inside_mirror);
ahoms's avatar
ahoms committed
971
	Roi image_roi;
972
973
	Point roi_bin_offset;
	calcImageRoi(chan_roi, roi_inside_mirror, image_roi, roi_bin_offset);
974
975
	calcChanRoiOffset(set_roi, image_roi, chan_roi_offset);
	calcFinalRoi(image_roi, chan_roi_offset, hw_roi);
976

977
	DEB_RETURN() << DEB_VAR3(hw_roi, chan_roi, chan_roi_offset);
ahoms's avatar
ahoms committed
978
979
}

980
void Camera::setRoi(const Roi& set_roi)
ahoms's avatar
ahoms committed
981
{
982
983
984
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(set_roi);

985
	checkRoiMode(set_roi);
986
987
	if (!set_roi.isActive()) {
		DEB_TRACE() << "Roi deactivated";
ahoms's avatar
ahoms committed
988
		return;
989
	}
ahoms's avatar
ahoms committed
990

991
	Roi hw_roi, chan_roi;
992
993
	Point chan_roi_offset;
	processSetRoi(set_roi, hw_roi, chan_roi, chan_roi_offset);
ahoms's avatar
ahoms committed
994

995
	writeChanRoi(chan_roi);
996
	m_chan_roi_offset = chan_roi_offset;
ahoms's avatar
ahoms committed
997
998
}

999
void Camera::getRoi(Roi& hw_roi)
ahoms's avatar
ahoms committed
1000
{
For faster browsing, not all history is shown. View entire blame