ROOTANA
TMidasOnline.cxx
Go to the documentation of this file.
1 /********************************************************************\
2 
3  Name: TMidasOnline.cxx
4  Created by: Konstantin Olchanski - TRIUMF
5 
6  Contents: C++ MIDAS analyzer
7 
8  $Id$
9 
10 \********************************************************************/
11 
12 #include "TMidasOnline.h"
13 
14 #include <string>
15 #include <assert.h>
16 
17 //#include "midas.h"
18 #include "msystem.h"
19 //#include "hardware.h"
20 //#include "ybos.h"
21 
22 
24 {
25  fDB = 0;
26  fStartHandler = 0;
27  fStopHandler = 0;
28  fPauseHandler = 0;
29  fResumeHandler = 0;
30  fEventRequests = 0;
31  fEventHandler = 0;
32 }
33 
35 {
36  disconnect();
37  assert(!"TMidasOnline::~TMidasOnline(): destruction of the TMidasOnline singleton is not permitted!");
38 }
39 
41 {
42  if (!gfMidas)
43  gfMidas = new TMidasOnline();
44 
45  return gfMidas;
46 }
47 
48 int TMidasOnline::connect(const char*hostname,const char*exptname,const char*progname)
49 {
50  int status;
51 
52  char xhostname[HOST_NAME_LENGTH];
53  char xexptname[NAME_LENGTH];
54 
55  /* get default from environment */
56  status = cm_get_environment(xhostname, sizeof(xhostname), xexptname, sizeof(xexptname));
57  assert(status == CM_SUCCESS);
58 
59  if (hostname)
60  strlcpy(xhostname,hostname,sizeof(xhostname));
61 
62  if (exptname)
63  strlcpy(xexptname,exptname,sizeof(xexptname));
64 
65  fHostname = xhostname;
66  fExptname = xexptname;
67 
68  fprintf(stderr, "TMidasOnline::connect: Connecting to experiment \"%s\" on host \"%s\"\n", fExptname.c_str(), fHostname.c_str());
69 
70  //int watchdog = DEFAULT_WATCHDOG_TIMEOUT;
71  int watchdog = 60*1000;
72 
73  status = cm_connect_experiment1((char*)fHostname.c_str(), (char*)fExptname.c_str(), (char*)progname, NULL, DEFAULT_ODB_SIZE, watchdog);
74 
75  if (status == CM_UNDEF_EXP)
76  {
77  fprintf(stderr, "TMidasOnline::connect: Error: experiment \"%s\" not defined.\n", fExptname.c_str());
78  return -1;
79  }
80  else if (status != CM_SUCCESS)
81  {
82  fprintf(stderr, "TMidasOnline::connect: Cannot connect to MIDAS, status %d.\n", status);
83  return -1;
84  }
85 
86  status = cm_get_experiment_database(&fDB, NULL);
87  assert(status == CM_SUCCESS);
88 
89  cm_set_watchdog_params(true, 60*1000);
90 
91  return 0;
92 }
93 
95 {
96  if (fDB)
97  {
98  fprintf(stderr, "TMidasOnline::disconnect: Disconnecting from experiment \"%s\" on host \"%s\"\n", fExptname.c_str(), fHostname.c_str());
99  cm_disconnect_experiment();
100  fDB = 0;
101  }
102 
103  return 0;
104 }
105 
107 {
108  cm_register_transition(TR_START, NULL, 300);
109  cm_register_transition(TR_PAUSE, NULL, 700);
110  cm_register_transition(TR_RESUME, NULL, 300);
111  cm_register_transition(TR_STOP, NULL, 700);
112 }
113 
114 void TMidasOnline::setTransitionHandlers(TransitionHandler start,TransitionHandler stop,TransitionHandler pause,TransitionHandler resume)
115 {
116  fStartHandler = start;
117  fStopHandler = stop;
118  fPauseHandler = pause;
119  fResumeHandler = resume;
120 }
121 
123 {
124  int transition, run_number, trans_time;
125 
126  int status = cm_query_transition(&transition, &run_number, &trans_time);
127  if (status != CM_SUCCESS)
128  return false;
129 
130  //printf("cm_query_transition: status %d, tr %d, run %d, time %d\n",status,transition,run_number,trans_time);
131 
132  for (unsigned i=0; i<fHandlers.size(); i++)
133  fHandlers[i]->Transition(transition, run_number, trans_time);
134 
135  if (transition == TR_START)
136  {
137  if (fStartHandler)
138  (*fStartHandler)(transition,run_number,trans_time);
139  return true;
140  }
141  else if (transition == TR_STOP)
142  {
143  if (fStopHandler)
144  (*fStopHandler)(transition,run_number,trans_time);
145  return true;
146 
147  }
148  else if (transition == TR_PAUSE)
149  {
150  if (fPauseHandler)
151  (*fPauseHandler)(transition,run_number,trans_time);
152  return true;
153 
154  }
155  else if (transition == TR_RESUME)
156  {
157  if (fResumeHandler)
158  (*fResumeHandler)(transition,run_number,trans_time);
159  return true;
160  }
161 
162  return false;
163 }
164 
165 bool TMidasOnline::poll(int mdelay)
166 {
167  //printf("poll!\n");
168 
169  if (checkTransitions())
170  return true;
171 
172  int status = cm_yield(mdelay);
173  if (status == RPC_SHUTDOWN || status == SS_ABORT)
174  {
175  fprintf(stderr, "TMidasOnline::poll: cm_yield(%d) status %d, shutting down.\n",mdelay,status);
176  disconnect();
177  return false;
178  }
179 
180  return true;
181 }
182 
183 bool TMidasOnline::sleep(int mdelay)
184 {
185  //printf("poll!\n");
186 
187  if (checkTransitions())
188  return true;
189 
190  int status = ss_suspend(mdelay, MSG_BM);
191  if (status == SS_SUCCESS)
192  return true;
193  if (status == SS_TIMEOUT)
194  return true;
195 #if 0
196  if (status == SS_SERVER_RECV) {
197  //printf("ss_suspend status %d\n", status);
198  // FIXME: maybe sleep here?
199  return true;
200  }
201 #endif
202  fprintf(stderr, "TMidasOnline::sleep(): Unexpected ss_suspend() status %d\n", status);
203 #if 0
204  if (status == RPC_SHUTDOWN || status == SS_ABORT)
205  {
206  fprintf(stderr, "TMidasOnline::poll: cm_yield(%d) status %d, shutting down.\n",mdelay,status);
207  disconnect();
208  return false;
209  }
210 #endif
211 
212  return true;
213 }
214 
215 void TMidasOnline::setEventHandler(EventHandler handler)
216 {
217  fEventHandler = handler;
218 }
219 
220 static void eventCallback(HNDLE buffer_handle, HNDLE request_id, EVENT_HEADER* pheader, void* pevent)
221 {
222 #if 0
223  printf("eventCallback: buffer %d, request %d, pheader %p (event_id: %d, trigger mask: 0x%x, serial: %d, time: %d, size: %d), pevent %p\n",
224  buffer_handle,
225  request_id,
226  pheader,
227  pheader->event_id,
228  pheader->trigger_mask,
229  pheader->serial_number,
230  pheader->time_stamp,
231  pheader->data_size,
232  pevent);
233 #endif
234 
236 
237  for (unsigned i=0; i<midas->fHandlers.size(); i++)
238  midas->fHandlers[i]->Event(pheader, sizeof(EVENT_HEADER) + pheader->data_size);
239 
240  if (midas->fEventHandler)
241  midas->fEventHandler(pheader,pevent,pheader->data_size);
242 }
243 
244 int TMidasOnline::receiveEvent(int requestId, void* pevent, int size, bool async)
245 {
247 
248  while (1)
249  {
250  if (!r)
251  {
252  fprintf(stderr, "TMidasOnline::receiveEvent: Cannot find request %d\n", requestId);
253  return -1;
254  }
255 
256  if (r->fRequestId == requestId)
257  break;
258 
259  r = r->fNext;
260  }
261 
262  int flag = 0;
263  if (async){
264 #ifdef BM_NO_WAIT
265  flag = BM_NO_WAIT;
266 #else
267  flag = ASYNC;
268 #endif
269  }
270 
271 
272  int status = bm_receive_event(r->fBufferHandle, pevent, &size, flag);
273 
274  if (status == BM_ASYNC_RETURN)
275  {
276  return 0;
277  }
278 
279  if (status != BM_SUCCESS)
280  {
281  fprintf(stderr, "TMidasOnline::receiveEvent: bm_receive_event() error %d\n", status);
282  return -1;
283  }
284 
285  return size;
286 }
287 
288 #ifndef EVENT_BUFFER_SIZE
289 #define EVENT_BUFFER_SIZE 0
290 #endif
291 
292 int TMidasOnline::eventRequest(const char* bufferName, int eventId, int triggerMask, int samplingType, bool poll)
293 {
294  int status;
295  EventRequest* r = new EventRequest();
296 
297  if (bufferName == NULL)
298  bufferName = EVENT_BUFFER_NAME;
299 
300  r->fNext = NULL;
301  r->fBufferName = bufferName;
302  r->fEventId = eventId;
303  r->fTriggerMask = triggerMask;
304  r->fSamplingType = samplingType;
305 
306 
307  /*---- open event buffer ---------------------------------------*/
308  status = bm_open_buffer((char*)bufferName, EVENT_BUFFER_SIZE, &r->fBufferHandle);
309  if (status!=SUCCESS && status!=BM_CREATED)
310  {
311  fprintf(stderr, "TMidasOnline::eventRequest: Cannot find data buffer \"%s\", bm_open_buffer() error %d\n", bufferName, status);
312  return -1;
313  }
314 
315  /* set the default buffer cache size (but not GET_RECENT sampling type*/
316  if(samplingType != GET_RECENT){
317  status = bm_set_cache_size(r->fBufferHandle, 100000, 0);
318  assert(status == BM_SUCCESS);
319  }
320 
321  if (poll)
322  status = bm_request_event(r->fBufferHandle, r->fEventId, r->fTriggerMask, r->fSamplingType, &r->fRequestId, NULL);
323  else
324  status = bm_request_event(r->fBufferHandle, r->fEventId, r->fTriggerMask, r->fSamplingType, &r->fRequestId, eventCallback);
325  assert(status == BM_SUCCESS);
326 
327  fprintf(stderr, "TMidasOnline::eventRequest: Event request: buffer \"%s\" (%d), event id 0x%x, trigger mask 0x%x, sample %d, request id: %d\n",bufferName,r->fBufferHandle,r->fEventId,r->fTriggerMask,r->fSamplingType,r->fRequestId);
328 
329  r->fNext = fEventRequests;
330  fEventRequests = r;
331 
332  return r->fRequestId;
333 };
334 
336 
337  if(!fEventRequests || !fEventRequests->fBufferHandle) return -1;
338 
339  int n_bytes;
340  bm_get_buffer_level(fEventRequests->fBufferHandle, &n_bytes);
341 
342  return n_bytes;
343 
344 }
345 
347 
348  if(!fEventRequests || !fEventRequests->fBufferHandle) return -1;
349 
350  BUFFER_HEADER buffer_header;
351  bm_get_buffer_info(fEventRequests->fBufferHandle,&buffer_header);
352 
353  return buffer_header.size;
354 
355 }
357 {
358  for (EventRequest* r = fEventRequests; r != NULL; r = r->fNext)
359  if (r->fRequestId == requestId)
360  {
361  int status = bm_delete_request(r->fRequestId);
362  assert(status == BM_SUCCESS);
363 
364  r->fBufferHandle = -1;
365  r->fRequestId = -1;
366  }
367 }
368 
370 {
371 }
372 
374 {
375  fHandlers.push_back(h);
376 }
377 
379 
380 //end
static void eventCallback(HNDLE buffer_handle, HNDLE request_id, EVENT_HEADER *pheader, void *pevent)
#define EVENT_BUFFER_SIZE
MIDAS online connection, including access to online ODB.
Definition: TMidasOnline.h:36
virtual ~TMHandlerInterface()
std::vector< TMHandlerInterface * > fHandlers
Definition: TMidasOnline.h:68
void RegisterHandler(TMHandlerInterface *h)
void setEventHandler(EventHandler handler)
Specify user handler for data events.
int receiveEvent(int requestId, void *pevent, int size, bool async)
Receive event by polling.
void registerTransitions()
Ask MIDAS to tell us about run transitions.
bool checkTransitions()
Check for pending transitions, call user handlers. Returns "true" if there were transitions.
TMidasOnline()
default constructor is private for singleton classes
std::string fExptname
experiment name, blank if only one experiment defined in exptab
Definition: TMidasOnline.h:56
TransitionHandler fPauseHandler
Definition: TMidasOnline.h:62
void deleteEventRequest(int requestId)
Delete data request.
TransitionHandler fStartHandler
Definition: TMidasOnline.h:60
bool sleep(int mdelay)
Sleep while checking for and answering MIDAS RPC requests (run transitions, etc)
int disconnect()
Disconnect from MIDAS.
TransitionHandler fStopHandler
Definition: TMidasOnline.h:61
TransitionHandler fResumeHandler
Definition: TMidasOnline.h:63
static TMidasOnline * instance()
EventRequest * fEventRequests
Definition: TMidasOnline.h:65
int getBufferLevel()
Get buffer level (ie the number of bytes in buffer)
int connect(const char *hostname, const char *exptname, const char *progname)
Connect to MIDAS experiment.
HNDLE fDB
ODB handle.
Definition: TMidasOnline.h:58
void setTransitionHandlers(TransitionHandler start, TransitionHandler stop, TransitionHandler pause, TransitionHandler resume)
Specify user handlers for run transitions.
virtual ~TMidasOnline()
destructor is private for singleton classes
int getBufferSize()
Get buffer size.
int eventRequest(const char *bufferName, int eventId, int triggerMask, int samplingType, bool poll=false)
Request data for delivery via callback (setEventHandler) or by polling (via receiveEvent)
EventHandler fEventHandler
Definition: TMidasOnline.h:66
static TMidasOnline * gfMidas
Definition: TMidasOnline.h:73
std::string fHostname
hostname where the mserver is running, blank if using shared memory
Definition: TMidasOnline.h:55
bool poll(int mdelay)
Check for all MIDAS events (new data events, run transitions)
size_t EXPRT strlcpy(char *dst, const char *src, size_t size)
Definition: strlcpy.cxx:39
Request events from online shared memory data buffer.
Definition: TMidasOnline.h:22
int fTriggerMask
request trigger mask
Definition: TMidasOnline.h:28
int fRequestId
request ID assigned by midas
Definition: TMidasOnline.h:30
int fEventId
request event ID
Definition: TMidasOnline.h:27
std::string fBufferName
name of the midas data buffer, e.g. "SYSTEM"
Definition: TMidasOnline.h:25
EventRequest * fNext
(internal use) list of all requests
Definition: TMidasOnline.h:24
HNDLE fBufferHandle
buffer handle from bm_open_buffer()
Definition: TMidasOnline.h:26
int fSamplingType
sampling type
Definition: TMidasOnline.h:29