AlcapDAQ  1
caenV767.cpp
Go to the documentation of this file.
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 
5 #include <sys/time.h>
6 #include <time.h>
7 
8 #include "midas.h"
9 
10 #include "crate.h"
11 #include "vme.h"
12 #include "odb_wrapper.h"
13 #include "diag.h"
14 
15 INT caenV767_pre_bor();
16 INT caenV767_eor();
17 INT caenV767_poll_live();
18 INT caenV767_read(char *pevent);
19 
21  NULL, // init
22  NULL, // exit
23  caenV767_pre_bor, // pre_bor
24  NULL, // bor
25  caenV767_eor, // eor
26  caenV767_poll_live, // poll_live
27  NULL, // poll_dead
28  NULL, // start_cycle
29  NULL, // stop_cycle
30  caenV767_read, // read
31 };
32 
33 #define CAENV767_MAX_DMA_SIZE 256
34 #define CAENV767_MAX_SIZE (32*1024*4)
35 #define ACTIVE_READOUT_MAX_PER_POLL (2*1024)
36 #define CAENV767_NUM_CHANNELS 128
37 
38 struct caenV767 {
39  bool enabled;
43  unsigned long vme_base;
44  char odb_name[20];
45  char bank_name[20];
47  unsigned char *active_readout_buffer;
51 };
52 
53 struct timeval block_start_time;
54 
55 #define MAX_CAENV767 4
57 
58 // Register offsets
59 #define CAENV767_OUTBUF 0x00
60 #define CAENV767_CTR1 0x10
61 #define CAENV767_STR2 0x48
62 #define CAENV767_EVT_COUNT 0x4C
63 #define CAENV767_OPHAND 0x50
64 #define CAENV767_OPCODE 0x52
65 #define CAENV767_CLEAR 0x54
66 
67 // Reserved value returned in output buffer when the FIFO is empty
68 #define CAENV767_NOT_VALID 0x00600000
69 
70 // Bits in status register 2
71 #define CAENV767_GLOBAL_TDC_ERROR 0x0008
72 
73 void caenV767_opcode_write(struct caenV767 *caen, short code)
74 {
75  // Wait for the microcontroller to become ready
76  while(!(vme_read_d16(caen->vme_handle, caen->vme_base | CAENV767_OPHAND) &
77  0x0002)) {
78  ss_sleep(10);
79  }
80 
81  // Wait a little longer
82  ss_sleep(10);
83 
84  // Write the opcode value
85  vme_write_d16(caen->vme_handle, caen->vme_base | CAENV767_OPCODE, code);
86 }
87 
89 {
90  // Wait for the microcontroller to become ready
91  while(!(vme_read_d16(caen->vme_handle, caen->vme_base | CAENV767_OPHAND) &
92  0x1)) {
93  ss_sleep(10);
94  }
95 
96  // Wait a little longer
97  ss_sleep(10);
98 
99  // Read the opcode value
100  return vme_read_d16(caen->vme_handle, caen->vme_base | CAENV767_OPCODE);
101 }
102 
103 /*
104  * caenV767_bor1
105  *
106  * Initialize one CAENV767 module.
107  */
109 {
110  // Get the VME base address of the module
111  caen->vme_base = odb_get_dword("/Equipment/Crate %d/Settings/%s/vme address",
112  crate_number, caen->odb_name);
113 
114  // Open a VME handle for memory-mapped access
115  struct vme_mapping_ctrl mapping = {
120  };
121 
122  struct vme_handle *handle =
123  vme_open(caen->vme_base, mapping, 0x200, CAENV767_MAX_DMA_SIZE);
124  caen->vme_handle = handle;
125 
126  // Determine whether we're supposed to do active readout
127  caen->do_active_readout =
128  odb_get_bool("/Equipment/Crate %d/Settings/%s/Active Readout mode",
129  crate_number, caen->odb_name);
130 
131  // Determine whether we should record trailing edges, or only leading edges
132  caen->record_trailing_edges =
133  odb_get_bool("/Equipment/Crate %d/Settings/%s/Record trailing edges",
134  crate_number, caen->odb_name);
135 
136  // Request a bus error when DMA transfer reaches end of data
137  vme_write_d16(caen->vme_handle, caen->vme_base | CAENV767_CTR1, 0x0020);
138 
139  // Read the half-full mark and the active readout buffer size
140  caen->half_full_level =
141  odb_get_int("/Equipment/Crate %d/Settings/%s/Half-full level",
142  crate_number, caen->odb_name);
144  odb_get_int("/Equipment/Crate %d/Settings/%s/Active readout buffer size",
145  crate_number, caen->odb_name);
146 
147  // Allocate the active readout buffer
148  caen->active_readout_buffer = new unsigned char[caen->active_readout_buffer_size];
149 
150  // Set various TDC options
151  caenV767_opcode_write(caen, 0x1200); // set start gating mode
152  caenV767_opcode_write(caen, 0x7100); // set DRDY = almost full
153  caenV767_opcode_write(caen, 0x7400); // prepare to set almost full level...
154  caenV767_opcode_write(caen, caen->half_full_level); // ...set almost full level
155  caenV767_opcode_write(caen, 0x4000); // enable readout of start time
156  caenV767_opcode_write(caen, 0x4300); // enable subtraction of start time
157  // from hit times
158 
159  if(caen->record_trailing_edges) {
160  caenV767_opcode_write(caen, 0x6600); // enable both edges on all channels
161  // and start
162  } else {
163  caenV767_opcode_write(caen, 0x6000); // enable only leading edge on all
164  // channels and start
165  }
166 
167  // Enable the CAEN channels according to the ODB settings
168  diag_print(1, "Enabling all channels on %s.\n", caen->odb_name);
169  caenV767_opcode_write(caen, 0x2300); // enable all channels first
170  BOOL channel_enable_array[CAENV767_NUM_CHANNELS], channelstatus;
171  odb_get_boolarray(&channel_enable_array[0], CAENV767_NUM_CHANNELS,
172  "/Equipment/Crate %d/Settings/%s/channels/channel enabled",
173  crate_number, caen->odb_name);
174  // disable each masked channel
175  for (int channel=0; channel<=(CAENV767_NUM_CHANNELS-1); channel++) {
176  channelstatus = channel_enable_array[channel];
177  if (channelstatus == 0) {
178  diag_print(1, "Disabling %s channel %d.\n", caen->odb_name, channel);
179  caenV767_opcode_write(caen, 0x2100 | channel);
180  }
181  }
182 
183  // Reset the TDC
184  vme_write_d16(caen->vme_handle, caen->vme_base | CAENV767_CLEAR, 1);
185 
186  // Clear for the next block
187  caen->active_readout_size = 0;
188 
189  return SUCCESS;
190 }
191 
192 /*
193  * caenV767_bor
194  *
195  * Called at the beginning of the run to discover CAENV767 modules
196  * and initialize them.
197  */
199 {
200  // Use the ODB to find any CAENV767 modules
201  for(int j = 0; j < MAX_CAENV767; j++) {
202 
203  bool enabled = false;
204 
205  if (odb_find_key("/Equipment/Crate %d/Settings/CAEN %d", crate_number, j)) {
206  diag_print(1, "ODB says CAEN %d is present, ", j);
207  enabled =
208  odb_get_bool("/Equipment/Crate %d/Settings/CAEN %d/enabled status",
209  crate_number, j);
210  if (enabled) {
211  diag_print(1, "and is enabled. Initializing...\n");
212  } else {
213  diag_print(1, "but is disabled.\n");
214  }
215  }
216 
217  caenV767[j].enabled = enabled;
218 
219  // Set up the name of the MIDAS bank associated with the module
220  sprintf(caenV767[j].bank_name, "CAE%d", j);
221  sprintf(caenV767[j].odb_name, "CAEN %d", j);
222 
223  if(enabled) {
224  caenV767_bor1(&caenV767[j]);
225  }
226  }
227 
228  return SUCCESS;
229 }
230 
232 {
233  vme_close(caen->vme_handle);
234  delete[] caen->active_readout_buffer;
235  return SUCCESS;
236 }
237 
238 /*
239  * caenV767_eor
240  *
241  * Called at the end of the run to release any resources that may have
242  * been allocated.
243  */
245 {
246 
247  for(int i = 0; i < MAX_CAENV767; i++) {
248  if(caenV767[i].enabled) {
249  int status = caenV767_eor1(&caenV767[i]);
250  if(status != SUCCESS) {
251  return status;
252  }
253  }
254  }
255 
256  return SUCCESS;
257 }
258 
259 INT caenV767_fifo_read(struct caenV767 *caen, unsigned char *buffer,
260  int max_size, bool in_active_readout)
261 {
262  if(!in_active_readout) {
263  int status = vme_dma_read(caen->vme_handle,
264  caen->vme_base | CAENV767_OUTBUF,
265  buffer,
266  max_size);
267  return status;
268  } else {
269  int size = 0;
270 
271  for(int i = 0; i < max_size / sizeof(DWORD); i++) {
272  DWORD word =
274 
275  if((word & CAENV767_NOT_VALID) == CAENV767_NOT_VALID) {
276  break;
277  }
278 
279  *((DWORD *) buffer) = word;
280  buffer += sizeof(DWORD);
281  size += sizeof(DWORD);
282  }
283 
284  return size;
285  }
286 }
287 
288 /*
289  * caenV767_poll1
290  *
291  * Performs active readout for a single CAENV767 FIFO.
292  */
294 {
295  // If active readout is not enabled, skip it.
296  if(!caen->do_active_readout) {
297  return SUCCESS;
298  }
299 
300  // Check whether there's anything at all in the buffer.
301 
302  // How many words do we expect?
303  struct timeval now;
304  gettimeofday(&now, NULL);
305  double block_seconds = (now.tv_sec - block_start_time.tv_sec) +
306  1e-6*(now.tv_usec - block_start_time.tv_usec);
307  int expected_words =
308  (int) (caen->bytes_per_second / block_seconds / sizeof(DWORD));
309 
310  // First check how much space we have available in the active
311  // readout buffer.
312  int size_left = caen->active_readout_buffer_size - caen->active_readout_size;
313  int size = MIN(ACTIVE_READOUT_MAX_PER_POLL, size_left);
314  size = MIN(size, expected_words);
315 
316  // Now try to read up to that amount, without using block transfers,
317  // which can potentially drop the last data word.
318  int status =
319  caenV767_fifo_read(caen,
321  size,
322  TRUE);
323 
324  // Check the status
325  if(status >= 0) {
326  caen->active_readout_size += status;
327  } else {
328  diag_print(0, "Status from caenV767_fifo_read is %d for %s\n", status,
329  caen->odb_name);
330  return FE_ERR_HW;
331  }
332 
334  return FE_NEED_STOP;
335  } else {
336  return SUCCESS;
337  }
338 }
339 
340 /*
341  * caenV767_poll_live
342  *
343  * Called periodically while a block is active; performs active readout.
344  *
345  * Returns:
346  * - ordinarily 0,
347  * - a request for a "soft stop" end-of-block, or
348  * - an error code
349  */
351 {
352  // If this is our first active readout pass, just remember the time.
353  if(block_start_time.tv_sec == 0 && block_start_time.tv_usec == 0) {
354  return SUCCESS;
355  }
356 
357  for(int i = 0; i < MAX_CAENV767; i++) {
358  if(caenV767[i].enabled) {
359  int status = caenV767_poll1(&caenV767[i]);
360  if(status != SUCCESS) {
361  return status;
362  }
363  }
364  }
365 
366  return SUCCESS;
367 }
368 
369 /*
370  * caenV767_read1
371  *
372  * Constructs the MIDAS bank for a single CAENV767.
373  */
374 INT caenV767_read1(struct caenV767 *caen, char *pevent)
375 {
376  // Create the MIDAS bank
377  DWORD *pdata;
378  bk_create(pevent, caen->bank_name, TID_DWORD, &pdata);
379 
380  // Copy data that was read during the active readout
381  int active_size = caen->active_readout_size;
382  memcpy(pdata, caen->active_readout_buffer, active_size);
383 
384  // Read any data remaining in the module
385  int status =
386  caenV767_fifo_read(caen, ((unsigned char *) pdata) + active_size,
388 
389  // Check the status
390  int final_size = 0;
391  if(status >= 0) {
392  final_size = status;
393  } else {
394  // handle the error
395  }
396 
397  // Check the TDC status for error codes (typically "DLL unlocked" problems)
398  // and add an error flag word if a problem is found.
399  short str2 = vme_read_d16(caen->vme_handle, caen->vme_base | CAENV767_STR2);
400  if(str2 & CAENV767_GLOBAL_TDC_ERROR) {
401  DWORD flag_word = CAENV767_NOT_VALID;
402  for(int tdc = 0; tdc < 4; tdc++) {
403  short ind_tdc_error_mask = (1 << (12+tdc));
404  if(str2 & (1 << (12+tdc))) {
405  flag_word |= (1 << tdc);
406  }
407  }
408 
409  pdata[(active_size + final_size)/sizeof(DWORD)] = flag_word;
410  final_size += sizeof(DWORD);
411 
412  diag_print(0, "TDC error in %s: 0x%08x\n", caen->odb_name, flag_word);
413  }
414 
415  // Close the bank
416  // Modified by VT on Oct-29-2010
417  //bk_close(pevent, pdata + (active_size + final_size)/sizeof(DWORD));
418  int total_size = active_size + final_size;
419  if ( total_size > 500000 ) {
420  printf("ERROR! Event size is too big (%i). The event will be rejected\n");
421  bk_close(pevent, pdata + 0);
422  } else {
423  bk_close(pevent, pdata + (active_size + final_size)/sizeof(DWORD));
424  }
425 
426 
427 
428  // Clear for the next block
429  caen->active_readout_size = 0;
430 
431  // Reset the TDC
432  vme_write_d16(caen->vme_handle, caen->vme_base | CAENV767_CLEAR, 1);
433 
434  // Update the expected rate.
435  if(block_start_time.tv_sec != 0) {
436  struct timeval now;
437  gettimeofday(&now, NULL);
438  double block_seconds = (now.tv_sec - block_start_time.tv_sec) +
439  1e-6*(now.tv_usec - block_start_time.tv_usec);
440  caen->bytes_per_second = (active_size + final_size)/block_seconds;
441  }
442  block_start_time.tv_sec = block_start_time.tv_usec = 0;
443 
444  return SUCCESS;
445 }
446 
447 /*
448  * caenV767_read
449  *
450  * Called at the end of a block to assemble data from that block into a
451  * MIDAS event.
452  */
453 INT caenV767_read(char *pevent)
454 {
455  for(int i = 0; i < MAX_CAENV767; i++) {
456  if(caenV767[i].enabled) {
457  int status = caenV767_read1(&caenV767[i], pevent);
458  if(status != SUCCESS) {
459  return status;
460  }
461  }
462  }
463 
464  return SUCCESS;
465 }