FrelonCamera.cpp 37.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 "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

ahoms's avatar
ahoms committed
35

36
Camera::Camera(Espia::SerialLine& espia_ser_line)
37
	: m_ser_line(espia_ser_line), m_timing_ctrl(m_model, m_ser_line),
38
	  m_mis_cb_act(false)
39
{
40
41
	DEB_CONSTRUCTOR();

42
43
44
45
46
47
48
49
50
51
52
53
	sync();
}

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

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

ahoms's avatar
ahoms committed
54
	Espia::Dev& dev = getEspiaDev();
55
56
57
58
59
60
61
62
63
	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
64

65
	DEB_TRACE() << "Synchronizing with the camera";
66

67
	m_model.reset();
68
	m_chan_roi_offset = 0;
69
	m_started = false;
70
71

	try {
72
		syncRegs();
73
74
	} catch (Exception e) {
		string err_msg = e.getErrMsg();
75
		DEB_TRACE() << "Error in sync: " << DEB_VAR1(err_msg);
76
77
78
79
80
81
82
83
84
		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?";
	}

85
	string ver;
86
	m_model.getFirmware().getVersionStr(ver);
87
88
	DEB_ALWAYS() << "Found Frelon " << m_model.getName() 
		     << " #" << m_model.getSerialNb() << ", FW:" << ver;
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
}

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);
104

105
106
	if (m_model.hasGoodHTD())
		syncRegsGoodHTD();
107
108
109
	else 
		syncRegsBadHTD();

110

ahoms's avatar
ahoms committed
111
112
113
114
	double exp_time;
	getExpTime(exp_time);
	m_trig_mode = (exp_time == 0) ? ExtGate : IntTrig;

115
116
117
118
119
120
	// 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);
121
122

	getRoiBinOffset(m_roi_bin_offset);
123
124
}

125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
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);
140
141
		bool ok = waitIdleStatus(status, use_ser_line, read_spb2);
		if (ok) {
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
			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));
}

157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192

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);
}


193
194
195
196
197
SerialLine& Camera::getSerialLine()
{
	return m_ser_line;
}

198
199
Espia::Dev& Camera::getEspiaDev()
{
200
	Espia::SerialLine& ser_line = m_ser_line.getEspiaSerialLine();
201
202
203
204
	Espia::Dev& dev = ser_line.getDev();
	return dev;
}

205
206
void Camera::sendCmd(Cmd cmd)
{
207
208
	DEB_MEMBER_FUNCT();
	const string& cmd_str = CmdStrMap[cmd];
209
	DEB_PARAM() << DEB_VAR2(cmd, cmd_str);
210
211
212
	if (cmd_str.empty())
		THROW_HW_ERROR(InvalidValue) << "Invalid " 
					     << DEB_VAR1(cmd);
213

214
	string resp;
215
	m_ser_line.sendFmtCmd(cmd_str, resp);
216
217
218
219
}

void Camera::writeRegister(Reg reg, int val)
{
220
	DEB_MEMBER_FUNCT();
221
222

	Timestamp t0 = Timestamp::now();
223
224
225
226
	int retry;
	bool end, prev_busy = false;
	for (retry = 0, end = false; !end; retry++) {
		bool fail, busy;
227
228
229
230
		try {
			m_ser_line.writeRegister(reg, val);
			if (retry > 0)
				DEB_WARNING() << "Succeeded after " << retry 
231
					      << " retrie(s)";
232
233
234
235
			return;
		} catch (Exception e) {
			string err_msg = e.getErrMsg();
			DEB_TRACE() << "Error in write: " << DEB_VAR1(err_msg);
236
237
238
239
240
241
242

			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)
243
244
245
				throw;
		}

246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
		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)";
268
269
270
271
}

void Camera::readRegister(Reg reg, int& val)
{
272
	DEB_MEMBER_FUNCT();
273
	m_ser_line.readRegister(reg, val);
274
275
276
277
}

void Camera::hardReset()
{
278
	DEB_MEMBER_FUNCT();
279

280
	DEB_TRACE() << "Reseting the camera";
281
	sendCmd(Reset);
282
283

	sync();
284
285
}

