SlsDetectorEiger.cpp 36.4 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
23
//###########################################################################
// 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/>.
//###########################################################################

#include "SlsDetectorEiger.h"
24
#include "lima/MiscUtils.h"
25

26
#include <emmintrin.h>
27
#include <sched.h>
28

29
30
31
using namespace std;
using namespace lima;
using namespace lima::SlsDetector;
32
using namespace lima::SlsDetector::Defs;
33
34
35
36

const int Eiger::ChipSize = 256;
const int Eiger::ChipGap = 2;
const int Eiger::HalfModuleChips = 4;
37
const int Eiger::NbRecvPorts = EigerNbRecvPorts;
38

39
40
41
42
43
44
45
const int Eiger::BitsPerXfer = 4;
const int Eiger::SuperColNbCols = 8;
const double Eiger::BaseChipXferFreq = 200; // Mbit/s
const double Eiger::MaxFebBebBandwidth = 25600; // Mbit/s
const Eiger::LinScale Eiger::ChipXfer2Buff(2.59, 0.85);
const Eiger::LinScale Eiger::ChipRealReadout(1.074, -4);

46
47
48
49
const unsigned long Eiger::BebFpgaWritePtrAddr = 0xD10000C4;
const unsigned long Eiger::BebFpgaReadPtrAddr = 0xD10000E4;
const unsigned long Eiger::BebFpgaPtrRange = 0x10000000;

50
51
Eiger::CorrBase::CorrBase(Eiger *eiger)
	: m_eiger(eiger)
52
53
{
	DEB_CONSTRUCTOR();
54
	m_nb_eiger_modules = m_eiger->getNbEigerModules();
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
}

Eiger::CorrBase::~CorrBase()
{
	DEB_DESTRUCTOR();
	if (m_eiger)
		m_eiger->removeCorr(this);
}

void Eiger::CorrBase::prepareAcq()
{
	DEB_MEMBER_FUNCT();

	if (!m_eiger)
		THROW_HW_ERROR(InvalidValue) << "Correction already removed";

71
	const FrameDim& recv_dim = m_eiger->getRecvFrameDim();
72
	m_mod_frame_dim = recv_dim * Point(1, 2);
73
74
75
	m_frame_size = m_mod_frame_dim.getSize() * Point(1, m_nb_eiger_modules);
	m_inter_lines.resize(m_nb_eiger_modules);
	for (int i = 0; i < m_nb_eiger_modules - 1; ++i) {
76
77
78
		m_inter_lines[i] = m_eiger->getInterModuleGap(i);
		m_frame_size += Point(0, m_inter_lines[i]);
	}
79
80
81
	m_inter_lines[m_nb_eiger_modules - 1] = 0;
}

82
83
84
85
86
87
void Eiger::BadRecvFrameCorr::BadFrameData::reset()
{
	last_idx = 0;
	bad_frame_list.clear();
}

88
89
Eiger::BadRecvFrameCorr::BadRecvFrameCorr(Eiger *eiger)
	: CorrBase(eiger)
90
91
{
	DEB_CONSTRUCTOR();
92
93
94
95
96
97
98
99
100

	m_cam = m_eiger->getCamera();
}

void Eiger::BadRecvFrameCorr::prepareAcq()
{
	DEB_MEMBER_FUNCT();

	CorrBase::prepareAcq();
101
	m_bfd.reset();
102
103
}

104
void Eiger::BadRecvFrameCorr::correctFrame(FrameType frame, void *ptr)
105
106
{
	DEB_MEMBER_FUNCT();
107

108
	char *bptr = (char *) ptr;
109
110
111
112
113
114
115
116
117
118
119
120
	IntList& bfl = m_bfd.bad_frame_list;
	int& last_idx = m_bfd.last_idx;
	if (bfl.empty()) {
		int bad_frames = m_cam->getNbBadFrames(0);
		if (bad_frames == last_idx)
			return;
		m_cam->getBadFrameList(0, last_idx, bad_frames, bfl);
	}
	IntList::iterator end = bfl.end();
	if (find(bfl.begin(), end, frame) != end) {
		Eiger::Geometry *geom = m_eiger->getGeometry();
		for (int i = 0; i < geom->getNbRecvs(); ++i) {
121
122
			Eiger::Geometry::Recv *recv = geom->getRecv(i);
			recv->fillBadFrame(frame, bptr);
123
		}
124
	}
125
126
127
128
	if (*(end - 1) > int(frame))
		return;
	last_idx += bfl.size();
	bfl.clear();
129
130
}

131
Eiger::InterModGapCorr::InterModGapCorr(Eiger *eiger)
132
	: CorrBase(eiger)
133
134
135
136
137
138
139
140
141
142
143
144
145
146
{
	DEB_CONSTRUCTOR();
}

