AlcapDAQ  1
sis3600.cpp
Go to the documentation of this file.
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 
5 #include "midas.h"
6 
7 #include "crate.h"
8 #include "vme.h"
9 #include "odb_wrapper.h"
10 #include "diag.h"
11 
12 INT sis3600_bor();
13 INT sis3600_eor();
14 INT sis3600_poll_live();
15 INT sis3600_read(char *pevent);
16 
18  NULL, // init
19  NULL, // exit
20  NULL, // pre_bor
21  sis3600_bor, // bor
22  sis3600_eor, // eor
23  sis3600_poll_live, // poll_live
24  NULL, // poll_dead
25  NULL, // start_cycle
26  NULL, // stop_cycle
27  sis3600_read, // read
28 };
29 
30 
31 
32 #define SIS3600_MAX_DMA_SIZE 256
33 #define SIS3600_MAX_SIZE (32*1024*4)
34 #define ACTIVE_READOUT_BUFFER_SIZE (32*1024*4)
35 #define ACTIVE_READOUT_MAX_PER_POLL (2*1024)
36 
37 struct sis3600 {
38  bool enabled;
39  bool do_active_readout;
40  struct vme_handle *vme_handle;
41  unsigned long vme_base;
42  char odb_name[20];
43  char bank_name[20];
46 };
47 
48 #define MAX_SIS3600 4
50 
51 #define SIS3600_CSR 0x000
52 #define SIS3600_KA_CLEAR 0x020
53 #define SIS3600_KA_ENABLENEXT 0x028
54 #define SIS3600_KA_RESET 0x060
55 #define SIS3600_OUTBUF 0x100
56 
57 #define SIS3600_CSR_FIFO_EMPTY_MASK 0x00000100
58 #define SIS3600_CSR_FIFO_ALMOST_EMPTY_MASK 0x00000200
59 
60 /*
61  * sis3600_bor1
62  *
63  * Initialize one SIS3600 module.
64  */
65 INT sis3600_bor1(struct sis3600 *sis)
66 {
67  // Get the VME base address of the module
68  sis->vme_base = odb_get_dword("/Equipment/Crate %d/Settings/%s/vme address",
69  crate_number, sis->odb_name);
70 
71  // Open a VME handle for memory-mapped access
72  struct vme_mapping_ctrl mapping = {
77  };
78 
79  struct vme_handle *handle =
80  vme_open(sis->vme_base, mapping, 0x200, SIS3600_MAX_DMA_SIZE);
81  sis->vme_handle = handle;
82 
83  // Reset
84  vme_write_d32(handle, sis->vme_base | SIS3600_KA_RESET, 0x1);
85 
86  // Clear for the next block
87  sis->active_readout_size = 0;
88 
89  // Read back current status register and check it
90  DWORD csr = vme_read_d32(handle, sis->vme_base | SIS3600_CSR);
91  if(csr != 0x00000300) {
92  diag_print(0, "Unexpected status 0x%08x on %s after reset, disabling\n",
93  csr, sis->odb_name);
94  sis->enabled = false;
95  return FE_ERR_HW;
96  }
97 
98  // Continue setup
99  vme_write_d32(handle, sis->vme_base | SIS3600_CSR, 0x08010000);
100  vme_write_d32(handle, sis->vme_base | SIS3600_KA_CLEAR, 0x1);
101  vme_write_d32(handle, sis->vme_base | SIS3600_KA_ENABLENEXT, 0x1);
102 
103  // Again check the status register value
104  csr = vme_read_d32(handle, sis->vme_base | SIS3600_CSR);
105  if(csr != 0x00018300) {
106  diag_print(0, "Unexpected status 0x%08x on %s after setup, disabling\n",
107  csr, sis->odb_name);
108  sis->enabled = false;
109  return FE_ERR_HW;
110  }
111 
112  // Determine whether we're supposed to do active readout
113  sis->do_active_readout =
114  odb_get_bool("/Equipment/Crate %d/Settings/%s/Active Readout mode",
115  crate_number, sis->odb_name);
116 
117  return SUCCESS;
118 }
119 
120 /*
121  * sis3600_bor
122  *
123  * Called at the beginning of the run to discover SIS3600 modules
124  * and initialize them.
125  */
126 INT sis3600_bor()
127 {
128  // Use the ODB to find any SIS3600 modules
129  for(int j = 0; j < MAX_SIS3600; j++) {
130 
131  bool enabled = false;
132 
133  if (odb_find_key("/Equipment/Crate %d/Settings/COMP %d", crate_number, j)) {
134  diag_print(1, "ODB says COMP %d is present, ", j);
135  enabled =
136  odb_get_bool("/Equipment/Crate %d/Settings/COMP %d/enabled status",
137  crate_number, j);
138  if (enabled) {
139  diag_print(1, "and is enabled. Initializing...\n");
140  } else {
141  diag_print(1, "but is disabled.\n");
142  }
143  }
144 
145  sis3600[j].enabled = enabled;
146 
147  // Set up the name of the MIDAS bank associated with the module
148  sprintf(sis3600[j].bank_name, "CMP%d", j);
149  sprintf(sis3600[j].odb_name, "COMP %d", j);
150 
151  if(enabled) {
152  sis3600_bor1(&sis3600[j]);
153  }
154  }
155 
156  return SUCCESS;
157 }
158 
159 INT sis3600_eor1(struct sis3600 *sis)
160 {
161  vme_close(sis->vme_handle);
162  return SUCCESS;
163 }
164 
165 /*
166  * sis3600_eor
167  *
168  * Called at the end of the run to release any resources that may have
169  * been allocated.
170  */
171 INT sis3600_eor()
172 {
173 
174  for(int i = 0; i < MAX_SIS3600; i++) {
175  if(sis3600[i].enabled) {
176  int status = sis3600_eor1(&sis3600[i]);
177  if(status != SUCCESS) {
178  return status;
179  }
180  }
181  }
182 
183  return SUCCESS;
184 }
185 
186 INT sis3600_fifo_read(struct sis3600 *sis, unsigned char *buffer,
187  int max_size, bool in_active_readout)
188 {
189  // If we're not in the active readout phase, then we simply do a big DMA.
190  // There is a 50% chance of losing one word at the end of the block.
191  if(!in_active_readout) {
192  int status = vme_dma_read(sis->vme_handle,
193  sis->vme_base | SIS3600_OUTBUF,
194  buffer,
195  max_size);
196  return status;
197  }
198 
199  // If we are in the active readout phase, then we have to be more careful.
200  // Before initiating a block transfer, we check whether the CSR
201  // indicates "almost empty." If it does not, a 256 byte (64 word)
202  // block transfer is safe. If it does, then we return nothing; we'll
203  // be back when there is enough data to bother with.
204  int size = 0;
205  while(size < max_size) {
206 
207  DWORD csr = vme_read_d32(sis->vme_handle, sis->vme_base | SIS3600_CSR);
209  return size;
210  }
211 
212  int size_this_time = MIN(max_size - size, 256);
213 
214  int status = vme_dma_read(sis->vme_handle,
215  sis->vme_base | SIS3600_OUTBUF,
216  buffer + size,
217  size_this_time);
218 
219  if(status >= 0) {
220  size += status;
221  }
222 
223  if(status != size_this_time) {
224  diag_print(0, "Retrieved only %d bytes from %s", status, sis->odb_name);
225  }
226  }
227 
228  return size;
229 }
230 
231 /*
232  * sis3600_poll1
233  *
234  * Performs active readout for a single SIS3600 FIFO.
235  */
236 INT sis3600_poll1(struct sis3600 *sis)
237 {
238  // If active readout is not enabled, skip it.
239  if(!sis->do_active_readout) {
240  return SUCCESS;
241  }
242 
243  // First check how much space we have available in the active
244  // readout buffer.
245  int size_left = ACTIVE_READOUT_BUFFER_SIZE - sis->active_readout_size;
246  int size = MIN(ACTIVE_READOUT_MAX_PER_POLL, size_left);
247 
248  // Now try to read up to that amount.
249  int status = sis3600_fifo_read(sis,
251  size, TRUE);
252 
253  // Check the status
254  if(status >= 0) {
255  sis->active_readout_size += status;
256  } else {
257  diag_print(0, "Status from sis3600_fifo_read is %d for %s.\n", status,
258  sis->odb_name);
259  return FE_ERR_HW;
260  }
261 
263  return FE_NEED_STOP;
264  } else {
265  return SUCCESS;
266  }
267 }
268 
269 /*
270  * sis3600_poll_live
271  *
272  * Called periodically while a block is active; performs active readout.
273  *
274  * Returns:
275  * - ordinarily 0,
276  * - a request for a "soft stop" end-of-block, or
277  * - an error code
278  */
279 INT sis3600_poll_live()
280 {
281  for(int i = 0; i < MAX_SIS3600; i++) {
282  if(sis3600[i].enabled) {
283  int status = sis3600_poll1(&sis3600[i]);
284  if(status != SUCCESS) {
285  return status;
286  }
287  }
288  }
289 
290  return SUCCESS;
291 }
292 
293 /*
294  * sis3600_read1
295  *
296  * Constructs the MIDAS bank for a single SIS3600.
297  */
298 INT sis3600_read1(struct sis3600 *sis, char *pevent)
299 {
300  // Create the MIDAS bank
301  DWORD *pdata;
302  bk_create(pevent, sis->bank_name, TID_DWORD, &pdata);
303 
304  // Copy data that was read during the active readout
305  int active_size = sis->active_readout_size;
306  memcpy(pdata, sis->active_readout_buffer, active_size);
307 
308  // Read any data remaining in the module
309  int status =
310  sis3600_fifo_read(sis, ((unsigned char *) pdata) + active_size,
312 
313  // Check the status
314  int final_size = 0;
315  if(status >= 0) {
316  final_size = status;
317  } else {
318  // handle the error
319  }
320 
321  // Close the bank
322  bk_close(pevent, pdata + (active_size + final_size)/sizeof(DWORD));
323 
324  // Clear for the next block
325  sis->active_readout_size = 0;
326 
327  // Clear FIFO
329 
330  return SUCCESS;
331 }
332 
333 /*
334  * sis3600_read
335  *
336  * Called at the end of a block to assemble data from that block into a
337  * MIDAS event.
338  */
339 INT sis3600_read(char *pevent)
340 {
341  for(int i = 0; i < MAX_SIS3600; i++) {
342  if(sis3600[i].enabled) {
343  int status = sis3600_read1(&sis3600[i], pevent);
344  if(status != SUCCESS) {
345  return status;
346  }
347  }
348  }
349 
350  return SUCCESS;
351 }