286
void Camera::getVersionStr(string& ver)
287
{
288
	DEB_MEMBER_FUNCT();
289
290
	string cmd = RegStrMap[Version] + "?";
	m_ser_line.sendFmtCmd(cmd, ver);
291
	DEB_RETURN() << DEB_VAR1(ver);
292
}
ahoms's avatar
ahoms committed
293
294
295

void Camera::getComplexSerialNb(int& complex_ser_nb)
{
296
	DEB_MEMBER_FUNCT();
ahoms's avatar
ahoms committed
297
	readRegister(CompSerNb, complex_ser_nb);
298
	DEB_RETURN() << DEB_VAR1(DEB_HEX(complex_ser_nb));
ahoms's avatar
ahoms committed
299
300
}

301
Model& Camera::getModel()
302
{
303
	return m_model;
ahoms's avatar
ahoms committed
304
305
}

306
307
308
309
310
TimingCtrl& Camera::getTimingCtrl()
{
	return m_timing_ctrl;
}

311
312
313
314
315
316
317
318
319
320
321
322
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;
		
323
	DEB_RETURN() << DEB_VAR1(DEB_HEX(modes_avail));
324
325
326
327
328
329
	return modes_avail;
}

string Camera::getInputChanModeName(FrameTransferMode ftm, 
				    InputChan input_chan)
{
330
	DEB_STATIC_FUNCT();
331
332
333
334
335
336
337
338

	ostringstream os;
	os << ((ftm == FTM) ? "FTM" : "FFM") << "-";
	string sep;
	for (int chan = 1; chan <= 4; chan++) {
		int chan_bit = 1 << (chan - 1);
		if ((input_chan & chan_bit) != 0) {
			os << sep << chan;
339
			sep = "&";
340
341
342
343
344
345
346
		}
	}
	string mode_name = os.str();
	DEB_RETURN() << DEB_VAR1(mode_name);
	return mode_name;
}

ahoms's avatar
ahoms committed
347
348
void Camera::setChanMode(int chan_mode)
{
349
350
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(chan_mode);
351
352
353
354
355
356
357
358
359
360
361
362
363
364

	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
365
366
367
368
369
	writeRegister(ChanMode, chan_mode);
}

void Camera::getChanMode(int& chan_mode)
{
370
	DEB_MEMBER_FUNCT();
ahoms's avatar
ahoms committed
371
	readRegister(ChanMode, chan_mode);
372
	DEB_RETURN() << DEB_VAR1(chan_mode);
ahoms's avatar
ahoms committed
373
374
}

375
void Camera::calcBaseChanMode(FrameTransferMode ftm, int& base_chan_mode)
ahoms's avatar
ahoms committed
376
{
377
	DEB_MEMBER_FUNCT();
ahoms's avatar
ahoms committed
378
	base_chan_mode = FTMChanRangeMap[ftm].first;
379
	DEB_RETURN() << DEB_VAR1(base_chan_mode);
ahoms's avatar
ahoms committed
380
381
}

382
383
void Camera::calcChanMode(FrameTransferMode ftm, InputChan input_chan,
			  int& chan_mode)
ahoms's avatar
ahoms committed
384
{
385
386
387
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR2(ftm, DEB_HEX(input_chan));

388
	calcBaseChanMode(ftm, chan_mode);
ahoms's avatar
ahoms committed
389
390
391
392
	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())
393
394
		THROW_HW_ERROR(InvalidValue) << "Invalid " 
					     << DEB_VAR1(input_chan);
ahoms's avatar
ahoms committed
395
	chan_mode += it - chan_list.begin();
396
397

	DEB_RETURN() << DEB_VAR1(chan_mode);
ahoms's avatar
ahoms committed
398
399
}

400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
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];
	DEB_RETURN() << DEB_VAR2(ftm, DEB_HEX(input_chan));
}

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

	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;
	}

	if (!valid_mode) 
		THROW_HW_ERROR(Error) << "Could not find valid " << ftm 
450
451
				      << "mode: " 
				      << DEB_VAR1(DEB_HEX(modes_avail));
452
453
454
455
456

	DEB_RETURN() << DEB_VAR1(DEB_HEX(input_chan)) 
		     << " [" << getInputChanModeName(ftm, input_chan) << "]";
}