void Eiger::InterModGapCorr::prepareAcq()
{
	DEB_MEMBER_FUNCT();

	CorrBase::prepareAcq();

	m_gap_list.clear();

	int mod_size = m_mod_frame_dim.getMemSize();
	int width = m_mod_frame_dim.getSize().getWidth();
147
148
	int ilw = width * m_mod_frame_dim.getDepth();
	for (int i = 0, start = 0; i < m_nb_eiger_modules - 1; ++i) {
149
		start += mod_size;
150
		int size = m_inter_lines[i] * ilw;
151
152
153
154
155
		m_gap_list.push_back(Block(start, size));
		start += size;
	}
}

156
void Eiger::InterModGapCorr::correctFrame(FrameType /*frame*/, void *ptr)
157
158
159
160
161
162
163
164
165
166
167
168
{
	DEB_MEMBER_FUNCT();
	
	char *dest = static_cast<char *>(ptr);
	BlockList::const_iterator it, end = m_gap_list.end();
	for (it = m_gap_list.begin(); it != end; ++it) {
		int start = it->first;
		int size = it->second;
		memset(dest + start, 0, size);
	}
}

169
Data Eiger::ModelReconstruction::process(Data& data)
170
171
172
{
	DEB_MEMBER_FUNCT();

173
	DEB_PARAM() << DEB_VAR4(m_eiger, data.frameNumber, 
174
				_processingInPlaceFlag, data.data());
175
176
177
178
	if (!m_eiger)
		return data;

	Data ret = _processingInPlaceFlag ? data : data.copy();
179

180
181
182
183
184
185
186
	FrameType frame = ret.frameNumber;
	void *ptr = ret.data();
	CorrList& corr_list = m_eiger->m_corr_list;
	CorrList::iterator it, end = corr_list.end();
	for (it = corr_list.begin(); it != end; ++it)
		(*it)->correctFrame(frame, ptr);

187
188
189
	return ret;
}

190
191
192
193
Eiger::Geometry::Recv::FrameData::FrameData()
{
}

194
195
Eiger::Geometry::Recv::FrameData::FrameData(const RecvImageData& /*image*/,
					    char *d)
196
197
198
199
	: dst(d)
{
}

200
201
Eiger::Geometry::Recv::Port::Port(Recv *recv, int port)
	: m_recv(recv), m_recv_idx(m_recv->m_idx), m_port(port)
202
203
{
	DEB_CONSTRUCTOR();
204
	DEB_PARAM() << DEB_VAR2(m_recv_idx, m_port);
205
206
207
	m_top_half_recv = (m_recv_idx % 2 == 0);
}

208
void Eiger::Geometry::Recv::Port::prepareAcq()
209
210
211
212
{
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(m_recv_idx);

213
214
215
	Geometry *geom = m_recv->m_eiger_geom;
	m_raw = geom->m_raw;
	const FrameDim& frame_dim = geom->m_recv_frame_dim;
216
217
	const Size& size = frame_dim.getSize();
	int depth = frame_dim.getDepth();
218
	m_dst.lw = size.getWidth() * depth;
219
	int recv_size = frame_dim.getMemSize();
220
221
	int src_port_offset = 0;
	int dst_port_offset = recv_size * m_recv_idx;
222

223
	m_pchips = HalfModuleChips / NbRecvPorts;
224
225
	m_src.cw = ChipSize * depth;
	m_dst.cw = m_src.cw;
226
	if (m_recv->m_pixel_depth_4)
227
228
		m_src.cw /= 2;
	m_src.lw = m_pchips * m_src.cw;
229

230
	if (m_raw) {
231
		// vert. port concat.
232
		dst_port_offset += ChipSize * m_dst.lw * m_port;
233
234
	} else {
		// inter-chip horz. gap
235
		m_dst.cw += ChipGap * depth;
236
		// horz. port concat.
237
238
239
240
241
242
243
244
245
246
247
248
249
250
		dst_port_offset += m_pchips * m_dst.cw * m_port;

		int mod_idx = m_recv_idx / 2;
		for (int i = 0; i < mod_idx; ++i)
			dst_port_offset += (geom->getInterModuleGap(i) *
					    m_dst.lw);
		if (m_top_half_recv) {
			// top-half module: vert-flipped data
			src_port_offset += (ChipSize - 1) * m_src.lw;
			m_src.lw *= -1;
		} else {
			// bottom-half module: inter-chip vert. gap
			dst_port_offset += (ChipGap / 2) * m_dst.lw;
		}
251
252
	}

253
254
	const int block_len = sizeof(__m128i);
	const int chip_blocks = ChipSize / 2 / block_len;
255
256
257
258
259
260
261
262

	const int port_lines = m_raw ? ChipSize : 1;
	m_port_blocks = chip_blocks * m_pchips * port_lines;
	DEB_TRACE() << DEB_VAR2(port_lines, m_port_blocks);
	m_src.len = ChipSize * abs(m_src.lw);
	m_src.off = src_port_offset;
	m_dst.off = dst_port_offset;
	DEB_TRACE() << DEB_VAR3(m_src.len, m_src.off, m_dst.off);
263
264
}

