ISIS Logo
PIXELMAN
EPICS plugin for Pixelman
pixelmanDriver.cpp
Go to the documentation of this file.
1 
4 #include <stddef.h>
5 #include <stdlib.h>
6 #include <stddef.h>
7 #include <cstring>
8 #include <string>
9 #include <stdio.h>
10 #include <stdint.h>
11 #include <map>
12 #include <sstream>
13 #include <fstream>
14 #include <algorithm>
15 
16 #include <stdexcept>
17 #include <iostream>
18 
19 #ifdef _WIN32
20 #include <windows.h>
21 #include <shlobj.h>
22 #include <io.h>
23 #include <process.h>
24 #include "Win32Exceptions.h"
25 #else
26 #include <unistd.h>
27 static void registerStructuredExceptionHandler() { }
28 static unsigned GetCurrentThreadId()
29 {
30  return 0;
31 }
32 #endif /* _WIN32 */
33 
34 #include "registryFunction.h"
35 #include "epicsThread.h"
36 #include "epicsExit.h"
37 #include "epicsStdio.h"
38 #include "dbStaticLib.h"
39 #include "subRecord.h"
40 #include "dbAccess.h"
41 #include "asDbLib.h"
42 #include "iocInit.h"
43 #include "iocsh.h"
44 
45 #include <epicsTypes.h>
46 #include <epicsTime.h>
47 #include <epicsThread.h>
48 #include <epicsString.h>
49 #include <epicsTimer.h>
50 #include <epicsMutex.h>
51 #include <epicsEvent.h>
52 #include <epicsMessageQueue.h>
53 #include <iocsh.h>
54 #include <errlog.h>
55 
56 #include <macLib.h>
57 #include <epicsGuard.h>
58 
59 // this should match DLL name (i.e. epics.dll)
60 #define PLUGIN_NAME "epics"
61 
62 #include "mpxpluginmgrapi.h"
63 
64 #include "pixelmanDriver.h"
65 
66 #include <epicsExport.h>
67 
68 static pixelmanDriver* g_epics = NULL;
69 
70 static void debugOutput(const char* msg)
71 {
72  //OutputDebugString(msg);
73 }
74 
75 static void epicsHelloWorldMenuItemFunc(MENUFUNCPAR par)
76 {
77 // MessageBox(NULL,"EPICS Hello world","EPICS Hello world",MB_OK);
78 }
79 
80 static void epicsFunc(void* in, void* out)
81 {
82  struct InParamStucture
83  {
84  u32 A; // first input parameter
85  double B[2]; // second
86  char C; // third
87  };
88  // Retype inputs to simplyfy access to each input parameter:
89  InParamStucture *par= (InParamStucture*)in;
90  char message[256];
91  sprintf(message,"Hello World\r(Inputs: %d,%lg,%lg,%c)",par->A,par->B[0],par->B[1],par->C);
92 // int ok=MessageBox(NULL,message,"Hello World",MB_OK);
93 // *((double*)out)=ok; // Set output to some value
94 }
95 
96 #if 0
97 // Description of parameters of HelloWorldFunc function.
98 static ExtFunctionInfo epicsFuncInfo={
99  epicsFunc, // Pointer to function performing an action
100  3, // Number of input parameters
101  1, // Number of output parameters
102  { // List of input parameter descriptions
103  {TYPE_U32,1,"A"}, // = first input parameter is 32 bit unsigned integer
104  {TYPE_DOUBLE,2,"B"}, // = second input parameter is array of two doubles
105  {TYPE_BYTE,1,"C"} // = third input parameter is 8 bit byte
106  },
107  { // List of output parameter descriptions
108  {TYPE_DOUBLE,1,"Out"} // = output is one double value
109  },
110  "HelloWorld", // Name of the plugin = name of this plugin
111  "Hello world", // Name of registered function = can differ to "C" name
112  "Function will show message box with gretings", // Description of function purpose
113  0 // flags = flags
114 };
115 #endif
116 
117 extern const FuncTableType *mgr;
118 
119 // pixelman exiting
120 static void mpxmgrExitCB(CBPARAM par, INTPTR userData)
121 {
122 // MessageBox(NULL,"pixelman exit cb","pixelman exit cb",MB_OK);
123 // epicsExit(0);
124 }
125 
126 // all plugins loaded
127 static void mpxmgrStartCB(CBPARAM par, INTPTR userData)
128 {
129 // MessageBox(NULL,"pixelman started cb","pixelman started cb",MB_OK);
130 }
131 
132 static void mpxmgrFrameNewCB(CBPARAM par, INTPTR userData)
133 {
134  FRAMEID frameID = par;
135 // MessageBox(NULL,"pixelman started cb","pixelman started cb",MB_OK);
136 }
137 
138 // acquisition started
139 static void mpxctrlAcqStartCB(CBPARAM par, INTPTR userData)
140 {
141  if (g_epics != NULL)
142  {
143  g_epics->pixelmanEventCB(pixelmanDriver::MPX_ACQSTART, userData);
144  }
145 // MessageBox(NULL,"acq start cb","acq start cb",MB_OK);
146 }
147 
148 static void mpxctrlAcqPreStartCB(CBPARAM par, INTPTR userData)
149 {
150  if (g_epics != NULL)
151  {
152  g_epics->pixelmanEventCB(pixelmanDriver::MPX_ACQPRESTART, userData);
153  }
154 // MessageBox(NULL,"acq start cb","acq start cb",MB_OK);
155 }
156 
157 // single acquisition completed
158 static void mpxctrlSingleAcqCompletedCB(CBPARAM par, INTPTR userData)
159 {
160  if (g_epics != NULL)
161  {
162  g_epics->pixelmanEventCB(pixelmanDriver::MPX_SINGLEACQCOMP, userData);
163  }
164 // MessageBox(NULL,"single acq complete cb","single acq complete cb",MB_OK);
165 }
166 
167 // series acquisition completed
168 static void mpxctrlSeriesAcqCompletedCB(CBPARAM par, INTPTR userData)
169 {
170  if (g_epics != NULL)
171  {
172  g_epics->pixelmanEventCB(pixelmanDriver::MPX_SERIESACQCOMP, userData);
173  }
174 // MessageBox(NULL,"series acq complete cb","series acq complete cb",MB_OK);
175 }
176 
177 static int myLog(const errlogSevEnum severity, const char *pformat, ... )
178 {
179  int n;
180  va_list pvar;
181  va_start(pvar, pformat);
182  n = errlogSevVprintf(severity, pformat, pvar);
183  mgr->logMsgV(PLUGIN_NAME, pformat, 0, pvar);
184  va_end(pvar);
185  return n;
186 }
187 
188 // info or error message
189 static void mpxctrlMessageCB(CBPARAM par, INTPTR userData)
190 {
191  const char* msg = NULL;
192  int msgType, status;
193  if (mgr != NULL && g_epics != NULL)
194  {
195  status = mgr->mpxCtrlGetInfoMsg(g_epics->getDevId(), &msgType, &msg);
196  if (status == MPXERR_NOERROR && msg != NULL)
197  {
198  debugOutput(msg);
199  debugOutput("\n");
200  if (msgType != MPXERR_ACQABORTED)
201  {
202  if (msgType < 0)
203  {
204  errlogSevPrintf(errlogMajor, "%s (%d)\n", msg, msgType);
205  }
206  else
207  {
208  errlogSevPrintf(errlogInfo, "%s (%d)\n", msg, msgType);
209  }
210  }
211  }
212  }
213 }
214 
215 extern "C" {
216 
220 static int pixelmanConfigure(const char *portName, const char* devName)
221 {
222  registerStructuredExceptionHandler();
223  try
224  {
225  g_epics = new pixelmanDriver(portName, devName);
226  return(asynSuccess);
227  }
228  catch(const std::exception& ex)
229  {
230  errlogSevPrintf(errlogMajor, "pixelmanConfigure failed: %s", ex.what());
231  return(asynError);
232  }
233 }
234 
235 // EPICS iocsh shell commands
236 
237 static const iocshArg initArg0 = { "portName", iocshArgString};
238 static const iocshArg initArg1 = { "devName", iocshArgString};
239 
240 static const iocshArg * const initArgs[] = { &initArg0, &initArg1 };
241 
242 static const iocshFuncDef initFuncDef = {"pixelmanConfigure", sizeof(initArgs) / sizeof(iocshArg*), initArgs};
243 
244 static void initCallFunc(const iocshArgBuf *args)
245 {
246  pixelmanConfigure(args[0].sval, args[1].sval);
247 }
248 
249 static void pixelmanRegister(void)
250 {
251  iocshRegister(&initFuncDef, initCallFunc);
252 }
253 
254 epicsExportRegistrar(pixelmanRegister);
255 
256 }
257 
258 extern "C" int pixelman_registerRecordDeviceDriver(struct dbBase *pdbbase);
259 
260 #define DBD_FILE "../dbd/pixelman.dbd"
261 #define DB_FILE "../db/pixelman.db"
262 
263 #ifdef _WIN32
264 PLUGIN_INIT_EXTENDED
265 #else
266 PLUGIN_INIT
267 #endif
268 {
269 // mgr->logErrorStr(Module, "Error in plugin function: Please call mom (tel. %d)", 0, MomTelNum);
270 // mgr->addMenuItem("EPICS Hello world", "Tests", epicsHelloWorldMenuItemFunc, 0, NULL, 0);
271 // mgr->addFuncItem(&epicsFuncInfo);
272 // DebugBreak();
273 
274  mgr->logShowWindow(1); // for debugging
275 
276 // ExtCBEventInfo epics_event;
277 // ITEMID id;
278 // strncpy(epics_event.pluginName, PLUGIN_NAME, NAME_LENGTH);
279 // strncpy(epics_event.cbEventName, "EPICSEvent", NAME_LENGTH);
280 // strncpy(epics_event.description, "An EPICS event", DESC_LENGTH);
281 // mgr->addCBEvent(&epics_event, &id);
282 
283  // set up output redirection
284  if (freopen("pixelman_iocout.log", "wt", stdout) == NULL)
285  {
286  mgr->logMsg(PLUGIN_NAME, "Error redirecting stdout to pixelman_iocout.log", 0);
287  }
288  if (freopen("pixelman_iocerr.log", "wt", stderr) == NULL)
289  {
290  mgr->logMsg(PLUGIN_NAME, "Error redirecting stderr to pixelman_iocerr.log", 0);
291  }
292  if (setvbuf(stdout, NULL, _IONBF, 0) != 0)
293  {
294  mgr->logMsg(PLUGIN_NAME, "Error making stdout unbuffered", 0);
295  }
296  if (setvbuf(stderr, NULL, _IONBF, 0) != 0)
297  {
298  mgr->logMsg(PLUGIN_NAME, "Error making stderr unbuffered", 0);
299  }
300 
301  if (mgr->registerCallback(MPXCTRL_NAME, MPXCTRL_CB_ACQPRESTART, mpxctrlAcqPreStartCB, NULL) != 0)
302  {
303  mgr->logMsg(PLUGIN_NAME, "Error registering prestart callback", 0);
304  }
305  mgr->registerCallback(MPXCTRL_NAME, MPXCTRL_CB_ACQSERCOMPL, mpxctrlSeriesAcqCompletedCB, NULL);
306  mgr->registerCallback(MPXCTRL_NAME, MPXCTRL_CB_INFOMSG, mpxctrlMessageCB, NULL);
307  mgr->registerCallback(MPXCTRL_NAME, MPXCTRL_CB_ACQSTART, mpxctrlAcqStartCB, NULL);
308 
309 // mgr->registerCallback(MPXMGR_NAME, MPXMGR_CB_EXIT, mpxmgrExitCB, NULL);
310 // mgr->registerCallback(MPXMGR_NAME, MPXMGR_CB_START, mpxmgrStartCB, NULL);
311 // mgr->registerCallback(MPXMGR_NAME, MPXMGR_CB_FRAME_NEW, mpxmgrFrameNewCB, NULL);
312 // mgr->registerCallback(MPXCTRL_NAME, MPXCTRL_CB_ACQCOMPL, mpxctrlSingleAcqCompletedCB, NULL);
313 
314 
315  const char* PIXELMANDIR = getenv("PIXELMANDIR");
316  if (PIXELMANDIR == NULL)
317  {
318  PIXELMANDIR = "<UNKNOWN>";
319  }
320  mgr->logMsg(PLUGIN_NAME, (std::string("Camera directory: ") + PIXELMANDIR).c_str(), 0);
321  if (false)
322  {
323  char macros[256];
324  const char* PVPREFIX = getenv("MYPVPREFIX");
325  if (PVPREFIX == NULL)
326  {
327  PVPREFIX = "test:";
328  }
329  epicsSnprintf(macros, sizeof(macros), "P=%s,Q=PIXELMAN:", PVPREFIX);
330  mgr->logMsg(PLUGIN_NAME, "Starting EPICS IOC", 0);
331  if (dbLoadDatabase(DBD_FILE, NULL, NULL))
332  {
333  mgr->logMsg(PLUGIN_NAME, "Error in plugin function: cannot load DBD file", 0);
334  return -1;
335  }
336 
337  pixelman_registerRecordDeviceDriver(pdbbase);
338 
339  pixelmanConfigure("MCP", "dummy");
340 // pixelmanConfigure("MCP", "BeARQuT");
341 
342  if (dbLoadRecords(DB_FILE, macros))
343  {
344  mgr->logMsg(PLUGIN_NAME, "Error in plugin function: cannot load DB file", 0);
345  return -1;
346  }
347  iocInit();
348  }
349  else
350  {
351  mgr->logMsg(PLUGIN_NAME, "Starting EPICS IOC - see pixelman_iocout.log and pixelman_iocerr.log", 0);
352  const char* PVPREFIX = getenv("MYPVPREFIX");
353  mgr->logMsg(PLUGIN_NAME, "PV prefix P=%s", 0, (PVPREFIX != NULL ? PVPREFIX : ""));
354  const char* EPICSPIXELMAN = getenv("EPICSPIXELMAN");
355  if (EPICSPIXELMAN == NULL)
356  {
357  EPICSPIXELMAN = ".";
358  }
359  std::string pix_cmd = std::string(EPICSPIXELMAN) + std::string("/pixelman.cmd");
360  mgr->logMsg(PLUGIN_NAME, (std::string("Loading ") + pix_cmd).c_str(), 0);
361  if (iocsh(pix_cmd.c_str()))
362  {
363  mgr->logMsg(PLUGIN_NAME, "Error in plugin function: cannot load pixelman.cmd", 0);
364  return -1;
365  }
366  }
367  return 0;
368 }
369 
370 static const char *driverName = "pixelmanDriver";
371 
372 pixelmanDriver::pixelmanDriver(const char *portName, const char* devName)
373  : asynPortDriver(portName,
374  0, /* maxAddr */
375  NUM_MCP_PARAMS,
376  asynInt32Mask | asynFloat64Mask | asynOctetMask | asynDrvUserMask, /* Interface mask */
377  asynInt32Mask | asynFloat64Mask | asynOctetMask, /* Interrupt mask */
378  ASYN_CANBLOCK, /* asynFlags. This driver can block but it is not multi-device */
379  1, /* Autoconnect */
380  0, /* Default priority */
381  0), /* Default stack size*/
382  m_acqRunning(false), m_cmd_running(false), m_start_running(false),
383  m_abort_running(false), m_devId(INVALID_DEVID_VALUE), m_autoRestart(0),
384  m_autoRestartDelay(0.0), m_eventCBQueue(40, sizeof(eventCBInfo)), m_runEndQueue(40, sizeof(RunEndInfo))
385 {
386 
387  const char *functionName = "pixelmanDriver";
388  std::ostringstream pix_items;
389 
390  createParam(P_acquireString, asynParamInt32, &P_acquire);
391  createParam(P_acqAbortString, asynParamInt32, &P_acqAbort);
392  createParam(P_acqStartString, asynParamInt32, &P_acqStart);
393  createParam(P_trigAcqStartString, asynParamInt32, &P_trigAcqStart);
394  createParam(P_trigAcqStopString, asynParamInt32, &P_trigAcqStop);
395  createParam(P_numberOfAcqString, asynParamInt32, &P_numberOfAcq);
396  createParam(P_timeOfEachAcqString, asynParamFloat64, &P_timeOfEachAcq);
397  createParam(P_fileFlagsString, asynParamInt32, &P_fileFlags);
398 // createParam(P_fileNameString, asynParamOctet, &P_fileName);
399  createParam(P_devIdString, asynParamInt32, &P_devId);
400  createParam(P_acqSActiveString, asynParamInt32, &P_acqSActive);
401  createParam(P_acqActiveString, asynParamInt32, &P_acqActive);
402  createParam(P_acqTypeString, asynParamInt32, &P_acqType);
403  createParam(P_acqTypeReqString, asynParamInt32, &P_acqTypeReq);
404  createParam(P_frameFilledString, asynParamInt32, &P_frameFilled);
405  createParam(P_acqTotalCountString, asynParamInt32, &P_acqTotalCount);
406  createParam(P_acqNumberString, asynParamInt32, &P_acqNumber);
407  createParam(P_acqModeString, asynParamInt32, &P_acqMode);
408  createParam(P_burstModeString, asynParamInt32, &P_burstMode);
409  createParam(P_extShutModeString, asynParamInt32, &P_extShutMode);
410  createParam(P_hwTimerString, asynParamInt32, &P_hwTimer);
411  createParam(P_saveConfigString, asynParamOctet, &P_saveConfig);
412  createParam(P_loadConfigString, asynParamOctet, &P_loadConfig);
413  createParam(P_saveDefConfigString, asynParamInt32, &P_saveDefConfig);
414  createParam(P_loadDefConfigString, asynParamInt32, &P_loadDefConfig);
415  createParam(P_acqHangString, asynParamInt32, &P_acqHang);
416  createParam(P_hangTimeString, asynParamFloat64, &P_hangTime);
417  createParam(P_autoRestartString, asynParamInt32, &P_autoRestart);
418  createParam(P_autoRestartDelayString, asynParamFloat64, &P_autoRestartDelay);
419  createParam(P_setPixelModeString, asynParamInt32, &P_setPixelMode);
420 
421  setIntegerParam(P_acquire, 0);
422  setIntegerParam(P_acqStart, 0);
423  setIntegerParam(P_acqAbort, 0);
424  setIntegerParam(P_acqSActive, 0);
425  setIntegerParam(P_acqActive, 0);
426  setIntegerParam(P_autoRestart, 0);
427 
428  int count = 0;
429  char name[NAME_LENGTH];
430  memset(name, 0, NAME_LENGTH);
431  DevInfo devInfo;
432  DEVID devId = INVALID_DEVID_VALUE;
433  if ( mgr != NULL && mgr->mpxCtrlGetFirstMpx(&devId, &count) == 0 )
434  {
435  errlogSevPrintf(errlogInfo, "There are %d devices available\n", count);
436  if (mgr->mpxCtrlGetCustomName(m_devId, name) == MPXERR_NOERROR)
437  {
438  name[NAME_LENGTH-1] = '\0';
439  }
440  else
441  {
442  name[0] = '\0';
443  }
444  mgr->mpxCtrlGetDevInfo(devId, &devInfo);
445  errlogSevPrintf(errlogInfo, "... devId %d name \"%s\" iface \"%s\" chipID \"%s\"\n", devId, name, devInfo.ifaceName, devInfo.chipboardID);
446  if (strcmp(devName, name) == 0 || strcmp(devName, devInfo.ifaceName) == 0)
447  {
448  errlogSevPrintf(errlogInfo, "Found device \"%s\" (devId %d)\n", devName, devId);
449  m_devId = devId;
450  memcpy(&m_devInfo, &devInfo, sizeof(DevInfo));
451  printDevInfo(&m_devInfo, pix_items);
452  }
453  while(mgr->mpxCtrlGetNextMpx(&devId) == 0)
454  {
455  mgr->mpxCtrlGetCustomName(devId, name);
456  mgr->mpxCtrlGetDevInfo(devId, &devInfo);
457  errlogSevPrintf(errlogInfo, "... devId %d name \"%s\" iface \"%s\" chipID \"%s\"\n", devId, name, devInfo.ifaceName, devInfo.chipboardID);
458  if (strcmp(devName, name) == 0 || strcmp(devName, devInfo.ifaceName) == 0)
459  {
460  errlogSevPrintf(errlogInfo, "Found device \"%s\" (devId %d)\n", devName, devId);
461  m_devId = devId;
462  memcpy(&m_devInfo, &devInfo, sizeof(DevInfo));
463  printDevInfo(&m_devInfo, pix_items);
464  }
465  }
466  }
467  setIntegerParam(P_devId, m_devId);
468  if (getDevId() == INVALID_DEVID_VALUE)
469  {
470  errlogSevPrintf(errlogMajor, "Device \"%s\" not found\n", devName);
471  }
472 
473  if (mgr != NULL)
474  {
475  getHwInfo(pix_items);
476  }
477 
478  createParam(P_dataFileNameString, asynParamOctet, &P_dataFileName);
479  m_paramInfo[P_dataFileName] = "DataFileName";
480 // m_paramInfo[P_dataFileName] = "Data file name";
481  createParam(P_shutrCLKShiftString, asynParamInt32, &P_shutrCLKShift);
482  m_paramInfo[P_shutrCLKShift] = "ShutrCLKShift";
483  createParam(P_tpxCubeBinString, asynParamFloat64, &P_tpxCubeBin);
484  m_paramInfo[P_tpxCubeBin] = "TpxCubeBin";
485  createParam(P_dataAcqModeString, asynParamInt32, &P_dataAcqMode);
486  m_paramInfo[P_dataAcqMode] = "AcqMode";
487  createParam(P_fileIndexString, asynParamInt32, &P_fileIndex);
488  m_paramInfo[P_fileIndex] = "FileIndexToSaveDataInto";
489 // m_paramInfo[P_fileIndex] = "Data file count";
490  createParam(P_saveRawDataString, asynParamInt32, &P_saveRawData);
491  m_paramInfo[P_saveRawData] = "SaveRawData";
492  createParam(P_nShuttersPerBurstString, asynParamInt32, &P_nShuttersPerBurst);
493  m_paramInfo[P_nShuttersPerBurst] = "TriggersPerBurst";
494  createParam(P_nTrigsBurstRefreshString, asynParamInt32, &P_nTrigsBurstRefresh);
495  m_paramInfo[P_nTrigsBurstRefresh] = "BurstsToTake";
496  createParam(P_cameraStatusString, asynParamInt32, &P_cameraStatus);
497  m_paramInfo[P_cameraStatus] = "CurrentStatus";
498  createParam(P_nTrigSavSubString, asynParamInt32, &P_nTrigSavSub);
499  m_paramInfo[P_nTrigSavSub] = "NtrigBeforeSavingSubImgSpectra";
500 
501  if (mgr != NULL)
502  {
503  ITEMID cbEventID;
504  ExtCBEventInfo extCBEventInfo;
505  if (mgr->getRegFirstCBEvent(&cbEventID, &extCBEventInfo) == 0)
506  {
507  pix_items << "Plugin " << extCBEventInfo.pluginName << " offers event callback " << extCBEventInfo.cbEventName << " (" << extCBEventInfo.description << ")" << std::endl;
508  while(mgr->getRegNextCBEvent(&cbEventID, &extCBEventInfo) == 0)
509  {
510  pix_items << "Plugin " << extCBEventInfo.pluginName << " offers event callback " << extCBEventInfo.cbEventName << " (" << extCBEventInfo.description << ")" << std::endl;
511  }
512  }
513  char name[MENU_LENGTH];
514  ITEMID itemID;
515  if (mgr->getFirstMenuItem(&itemID, name) == 0)
516  {
517  pix_items << "Menu item " << name << std::endl;
518  while(mgr->getNextMenuItem(&itemID, name) == 0)
519  {
520  pix_items << "Menu item " << name << std::endl;
521  }
522  }
523  ITEMID funcID;
524  ExtFunctionInfo funcInfo;
525  if (mgr->getRegFirstFunc(&funcID, &funcInfo) == 0)
526  {
527  pix_items << "Plugin " << funcInfo.pluginName << " offers function " << funcInfo.functionName << " (" << funcInfo.description << ")" << std::endl;
528  while(mgr->getRegNextFunc(&funcID, &funcInfo) == 0)
529  {
530  pix_items << "Plugin " << funcInfo.pluginName << " offers function " << funcInfo.functionName << " (" << funcInfo.description << ")" << std::endl;
531  for(int i=0; i<funcInfo.paramInCount; ++i)
532  {
533  pix_items << " arg_in[" << i << "] " << funcInfo.paramsInfoIn[i].description << std::endl;
534  }
535  for(int i=0; i<funcInfo.paramOutCount; ++i)
536  {
537  pix_items << " arg_out[" << i << "] " << funcInfo.paramsInfoOut[i].description << std::endl;
538  }
539  }
540  }
541  }
542 
543  try
544  {
545  std::fstream pfile("pixitems.txt", std::ios::out);
546  pfile << pix_items.str();
547  pfile.close();
548  }
549  catch(const std::exception& ex)
550  {
551  ;
552  }
553 
554  // Create the thread for background tasks (not used at present, could be used for I/O intr scanning)
555  if (epicsThreadCreate("pixelmanDriverPoller",
556  epicsThreadPriorityMedium,
557  epicsThreadGetStackSize(epicsThreadStackMedium),
558  (EPICSTHREADFUNC)pollerThreadC, this) == 0)
559  {
560  errlogSevPrintf(errlogMajor, "%s:%s: epicsThreadCreate failure\n", driverName, functionName);
561  return;
562  }
563  if (epicsThreadCreate("pixelmanDriverRestarter",
564  epicsThreadPriorityMedium,
565  epicsThreadGetStackSize(epicsThreadStackMedium),
566  (EPICSTHREADFUNC)pixelmanDriverRestarterC, this) == 0)
567  {
568  errlogSevPrintf(errlogMajor, "%s:%s: epicsThreadCreate failure\n", driverName, functionName);
569  return;
570  }
571  if (epicsThreadCreate("pixelmanEventCBProcess",
572  epicsThreadPriorityMedium,
573  epicsThreadGetStackSize(epicsThreadStackMedium),
574  (EPICSTHREADFUNC)pixelmanEventCBProcessC, this) == 0)
575  {
576  errlogSevPrintf(errlogMajor, "%s:%s: epicsThreadCreate failure\n", driverName, functionName);
577  return;
578  }
579  if (epicsThreadCreate("pixelmanDriverSaver",
580  epicsThreadPriorityMedium,
581  epicsThreadGetStackSize(epicsThreadStackMedium),
582  (EPICSTHREADFUNC)saverThreadC, this) == 0)
583  {
584  errlogSevPrintf(errlogMajor, "%s:%s: epicsThreadCreate failure\n", driverName, functionName);
585  return;
586  }
587 }
588 
589 int pixelmanDriver::getDevId() const
590 {
591  return m_devId;
592 }
593 
594 void pixelmanDriver::pixelmanDriverRestarterC(void* arg)
595 {
596  pixelmanDriver* driver = (pixelmanDriver*)arg;
597  driver->pixelmanDriverRestarter();
598 }
599 
600 static void myExitFunc(const char* msg)
601 {
602 // errlogSevPrintf(errlogMajor, msg);
603 // errlogFlush();
604 // epicsThreadSleep(5.0);
605 // epicsExit(1);
606 #if defined(_DEBUG)
607  DebugBreak();
608 #else
609  _exit(0);
610 #endif /* _DEBUG */
611 }
612 
613 void pixelmanDriver::pixelmanDriverRestarter()
614 {
615  static const char* functionName = "pixelmanDriverRestarter";
616  registerStructuredExceptionHandler();
617  double delay = 1.0;
618  double tdiff;
619  epicsTimeStamp now;
620  while(true)
621  {
622  epicsThreadSleep(delay);
623  if (m_autoRestart != 0)
624  {
625  epicsTimeGetCurrent(&now);
626  if (m_cmd_running)
627  {
628  tdiff = epicsTimeDiffInSeconds(&now, &m_cmd_time);
629  if (tdiff > m_autoRestartDelay)
630  {
631  myExitFunc("pixelmanDriverRestarter: exiting (cmd)");
632  }
633  }
634  if (m_abort_running)
635  {
636  tdiff = epicsTimeDiffInSeconds(&now, &m_abort_time);
637  if (tdiff > m_autoRestartDelay)
638  {
639  myExitFunc("pixelmanDriverRestarter: exiting (abort)");
640  }
641  }
642  }
643  }
644 }
645 
646 
647 void pixelmanDriver::pollerThreadC(void* arg)
648 {
649  pixelmanDriver* driver = (pixelmanDriver*)arg;
650  driver->pollerThread();
651 }
652 
653 void pixelmanDriver::saverThreadC(void* arg)
654 {
655  pixelmanDriver* driver = (pixelmanDriver*)arg;
656  driver->saverThread();
657 }
658 
659 void pixelmanDriver::pollerThread()
660 {
661  static const char* functionName = "pollerThread";
662  double delay = 0.5;
663  int acqNumber = 0, acqTotalCount = 0, acqType = 0, acqMode = 0, hwTimer = 0;
664  static u32 lastFrameFilled = 0;
665  u32 frameFilled = 0;
666  DEVID devId;
667  epicsTimeStamp stop_begin, now;
668  int cameraStatus, lastCameraStatus = STATUS_IDLE;
669  int fileIndex, lastFileIndex = -1;
670  bool file_to_save = false;
671 
672  registerStructuredExceptionHandler();
673  epicsTimeGetCurrent(&stop_begin);
674  while(mgr != NULL)
675  {
676  epicsThreadSleep(delay);
677  devId = getDevId();
678  lock();
679  mgr->mpxCtrlGetAcqInfo(devId, &acqNumber, &acqTotalCount, &acqType, &frameFilled);
680  mgr->mpxCtrlGetAcqMode(devId, &acqMode); // this return full mode, so need to maks off burst etc.
681  mgr->mpxCtrlGetHwTimer(devId, &hwTimer);
682  getAllHwItems();
683  getIntegerParam(P_autoRestart, &m_autoRestart);
684  getDoubleParam(P_autoRestartDelay, &m_autoRestartDelay);
685  getIntegerParam(P_cameraStatus, &cameraStatus);
686  getIntegerParam(P_fileIndex, &fileIndex);
687  if (lastFileIndex == -1)
688  {
689  lastFileIndex = fileIndex;
690  }
691  setIntegerParam(P_acqType, acqType);
692  setIntegerParam(P_frameFilled, frameFilled);
693  setIntegerParam(P_acqTotalCount, acqTotalCount);
694  setIntegerParam(P_acqNumber, acqNumber);
695  setIntegerParam(P_acqMode, (acqMode & 0xff) );
696  setIntegerParam(P_burstMode, ((acqMode & ACQMODE_BURST) != 0) );
697  setIntegerParam(P_extShutMode, ((acqMode & ACQMODE_EXTSHUTTER) != 0) );
698  setIntegerParam(P_hwTimer, hwTimer);
699 
700  epicsTimeGetCurrent(&now);
701  double tdiff = epicsTimeDiffInSeconds(&now, &stop_begin);
702  bool acqHang = false;
703  if (cameraStatus == STATUS_ACQUIRING) // once we are acquiring, we'll have something to save later
704  {
705  file_to_save = true;
706  }
707 
708  if (m_acqRunning)
709  {
710  setIntegerParam(P_acquire, 1);
711  setIntegerParam(P_acqActive, 1);
712  if (frameFilled == lastFrameFilled)
713  {
714  if (tdiff > m_autoRestartDelay)
715  {
716  acqHang = true;
717  if (m_autoRestart != 0)
718  {
719  myExitFunc("pollerThread: exiting");
720  }
721  }
722  }
723  else
724  {
725  lastFrameFilled = frameFilled;
726  epicsTimeGetCurrent(&stop_begin);
727  tdiff = 0.0;
728  }
729  }
730  else
731  {
732  setIntegerParam(P_acquire, 0);
733  setIntegerParam(P_acqActive, 0);
734  epicsTimeGetCurrent(&stop_begin);
735  tdiff = 0.0;
736  }
737  setDoubleParam(P_hangTime, tdiff);
738  if (acqHang)
739  {
740  setIntegerParam(P_acqHang, 1);
741  }
742  else
743  {
744  setIntegerParam(P_acqHang, 0);
745  }
746  if (file_to_save && fileIndex > lastFileIndex)
747  {
748  saveFinished(lastFileIndex);
749  file_to_save = false;
750  }
751  lastCameraStatus = cameraStatus;
752  lastFileIndex = fileIndex;
753  callParamCallbacks();
754  unlock();
755  }
756 }
757 
758 void pixelmanDriver::saveFinished(int fileIndex)
759 {
760  RunEndInfo info;
761  getStringParam(P_dataFileName, sizeof(info.fileName), info.fileName);
762  info.fileIndex = fileIndex;
763  m_runEndQueue.send(&info, sizeof(RunEndInfo), 1.0);
764 }
765 
766 static std::string quote(const std::string& str)
767 {
768 // return std::string("\"") + str + "\"";
769  return str;
770 }
771 
772 void pixelmanDriver::saverThread()
773 {
774  RunEndInfo info;
775  const char* end_of_run = getenv("PIXELMANENDCMD");
776  const char* comspec = getenv("COMSPEC");
777  const char* pixelmandir = getenv("PIXELMANDIR");
778  epicsThreadSleep(1.0); // wait for constructor to finish
779  while( m_runEndQueue.receive(&info, sizeof(RunEndInfo)) > 0 )
780  {
781  errlogSevPrintf(errlogInfo, "Saved \"%s\" index %d\n", info.fileName, info.fileIndex);
782  mgr->logMsg(PLUGIN_NAME, "Saved \"%s\" index %d", 0, info.fileName, info.fileIndex);
783  if (end_of_run != NULL)
784  {
785  errlogSevPrintf(errlogInfo, "Executing \"%s\"\n", end_of_run);
786  mgr->logMsg(PLUGIN_NAME, "Executing \"%s\"", 0, end_of_run);
787  char cFileIndex[32];
788  sprintf(cFileIndex, "%d", info.fileIndex);
789 #ifdef _WIN32
790  if (_spawnl(_P_WAIT, comspec, comspec, "/c", quote(end_of_run).c_str(), quote(pixelmandir).c_str(), quote(info.fileName).c_str(), cFileIndex, NULL) != 0)
791 #else
792  // do something on linux
793 #endif
794  {
795  mgr->logMsg(PLUGIN_NAME, "ERROR executing \"%s\"", 0, end_of_run);
796  }
797  }
798  }
799 }
800 
801 #define THROW_IF_ACQ_ACTIVE \
802  if (m_acqRunning) \
803  { \
804  std::ostringstream acq_active_mess; \
805  acq_active_mess << functionName << ": cannot set " << paramName << " when acq active"; \
806  throw std::runtime_error(acq_active_mess.str().c_str()); \
807  }
808 
809 #define THROW_IF_ACQ_NOT_ACTIVE \
810  if (!m_acqRunning) \
811  { \
812  std::ostringstream acq_not_active_mess; \
813  acq_not_active_mess << functionName << ": cannot set " << paramName << " when acq is not active"; \
814  throw std::runtime_error(acq_not_active_mess.str().c_str()); \
815  }
816 
817 asynStatus pixelmanDriver::writeFloat64(asynUser *pasynUser, epicsFloat64 value)
818 {
819  int function = pasynUser->reason;
820  const char* functionName = "writeFloat64";
821  asynStatus status = asynSuccess;
822  const char *paramName = NULL;
823  getParamName(function, &paramName);
824  DEVID devId = getDevId();
825  registerStructuredExceptionHandler();
826  debugOutput(paramName);
827  debugOutput("\n");
828  cmdStart();
829  try
830  {
831  if (mgr == NULL)
832  {
833  throw std::runtime_error("pixelman not initialised");
834  }
835  else if (function == P_tpxCubeBin)
836  {
837  THROW_IF_ACQ_ACTIVE;
838  setDoubleParam(function, value);
839  setHwItem(m_paramInfo[function], function);
840  }
841  asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
842  "%s:%s: function=%d, name=%s, value=%f\n",
843  driverName, functionName, function, paramName, value);
844  status = asynSuccess;
845  }
846  catch(const std::exception& ex)
847  {
848  epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
849  "%s:%s: status=%d, function=%d, name=%s, value=%f, error=%s",
850  driverName, functionName, status, function, paramName, value, ex.what());
851  status = asynError;
852  }
853  if (status == asynSuccess)
854  {
855  status = asynPortDriver::writeFloat64(pasynUser, value);
856  }
857  cmdEnd();
858  return status;
859 }
860 
861 asynStatus pixelmanDriver::writeInt32(asynUser *pasynUser, epicsInt32 value)
862 {
863  int function = pasynUser->reason;
864  int acqMode;
865  const char* functionName = "writeInt32";
866  asynStatus status = asynSuccess;
867  const char *paramName = NULL;
868  getParamName(function, &paramName);
869  DEVID devId = getDevId();
870  registerStructuredExceptionHandler();
871  debugOutput(paramName);
872  debugOutput("\n");
873  cmdStart();
874  try
875  {
876  if (mgr == NULL)
877  {
878  throw std::runtime_error("pixelman not initialised");
879  }
880  else if ( function == P_acqStart || (function == P_acquire && value == 1) )
881  {
882  THROW_IF_ACQ_ACTIVE;
883  setIntegerParam(P_acquire, 1);
884  int acqTypeReq;
885  getIntegerParam(P_acqTypeReq, &acqTypeReq);
886  AcquisitionThreadArgs* args = createAcquisitionThreadArgs(acqTypeReq);
887  if (epicsThreadCreate("pixelmanAcquisitionStart",
888  epicsThreadPriorityMedium,
889  epicsThreadGetStackSize(epicsThreadStackMedium),
890  (EPICSTHREADFUNC)acquisitionThreadC, args) == 0)
891  {
892  errlogSevPrintf(errlogMajor, "%s:%s: epicsThreadCreate failure\n", driverName, functionName);
893  }
894  epicsThreadSleep(0.1);
895  }
896  else if (function == P_acqAbort || (function == P_acquire && value == 0) )
897  {
898  THROW_IF_ACQ_NOT_ACTIVE;
899  AcquisitionThreadArgs* args = createAcquisitionThreadArgs(ACQ_ABORT);
900 // if (epicsThreadCreate("pixelmanAcquisitionAbort",
901 // epicsThreadPriorityMedium,
902 // epicsThreadGetStackSize(epicsThreadStackMedium),
903 // (EPICSTHREADFUNC)acquisitionThreadC, args) == 0)
904 // {
905 // errlogSevPrintf(errlogMajor, "%s:%s: epicsThreadCreate failure\n", driverName, functionName);
906 // }
907 // epicsThreadSleep(0.1);
908  acquisitionThreadC(args);
909  setIntegerParam(P_acquire, 0);
910  }
911  else if (function == P_trigAcqStart)
912  {
913  THROW_IF_ACQ_NOT_ACTIVE;
914  mgr->mpxCtrlTrigger(devId, TRIGGER_ACQSTART);
915  mgr->logMsg(PLUGIN_NAME, "Acquisition Start triggered", 0);
916  }
917  else if (function == P_trigAcqStop)
918  {
919  THROW_IF_ACQ_NOT_ACTIVE;
920  mgr->mpxCtrlTrigger(devId, TRIGGER_ACQSTOP);
921  mgr->logMsg(PLUGIN_NAME, "Acquisition Stop triggered", 0);
922  }
923  else if (function == P_acqMode)
924  {
925  THROW_IF_ACQ_ACTIVE;
926  mgr->mpxCtrlGetAcqMode(devId, &acqMode); // this return full mode, so need to maks off burst etc.
927  acqMode &= ~0xff;
928  acqMode |= value;
929  mgr->mpxCtrlSetAcqMode(devId, acqMode);
930  }
931  else if (function == P_burstMode)
932  {
933  THROW_IF_ACQ_ACTIVE;
934  mgr->mpxCtrlGetAcqMode(devId, &acqMode); // this return full mode, so need to maks off burst etc.
935  if (value != 0)
936  {
937  acqMode |= ACQMODE_BURST;
938  }
939  else
940  {
941  acqMode &= ~ACQMODE_BURST;
942  }
943  mgr->mpxCtrlSetAcqMode(devId, acqMode);
944  }
945  else if (function == P_extShutMode)
946  {
947  THROW_IF_ACQ_ACTIVE;
948  mgr->mpxCtrlGetAcqMode(devId, &acqMode); // this return full mode, so need to maks off burst etc.
949  if (value != 0)
950  {
951  acqMode |= ACQMODE_EXTSHUTTER;
952  }
953  else
954  {
955  acqMode &= ~ACQMODE_EXTSHUTTER;
956  }
957  mgr->mpxCtrlSetAcqMode(devId, acqMode);
958  }
959  else if (function == P_hwTimer)
960  {
961  THROW_IF_ACQ_ACTIVE;
962  mgr->mpxCtrlSetHwTimer(devId, value);
963  }
964  else if (function == P_saveDefConfig)
965  {
966  THROW_IF_ACQ_ACTIVE;
967  mgr->mpxCtrlSaveMpxCfgAsDefault(devId);
968  }
969  else if (function == P_loadDefConfig)
970  {
971  THROW_IF_ACQ_ACTIVE;
972  mgr->mpxCtrlLoadMpxCfg(devId, NULL);
973  }
974  else if (function == P_setPixelMode)
975  {
976  THROW_IF_ACQ_ACTIVE;
977  setPixelMode(value);
978  }
979  else if (function == P_shutrCLKShift || function == P_dataAcqMode || function == P_fileIndex || function == P_saveRawData ||
980  function == P_nShuttersPerBurst || function == P_nTrigsBurstRefresh || function == P_nTrigSavSub)
981  {
982  THROW_IF_ACQ_ACTIVE;
983  setIntegerParam(function, value);
984  setHwItem(m_paramInfo[function], function);
985  }
986  asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
987  "%s:%s: function=%d, name=%s, value=%d\n",
988  driverName, functionName, function, paramName, value);
989  status = asynSuccess;
990  }
991  catch(const std::exception& ex)
992  {
993  epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
994  "%s:%s: status=%d, function=%d, name=%s, value=%d, error=%s",
995  driverName, functionName, status, function, paramName, value, ex.what());
996  status = asynError;
997  }
998  if (status == asynSuccess)
999  {
1000  status = asynPortDriver::writeInt32(pasynUser, value);
1001  }
1002  cmdEnd();
1003  return status;
1004 }
1005 
1006 asynStatus pixelmanDriver::writeOctet(asynUser *pasynUser, const char *value, size_t maxChars, size_t *nActual)
1007 {
1008  int function = pasynUser->reason;
1009  const char* functionName = "writeOctet";
1010  asynStatus status = asynSuccess;
1011  const char *paramName = NULL;
1012  getParamName(function, &paramName);
1013  DEVID devId = getDevId();
1014  registerStructuredExceptionHandler();
1015  debugOutput(paramName);
1016  debugOutput("\n");
1017  cmdStart();
1018  std::string value_s;
1019  // we might get an embedded NULL from channel access char waveform records
1020  if ( (maxChars > 0) && (value[maxChars-1] == '\0') )
1021  {
1022  value_s.assign(value, maxChars-1);
1023  }
1024  else
1025  {
1026  value_s.assign(value, maxChars);
1027  }
1028 
1029  try
1030  {
1031  if (mgr == NULL)
1032  {
1033  throw std::runtime_error("pixelman not initialised");
1034  }
1035  else if (function == P_dataFileName)
1036  {
1037  THROW_IF_ACQ_ACTIVE;
1038  std::string fname(value_s);
1039  const char* invalid_chars = "<>:\"|?*";
1040  for(int i=0; i<strlen(invalid_chars); ++i)
1041  {
1042  std::replace(fname.begin(), fname.end(), invalid_chars[i], '_');
1043  }
1044  // create any missing intermediate directories
1045  size_t pos = fname.find_last_of("/\\");
1046 #ifdef _WIN32
1047  if (pos != std::string::npos && pos > 0)
1048  {
1049  char absPath[MAX_PATH];
1050  std::replace(fname.begin(), fname.end(), '/', '\\');
1051  if ( _fullpath(absPath, fname.substr(0,pos).c_str(), sizeof(absPath)) == NULL )
1052  {
1053  strncpy(absPath, fname.substr(0,pos).c_str(), sizeof(absPath));
1054  }
1055  if ( (_access(absPath, 0) != 0) && (SHCreateDirectoryEx(NULL, absPath, NULL) != ERROR_SUCCESS) )
1056  {
1057  throw std::runtime_error( (std::string("Cannot create directory ") + absPath).c_str() );
1058  }
1059  }
1060 #endif /* _WIN32 */
1061  setStringParam(function, value_s.c_str());
1062  setHwItem(m_paramInfo[function], function);
1063  }
1064  else if (function == P_saveConfig)
1065  {
1066  THROW_IF_ACQ_ACTIVE;
1067  mgr->mpxCtrlSaveMpxCfg(devId, (value_s.size() > 0 ? value_s.c_str() : NULL) );
1068  }
1069  else if (function == P_loadConfig)
1070  {
1071  THROW_IF_ACQ_ACTIVE;
1072  mgr->mpxCtrlLoadMpxCfg(devId, (value_s.size() > 0 ? value_s.c_str() : NULL) );
1073  }
1074  asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
1075  "%s:%s: function=%d, name=%s, value=%s\n",
1076  driverName, functionName, function, paramName, value_s.c_str());
1077  status = asynSuccess;
1078  }
1079  catch(const std::exception& ex)
1080  {
1081  *nActual = 0;
1082  epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
1083  "%s:%s: status=%d, function=%d, name=%s, value=%s, error=%s",
1084  driverName, functionName, status, function, paramName, value_s.c_str(), ex.what());
1085  status = asynError;
1086  }
1087  if (status == asynSuccess)
1088  {
1089  *nActual = value_s.size();
1090  status = asynPortDriver::writeOctet(pasynUser, value, maxChars, nActual);
1091  }
1092  cmdEnd();
1093  return status;
1094 }
1095 
1096 
1097 // maybe not call callParamCallbacks() ? for MPX_SINGLEACQCOMP as it might be at a very high rate
1098 // the value will get propagated when poller thread call callParamCallbacks()
1099 
1100 void pixelmanDriver::pixelmanEventCB(PixelmanCBEvent e, intptr_t userData)
1101 {
1102  eventCBInfo info(e);
1103  m_eventCBQueue.send(&info, sizeof(eventCBInfo), 1.0);
1104 }
1105 
1106 
1107 void pixelmanDriver::pixelmanEventCBProcessC(void* arg)
1108 {
1109  pixelmanDriver* driver = (pixelmanDriver*)arg;
1110  driver->pixelmanEventCBProcess();
1111 }
1112 
1113 void pixelmanDriver::pixelmanEventCBProcess()
1114 {
1115  eventCBInfo info;
1116  epicsThreadSleep(1.0); // wait for constructor to finish
1117  while(m_eventCBQueue.receive(&info, sizeof(eventCBInfo)) > 0)
1118  {
1119  lock();
1120  switch(info.type)
1121  {
1122  case MPX_ACQPRESTART:
1123 // m_acqRunning = true;
1124  setIntegerParam(P_acquire, 1);
1125  setIntegerParam(P_acqActive, 1);
1126  setIntegerParam(P_acqSActive, 1);
1127  break;
1128 
1129  case MPX_ACQSTART: // called for each single acquisition ?
1130 // m_acqRunning = true;
1131  setIntegerParam(P_acquire, 1);
1132  setIntegerParam(P_acqActive, 1);
1133  setIntegerParam(P_acqSActive, 1);
1134  break;
1135 
1136  case MPX_SINGLEACQCOMP: // called for each single acquisition
1137  setIntegerParam(P_acqSActive, 0);
1138  break;
1139 
1140  case MPX_SERIESACQCOMP:
1141 // m_acqRunning = false;
1142  setIntegerParam(P_acquire, 0);
1143  setIntegerParam(P_acqActive, 0);
1144  break;
1145 
1146  default:
1147  break;
1148  }
1149  callParamCallbacks();
1150  unlock();
1151  }
1152 }
1153 
1154 void pixelmanDriver::acquisitionThreadC(void* arg)
1155 {
1156  AcquisitionThreadArgs* args = (AcquisitionThreadArgs*)arg;
1157  args->driver->acquisitionThread(args);
1158 }
1159 
1160 // acquisition commands block, so need to run in separate thread
1161 void pixelmanDriver::acquisitionThread(AcquisitionThreadArgs* args)
1162 {
1163  registerStructuredExceptionHandler();
1164  if (mgr == NULL)
1165  {
1166  errlogSevPrintf(errlogMajor, "acquisitionThread: pixelman not initialised\n");
1167  delete args;
1168  return;
1169  }
1170  int status;
1171  char buffer[256];
1172  sprintf(buffer, "acquisitionThread start %d %d %d %d %d\n", GetCurrentThreadId(), args->acq_type, (m_acqRunning ? 1 : 0), (m_start_running ? 1 : 0), (m_abort_running ? 1 : 0));
1173  debugOutput(buffer);
1174  try
1175  {
1176  switch(args->acq_type)
1177  {
1178  case ACQ_FRAME:
1179  if (m_acq_start_mutex.tryLock())
1180  {
1181 // epicsGuard<epicsMutex> _lock(m_acq_start_mutex);
1182  epicsTimeGetCurrent(&m_start_time);
1183  m_start_running = true;
1184  m_acqRunning = true;
1185  mgr->logMsg(PLUGIN_NAME, "Starting frame acqusition: num %d time %f file flags %d file name \"%s\"", 0, args->numberOfAcq, args->timeOfEachAcq, args->fileFlags, args->fileName);
1186  if ( (status = mgr->mpxCtrlPerformFrameAcq(getDevId(), args->numberOfAcq, args->timeOfEachAcq, args->fileFlags, args->fileName)) != MPXERR_NOERROR )
1187  {
1188  if (status != MPXERR_ACQABORTED)
1189  {
1190  errlogSevPrintf(errlogMajor, "Error from mpxCtrlPerformFrameAcq %d", status); // if we abort acquisition it is also an error
1191  }
1192  }
1193  else
1194  {
1195  mgr->logMsg(PLUGIN_NAME, "Frame acqusition complete", 0);
1196  }
1197  m_acqRunning = false;
1198  m_start_running = false;
1199  m_acq_start_mutex.unlock();
1200  }
1201  else
1202  {
1203  mgr->logMsg(PLUGIN_NAME, "Cannot start frame acqusition - already in progress", 0);
1204  debugOutput("Cannot start frame acqusition - already in progress\n");
1205  }
1206  break;
1207 
1208  case ACQ_INTEGRAL:
1209  if (m_acq_start_mutex.tryLock())
1210  {
1211 // epicsGuard<epicsMutex> _lock(m_acq_start_mutex);
1212  epicsTimeGetCurrent(&m_start_time);
1213  m_start_running = true;
1214  m_acqRunning = true;
1215  mgr->logMsg(PLUGIN_NAME, "Starting integral acqusition: num %d time %f file flags %d file name \"%s\"", 0, args->numberOfAcq, args->timeOfEachAcq, args->fileFlags, args->fileName);
1216  if ( (status = mgr->mpxCtrlPerformIntegralAcq(getDevId(), args->numberOfAcq, args->timeOfEachAcq, args->fileFlags, args->fileName)) != MPXERR_NOERROR)
1217  {
1218  if (status != MPXERR_ACQABORTED)
1219  {
1220  errlogSevPrintf(errlogInfo, "Error from mpxCtrlPerformIntegralAcq %d", status); // if we abort acquisition it is also an error
1221  }
1222  }
1223  else
1224  {
1225  mgr->logMsg(PLUGIN_NAME, "Integral acqusition complete", 0);
1226  }
1227  m_acqRunning = false;
1228  m_start_running = false;
1229  m_acq_start_mutex.unlock();
1230  }
1231  else
1232  {
1233  mgr->logMsg(PLUGIN_NAME, "Cannot start integral acqusition - already in progress", 0);
1234  debugOutput("Cannot start integral acqusition - already in progress\n");
1235  }
1236  break;
1237 
1238  case ACQ_ABORT:
1239  if (m_acq_abort_mutex.tryLock())
1240  {
1241 // epicsGuard<epicsMutex> _lock(m_acq_abort_mutex);
1242  epicsTimeGetCurrent(&m_abort_time);
1243  m_abort_running = true;
1244  if ( (status = mgr->mpxCtrlAbortOperation(getDevId())) == MPXERR_NOERROR )
1245  {
1246  m_acqRunning = false;
1247  mgr->logMsg(PLUGIN_NAME, "Acquisition Aborted", 0);
1248  }
1249  else
1250  {
1251  errlogSevPrintf(errlogMajor, "Error from mpxCtrlAbortOperation %d", status);
1252  mgr->logMsg(PLUGIN_NAME, "Error Aborting Acquisition", 0);
1253  }
1254  m_abort_running = false;
1255  m_acq_abort_mutex.unlock();
1256  }
1257  else
1258  {
1259  mgr->logMsg(PLUGIN_NAME, "Cannot abort acqusition - already in progress", 0);
1260  debugOutput("Cannot abort acqusition - already in progress\n");
1261  }
1262  break;
1263 
1264  default:
1265  mgr->logMsg(PLUGIN_NAME, "Unknown acqusition mode requested", 0);
1266  break;
1267 
1268  }
1269  }
1270  catch(const std::exception& ex)
1271  {
1272  errlogSevPrintf(errlogMajor, "Error from acquisitionThread %s", ex.what());
1273  }
1274  catch(...)
1275  {
1276  errlogSevPrintf(errlogMajor, "Error from acquisitionThread");
1277  }
1278  sprintf(buffer, "acquisitionThread stop %d %d %d %d %d\n", GetCurrentThreadId(), args->acq_type, (m_acqRunning ? 1 : 0), (m_start_running ? 1 : 0), (m_abort_running ? 1 : 0));
1279  debugOutput(buffer);
1280  delete args;
1281 }
1282 
1283 void pixelmanDriver::getHwInfo(std::ostream& os)
1284 {
1285  int hwcount = 0;
1286  int status;
1287  DEVID devId = getDevId();
1288  mgr->mpxCtrlGetHwInfoCount(devId, &hwcount);
1289  int dataSize;
1290  HwInfoItem* infoItem;
1291  int allocDataSize = 1024;
1292 
1293  for(int i=0; i<hwcount; ++i)
1294  {
1295  infoItem = new HwInfoItem;
1296  infoItem->data = new char[allocDataSize];
1297  dataSize = allocDataSize;
1298  if ( (status = mgr->mpxCtrlGetHwInfoItem(devId, i, infoItem, &dataSize)) != MPXERR_NOERROR )
1299  {
1300  // we need more space, dataSize will now contain what we really need
1301  delete []((char*)infoItem->data);
1302  infoItem->data = new char[dataSize];
1303  status = mgr->mpxCtrlGetHwInfoItem(devId, i, infoItem, &dataSize);
1304  }
1305  if (status != MPXERR_NOERROR)
1306  {
1307  errlogSevPrintf(errlogMajor, "getHwInfo: error from mpxCtrlGetHwInfoItem %d", status);
1308  continue;
1309  }
1310  m_hwInfo[infoItem->name] = HwInfo(infoItem, i, dataSize);
1311  os << "HWINFO: Found " << nameofType[infoItem->type] << "[" << infoItem->count << "] \"" << infoItem->name << "\" (" << infoItem->descr << ")\n";
1312  }
1313 }
1314 
1315 void pixelmanDriver::getAllHwItems()
1316 {
1317  for(std::map<int,std::string>::const_iterator it = m_paramInfo.begin(); it != m_paramInfo.end(); ++it)
1318  {
1319  getHwItem(it->second, it->first);
1320  }
1321 }
1322 
1323 void pixelmanDriver::getHwItem(const std::string& name, int param)
1324 {
1325  if ( m_hwInfo.find(name) == m_hwInfo.end() )
1326  {
1327  return;
1328  }
1329  DEVID devId = getDevId();
1330  HwInfo& info = m_hwInfo[name];
1331  int dataSize = info.dataSize;
1332  asynStatus astatus = asynSuccess;
1333  int status = mgr->mpxCtrlGetHwInfoItem(devId, info.index, info.item, &dataSize);
1334  if (status != MPXERR_NOERROR)
1335  {
1336  delete []((char*)info.item->data);
1337  info.item->data = new char[dataSize];
1338  info.dataSize = dataSize;
1339  status = mgr->mpxCtrlGetHwInfoItem(devId, info.index, info.item, &dataSize);
1340  }
1341  if (status != MPXERR_NOERROR)
1342  {
1343  errlogSevPrintf(errlogMajor, "getHwItem: error %d for %s", status, name.c_str());
1344  return;
1345  }
1346  switch(info.item->type)
1347  {
1348  case TYPE_BOOL:
1349  case TYPE_I32:
1350  astatus = setIntegerParam(param, *(int*)info.item->data);
1351  break;
1352 
1353  case TYPE_U32:
1354  astatus = setIntegerParam(param, *(unsigned*)info.item->data);
1355  break;
1356 
1357  case TYPE_FLOAT:
1358  astatus = setDoubleParam(param, *(float*)info.item->data);
1359  break;
1360 
1361  case TYPE_DOUBLE:
1362  astatus = setDoubleParam(param, *(double*)info.item->data);
1363  break;
1364 
1365  case TYPE_I16:
1366  astatus = setIntegerParam(param, *(short*)info.item->data);
1367  break;
1368 
1369  case TYPE_U16:
1370  astatus = setIntegerParam(param, *(unsigned short*)info.item->data);
1371  break;
1372 
1373  case TYPE_BYTE:
1374  astatus = setIntegerParam(param, *(unsigned char*)info.item->data);
1375  break;
1376 
1377  case TYPE_CHAR:
1378  case TYPE_UCHAR:
1379  {
1380  std::string s((char*)info.item->data, info.item->count);
1381  astatus = setStringParam(param, s.c_str());
1382  }
1383  break;
1384 
1385  case TYPE_STRING:
1386  astatus = setStringParam(param, (char*)info.item->data);
1387  break;
1388 
1389  default:
1390  errlogSevPrintf(errlogMajor, "getHwItem: unknown item type %d for %s", info.item->type, name.c_str());
1391  break;
1392  }
1393  if (astatus != asynSuccess)
1394  {
1395  errlogSevPrintf(errlogMajor, "getHwItem: error setting asyn parameter for %s", name.c_str());
1396  }
1397 }
1398 
1400 void pixelmanDriver::setHwItem(const std::string& name, int param)
1401 {
1402  if ( m_hwInfo.find(name) == m_hwInfo.end() )
1403  {
1404  errlogSevPrintf(errlogMajor, "setHwItem: unknown item \"%s\"", name.c_str());
1405  return;
1406  }
1407  DEVID devId = getDevId();
1408  HwInfo& info = m_hwInfo[name];
1409  int status = 0;
1410  asynStatus astatus = asynSuccess;
1411  int ival;
1412  float fval;
1413  double dval;
1414  short sval;
1415  unsigned short usval;
1416  unsigned char bval;
1417  switch(info.item->type)
1418  {
1419  case TYPE_BOOL:
1420  case TYPE_I32:
1421  case TYPE_U32:
1422  if ( (astatus = getIntegerParam(param, &ival)) == asynSuccess )
1423  {
1424  status = mgr->mpxCtrlSetHwInfoItem(devId, info.index, (byte*)&ival, sizeof(ival));
1425  }
1426  break;
1427 
1428  case TYPE_FLOAT:
1429  if ( (astatus = getDoubleParam(param, &dval)) == asynSuccess )
1430  {
1431  fval = (float)dval;
1432  status = mgr->mpxCtrlSetHwInfoItem(devId, info.index, (byte*)&fval, sizeof(fval));
1433  }
1434  break;
1435 
1436  case TYPE_DOUBLE:
1437  if ( (astatus = getDoubleParam(param, &dval)) == asynSuccess )
1438  {
1439  status = mgr->mpxCtrlSetHwInfoItem(devId, info.index, (byte*)&dval, sizeof(dval));
1440  }
1441  break;
1442 
1443  case TYPE_I16:
1444  if ( (astatus = getIntegerParam(param, &ival)) == asynSuccess )
1445  {
1446  sval = ival;
1447  status = mgr->mpxCtrlSetHwInfoItem(devId, info.index, (byte*)&sval, sizeof(sval));
1448  }
1449  break;
1450 
1451  case TYPE_U16:
1452  if ( (astatus = getIntegerParam(param, &ival)) == asynSuccess )
1453  {
1454  usval = ival;
1455  status = mgr->mpxCtrlSetHwInfoItem(devId, info.index, (byte*)&usval, sizeof(usval));
1456  }
1457  break;
1458 
1459  case TYPE_BYTE:
1460  if ( (astatus = getIntegerParam(param, &ival)) == asynSuccess )
1461  {
1462  bval = ival;
1463  status = mgr->mpxCtrlSetHwInfoItem(devId, info.index, &bval, sizeof(bval));
1464  }
1465  break;
1466 
1467  case TYPE_CHAR:
1468  case TYPE_UCHAR:
1469  {
1470  int n = info.item->count;
1471  char* buffer = new char[n];
1472  memset(buffer, 0, n);
1473  if ( (astatus = getStringParam(param, n, buffer)) == asynSuccess )
1474  {
1475  status = mgr->mpxCtrlSetHwInfoItem(devId, info.index, (byte*)buffer, n);
1476  }
1477  delete []buffer;
1478  break;
1479  }
1480 
1481  case TYPE_STRING:
1482  {
1483  char* buffer = new char[info.dataSize];
1484  memset(buffer, 0, info.dataSize);
1485  if ( (astatus = getStringParam(param, info.dataSize, buffer)) == asynSuccess )
1486  {
1487  status = mgr->mpxCtrlSetHwInfoItem(devId, info.index, (byte*)buffer, info.dataSize);
1488  }
1489  delete []buffer;
1490  break;
1491  }
1492 
1493  default:
1494  errlogSevPrintf(errlogMajor, "setHwItem: unknown item type %d for %s", info.item->type, name.c_str());
1495  break;
1496  }
1497  if (astatus != asynSuccess)
1498  {
1499  errlogSevPrintf(errlogMajor, "setHwItem: error reading asyn parameter for %s", name.c_str());
1500  }
1501  if (status != MPXERR_NOERROR)
1502  {
1503  errlogSevPrintf(errlogMajor, "setHwItem: error %d for %s", status, name.c_str());
1504  }
1505 }
1506 
1507 pixelmanDriver::AcquisitionThreadArgs* pixelmanDriver::createAcquisitionThreadArgs(int at)
1508 {
1509  AcquisitionThreadArgs* args = new AcquisitionThreadArgs(this, at);
1510  memset(args->fileName, 0, sizeof(args->fileName));
1511  getIntegerParam(P_numberOfAcq, &(args->numberOfAcq));
1512  getIntegerParam(P_fileFlags, reinterpret_cast<int*>(&(args->fileFlags)));
1513  getDoubleParam(P_timeOfEachAcq, &(args->timeOfEachAcq));
1514  getStringParam(P_dataFileName, sizeof(args->fileName), args->fileName);
1515  return args;
1516 }
1517 
1518 // pixel mode = {p0, p1}; mode: 0 - medipix, 1 - TOT, 2 - Timepix 1-hit, 3 - Timepix
1519 void pixelmanDriver::setPixelMode(unsigned mode)
1520 {
1521  DEVID devId = getDevId();
1522  if (mode > 3)
1523  {
1524  errlogSevPrintf(errlogMajor, "setPixelMode: invalid mode");
1525  return;
1526  }
1527  if (m_devInfo.numberOfChips * MATRIX_SIZE != m_devInfo.pixCount)
1528  {
1529  errlogSevPrintf(errlogMajor, "setPixelMode: invalid number of pixels");
1530  return;
1531  }
1532  if (m_devInfo.mpxType != MPX_TPX)
1533  {
1534  errlogSevPrintf(errlogMajor, "setPixelMode: not timepix");
1535  return;
1536  }
1537  int npixels = m_devInfo.pixCount;
1538  TpxPixCfg* pixels(new TpxPixCfg[npixels]);
1539  if (mgr->mpxCtrlGetPixelsCfg(devId, reinterpret_cast<byte*>(pixels), npixels * sizeof(TpxPixCfg), ALLCHIPS) != MPXERR_NOERROR)
1540  {
1541  errlogSevPrintf(errlogMajor, "setPixelMode: mpxCtrlGetPixelsCfg failed");
1542  delete[] pixels;
1543  return;
1544  }
1545  for(int i=0; i<npixels; ++i)
1546  {
1547  pixels[i].mode = mode;
1548  }
1549  if (mgr->mpxCtrlSetPixelsCfg(devId, reinterpret_cast<byte*>(pixels), npixels * sizeof(TpxPixCfg), ALLCHIPS) != MPXERR_NOERROR)
1550  {
1551  errlogSevPrintf(errlogMajor, "setPixelMode: mpxCtrlSetPixelsCfg failed");
1552  delete[] pixels;
1553  return;
1554  }
1555  delete[] pixels;
1556  return;
1557 }
1558 
1559 void pixelmanDriver::printDevInfo(DevInfo* devInfo, std::ostream& os)
1560 {
1561  os << "Number of pixels: " << devInfo->pixCount << std::endl;
1562  os << "Row length: " << devInfo->rowLen << std::endl;
1563  os << "Number of chips: " << devInfo->numberOfChips << std::endl;
1564  os << "Number rows: " << devInfo->numberOfRows << std::endl;
1565  os << "Medipix type: " << devInfo->mpxType << std::endl;
1566  os << "Supported acq modes: " << devInfo->suppAcqModes << std::endl;
1567  os << "Support callbacks: " << devInfo->suppCallback << std::endl;
1568 }
abort acquisition
start frame acquisition
dbLoadDatabase(TOP)/dbd/pixelman.dbd"
Register all support components ;.
iocInit
ISIS common init ;.
Definition: pixelman.cmd:46
start integral acquisition
Header for pixelman EPICS plugin.
pixelmanConfigure("MCP","$(PIXDET=dummy)")
ISIS common init ;.
dbLoadRecords("$(TOP)/db/pixelman.db","P=$(MYPVPREFIX=),Q=PIXELMAN:")
ISIS common init ;.
camera not taking data
pixelman asyn driver
Copyright © 2013 Science and Technology Facilities Council | Generated by   doxygen 1.8.8