ahoms's avatar
ahoms committed
457
458
void Camera::setInputChan(InputChan input_chan)
{
459
460
461
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(DEB_HEX(input_chan));

ahoms's avatar
ahoms committed
462
463
464
	FrameTransferMode ftm;
	getFrameTransferMode(ftm);
	int chan_mode;
465
	calcChanMode(ftm, input_chan, chan_mode);
ahoms's avatar
ahoms committed
466
467
468
469
470
	setChanMode(chan_mode);
}

void Camera::getInputChan(InputChan& input_chan)
{
471
472
	DEB_MEMBER_FUNCT();

ahoms's avatar
ahoms committed
473
	FrameTransferMode ftm;
474
	int chan_mode;
ahoms's avatar
ahoms committed
475
	getChanMode(chan_mode);
476
	calcFTMInputChan(chan_mode, ftm, input_chan);
477
478

	DEB_RETURN() << DEB_VAR1(DEB_HEX(input_chan));
ahoms's avatar
ahoms committed
479
480
481
482
}

void Camera::setFrameTransferMode(FrameTransferMode ftm)
{
483
484
485
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(ftm);
	
ahoms's avatar
ahoms committed
486
487
488
489
490
491
492
	FrameTransferMode prev_ftm;
	getFrameTransferMode(prev_ftm);
	if (ftm == prev_ftm) {
		DEB_TRACE() << "Nothing to do";
		return;
	}

493
494
	InputChan input_chan;
	getInputChan(input_chan);
ahoms's avatar
ahoms committed
495
	int chan_mode;
496
497
498
499
500
501
502
503
504
505
506
	try {
		calcChanMode(ftm, input_chan, chan_mode);
		setChanMode(chan_mode);
	} catch (...) {
		DEB_TRACE() << DEB_VAR1(DEB_HEX(input_chan)) 
			    << " not available in " << DEB_VAR1(ftm);
		DEB_TRACE() << "  Trying default input channel";
		getDefInputChan(ftm, input_chan);
		calcChanMode(ftm, input_chan, chan_mode);
		setChanMode(chan_mode);
	}
ahoms's avatar
ahoms committed
507
508
509
510
511
512
513
514

	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
515
516
517
518
}

void Camera::getFrameTransferMode(FrameTransferMode& ftm)
{
519
520
	DEB_MEMBER_FUNCT();

ahoms's avatar
ahoms committed
521
522
523
524
525
526
527
	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;
528
529
		if ((chan_mode >= range.first) && (chan_mode < range.second)) {
			DEB_RETURN() << DEB_VAR1(ftm);
ahoms's avatar
ahoms committed
530
			return;
531
		}
ahoms's avatar
ahoms committed
532
533
	}

534
	THROW_HW_ERROR(Error) << "Invalid " << DEB_VAR1(chan_mode);
ahoms's avatar
ahoms committed
535
536
}

537
538
539
540
541
542
543
544
545
546
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
547
548
void Camera::getFrameDim(FrameDim& frame_dim)
{
549
550
	DEB_MEMBER_FUNCT();

551
	getMaxFrameDim(frame_dim);
ahoms's avatar
ahoms committed
552
553
554
555
	FrameTransferMode ftm;
	getFrameTransferMode(ftm);
	if (ftm == FTM)
		frame_dim /= Point(1, 2);
556
557

	DEB_RETURN() << DEB_VAR1(frame_dim);
ahoms's avatar
ahoms committed
558
559
560
561
}

void Camera::setFlipMode(int flip_mode)
{
562
563
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(flip_mode);
564
	writeRegister(FlipMode, flip_mode);
ahoms's avatar
ahoms committed
565
566
567
568
}

void Camera::getFlipMode(int& flip_mode)
{
569
	DEB_MEMBER_FUNCT();
570
	readRegister(FlipMode, flip_mode);
571
	DEB_RETURN() << DEB_VAR1(flip_mode);
ahoms's avatar
ahoms committed
572
573
}