265
FrameDim Eiger::Geometry::Recv::Port::getSrcFrameDim()
266
267
{
	DEB_MEMBER_FUNCT();
268
269
270
	FrameDim fdim(abs(m_src.lw), ChipSize, Bpp8);
	DEB_RETURN() << DEB_VAR1(fdim);
	return fdim;
271
272
}

273
void Eiger::Geometry::Recv::Port::copy(char *dst, char *src)
274
275
276
{
	DEB_MEMBER_FUNCT();

277
	bool valid_data = (src != NULL);
278
279
	src += m_src.off;
	dst += m_dst.off;
280

281
	const int& lines = ChipSize;
282
283
284
285
286
287
288
289
290
291
	if (m_raw) {
		int size = m_src.lw * lines;
		if (valid_data)
			memcpy(dst, src, size);
		else
			memset(dst, 0xff, size);
		return;
	}

	for (int i = 0; i < lines; ++i, src += m_src.lw, dst += m_dst.lw) {
292
293
		char *s = src;
		char *d = dst;
294
		for (int j = 0; j < m_pchips; ++j, s += m_src.cw, d += m_dst.cw)
295
			if (valid_data)
296
				memcpy(d, s, m_src.cw);
297
			else
298
				memset(d, 0xff, m_src.cw);
299
300
301
	}
}

302
Eiger::Geometry::Recv::Recv(Geometry *eiger_geom, int idx)
303
	: m_eiger_geom(eiger_geom), m_idx(idx)
304
305
306
307
308
309
310
311
312
313
{
	DEB_CONSTRUCTOR();
	DEB_PARAM() << DEB_VAR1(m_idx);

	for (int i = 0; i < NbRecvPorts; ++i) {
		Port *p = new Port(this, i);
		m_port_list.push_back(p);
	}
}

314
int Eiger::Geometry::Recv::getNbPorts()
315
316
317
318
319
320
{
	DEB_MEMBER_FUNCT();
	DEB_RETURN() << DEB_VAR1(NbRecvPorts);
	return NbRecvPorts;
}

321
Eiger::Geometry::Recv::Port *Eiger::Geometry::Recv::getPort(int port_idx)
322
323
324
325
326
{
	DEB_MEMBER_FUNCT();
	return m_port_list[port_idx];
}

327
void Eiger::Geometry::Recv::prepareAcq()
328
329
{
	DEB_MEMBER_FUNCT();
330
331
332

	m_pixel_depth_4 = (m_eiger_geom->m_pixel_depth == PixelDepth4);

333
334
335
336
337
	PortList::iterator it, end = m_port_list.end();
	for (it = m_port_list.begin(); it != end; ++it)
		(*it)->prepareAcq();
}

338
void Eiger::Geometry::Recv::copy(const FrameData& data)
339
340
341
{
	DEB_MEMBER_FUNCT();
	for (int i = 0; i < getNbPorts(); ++i)
342
		m_port_list[i]->copy(data.dst, data.src[i]);
343
344
345
346
347
}

void Eiger::Geometry::Recv::fillBadFrame(FrameType frame, char *bptr)
{
	DEB_MEMBER_FUNCT();
348
	DEB_PARAM() << DEB_VAR2(m_idx, frame);
349
350
351
352
	FrameData data;
	for (int i = 0; i < getNbPorts(); ++i)
		data.src[i] = NULL;
	data.dst = bptr;
353
	processFrame(data);
354
355
}

356
void Eiger::Geometry::Recv::expandPixelDepth4(const FrameData& data)
357
358
{
	DEB_MEMBER_FUNCT();
359
	DEB_PARAM() << DEB_VAR3(DEB_HEX((unsigned long) data.src[0]),
360
				DEB_HEX((unsigned long) data.src[1]),
361
				DEB_HEX((unsigned long) data.dst));
362

363
	const int nb_ports = NbRecvPorts;
364
	Port *port = m_port_list[0];
365
	const bool raw = port->m_raw;
366
	int pi;
367
368
369
	char *src[EigerNbRecvPorts];
	for (pi = 0; pi < nb_ports; ++pi) {
		src[pi] = data.src[pi] + m_port_list[pi]->m_src.off;
370
		unsigned long s = (unsigned long) src[pi];
371
372
373
374
		if ((s & 15) != 0)
			THROW_HW_ERROR(Error) << "Missaligned src: "
					      << DEB_VAR1(DEB_HEX(s));
	}
375
376
	pi = 0;
	char *dst = data.dst + port->m_dst.off;
377
	unsigned long d = (unsigned long) dst;
378
	int dest_misalign = (d & 15);
379
	if (raw && dest_misalign)
380
381
		THROW_HW_ERROR(Error) << "Missaligned dest: "
				      << DEB_VAR1(DEB_HEX(d));
382

383
	DEB_TRACE() << DEB_VAR1(dest_misalign);
384
385
386
	DEB_TRACE() << DEB_VAR3(DEB_HEX((unsigned long) src[0]),
				DEB_HEX((unsigned long) src[1]),
				DEB_HEX((unsigned long) dst));
387
388
	bool valid_data = data.valid.test(pi);
	const int block_len = sizeof(__m128i);
389
	int nb_blocks = port->m_src.len * nb_ports / block_len;
390
	const int chip_blocks = ChipSize / 2 / block_len;
391
	const int port_blocks = port->m_port_blocks;
392
393
	const __m128i *src128 = (const __m128i *) src[pi];
	__m128i *dst128 = (__m128i *) dst;
394
	const __m128i m = _mm_set1_epi8(0xf);
395
396
	const int block_bits = block_len * 8;
	const int gap_bits = ChipGap * 8;
397
398
	const __m128i block64_bits128 = _mm_set_epi64x(0, 64);
	const __m128i gap_bits128 = _mm_set_epi64x(0, gap_bits);
399
	int shift_l = 0;
400
401
402
	__m128i shift_l128, shift_r128;
	__m128i m64_0 = _mm_set_epi64x(0, -1);
	__m128i m64_1 = _mm_set_epi64x(-1, 0);
403
 	bool reverse = (port->m_src.lw < 0);
404
405
406
407
408
	__m128i m0, prev;
	int chip_count = 0;

#define load_dst128()							\
	do {								\
409
410
		dest_misalign = ((unsigned long) dst & 15);		\
		dst128 = (__m128i *) (dst - dest_misalign);		\
411
412
413
414
415
416
417
418
419
420
421
422
423
424
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
		shift_l = dest_misalign * 8;				\
		shift_l128 = _mm_set_epi64x(0, shift_l % 64);		\
		shift_r128 = _mm_sub_epi64(block64_bits128, shift_l128); \
		if (shift_l != 0) {					\
			m0 = _mm_srl_epi64(_mm_set1_epi8(0xff), shift_r128); \
			if (shift_l < 64)				\
				m0 = _mm_and_si128(m0, m64_0);		\
			prev = _mm_and_si128(_mm_load_si128(dst128), m0); \
		} else {						\
			prev = _mm_setzero_si128();			\
		}							\
	} while (0)

#define pad_dst128()							\
	do {								\
		shift_l += gap_bits;					\
		if (shift_l % 64 == 0)					\
			shift_l128 = _mm_setzero_si128();		\
		else							\
			shift_l128 = _mm_add_epi64(shift_l128, gap_bits128); \
		shift_r128 = _mm_sub_epi64(block64_bits128, shift_l128); \
		if (shift_l == block_bits) {				\
			_mm_store_si128(dst128++, prev);		\
			prev = _mm_setzero_si128();			\
			shift_l = 0;					\
		}							\
	} while (0)

#define sync_dst128()							\
	do {								\
		if (shift_l != 0) {					\
			m0 = _mm_sll_epi64(_mm_set1_epi8(0xff), shift_l128); \
			if (shift_l >= 64)				\
				m0 = _mm_and_si128(m0, m64_1);		\
			__m128i a = _mm_and_si128(_mm_load_si128(dst128), m0); \
			_mm_store_si128(dst128, _mm_or_si128(prev, a));	\
		}							\
	} while (0)

450
	if (!raw)
451
		load_dst128();
452
	for (int i = 0; i < nb_blocks; ++i) {
453
		if (i == 0)
454
455
456
			DEB_TRACE() << DEB_VAR3(DEB_HEX((unsigned long) src128),
						DEB_HEX((unsigned long) dst128),
						nb_blocks);
457
458
		if (!raw && i && (i % chip_blocks == 0) &&
		    (++chip_count % HalfModuleChips > 0))
459
460
461
462
			pad_dst128();
		if (i && (i % port_blocks == 0)) {
			if (reverse)
				src128 -= 2 * port_blocks;
463
			src[pi++] = (char *) src128;
464
465
			pi %= nb_ports;
			valid_data = data.valid.test(pi);
466
			src128 = (const __m128i *) src[pi];
467
468
469
470
471
472
473
474
475
476
477
478
		}
		__m128i p4_raw;
		if (valid_data)
			p4_raw = _mm_load_si128(src128);
		else
			p4_raw = _mm_set1_epi8(0xff);
		++src128;
		__m128i p4_shr = _mm_srli_epi16(p4_raw, 4);
		__m128i i8_0 = _mm_and_si128(p4_raw, m);
		__m128i i8_1 = _mm_and_si128(p4_shr, m);
		__m128i p8_0 = _mm_unpacklo_epi8(i8_0, i8_1);
		__m128i p8_1 = _mm_unpackhi_epi8(i8_0, i8_1);
479
		if (raw) {
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
506
507
508
509
510
			_mm_store_si128(dst128++, p8_0);
			_mm_store_si128(dst128++, p8_1);
			continue;
		}
		__m128i p8_0l = _mm_sll_epi64(p8_0, shift_l128);
		__m128i p8_0r = _mm_srl_epi64(p8_0, shift_r128);
		__m128i p8_1l = _mm_sll_epi64(p8_1, shift_l128);
		__m128i p8_1r = _mm_srl_epi64(p8_1, shift_r128);
		__m128i d0, d1, d2, d3, d4;
		if (shift_l < 64) {
			d0 = p8_0l;
			d1 = p8_0r;
			d2 = p8_1l;
			d3 = p8_1r;
			d4 = _mm_setzero_si128();
		} else {
			d0 = _mm_setzero_si128();
			d1 = p8_0l;
			d2 = p8_0r;
			d3 = p8_1l;
			d4 = p8_1r;
		}
		__m128i d10 = _mm_slli_si128(d1, 8);
		__m128i d11 = _mm_srli_si128(d1, 8);
		__m128i d30 = _mm_slli_si128(d3, 8);
		__m128i d31 = _mm_srli_si128(d3, 8);
		prev = _mm_or_si128(prev, d0);
		_mm_store_si128(dst128++, _mm_or_si128(prev, d10));
		prev = _mm_or_si128(d11, d2);
		_mm_store_si128(dst128++, _mm_or_si128(prev, d30));
		prev = _mm_or_si128(d31, d4);
511
	}
512
	if (!raw)
513
		sync_dst128();
514
515
}