574
void Camera::checkFlip(Flip& flip)
ahoms's avatar
ahoms committed
575
{
576
577
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(flip);
578
579
580
581
582
583
584
585
586
	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
587
588
589
	setFlipMode(flip_mode);
}

590
void Camera::getFlip(Flip& flip)
ahoms's avatar
ahoms committed
591
{
592
593
	DEB_MEMBER_FUNCT();

ahoms's avatar
ahoms committed
594
595
596
597
	int flip_mode;
	getFlipMode(flip_mode);
	flip.x = (flip_mode >> 1) & 1;
	flip.y = (flip_mode >> 0) & 1;
598
599

	DEB_RETURN() << DEB_VAR1(flip);
ahoms's avatar
ahoms committed
600
601
}

602
603
void Camera::checkBin(Bin& bin)
{
604
605
606
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(bin);
	
607
608
609
	int bin_x = min(bin.getX(), int(MaxBinX));
	int bin_y = min(bin.getY(), int(MaxBinY));
	bin = Bin(bin_x, bin_y);
610
611

	DEB_RETURN() << DEB_VAR1(bin);
612
613
}

ahoms's avatar
ahoms committed
614
615
void Camera::setBin(const Bin& bin)
{
616
617
618
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(bin);
	
619
	if ((bin.getX() > MaxBinX) || (bin.getY() > MaxBinY))
620
		THROW_HW_ERROR(InvalidValue) << "Invalid " << DEB_VAR1(bin)
621
622
					     << ". Max. HW binning is " 
					     << Bin(MaxBinX, MaxBinY);
623

ahoms's avatar
ahoms committed
624
625
	Bin curr_bin;
	getBin(curr_bin);
626
627
	DEB_TRACE() << DEB_VAR1(curr_bin);
	if (bin == curr_bin) 
ahoms's avatar
ahoms committed
628
629
		return;

630
	DEB_TRACE() << "Reseting Roi";
631
632
633
	Roi roi;
	setRoi(roi);

ahoms's avatar
ahoms committed
634
635
	writeRegister(BinHorz, bin.getX());
	writeRegister(BinVert, bin.getY());
636
637

	resetRoiBinOffset();
ahoms's avatar
ahoms committed
638
639
640
641
}

void Camera::getBin(Bin& bin)
{
642
	DEB_MEMBER_FUNCT();
ahoms's avatar
ahoms committed
643
644
645
646
	int bin_x, bin_y;
	readRegister(BinHorz, bin_x);
	readRegister(BinVert, bin_y);
	bin = Bin(bin_x, bin_y);
647
	DEB_RETURN() << DEB_VAR1(bin);
ahoms's avatar
ahoms committed
648
649
650
651
}

void Camera::setRoiMode(RoiMode roi_mode)
{
652
653
654
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(roi_mode);

ahoms's avatar
ahoms committed
655
	bool roi_hw   = (roi_mode == Slow) || (roi_mode == Fast);
656
	bool roi_fast = (roi_mode == Fast);
ahoms's avatar
ahoms committed
657
	bool roi_kin  = (roi_mode == Kinetic);
658
	DEB_TRACE() << DEB_VAR3(roi_hw, roi_fast, roi_kin);
ahoms's avatar
ahoms committed
659
660
661
662

	writeRegister(RoiEnable,  roi_hw);
	writeRegister(RoiFast,    roi_fast);
	writeRegister(RoiKinetic, roi_kin);
663
664
665

	if (roi_mode == None)
		resetRoiBinOffset();
ahoms's avatar
ahoms committed
666
667
668
669
}

void Camera::getRoiMode(RoiMode& roi_mode)
{
670
671
	DEB_MEMBER_FUNCT();

ahoms's avatar
ahoms committed
672
673
674
675
	int roi_hw, roi_fast, roi_kin;
	readRegister(RoiEnable,  roi_hw);
	readRegister(RoiFast,    roi_fast);
	readRegister(RoiKinetic, roi_kin);
676
	DEB_TRACE() << DEB_VAR3(roi_hw, roi_fast, roi_kin);
ahoms's avatar
ahoms committed
677

678
	if (roi_kin)
ahoms's avatar
ahoms committed
679
680
681
682
683
684
685
		roi_mode = Kinetic;
	else if (roi_fast && roi_hw)
		roi_mode = Fast;
	else if (roi_hw)
		roi_mode = Slow;
	else
		roi_mode = None;
686
687

	DEB_RETURN() << DEB_VAR1(roi_mode);
ahoms's avatar
ahoms committed
688
689
}

690
Flip Camera::getMirror()
ahoms's avatar
ahoms committed
691
{
692
	DEB_MEMBER_FUNCT();
693

694
695
	InputChan curr;
	getInputChan(curr);
696
	Flip mirror;
697
698
	mirror.x = isChanActive(curr, Chan12) || isChanActive(curr, Chan34);
	mirror.y = isChanActive(curr, Chan13) || isChanActive(curr, Chan24);
699

700
	DEB_RETURN() << DEB_VAR1(mirror);
701
	return mirror;
ahoms's avatar
ahoms committed
702
703
}

704
Point Camera::getNbChan()
ahoms's avatar
ahoms committed
705
{
706
	DEB_MEMBER_FUNCT();
707
	Point nb_chan = Point(getMirror()) + 1;
708
	DEB_RETURN() << DEB_VAR1(nb_chan);
709
	return nb_chan;
ahoms's avatar
ahoms committed
710
711
}

712
Size Camera::getCcdSize()
ahoms's avatar
ahoms committed
713
{
714
	DEB_MEMBER_FUNCT();
ahoms's avatar
ahoms committed
715
716
	FrameDim frame_dim;
	getFrameDim(frame_dim);
717
	Size ccd_size = frame_dim.getSize();
718
	DEB_RETURN() << DEB_VAR1(ccd_size);
719
	return ccd_size;
ahoms's avatar
ahoms committed
720
721
}

722
Size Camera::getChanSize()
ahoms's avatar
ahoms committed
723
{
724
	DEB_MEMBER_FUNCT();
725
	Size chan_size = getCcdSize() / getNbChan();
726
	DEB_RETURN() << DEB_VAR1(chan_size);
727
728
729
730
731
732
	return chan_size;
}

Flip Camera::getRoiInsideMirror()
{
	DEB_MEMBER_FUNCT();
733
734
	Flip roi_inside_mirror(m_chan_roi_offset.x > 0, 
			       m_chan_roi_offset.y > 0);
735
736
	DEB_RETURN() << DEB_VAR1(roi_inside_mirror);
	return roi_inside_mirror;
ahoms's avatar
ahoms committed
737
738
}

739
void Camera::xformChanCoords(const Point& point, Point& xform_point, 
ahoms's avatar
ahoms committed
740
741
			     Corner& ref_corner)
{
742
743
744
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(point);

745
746
	Flip chan_flip;
	getFlip(chan_flip);
747
748
	Flip mirror = getMirror();
	Size chan_size = getChanSize();
ahoms's avatar
ahoms committed
749

750
751
752
753
754
	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);
755
	DEB_TRACE() << DEB_VAR2(chan_flip, readout_flip);
756

757
758
	Flip effect_flip = chan_flip & readout_flip;
	DEB_TRACE() << "After flip: " << DEB_VAR1(effect_flip);
ahoms's avatar
ahoms committed
759
760

	if (mirror.x)
761
		effect_flip.x = (point.x >= chan_size.getWidth());
ahoms's avatar
ahoms committed
762
	if (mirror.y)
763
764
		effect_flip.y = (point.y >= chan_size.getHeight());
	DEB_TRACE() << "After mirror: " << DEB_VAR1(effect_flip);
ahoms's avatar
ahoms committed
765

766
	ref_corner = effect_flip.getRefCorner();
ahoms's avatar
ahoms committed
767

768
769
770
	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
771
772
}

773
774
void Camera::calcImageRoi(const Roi& chan_roi, const Flip& roi_inside_mirror,
			  Roi& image_roi, Point& roi_bin_offset)
ahoms's avatar
ahoms committed
775
{
776
	DEB_MEMBER_FUNCT();
777
	DEB_PARAM() << DEB_VAR2(chan_roi, roi_inside_mirror);
778

779
780
	Point image_tl, chan_tl = chan_roi.getTopLeft();
	Point image_br, chan_br = chan_roi.getBottomRight();
ahoms's avatar
ahoms committed
781
	Corner c_tl, c_br;
782
783
784
785
	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);