516
517
Eiger::Geometry::Geometry()
	: m_raw(false), m_image_type(Bpp16), m_pixel_depth(PixelDepth16)
518
519
{
	DEB_CONSTRUCTOR();
520
}
521

522
523
524
525
526
527
528
int Eiger::Geometry::getInterModuleGap(int det)
{
	DEB_MEMBER_FUNCT();
	if (det >= getNbEigerModules() - 1)
		THROW_HW_ERROR(InvalidValue) << "Invalid " << DEB_VAR1(det);
	return 36;
}
529

530
531
532
533
534
535
536
537
538
539
540
541
void Eiger::Geometry::setNbRecvs(int nb_recv)
{
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(nb_recv);

	int curr_nb_recv = m_recv_list.size();
	if (curr_nb_recv > nb_recv) {
		m_recv_list.resize(nb_recv);
		return;
	}

	for (int i = curr_nb_recv; i < nb_recv; ++i) {
542
543
		Recv *r = new Recv(this, i);
		m_recv_list.push_back(r);
544
545
546
	}
}

547
void Eiger::Geometry::prepareAcq()
548
{
549
550
551
552
553
554
555
	DEB_MEMBER_FUNCT();

	m_recv_frame_dim = getRecvFrameDim(m_raw);

	RecvList::iterator rit, rend = m_recv_list.end();
	for (rit = m_recv_list.begin(); rit != rend; ++rit)
		(*rit)->prepareAcq();
556
557
}

558
FrameDim Eiger::Geometry::getFrameDim(bool raw)
559
560
561
{
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(raw);
562
	FrameDim frame_dim = getRecvFrameDim(raw);
563
	Size size = frame_dim.getSize();
564
	size *= Point(1, getNbRecvs());
565
	if (!raw)
566
		for (int i = 0; i < getNbEigerModules() - 1; ++i)
567
568
569
			size += Point(0, getInterModuleGap(i));
	frame_dim.setSize(size);
	DEB_RETURN() << DEB_VAR1(frame_dim);
570
	return frame_dim;
571
572
}

573
FrameDim Eiger::Geometry::getRecvFrameDim(bool raw)
574
575
576
{
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(raw);
577
578
	FrameDim frame_dim;
	frame_dim.setImageType(m_image_type);
579
	Size size(ChipSize * HalfModuleChips, ChipSize);
580
	if (raw) {
581
582
		size /= Point(NbRecvPorts, 1);
		size *= Point(1, NbRecvPorts);
583
	} else {
584
		size += Point(ChipGap, ChipGap) * Point(3, 1) / Point(1, 2);
585
	}
586
	frame_dim.setSize(size);
587
	DEB_RETURN() << DEB_VAR1(frame_dim);
588
589
590
	return frame_dim;
}

591
592
593
594
595
Eiger::Beb::Beb(const std::string& host_name)
	: shell(host_name), fpga_mem(shell)
{
}

596
Eiger::Recv::Recv(Eiger *eiger, int idx)
597
	: m_eiger(eiger), m_idx(idx)
598
599
600
601
602
{
	DEB_CONSTRUCTOR();
	DEB_PARAM() << DEB_VAR1(m_idx);

	m_geom = m_eiger->m_geom.getRecv(m_idx);
603
604
	Camera *cam = m_eiger->getCamera(); 
	m_recv = cam->getRecv(m_idx);
605
606
}