786

ahoms's avatar
ahoms committed
787
788
	Bin bin;
	getBin(bin);
789
790
791
792
793
794
	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);
795
	DEB_TRACE() << "After mirror shift " << DEB_VAR1(unbinned_roi);
796

ahoms's avatar
ahoms committed
797
	image_roi = unbinned_roi.getBinned(bin);
798

799
800
801
802
803
804
805
	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
806
807
}

808
void Camera::calcFinalRoi(const Roi& image_roi, const Point& chan_roi_offset,
809
			  Roi& final_roi)
ahoms's avatar
ahoms committed
810
{
811
	DEB_MEMBER_FUNCT();
812
	DEB_PARAM() << DEB_VAR2(image_roi, chan_roi_offset);
813

814
	Point tl = image_roi.getTopLeft() + chan_roi_offset;
815
	Point nb_chan = getNbChan();
ahoms's avatar
ahoms committed
816
817
	Size size = image_roi.getSize() * nb_chan;
	final_roi = Roi(tl, size);
818
819

	DEB_RETURN() << DEB_VAR1(final_roi);
ahoms's avatar
ahoms committed
820
821
}

822
823
void Camera::calcChanRoi(const Roi& image_roi, Roi& chan_roi,
			 Flip& roi_inside_mirror)
ahoms's avatar
ahoms committed
824
{
825
826
827
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(image_roi);

ahoms's avatar
ahoms committed
828
829
830
	Bin bin;
	getBin(bin);
	Roi unbinned_roi = image_roi.getUnbinned(bin);
831
832
	DEB_TRACE() << DEB_VAR1(unbinned_roi);

833
834
835
836
837
838
839
	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
840
	Corner c_tl, c_br;
841
842
	xformChanCoords(image_tl, chan_tl, c_tl);
	xformChanCoords(image_br, chan_br, c_br);
ahoms's avatar
ahoms committed
843
844

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

ahoms's avatar
ahoms committed
847
848
849
850
851
	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());
852
853
	DEB_TRACE() << DEB_VAR2(two_xchan, two_ychan);

854
	Size chan_size = getChanSize();
ahoms's avatar
ahoms committed
855
856
857
858
859
860
	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);
861

862
863
864
	roi_inside_mirror = getMirror();
	roi_inside_mirror.x &= (image_tl.x > chan_br.x);
	roi_inside_mirror.y &= (image_tl.y > chan_br.y);
865
866

	DEB_RETURN() << DEB_VAR2(chan_roi, roi_inside_mirror);
ahoms's avatar
ahoms committed
867
868
}

869
870
void Camera::calcChanRoiOffset(const Roi& req_roi, const Roi& image_roi,
			       Point& chan_roi_offset)
ahoms's avatar
ahoms committed
871
{
872
873
874
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR2(req_roi, image_roi);

ahoms's avatar
ahoms committed
875
876
	Point virt_tl = image_roi.getTopLeft();

877
	Size image_size, ccd_size = getCcdSize();
878
879
880
881
	Bin bin;
	getBin(bin);
	ccd_size /= bin;

ahoms's avatar
ahoms committed
882
	image_size = image_roi.getSize();
883
	Point image_br = image_roi.getBottomRight();
ahoms's avatar
ahoms committed
884

885
	Point mirror_tl = ccd_size - (image_br + 1) - image_size;
ahoms's avatar
ahoms committed
886
	Point req_tl = req_roi.getTopLeft();
887
	if (req_tl.x > image_br.x)
ahoms's avatar
ahoms committed
888
		virt_tl.x = mirror_tl.x;
889
	if (req_tl.y > image_br.y)
ahoms's avatar
ahoms committed
890
891
		virt_tl.y = mirror_tl.y;

892
893
	chan_roi_offset = virt_tl - image_roi.getTopLeft();
	DEB_RETURN() << DEB_VAR1(chan_roi_offset);
ahoms's avatar
ahoms committed
894
895
896
897
}

void Camera::checkRoiMode(const Roi& roi)
{
898
899
900
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(roi);

ahoms's avatar
ahoms committed
901
902
903
904
905
906
907
908
909
	RoiMode roi_mode;
	getRoiMode(roi_mode);
	if (!roi.isActive())
		roi_mode = None;
	else if (roi_mode == None)
		roi_mode = Slow;
	setRoiMode(roi_mode);
}

910
void Camera::checkRoi(const Roi& set_roi, Roi& hw_roi)
ahoms's avatar
ahoms committed
911
{
912
913
914
915
916
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(set_roi);

	if (set_roi.isActive()) {
		Roi chan_roi;
917
918
		Point chan_roi_offset;
		processSetRoi(set_roi, hw_roi, chan_roi, chan_roi_offset);
919
	} else 
920
		hw_roi = set_roi;
ahoms's avatar
ahoms committed
921

922
	DEB_RETURN() << DEB_VAR1(hw_roi);
ahoms's avatar
ahoms committed
923
924
}

925
void Camera::processSetRoi(const Roi& set_roi, Roi& hw_roi, 
926
			   Roi& chan_roi, Point& chan_roi_offset)
ahoms's avatar
ahoms committed
927
{
928
929
930
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(set_roi);

931
932
	Roi aligned_roi = set_roi;
	aligned_roi.alignCornersTo(Point(32, 1), Ceil);
933
934
	Flip roi_inside_mirror;
	calcChanRoi(aligned_roi, chan_roi, roi_inside_mirror);
ahoms's avatar
ahoms committed
935
	Roi image_roi;
936
937
	Point roi_bin_offset;
	calcImageRoi(chan_roi, roi_inside_mirror, image_roi, roi_bin_offset);
938
939
	calcChanRoiOffset(set_roi, image_roi, chan_roi_offset);
	calcFinalRoi(image_roi, chan_roi_offset, hw_roi);
940

941
	DEB_RETURN() << DEB_VAR3(hw_roi, chan_roi, chan_roi_offset);
ahoms's avatar
ahoms committed
942
943
}

944
void Camera::setRoi(const Roi& set_roi)
ahoms's avatar
ahoms committed
945
{
946
947
948
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(set_roi);

949
	checkRoiMode(set_roi);
950
951
	if (!set_roi.isActive()) {
		DEB_TRACE() << "Roi deactivated";
ahoms's avatar
ahoms committed
952
		return;
953
	}
ahoms's avatar
ahoms committed
954

955
	Roi hw_roi, chan_roi;
956
957
	Point chan_roi_offset;
	processSetRoi(set_roi, hw_roi, chan_roi, chan_roi_offset);
ahoms's avatar
ahoms committed
958

959
	writeChanRoi(chan_roi);
960
	m_chan_roi_offset = chan_roi_offset;
ahoms's avatar
ahoms committed
961
962
}

963
void Camera::getRoi(Roi& hw_roi)
ahoms's avatar
ahoms committed
964
{
965
966
	DEB_MEMBER_FUNCT();

967
968
969
970
971
972
973
	hw_roi.reset();

	RoiMode roi_mode;
	getRoiMode(roi_mode);
	if (roi_mode == None)
		return;

974
975
976
977
978
979
980
	Roi chan_roi, image_roi;
	readChanRoi(chan_roi);

	Flip roi_inside_mirror = getRoiInsideMirror();
	Point roi_bin_offset;
	calcImageRoi(chan_roi, roi_inside_mirror, image_roi, roi_bin_offset);

981
	calcFinalRoi(image_roi, m_chan_roi_offset, hw_roi);
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
	DEB_RETURN() << DEB_VAR1(hw_roi);
}

void Camera::writeChanRoi(const Roi& chan_roi)
{
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(chan_roi);
	
	Point tl  = chan_roi.getTopLeft();
	Size size = chan_roi.getSize();
	
	writeRegister(RoiPixelBegin, tl.x);
	writeRegister(RoiPixelWidth, size.getWidth());
	writeRegister(RoiLineBegin,  tl.y);
	writeRegister(RoiLineWidth,  size.getHeight());
}

void Camera::readChanRoi(Roi& chan_roi)
{
For faster browsing, not all history is shown. View entire blame