607
Eiger::Recv::~Recv()
608
{
609
	DEB_DESTRUCTOR();
610
611
}

612
void Eiger::Recv::prepareAcq()
613
614
{
	DEB_MEMBER_FUNCT();
615
616
	m_data_offset = m_geom->getDstBufferOffset();
	DEB_TRACE() << DEB_VAR2(m_idx, m_data_offset);
617
618
}

619
bool Eiger::Recv::processOneFrame(FrameType frame, char *bptr)
620
621
{
	DEB_MEMBER_FUNCT();
622
623
	DEB_PARAM() << DEB_VAR2(m_idx, frame);
	RecvImageData data;
624
	//data.frame = frame;
625
	data.buffer = bptr;
626
	return m_recv->getImage(data);
627
628
}

629
void Eiger::Recv::processBadFrame(FrameType frame, char *bptr)
630
631
{
	DEB_MEMBER_FUNCT();
632
633
	DEB_PARAM() << DEB_VAR2(m_idx, frame);
	m_geom->fillBadFrame(frame, bptr);
634
635
}

636
637
Eiger::Thread::Thread(Eiger *eiger, int idx)
	: m_eiger(eiger), m_idx(idx)
638
639
640
{
	DEB_MEMBER_FUNCT();

641
	AutoMutex l = lock();
642
643
644
645
646
647
648
649
650
651
652
	m_state = Init;

	start();

	struct sched_param param;
	param.sched_priority = 50;
	int ret = pthread_setschedparam(m_thread, SCHED_RR, &param);
	if (ret != 0)
		DEB_ERROR() << "Could not set real-time priority!!";

	while (m_state == Init)
653
		wait();
654
655
}

656
Eiger::Thread::~Thread()
657
{
658
659
660
	DEB_DESTRUCTOR();

	AutoMutex l = lock();
661
	m_state = Quitting;
662
663
664
	broadcast();
	while (m_state != End)
		wait();
665
666
}

667
void Eiger::Thread::threadFunction()
668
669
670
{
	DEB_MEMBER_FUNCT();

671
672
	State& s = m_state;

673
	AutoMutex l = lock();
674
	s = Ready;
675
	broadcast();
676

677
678
679
680
681
682
683
684
685
686
687
688
	while (s != Quitting) {
		while ((s == Ready) || (s == Stopping)
		       || ((s == Running) && m_eiger->allFramesAcquired())) {
			if (s == Stopping) {
				s = Ready;
				broadcast();
			}
			wait();
		}
		if (s == Running)
			m_eiger->processOneFrame(l);
	}
689

690
	s = End;
691
	broadcast();
692
693
}

694
void Eiger::Thread::setCPUAffinity(CPUAffinity aff)
695
696
{
	DEB_MEMBER_FUNCT();
697
	DEB_PARAM() << DEB_VAR1(aff);
698

699
        aff.applyToTask(getThreadID(), false);
700
701
}

702
void Eiger::Thread::prepareAcq()
703
704
705
706
{
	DEB_MEMBER_FUNCT();
}

707
Eiger::Eiger(Camera *cam)
708
	: Model(cam, EigerDet), m_fixed_clock_div(false)
709
710
711
712
713
714
{
	DEB_CONSTRUCTOR();

	int nb_det_modules = getNbDetModules();
	DEB_TRACE() << "Using Eiger detector, " << DEB_VAR1(nb_det_modules);

715
716
717
718
719
720
721
	NameList host_name_list = getCamera()->getHostnameList();
	NameList::const_iterator it, end = host_name_list.end();
	for (it = host_name_list.begin(); it != end; ++it) {
		Beb *beb = new Beb(*it);
		m_beb_list.push_back(beb);
	}

722
723
724
725
726
727
728
	m_geom.setNbRecvs(nb_det_modules);

	for (int i = 0; i < nb_det_modules; ++i) {
		Recv *r = new Recv(this, i);
		m_recv_list.push_back(r);
	}

729
730
	setNbProcessingThreads(1);

731
732
733
734
735
	if (isTenGigabitEthernetEnabled()) {
		DEB_TRACE() << "Forcing 10G Ethernet flow control";
		setFlowControl10G(true);
	}

736
737
	m_reconstruction = new ModelReconstruction(this);

738
739
740
741
742
743
744
745
	updateCameraModel();

	getClockDiv(m_clock_div);
}

Eiger::~Eiger()
{
	DEB_DESTRUCTOR();
746
	getCamera()->waitAcqState(Idle);
747
748
	m_reconstruction->m_eiger = NULL;
	m_reconstruction->unref();
749
750
751
752
753
754
755
756
757
	removeAllCorr();
}

void Eiger::getFrameDim(FrameDim& frame_dim, bool raw)
{
	DEB_MEMBER_FUNCT();
	DEB_PARAM() << DEB_VAR1(raw);
	frame_dim = m_geom.getFrameDim(raw);
	DEB_RETURN() << DEB_VAR1(frame_dim);
758
759
}

760
761
762
763
764
765
void Eiger::getDetMap(Data& /*det_map*/)
{
	DEB_MEMBER_FUNCT();
	THROW_HW_ERROR(NotSupported) << "DetMap not implemented yet";
}

766
767
768
769
770
string Eiger::getName()
{
	DEB_MEMBER_FUNCT();
	ostringstream os;
	os << "PSI/Eiger-";
771
	int nb_modules = getNbEigerModules();
772
773
	if (nb_modules == 1) {
		os << "500k";
774
775
	} else if (nb_modules % 2 == 0) {
		os << (nb_modules / 2) << "M";
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
	} else {
		os << nb_modules << "-Modules";
	}
	string name = os.str();
	DEB_RETURN() << DEB_VAR1(name);
	return name;
}

void Eiger::getPixelSize(double& x_size, double& y_size)
{
	DEB_MEMBER_FUNCT();
	x_size = y_size = 75e-6;
	DEB_RETURN() << DEB_VAR2(x_size, y_size);
}

791
792
void Eiger::getDACInfo(NameList& name_list, IntList& idx_list,
		       IntList& milli_volt_list)
793
794
795
{
	DEB_MEMBER_FUNCT();

796
#define EIGER_DAC(x)			{x, 0}
797
798
799
800
801
802
#define EIGER_DAC_MV(x)			{x, 1}

	static struct DACData {
		DACIndex idx;
		int milli_volt;
	} EigerDACList[] = {
803
804
805
806
807
		EIGER_DAC(EigerVcmpLL),
		EIGER_DAC(EigerVcmpLR),
		EIGER_DAC(EigerVcmpRL),
		EIGER_DAC(EigerVcmpRR),
		EIGER_DAC(Threshold),
808
809
810
811
	};
	const unsigned int size = C_LIST_SIZE(EigerDACList);

	name_list.resize(size);
812
	idx_list.resize(size);
813
814
815
	milli_volt_list.resize(size);
	struct DACData *data = EigerDACList;
	for (unsigned int i = 0; i < size; ++i, ++data) {
816
		ostringstream os;
817
		os << data->idx;
818
		name_list[i] = os.str();
819
820
		idx_list[i] = int(data->idx);
		milli_volt_list[i] = data->milli_volt;
821
		DEB_RETURN() << DEB_VAR2(name_list[i], idx_list[i]);
822
823
824
	}
}

825
826
void Eiger::getADCInfo(NameList& name_list, IntList& idx_list,
		       FloatList& factor_list, FloatList& min_val_list)
827
828
829
{
	DEB_MEMBER_FUNCT();

830
831
#define EIGER_TEMP_FACTOR		(1 / 1000.0)

832
#define EIGER_TEMP(x)			{x, EIGER_TEMP_FACTOR, 0}
833
834
835
836
837
838
839
840
841
842
843
844
845

	static struct ADCData {
		ADCIndex idx;
		double factor, min_val;
	} EigerADCList[] = {
		EIGER_TEMP(TempFPGA),
		EIGER_TEMP(TempFPGAExt),
		EIGER_TEMP(Temp10GE),
		EIGER_TEMP(TempDCDC),
		EIGER_TEMP(TempSODL),
		EIGER_TEMP(TempSODR),
		EIGER_TEMP(TempFPGAFL),
		EIGER_TEMP(TempFPGAFR),
846
847
848
849
	};
	const unsigned int size = C_LIST_SIZE(EigerADCList);

	name_list.resize(size);
850
851
852
853
854
	idx_list.resize(size);
	factor_list.resize(size);
	min_val_list.resize(size);
	struct ADCData *data = EigerADCList;
	for (unsigned int i = 0; i < size; ++i, ++data) {
855
		ostringstream os;
856
		os << data->idx;
857
		name_list[i] = os.str();
858
859
860
861
862
		idx_list[i] = int(data->idx);
		factor_list[i] = data->factor;
		min_val_list[i] = data->min_val;
		DEB_RETURN() << DEB_VAR4(name_list[i], idx_list[i], 
					 factor_list[i], min_val_list[i]);
863
864
865
	}
}

866
void Eiger::getTimeRanges(TimeRanges& time_ranges)
867
868
869
{
	DEB_MEMBER_FUNCT();

870
	PixelDepth pixel_depth;
871
	Camera* cam = getCamera();
872
	cam->getPixelDepth(pixel_depth);
873
874
875
876
877
878
	ClockDiv clock_div;
	getClockDiv(clock_div);
	ParallelMode parallel_mode;
	getParallelMode(parallel_mode);

	calcTimeRanges(pixel_depth, clock_div, parallel_mode, time_ranges);
879
880
881

	double readout_time;
	measureReadoutTime(readout_time);
882
883
884
885
886
887
888
889
}

void Eiger::calcTimeRanges(PixelDepth pixel_depth, ClockDiv clock_div,
			   ParallelMode parallel_mode,
			   TimeRanges& time_ranges)
{
	DEB_STATIC_FUNCT();
	DEB_PARAM() << DEB_VAR3(pixel_depth, clock_div, parallel_mode);
890

891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
	// times are in usec, freq in MHz
	int period_factor = 1 << int(clock_div);
	double xfer_freq = BaseChipXferFreq / period_factor;
	DEB_TRACE() << DEB_VAR2(period_factor, xfer_freq);

	double xfer_2_buff = ChipXfer2Buff.calcY(period_factor);
	DEB_TRACE() << DEB_VAR1(xfer_2_buff);

	const int super_col_pixels = SuperColNbCols * ChipSize;
	double theo_single_readout = super_col_pixels * BitsPerXfer / xfer_freq;
	// theoretical -> measured correction
	double real_single_readout = ChipRealReadout.calcY(theo_single_readout);
	DEB_TRACE() << DEB_VAR2(theo_single_readout, real_single_readout);

	int readout_cycles;
	if (pixel_depth == PixelDepth4)
		readout_cycles = 1;
	else if (pixel_depth == PixelDepth8)
		readout_cycles = 2;
	else
		readout_cycles = 3;
	double min_chip_readout = real_single_readout * readout_cycles;
	DEB_TRACE() << DEB_VAR2(readout_cycles, min_chip_readout);

	int mem_xfer_blocks = pixel_depth / BitsPerXfer;
	const int nb_super_cols = ChipSize / SuperColNbCols * HalfModuleChips;
	double feb_beb_bw = (xfer_freq * nb_super_cols / readout_cycles *
			     mem_xfer_blocks);
	DEB_TRACE() << DEB_VAR2(feb_beb_bw, MaxFebBebBandwidth);
	double chip_readout = min_chip_readout;
	if (feb_beb_bw > MaxFebBebBandwidth) {
		chip_readout *= feb_beb_bw / MaxFebBebBandwidth;
		DEB_TRACE() << "limiting chip readout freq: "
			    << DEB_VAR2(min_chip_readout, chip_readout);
925
	}
926
927
928
929
	double full_readout = xfer_2_buff + chip_readout;
	DEB_TRACE() << DEB_VAR1(full_readout);

	bool parallel = (parallel_mode == Parallel);
930

931
	double min_exp = 10;
932
933
	double min_period = (parallel ? 0 : min_exp) + full_readout;
	double min_lat = parallel ? xfer_2_buff : full_readout;
934

935
936
937
938
939
940
941
	// Timing hardware uses 32-bit, base-10 floating-point registers:
	//   29 bits: mantissa
	//    3 bits: exponent
	// Time unit: 10 nsec 
	// Max value: 2^29 * 10^(2^3 - 1) * 10 nsec = 1.7 years
	// Using 1000 sec as a reasonable upper limit

942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
	time_ranges.min_exp_time = min_exp * 1e-6;
	time_ranges.max_exp_time = 1e3;
	time_ranges.min_lat_time = min_lat * 1e-6;
	time_ranges.max_lat_time = 1e3;
	time_ranges.min_frame_period = min_period * 1e-6;
	time_ranges.max_frame_period = 1e3;

	DEB_RETURN() << DEB_VAR2(time_ranges.min_exp_time, 
				 time_ranges.max_exp_time);
	DEB_RETURN() << DEB_VAR2(time_ranges.min_lat_time, 
				 time_ranges.max_lat_time);
	DEB_RETURN() << DEB_VAR2(time_ranges.min_frame_period, 
				 time_ranges.max_frame_period);
}

957
void Eiger::measureReadoutTime(double& /*readout_time*/)
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
{
	DEB_MEMBER_FUNCT();

	Camera* cam = getCamera();

	class SyncParams
	{


	private:
		double prev_exp, prev_period;
		TrigMode prev_trig_mode;
	};

	// exp, period, trigmode, nb_frames
	double prev_exp, prev_period;
	cam->getExpTime(prev_exp);
	cam->getFramePeriod(prev_period);
	FrameType prev_nb_frames;
	cam->getNbFrames(prev_nb_frames);
	Defs::TrigMode prev_trig_mode;
	cam->getTrigMode(prev_trig_mode);


	/*
	DEB_ALWAYS() << "calling startAcquisition";
	cam->m_det->startAcquisition();

	DEB_ALWAYS() << "calling stopAcquisition";
	cam->m_det->stopAcquisition();

989
	readout_time = 0;
990
991
992
	 */
}

993
994
995
int Eiger::getNbFrameMapItems()
{
	DEB_MEMBER_FUNCT();
996
	int nb_items = 1;
997
998
999
1000
	DEB_RETURN() << DEB_VAR1(nb_items);
	return nb_items;
}