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 
76 #if 0
77 static void epicsHelloWorldMenuItemFunc(MENUFUNCPAR par)
78 {
79 // MessageBox(NULL,"EPICS Hello world","EPICS Hello world",MB_OK);
80 }
81 static void epicsFunc(void* in, void* out)
82 {
83  struct InParamStucture
84  {
85  u32 A; // first input parameter
86  double B[2]; // second
87  char C; // third
88  };
89  // Retype inputs to simplyfy access to each input parameter:
90  InParamStucture *par= (InParamStucture*)in;
91  char message[256];
92  sprintf(message,"Hello World\r(Inputs: %d,%lg,%lg,%c)",par->A,par->B[0],par->B[1],par->C);
93 // int ok=MessageBox(NULL,message,"Hello World",MB_OK);
94 // *((double*)out)=ok; // Set output to some value
95 }
96 
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 static int epicsFrameFilter(INTPTR userData, byte *in, byte *out)
118 {
119  FRAMEID fID = *(FRAMEID *) in;
120  ITEMID iID = *(ITEMID *) (in + sizeof(FRAMEID));
121  if (g_epics != NULL)
122  {
123  g_epics->frameFilter(fID, iID, userData);
124  }
125  return 0;
126 }
127 
128 // Description of parameters of HelloWorldFunc function.
129 static ExtFunctionInfo epicsFrameFilterFuncInfo = {
130  epicsFrameFilter, // Pointer to function performing an action
131  2, // Number of input parameters
132  0, // Number of output parameters
133  { // List of input parameter descriptions
134  {TYPE_U32, 1, "ID of frame"}, // description of first parameter
135  {TYPE_U32, 1, "ID of filter instance"}, // description of second parameter
136  },
137  { // List of output parameter descriptions
138  },
139  PLUGIN_NAME, // Name of the plugin = name of this plugin
140  "epicsFrameFilter", // Name of registered function = can differ to "C" name
141  "EPICS Frame Filter", // Description of function purpose
142  FUNCFLAG_FILTER // flags = flags
143 };
144 
145 extern const FuncTableType *mgr;
146 
147 // pixelman exiting
148 static void mpxmgrExitCB(CBPARAM par, INTPTR userData)
149 {
150 // MessageBox(NULL,"pixelman exit cb","pixelman exit cb",MB_OK);
151 // epicsExit(0);
152 }
153 
154 // all plugins loaded
155 static void mpxmgrStartCB(CBPARAM par, INTPTR userData)
156 {
157 // MessageBox(NULL,"pixelman started cb","pixelman started cb",MB_OK);
158 }
159 
160 static void mpxmgrFrameNewCB(CBPARAM par, INTPTR userData)
161 {
162  if (g_epics != NULL)
163  {
164  g_epics->pixelmanEventCB(pixelmanDriver::MPX_FRAMENEW, par, userData);
165  }
166 // MessageBox(NULL,"pixelman new frame cb","pixelman new frame cb",MB_OK);
167 }
168 
169 // acquisition started
170 static void mpxctrlAcqStartCB(CBPARAM par, INTPTR userData)
171 {
172  if (g_epics != NULL)
173  {
174  g_epics->pixelmanEventCB(pixelmanDriver::MPX_ACQSTART, par, userData);
175  }
176 // MessageBox(NULL,"acq start cb","acq start cb",MB_OK);
177 }
178 
179 static void mpxctrlAcqPreStartCB(CBPARAM par, INTPTR userData)
180 {
181  if (g_epics != NULL)
182  {
183  g_epics->pixelmanEventCB(pixelmanDriver::MPX_ACQPRESTART, par, userData);
184  }
185 // MessageBox(NULL,"acq start cb","acq start cb",MB_OK);
186 }
187 
188 // single acquisition completed
189 static void mpxctrlSingleAcqCompletedCB(CBPARAM par, INTPTR userData)
190 {
191  if (g_epics != NULL)
192  {
193  g_epics->pixelmanEventCB(pixelmanDriver::MPX_SINGLEACQCOMP, par, userData);
194  }
195 // MessageBox(NULL,"single acq complete cb","single acq complete cb",MB_OK);
196 }
197 
198 // series acquisition completed
199 static void mpxctrlSeriesAcqCompletedCB(CBPARAM par, INTPTR userData)
200 {
201  if (g_epics != NULL)
202  {
203  g_epics->pixelmanEventCB(pixelmanDriver::MPX_SERIESACQCOMP, par, userData);
204  }
205 // MessageBox(NULL,"series acq complete cb","series acq complete cb",MB_OK);
206 }
207 
208 static int myLog(const errlogSevEnum severity, const char *pformat, ... )
209 {
210  int n;
211  va_list pvar;
212  va_start(pvar, pformat);
213  n = errlogSevVprintf(severity, pformat, pvar);
214  mgr->logMsgV(PLUGIN_NAME, pformat, 0, pvar);
215  va_end(pvar);
216  return n;
217 }
218 
219 // info or error message
220 static void mpxctrlMessageCB(CBPARAM par, INTPTR userData)
221 {
222  const char* msg = NULL;
223  int msgType, status;
224  if (mgr != NULL && g_epics != NULL)
225  {
226  status = mgr->mpxCtrlGetInfoMsg(g_epics->getDevId(), &msgType, &msg);
227  if (status == MPXERR_NOERROR && msg != NULL)
228  {
229  debugOutput(msg);
230  debugOutput("\n");
231  if (msgType != MPXERR_ACQABORTED)
232  {
233  if (msgType < 0)
234  {
235  errlogSevPrintf(errlogMajor, "%s (%d)\n", msg, msgType);
236  }
237  else
238  {
239  errlogSevPrintf(errlogInfo, "%s (%d)\n", msg, msgType);
240  }
241  }
242  }
243  }
244 }
245 
246 extern "C" {
247 
251 static int pixelmanConfigure(const char *portName, const char* devName)
252 {
253  registerStructuredExceptionHandler();
254  try
255  {
256  g_epics = new pixelmanDriver(portName, devName);
257  return(asynSuccess);
258  }
259  catch(const std::exception& ex)
260  {
261  errlogSevPrintf(errlogMajor, "pixelmanConfigure failed: %s", ex.what());
262  return(asynError);
263  }
264 }
265 
266 // EPICS iocsh shell commands
267 
268 static const iocshArg initArg0 = { "portName", iocshArgString};
269 static const iocshArg initArg1 = { "devName", iocshArgString};
270 
271 static const iocshArg * const initArgs[] = { &initArg0, &initArg1 };
272 
273 static const iocshFuncDef initFuncDef = {"pixelmanConfigure", sizeof(initArgs) / sizeof(iocshArg*), initArgs};
274 
275 static void initCallFunc(const iocshArgBuf *args)
276 {
277  pixelmanConfigure(args[0].sval, args[1].sval);
278 }
279 
280 static void pixelmanRegister(void)
281 {
282  iocshRegister(&initFuncDef, initCallFunc);
283 }
284 
285 epicsExportRegistrar(pixelmanRegister);
286 
287 }
288 
289 extern "C" int pixelman_registerRecordDeviceDriver(struct dbBase *pdbbase);
290 
291 #define DBD_FILE "../dbd/pixelman.dbd"
292 #define DB_FILE "../db/pixelman.db"
293 
294 #ifdef _WIN32
295 PLUGIN_INIT_EXTENDED
296 #else
297 PLUGIN_INIT
298 #endif
299 {
300 // mgr->logErrorStr(Module, "Error in plugin function: Please call mom (tel. %d)", 0, MomTelNum);
301 // mgr->addMenuItem("EPICS Hello world", "Tests", epicsHelloWorldMenuItemFunc, 0, NULL, 0);
302 // mgr->addFuncItem(&epicsFuncInfo);
303 // DebugBreak();
304 
305  mgr->logShowWindow(1); // for debugging
306 
307 // ExtCBEventInfo epics_event;
308 // ITEMID id;
309 // strncpy(epics_event.pluginName, PLUGIN_NAME, NAME_LENGTH);
310 // strncpy(epics_event.cbEventName, "EPICSEvent", NAME_LENGTH);
311 // strncpy(epics_event.description, "An EPICS event", DESC_LENGTH);
312 // mgr->addCBEvent(&epics_event, &id);
313 
314  // set up output redirection
315  if (freopen("pixelman_iocout.log", "wt", stdout) == NULL)
316  {
317  mgr->logMsg(PLUGIN_NAME, "Error redirecting stdout to pixelman_iocout.log", 0);
318  }
319  if (freopen("pixelman_iocerr.log", "wt", stderr) == NULL)
320  {
321  mgr->logMsg(PLUGIN_NAME, "Error redirecting stderr to pixelman_iocerr.log", 0);
322  }
323  if (setvbuf(stdout, NULL, _IONBF, 0) != 0)
324  {
325  mgr->logMsg(PLUGIN_NAME, "Error making stdout unbuffered", 0);
326  }
327  if (setvbuf(stderr, NULL, _IONBF, 0) != 0)
328  {
329  mgr->logMsg(PLUGIN_NAME, "Error making stderr unbuffered", 0);
330  }
331 
332  if (mgr->registerCallback(MPXCTRL_NAME, MPXCTRL_CB_ACQPRESTART, mpxctrlAcqPreStartCB, NULL) != 0)
333  {
334  mgr->logMsg(PLUGIN_NAME, "Error registering prestart callback", 0);
335  }
336  mgr->registerCallback(MPXCTRL_NAME, MPXCTRL_CB_ACQSERCOMPL, mpxctrlSeriesAcqCompletedCB, NULL);
337  mgr->registerCallback(MPXCTRL_NAME, MPXCTRL_CB_INFOMSG, mpxctrlMessageCB, NULL);
338  mgr->registerCallback(MPXCTRL_NAME, MPXCTRL_CB_ACQSTART, mpxctrlAcqStartCB, NULL);
339 
340 // mgr->registerCallback(MPXMGR_NAME, MPXMGR_CB_EXIT, mpxmgrExitCB, NULL);
341 // mgr->registerCallback(MPXMGR_NAME, MPXMGR_CB_START, mpxmgrStartCB, NULL);
342  mgr->registerCallback(MPXMGR_NAME, MPXMGR_CB_FRAME_NEW, mpxmgrFrameNewCB, NULL);
343  mgr->registerCallback(MPXCTRL_NAME, MPXCTRL_CB_ACQCOMPL, mpxctrlSingleAcqCompletedCB, NULL);
344 
345  mgr->addFuncItem(&epicsFrameFilterFuncInfo);
346 
347  const char* PIXELMANDIR = getenv("PIXELMANDIR");
348  if (PIXELMANDIR == NULL)
349  {
350  PIXELMANDIR = "<UNKNOWN>";
351  }
352  mgr->logMsg(PLUGIN_NAME, (std::string("Camera directory: ") + PIXELMANDIR).c_str(), 0);
353  if (false)
354  {
355  char macros[256];
356  const char* PVPREFIX = getenv("MYPVPREFIX");
357  if (PVPREFIX == NULL)
358  {
359  PVPREFIX = "test:";
360  }
361  epicsSnprintf(macros, sizeof(macros), "P=%s,Q=PIXELMAN:", PVPREFIX);
362  mgr->logMsg(PLUGIN_NAME, "Starting EPICS IOC", 0);
363  if (dbLoadDatabase(DBD_FILE, NULL, NULL))
364  {
365  mgr->logMsg(PLUGIN_NAME, "Error in plugin function: cannot load DBD file", 0);
366  return -1;
367  }
368 
369  pixelman_registerRecordDeviceDriver(pdbbase);
370 
371  pixelmanConfigure("MCP", "dummy");
372 // pixelmanConfigure("MCP", "BeARQuT");
373 
374  if (dbLoadRecords(DB_FILE, macros))
375  {
376  mgr->logMsg(PLUGIN_NAME, "Error in plugin function: cannot load DB file", 0);
377  return -1;
378  }
379  iocInit();
380  }
381  else
382  {
383  mgr->logMsg(PLUGIN_NAME, "Starting EPICS IOC - see pixelman_iocout.log and pixelman_iocerr.log", 0);
384  const char* PVPREFIX = getenv("MYPVPREFIX");
385  mgr->logMsg(PLUGIN_NAME, "PV prefix P=%s", 0, (PVPREFIX != NULL ? PVPREFIX : ""));
386  const char* EPICSPIXELMAN = getenv("EPICSPIXELMAN");
387  if (EPICSPIXELMAN == NULL)
388  {
389  EPICSPIXELMAN = ".";
390  }
391  std::string pix_cmd = std::string(EPICSPIXELMAN) + std::string("/pixelman.cmd");
392  mgr->logMsg(PLUGIN_NAME, (std::string("Loading ") + pix_cmd).c_str(), 0);
393  if (iocsh(pix_cmd.c_str()))
394  {
395  mgr->logMsg(PLUGIN_NAME, "Error in plugin function: cannot load pixelman.cmd", 0);
396  return -1;
397  }
398  }
399  return 0;
400 }
401 
402 static const char *driverName = "pixelmanDriver";
403 
404 pixelmanDriver::pixelmanDriver(const char *portName, const char* devName)
405  : ADDriver(portName,
406  1, /* maxAddr */
407  NUM_MCP_PARAMS,
408  0, // maxBuffers
409  0, // maxMemory
410  asynInt32Mask | asynInt32ArrayMask | asynFloat64Mask | asynFloat64ArrayMask | asynOctetMask | asynDrvUserMask, /* Interface mask */
411  asynInt32Mask | asynInt32ArrayMask | asynFloat64Mask | asynFloat64ArrayMask | asynOctetMask, /* Interrupt mask */
412  ASYN_CANBLOCK, /* asynFlags. This driver can block but it is not multi-device */
413  1, /* Autoconnect */
414  0, /* Default priority */
415  0), /* Default stack size*/
416  m_acqRunning(false), m_cmd_running(false), m_start_running(false),
417  m_abort_running(false), m_devId(INVALID_DEVID_VALUE), m_autoRestart(0),
418  m_autoRestartDelay(0.0), m_eventCBQueue(40, sizeof(eventCBInfo)),
419  m_runEndQueue(40, sizeof(RunEndInfo)), m_frameQueue(40, sizeof(FrameInfo)), m_currentFrameID(0), m_pRaw(NULL)
420 {
421 
422  const char *functionName = "pixelmanDriver";
423  std::ostringstream pix_items;
424 // while(!IsDebuggerPresent())
425 // {
426 // epicsThreadSleep(2.0);
427 // }
428  createParam(P_acqAbortString, asynParamInt32, &P_acqAbort);
429  createParam(P_acqStartString, asynParamInt32, &P_acqStart);
430  createParam(P_trigAcqStartString, asynParamInt32, &P_trigAcqStart);
431  createParam(P_trigAcqStopString, asynParamInt32, &P_trigAcqStop);
432  createParam(P_numberOfAcqString, asynParamInt32, &P_numberOfAcq);
433  createParam(P_timeOfEachAcqString, asynParamFloat64, &P_timeOfEachAcq);
434  createParam(P_fileFlagsString, asynParamInt32, &P_fileFlags);
435 // createParam(P_fileNameString, asynParamOctet, &P_fileName);
436  createParam(P_devIdString, asynParamInt32, &P_devId);
437  createParam(P_acqSActiveString, asynParamInt32, &P_acqSActive);
438  createParam(P_acqActiveString, asynParamInt32, &P_acqActive);
439  createParam(P_acqTypeString, asynParamInt32, &P_acqType);
440  createParam(P_acqTypeReqString, asynParamInt32, &P_acqTypeReq);
441  createParam(P_frameFilledString, asynParamInt32, &P_frameFilled);
442  createParam(P_acqTotalCountString, asynParamInt32, &P_acqTotalCount);
443  createParam(P_acqNumberString, asynParamInt32, &P_acqNumber);
444  createParam(P_acqModeString, asynParamInt32, &P_acqMode);
445  createParam(P_burstModeString, asynParamInt32, &P_burstMode);
446  createParam(P_extShutModeString, asynParamInt32, &P_extShutMode);
447  createParam(P_hwTimerString, asynParamInt32, &P_hwTimer);
448  createParam(P_saveConfigString, asynParamOctet, &P_saveConfig);
449  createParam(P_loadConfigString, asynParamOctet, &P_loadConfig);
450  createParam(P_saveDefConfigString, asynParamInt32, &P_saveDefConfig);
451  createParam(P_loadDefConfigString, asynParamInt32, &P_loadDefConfig);
452  createParam(P_acqHangString, asynParamInt32, &P_acqHang);
453  createParam(P_hangTimeString, asynParamFloat64, &P_hangTime);
454  createParam(P_autoRestartString, asynParamInt32, &P_autoRestart);
455  createParam(P_autoRestartDelayString, asynParamFloat64, &P_autoRestartDelay);
456  createParam(P_setPixelModeString, asynParamInt32, &P_setPixelMode);
457  createParam(P_frameIDString, asynParamInt32, &P_frameID);
458 
459  setIntegerParam(ADAcquire, 0);
460  setIntegerParam(P_acqStart, 0);
461  setIntegerParam(P_acqAbort, 0);
462  setIntegerParam(P_acqSActive, 0);
463  setIntegerParam(P_acqActive, 0);
464  setIntegerParam(P_autoRestart, 0);
465  setDoubleParam(P_autoRestartDelay, 0.0);
466  setIntegerParam(P_frameID, 0);
467 
468  int maxSizeX = 512, maxSizeY = 512;
469  NDDataType_t dataType = NDInt32; // data type for each frame
470  int status = setStringParam (ADManufacturer, "PIXELMAN");
471  status |= setStringParam (ADModel, "PIXELMAN");
472  status |= setIntegerParam(ADMaxSizeX, maxSizeX);
473  status |= setIntegerParam(ADMaxSizeY, maxSizeY);
474  status |= setIntegerParam(ADMinX, 0);
475  status |= setIntegerParam(ADMinY, 0);
476  status |= setIntegerParam(ADBinX, 1);
477  status |= setIntegerParam(ADBinY, 1);
478  status |= setIntegerParam(ADReverseX, 0);
479  status |= setIntegerParam(ADReverseY, 0);
480  status |= setIntegerParam(ADSizeX, maxSizeX);
481  status |= setIntegerParam(ADSizeY, maxSizeY);
482  status |= setIntegerParam(NDArraySizeX, maxSizeX);
483  status |= setIntegerParam(NDArraySizeY, maxSizeY);
484  status |= setIntegerParam(NDArraySize, 0);
485  status |= setIntegerParam(NDDataType, dataType);
486  status |= setIntegerParam(ADImageMode, ADImageContinuous);
487  status |= setDoubleParam (ADAcquireTime, .001);
488  status |= setDoubleParam (ADAcquirePeriod, .005);
489  status |= setIntegerParam(ADNumImages, 100);
490 
491  if (status) {
492  printf("%s: unable to set DAE parameters\n", functionName);
493  return;
494  }
495 
496 
497  int count = 0;
498  char name[NAME_LENGTH];
499  memset(name, 0, NAME_LENGTH);
500  DevInfo devInfo;
501  DEVID devId = INVALID_DEVID_VALUE;
502  if ( mgr != NULL && mgr->mpxCtrlGetFirstMpx(&devId, &count) == 0 )
503  {
504  errlogSevPrintf(errlogInfo, "There are %d devices available\n", count);
505  if (mgr->mpxCtrlGetCustomName(m_devId, name) == MPXERR_NOERROR)
506  {
507  name[NAME_LENGTH-1] = '\0';
508  }
509  else
510  {
511  name[0] = '\0';
512  }
513  mgr->mpxCtrlGetDevInfo(devId, &devInfo);
514  errlogSevPrintf(errlogInfo, "... devId %d name \"%s\" iface \"%s\" chipID \"%s\"\n", devId, name, devInfo.ifaceName, devInfo.chipboardID);
515  if (strcmp(devName, name) == 0 || strcmp(devName, devInfo.ifaceName) == 0)
516  {
517  errlogSevPrintf(errlogInfo, "Found device \"%s\" (devId %d)\n", devName, devId);
518  m_devId = devId;
519  memcpy(&m_devInfo, &devInfo, sizeof(DevInfo));
520  printDevInfo(&m_devInfo, pix_items);
521  }
522  while(mgr->mpxCtrlGetNextMpx(&devId) == 0)
523  {
524  mgr->mpxCtrlGetCustomName(devId, name);
525  mgr->mpxCtrlGetDevInfo(devId, &devInfo);
526  errlogSevPrintf(errlogInfo, "... devId %d name \"%s\" iface \"%s\" chipID \"%s\"\n", devId, name, devInfo.ifaceName, devInfo.chipboardID);
527  if (strcmp(devName, name) == 0 || strcmp(devName, devInfo.ifaceName) == 0)
528  {
529  errlogSevPrintf(errlogInfo, "Found device \"%s\" (devId %d)\n", devName, devId);
530  m_devId = devId;
531  memcpy(&m_devInfo, &devInfo, sizeof(DevInfo));
532  printDevInfo(&m_devInfo, pix_items);
533  }
534  }
535  }
536  setIntegerParam(P_devId, m_devId);
537  if (getDevId() == INVALID_DEVID_VALUE)
538  {
539  errlogSevPrintf(errlogMajor, "Device \"%s\" not found\n", devName);
540  }
541 
542  if (mgr != NULL)
543  {
544  getHwInfo(pix_items);
545  }
546 
547  createParam(P_dataFileNameString, asynParamOctet, &P_dataFileName);
548  m_paramInfo[P_dataFileName] = "DataFileName";
549 // m_paramInfo[P_dataFileName] = "Data file name";
550  createParam(P_shutrCLKShiftString, asynParamInt32, &P_shutrCLKShift);
551  m_paramInfo[P_shutrCLKShift] = "ShutrCLKShift";
552  createParam(P_tpxCubeBinString, asynParamFloat64, &P_tpxCubeBin);
553  m_paramInfo[P_tpxCubeBin] = "TpxCubeBin";
554  createParam(P_dataAcqModeString, asynParamInt32, &P_dataAcqMode);
555  m_paramInfo[P_dataAcqMode] = "AcqMode";
556  createParam(P_fileIndexString, asynParamInt32, &P_fileIndex);
557  m_paramInfo[P_fileIndex] = "FileIndexToSaveDataInto";
558 // m_paramInfo[P_fileIndex] = "Data file count";
559  createParam(P_saveRawDataString, asynParamInt32, &P_saveRawData);
560  m_paramInfo[P_saveRawData] = "SaveRawData";
561  createParam(P_nShuttersPerBurstString, asynParamInt32, &P_nShuttersPerBurst);
562  m_paramInfo[P_nShuttersPerBurst] = "TriggersPerBurst";
563  createParam(P_nTrigsBurstRefreshString, asynParamInt32, &P_nTrigsBurstRefresh);
564  m_paramInfo[P_nTrigsBurstRefresh] = "BurstsToTake";
565  createParam(P_cameraStatusString, asynParamInt32, &P_cameraStatus);
566  m_paramInfo[P_cameraStatus] = "CurrentStatus";
567  createParam(P_nTrigSavSubString, asynParamInt32, &P_nTrigSavSub);
568  m_paramInfo[P_nTrigSavSub] = "NtrigBeforeSavingSubImgSpectra";
569 
570  setIntegerParam(P_cameraStatus, STATUS_IDLE);
571  setIntegerParam(P_fileIndex, 0);
572 
573  if (mgr != NULL)
574  {
575  ITEMID cbEventID;
576  ExtCBEventInfo extCBEventInfo;
577  if (mgr->getRegFirstCBEvent(&cbEventID, &extCBEventInfo) == 0)
578  {
579  pix_items << "Plugin " << extCBEventInfo.pluginName << " offers event callback " << extCBEventInfo.cbEventName << " (" << extCBEventInfo.description << ")" << std::endl;
580  while(mgr->getRegNextCBEvent(&cbEventID, &extCBEventInfo) == 0)
581  {
582  pix_items << "Plugin " << extCBEventInfo.pluginName << " offers event callback " << extCBEventInfo.cbEventName << " (" << extCBEventInfo.description << ")" << std::endl;
583  }
584  }
585  char name[MENU_LENGTH];
586  ITEMID itemID;
587  if (mgr->getFirstMenuItem(&itemID, name) == 0)
588  {
589  pix_items << "Menu item " << name << std::endl;
590  while(mgr->getNextMenuItem(&itemID, name) == 0)
591  {
592  pix_items << "Menu item " << name << std::endl;
593  }
594  }
595  ITEMID funcID;
596  ExtFunctionInfo funcInfo;
597  if (mgr->getRegFirstFunc(&funcID, &funcInfo) == 0)
598  {
599  pix_items << "Plugin " << funcInfo.pluginName << " offers function " << funcInfo.functionName << " (" << funcInfo.description << ")" << std::endl;
600  while(mgr->getRegNextFunc(&funcID, &funcInfo) == 0)
601  {
602  pix_items << "Plugin " << funcInfo.pluginName << " offers function " << funcInfo.functionName << " (" << funcInfo.description << ")" << std::endl;
603  for(int i=0; i<funcInfo.paramInCount; ++i)
604  {
605  pix_items << " arg_in[" << i << "] " << funcInfo.paramsInfoIn[i].description << std::endl;
606  }
607  for(int i=0; i<funcInfo.paramOutCount; ++i)
608  {
609  pix_items << " arg_out[" << i << "] " << funcInfo.paramsInfoOut[i].description << std::endl;
610  }
611  }
612  }
613  }
614 
615  try
616  {
617  std::fstream pfile("pixitems.txt", std::ios::out);
618  pfile << pix_items.str();
619  pfile.close();
620  }
621  catch(const std::exception& ex)
622  {
623  ;
624  }
625 
626  // Create the thread for background tasks (not used at present, could be used for I/O intr scanning)
627  if (epicsThreadCreate("pixelmanDriverPoller",
628  epicsThreadPriorityMedium,
629  epicsThreadGetStackSize(epicsThreadStackMedium),
630  (EPICSTHREADFUNC)pollerThreadC, this) == 0)
631  {
632  errlogSevPrintf(errlogMajor, "%s:%s: epicsThreadCreate failure\n", driverName, functionName);
633  return;
634  }
635  if (epicsThreadCreate("pixelmanDriverRestarter",
636  epicsThreadPriorityMedium,
637  epicsThreadGetStackSize(epicsThreadStackMedium),
638  (EPICSTHREADFUNC)pixelmanDriverRestarterC, this) == 0)
639  {
640  errlogSevPrintf(errlogMajor, "%s:%s: epicsThreadCreate failure\n", driverName, functionName);
641  return;
642  }
643  if (epicsThreadCreate("pixelmanEventCBProcess",
644  epicsThreadPriorityMedium,
645  epicsThreadGetStackSize(epicsThreadStackMedium),
646  (EPICSTHREADFUNC)pixelmanEventCBProcessC, this) == 0)
647  {
648  errlogSevPrintf(errlogMajor, "%s:%s: epicsThreadCreate failure\n", driverName, functionName);
649  return;
650  }
651  if (epicsThreadCreate("pixelmanDriverSaver",
652  epicsThreadPriorityMedium,
653  epicsThreadGetStackSize(epicsThreadStackMedium),
654  (EPICSTHREADFUNC)saverThreadC, this) == 0)
655  {
656  errlogSevPrintf(errlogMajor, "%s:%s: epicsThreadCreate failure\n", driverName, functionName);
657  return;
658  }
659 }
660 
661 int pixelmanDriver::getDevId() const
662 {
663  return m_devId;
664 }
665 
666 void pixelmanDriver::pixelmanDriverRestarterC(void* arg)
667 {
668  pixelmanDriver* driver = (pixelmanDriver*)arg;
669  driver->pixelmanDriverRestarter();
670 }
671 
672 static void myExitFunc(const char* msg)
673 {
674 // errlogSevPrintf(errlogMajor, msg);
675 // errlogFlush();
676 // epicsThreadSleep(5.0);
677 // epicsExit(1);
678 #if defined(_DEBUG)
679  DebugBreak();
680 #else
681  _exit(0);
682 #endif /* _DEBUG */
683 }
684 
685 void pixelmanDriver::pixelmanDriverRestarter()
686 {
687  static const char* functionName = "pixelmanDriverRestarter";
688  registerStructuredExceptionHandler();
689  double delay = 1.0;
690  double tdiff;
691  epicsTimeStamp now;
692  while(true)
693  {
694  epicsThreadSleep(delay);
695  if (m_autoRestart != 0)
696  {
697  epicsTimeGetCurrent(&now);
698  if (m_cmd_running)
699  {
700  tdiff = epicsTimeDiffInSeconds(&now, &m_cmd_time);
701  if (tdiff > m_autoRestartDelay)
702  {
703  myExitFunc("pixelmanDriverRestarter: exiting (cmd)");
704  }
705  }
706  if (m_abort_running)
707  {
708  tdiff = epicsTimeDiffInSeconds(&now, &m_abort_time);
709  if (tdiff > m_autoRestartDelay)
710  {
711  myExitFunc("pixelmanDriverRestarter: exiting (abort)");
712  }
713  }
714  }
715  }
716 }
717 
718 
719 void pixelmanDriver::pollerThreadC(void* arg)
720 {
721  pixelmanDriver* driver = (pixelmanDriver*)arg;
722  driver->pollerThread();
723 }
724 
725 void pixelmanDriver::saverThreadC(void* arg)
726 {
727  pixelmanDriver* driver = (pixelmanDriver*)arg;
728  driver->saverThread();
729 }
730 
731 void pixelmanDriver::pollerThread()
732 {
733  static const char* functionName = "pollerThread";
734  double delay = 0.5;
735  int acqNumber = 0, acqTotalCount = 0, acqType = 0, acqMode = 0, hwTimer = 0;
736  static u32 lastFrameFilled = 0;
737  u32 frameFilled = 0;
738  DEVID devId;
739  epicsTimeStamp stop_begin, now;
740  int cameraStatus, lastCameraStatus = STATUS_IDLE;
741  int fileIndex, lastFileIndex = -1;
742  bool file_to_save = false;
743 
744  registerStructuredExceptionHandler();
745  epicsTimeGetCurrent(&stop_begin);
746  while(mgr != NULL)
747  {
748  epicsThreadSleep(delay);
749  devId = getDevId();
750  lock();
751  mgr->mpxCtrlGetAcqInfo(devId, &acqNumber, &acqTotalCount, &acqType, &frameFilled);
752  mgr->mpxCtrlGetAcqMode(devId, &acqMode); // this return full mode, so need to maks off burst etc.
753  mgr->mpxCtrlGetHwTimer(devId, &hwTimer);
754  getAllHwItems();
755  getIntegerParam(P_autoRestart, &m_autoRestart);
756  getDoubleParam(P_autoRestartDelay, &m_autoRestartDelay);
757  getIntegerParam(P_cameraStatus, &cameraStatus);
758  getIntegerParam(P_fileIndex, &fileIndex);
759  if (lastFileIndex == -1)
760  {
761  lastFileIndex = fileIndex;
762  }
763  setIntegerParam(P_acqType, acqType);
764  setIntegerParam(P_frameFilled, frameFilled);
765  setIntegerParam(P_acqTotalCount, acqTotalCount);
766  setIntegerParam(P_acqNumber, acqNumber);
767  setIntegerParam(P_acqMode, (acqMode & 0xff) );
768  setIntegerParam(P_burstMode, ((acqMode & ACQMODE_BURST) != 0) );
769  setIntegerParam(P_extShutMode, ((acqMode & ACQMODE_EXTSHUTTER) != 0) );
770  setIntegerParam(P_hwTimer, hwTimer);
771 
772  epicsTimeGetCurrent(&now);
773  double tdiff = epicsTimeDiffInSeconds(&now, &stop_begin);
774  bool acqHang = false;
775  if (cameraStatus == STATUS_ACQUIRING) // once we are acquiring, we'll have something to save later
776  {
777  file_to_save = true;
778  }
779 
780  if (m_acqRunning)
781  {
782  setIntegerParam(ADAcquire, 1);
783  setIntegerParam(P_acqActive, 1);
784  if (frameFilled == lastFrameFilled)
785  {
786  if (tdiff > m_autoRestartDelay)
787  {
788  acqHang = true;
789  if (m_autoRestart != 0)
790  {
791  myExitFunc("pollerThread: exiting");
792  }
793  }
794  }
795  else
796  {
797  lastFrameFilled = frameFilled;
798  epicsTimeGetCurrent(&stop_begin);
799  tdiff = 0.0;
800  }
801  setShutter(1);
802  readFrame();
803  setShutter(0);
804  }
805  else
806  {
807  setIntegerParam(ADAcquire, 0);
808  setIntegerParam(P_acqActive, 0);
809  setADAcquire(0);
810  epicsTimeGetCurrent(&stop_begin);
811  tdiff = 0.0;
812  }
813  setDoubleParam(P_hangTime, tdiff);
814  if (acqHang)
815  {
816  setIntegerParam(P_acqHang, 1);
817  }
818  else
819  {
820  setIntegerParam(P_acqHang, 0);
821  }
822  if (file_to_save && fileIndex > lastFileIndex)
823  {
824  saveFinished(lastFileIndex);
825  file_to_save = false;
826  }
827  lastCameraStatus = cameraStatus;
828  lastFileIndex = fileIndex;
829  callParamCallbacks();
830  unlock();
831  }
832 }
833 
834 void pixelmanDriver::saveFinished(int fileIndex)
835 {
836  RunEndInfo info;
837  getStringParam(P_dataFileName, sizeof(info.fileName), info.fileName);
838  info.fileIndex = fileIndex;
839  m_runEndQueue.send(&info, sizeof(RunEndInfo), 1.0);
840 }
841 
842 static std::string quote(const std::string& str)
843 {
844 // return std::string("\"") + str + "\"";
845  return str;
846 }
847 
848 void pixelmanDriver::saverThread()
849 {
850  RunEndInfo info;
851  const char* end_of_run = getenv("PIXELMANENDCMD");
852  const char* comspec = getenv("COMSPEC");
853  const char* pixelmandir = getenv("PIXELMANDIR");
854  epicsThreadSleep(1.0); // wait for constructor to finish
855  while( m_runEndQueue.receive(&info, sizeof(RunEndInfo)) > 0 )
856  {
857  errlogSevPrintf(errlogInfo, "Saved \"%s\" index %d\n", info.fileName, info.fileIndex);
858  mgr->logMsg(PLUGIN_NAME, "Saved \"%s\" index %d", 0, info.fileName, info.fileIndex);
859  if (end_of_run != NULL)
860  {
861  errlogSevPrintf(errlogInfo, "Executing \"%s\"\n", end_of_run);
862  mgr->logMsg(PLUGIN_NAME, "Executing \"%s\"", 0, end_of_run);
863  char cFileIndex[32];
864  sprintf(cFileIndex, "%d", info.fileIndex);
865 #ifdef _WIN32
866  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)
867 #else
868  // do something on linux
869 #endif
870  {
871  mgr->logMsg(PLUGIN_NAME, "ERROR executing \"%s\"", 0, end_of_run);
872  }
873  }
874  }
875 }
876 
877 #define THROW_IF_ACQ_ACTIVE \
878  if (m_acqRunning) \
879  { \
880  std::ostringstream acq_active_mess; \
881  acq_active_mess << functionName << ": cannot set " << paramName << " when acq active"; \
882  throw std::runtime_error(acq_active_mess.str().c_str()); \
883  }
884 
885 #define THROW_IF_ACQ_NOT_ACTIVE \
886  if (!m_acqRunning) \
887  { \
888  std::ostringstream acq_not_active_mess; \
889  acq_not_active_mess << functionName << ": cannot set " << paramName << " when acq is not active"; \
890  throw std::runtime_error(acq_not_active_mess.str().c_str()); \
891  }
892 
893 asynStatus pixelmanDriver::writeFloat64(asynUser *pasynUser, epicsFloat64 value)
894 {
895  int function = pasynUser->reason;
896  const char* functionName = "writeFloat64";
897  asynStatus status = asynSuccess;
898  const char *paramName = NULL;
899  getParamName(function, &paramName);
900 
901  if (function < FIRST_MCP_PARAM)
902  {
903  return ADDriver::writeFloat64(pasynUser, value);
904  }
905 
906  DEVID devId = getDevId();
907  registerStructuredExceptionHandler();
908  debugOutput(paramName);
909  debugOutput("\n");
910  cmdStart();
911 
912  try
913  {
914  if (mgr == NULL)
915  {
916  throw std::runtime_error("pixelman not initialised");
917  }
918  else if (function == P_tpxCubeBin)
919  {
920  THROW_IF_ACQ_ACTIVE;
921  setDoubleParam(function, value);
922  setHwItem(m_paramInfo[function], function);
923  }
924  asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
925  "%s:%s: function=%d, name=%s, value=%f\n",
926  driverName, functionName, function, paramName, value);
927  status = asynSuccess;
928  }
929  catch(const std::exception& ex)
930  {
931  epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
932  "%s:%s: status=%d, function=%d, name=%s, value=%f, error=%s",
933  driverName, functionName, status, function, paramName, value, ex.what());
934  status = asynError;
935  }
936  if (status == asynSuccess)
937  {
938  status = asynPortDriver::writeFloat64(pasynUser, value);
939  }
940  cmdEnd();
941  return status;
942 }
943 
944 asynStatus pixelmanDriver::writeInt32(asynUser *pasynUser, epicsInt32 value)
945 {
946  int function = pasynUser->reason;
947  int acqMode;
948  const char* functionName = "writeInt32";
949  asynStatus status = asynSuccess;
950  const char *paramName = NULL;
951  getParamName(function, &paramName);
952 
953  if (function < FIRST_MCP_PARAM && function != ADAcquire)
954  {
955  return ADDriver::writeInt32(pasynUser, value);
956  }
957 
958  DEVID devId = getDevId();
959  registerStructuredExceptionHandler();
960  debugOutput(paramName);
961  debugOutput("\n");
962  cmdStart();
963  try
964  {
965  if (mgr == NULL)
966  {
967  throw std::runtime_error("pixelman not initialised");
968  }
969  else if ( function == P_acqStart || (function == ADAcquire && value == 1) )
970  {
971  THROW_IF_ACQ_ACTIVE;
972  setIntegerParam(ADAcquire, 1);
973  int acqTypeReq;
974  getIntegerParam(P_acqTypeReq, &acqTypeReq);
975  AcquisitionThreadArgs* args = createAcquisitionThreadArgs(acqTypeReq);
976  if (epicsThreadCreate("pixelmanAcquisitionStart",
977  epicsThreadPriorityMedium,
978  epicsThreadGetStackSize(epicsThreadStackMedium),
979  (EPICSTHREADFUNC)acquisitionThreadC, args) == 0)
980  {
981  errlogSevPrintf(errlogMajor, "%s:%s: epicsThreadCreate failure\n", driverName, functionName);
982  }
983  setADAcquire(1);
984  epicsThreadSleep(0.1);
985  }
986  else if (function == P_acqAbort || (function == ADAcquire && value == 0) )
987  {
988  THROW_IF_ACQ_NOT_ACTIVE;
989  AcquisitionThreadArgs* args = createAcquisitionThreadArgs(ACQ_ABORT);
990 // if (epicsThreadCreate("pixelmanAcquisitionAbort",
991 // epicsThreadPriorityMedium,
992 // epicsThreadGetStackSize(epicsThreadStackMedium),
993 // (EPICSTHREADFUNC)acquisitionThreadC, args) == 0)
994 // {
995 // errlogSevPrintf(errlogMajor, "%s:%s: epicsThreadCreate failure\n", driverName, functionName);
996 // }
997 // epicsThreadSleep(0.1);
998  acquisitionThreadC(args);
999  setIntegerParam(ADAcquire, 0);
1000  setADAcquire(0);
1001  }
1002  else if (function == P_trigAcqStart)
1003  {
1004  THROW_IF_ACQ_NOT_ACTIVE;
1005  mgr->mpxCtrlTrigger(devId, TRIGGER_ACQSTART);
1006  mgr->logMsg(PLUGIN_NAME, "Acquisition Start triggered", 0);
1007  }
1008  else if (function == P_trigAcqStop)
1009  {
1010  THROW_IF_ACQ_NOT_ACTIVE;
1011  mgr->mpxCtrlTrigger(devId, TRIGGER_ACQSTOP);
1012  mgr->logMsg(PLUGIN_NAME, "Acquisition Stop triggered", 0);
1013  }
1014  else if (function == P_acqMode)
1015  {
1016  THROW_IF_ACQ_ACTIVE;
1017  mgr->mpxCtrlGetAcqMode(devId, &acqMode); // this return full mode, so need to maks off burst etc.
1018  acqMode &= ~0xff;
1019  acqMode |= value;
1020  mgr->mpxCtrlSetAcqMode(devId, acqMode);
1021  }
1022  else if (function == P_burstMode)
1023  {
1024  THROW_IF_ACQ_ACTIVE;
1025  mgr->mpxCtrlGetAcqMode(devId, &acqMode); // this return full mode, so need to maks off burst etc.
1026  if (value != 0)
1027  {
1028  acqMode |= ACQMODE_BURST;
1029  }
1030  else
1031  {
1032  acqMode &= ~ACQMODE_BURST;
1033  }
1034  mgr->mpxCtrlSetAcqMode(devId, acqMode);
1035  }
1036  else if (function == P_extShutMode)
1037  {
1038  THROW_IF_ACQ_ACTIVE;
1039  mgr->mpxCtrlGetAcqMode(devId, &acqMode); // this return full mode, so need to maks off burst etc.
1040  if (value != 0)
1041  {
1042  acqMode |= ACQMODE_EXTSHUTTER;
1043  }
1044  else
1045  {
1046  acqMode &= ~ACQMODE_EXTSHUTTER;
1047  }
1048  mgr->mpxCtrlSetAcqMode(devId, acqMode);
1049  }
1050  else if (function == P_hwTimer)
1051  {
1052  THROW_IF_ACQ_ACTIVE;
1053  mgr->mpxCtrlSetHwTimer(devId, value);
1054  }
1055  else if (function == P_saveDefConfig)
1056  {
1057  THROW_IF_ACQ_ACTIVE;
1058  mgr->mpxCtrlSaveMpxCfgAsDefault(devId);
1059  }
1060  else if (function == P_loadDefConfig)
1061  {
1062  THROW_IF_ACQ_ACTIVE;
1063  mgr->mpxCtrlLoadMpxCfg(devId, NULL);
1064  }
1065  else if (function == P_setPixelMode)
1066  {
1067  THROW_IF_ACQ_ACTIVE;
1068  setPixelMode(value);
1069  }
1070  else if (function == P_shutrCLKShift || function == P_dataAcqMode || function == P_fileIndex || function == P_saveRawData ||
1071  function == P_nShuttersPerBurst || function == P_nTrigsBurstRefresh || function == P_nTrigSavSub)
1072  {
1073  THROW_IF_ACQ_ACTIVE;
1074  setIntegerParam(function, value);
1075  setHwItem(m_paramInfo[function], function);
1076  }
1077  asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
1078  "%s:%s: function=%d, name=%s, value=%d\n",
1079  driverName, functionName, function, paramName, value);
1080  status = asynSuccess;
1081  }
1082  catch(const std::exception& ex)
1083  {
1084  epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
1085  "%s:%s: status=%d, function=%d, name=%s, value=%d, error=%s",
1086  driverName, functionName, status, function, paramName, value, ex.what());
1087  status = asynError;
1088  }
1089  if (status == asynSuccess)
1090  {
1091  if (function == ADAcquire)
1092  {
1093  status = ADDriver::writeInt32(pasynUser, value);
1094  }
1095  else
1096  {
1097  status = asynPortDriver::writeInt32(pasynUser, value);
1098  }
1099  }
1100  cmdEnd();
1101  return status;
1102 }
1103 
1104 asynStatus pixelmanDriver::writeOctet(asynUser *pasynUser, const char *value, size_t maxChars, size_t *nActual)
1105 {
1106  int function = pasynUser->reason;
1107  const char* functionName = "writeOctet";
1108  asynStatus status = asynSuccess;
1109  const char *paramName = NULL;
1110  getParamName(function, &paramName);
1111 
1112  if (function < FIRST_MCP_PARAM)
1113  {
1114  return ADDriver::writeOctet(pasynUser, value, maxChars, nActual);
1115  }
1116 
1117  DEVID devId = getDevId();
1118  registerStructuredExceptionHandler();
1119  debugOutput(paramName);
1120  debugOutput("\n");
1121  cmdStart();
1122  std::string value_s;
1123  // we might get an embedded NULL from channel access char waveform records
1124  if ( (maxChars > 0) && (value[maxChars-1] == '\0') )
1125  {
1126  value_s.assign(value, maxChars-1);
1127  }
1128  else
1129  {
1130  value_s.assign(value, maxChars);
1131  }
1132 
1133  try
1134  {
1135  if (mgr == NULL)
1136  {
1137  throw std::runtime_error("pixelman not initialised");
1138  }
1139  else if (function == P_dataFileName)
1140  {
1141  THROW_IF_ACQ_ACTIVE;
1142  std::string fname(value_s);
1143  const char* invalid_chars = "<>:\"|?*";
1144  for(int i=0; i<strlen(invalid_chars); ++i)
1145  {
1146  std::replace(fname.begin(), fname.end(), invalid_chars[i], '_');
1147  }
1148  // create any missing intermediate directories
1149  size_t pos = fname.find_last_of("/\\");
1150 #ifdef _WIN32
1151  if (pos != std::string::npos && pos > 0)
1152  {
1153  char absPath[MAX_PATH];
1154  std::replace(fname.begin(), fname.end(), '/', '\\');
1155  if ( _fullpath(absPath, fname.substr(0,pos).c_str(), sizeof(absPath)) == NULL )
1156  {
1157  strncpy(absPath, fname.substr(0,pos).c_str(), sizeof(absPath));
1158  }
1159  if ( (_access(absPath, 0) != 0) && (SHCreateDirectoryEx(NULL, absPath, NULL) != ERROR_SUCCESS) )
1160  {
1161  throw std::runtime_error( (std::string("Cannot create directory ") + absPath).c_str() );
1162  }
1163  }
1164 #endif /* _WIN32 */
1165  setStringParam(function, value_s.c_str());
1166  setHwItem(m_paramInfo[function], function);
1167  }
1168  else if (function == P_saveConfig)
1169  {
1170  THROW_IF_ACQ_ACTIVE;
1171  mgr->mpxCtrlSaveMpxCfg(devId, (value_s.size() > 0 ? value_s.c_str() : NULL) );
1172  }
1173  else if (function == P_loadConfig)
1174  {
1175  THROW_IF_ACQ_ACTIVE;
1176  mgr->mpxCtrlLoadMpxCfg(devId, (value_s.size() > 0 ? value_s.c_str() : NULL) );
1177  }
1178  asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
1179  "%s:%s: function=%d, name=%s, value=%s\n",
1180  driverName, functionName, function, paramName, value_s.c_str());
1181  status = asynSuccess;
1182  }
1183  catch(const std::exception& ex)
1184  {
1185  *nActual = 0;
1186  epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
1187  "%s:%s: status=%d, function=%d, name=%s, value=%s, error=%s",
1188  driverName, functionName, status, function, paramName, value_s.c_str(), ex.what());
1189  status = asynError;
1190  }
1191  if (status == asynSuccess)
1192  {
1193  *nActual = value_s.size();
1194  status = asynPortDriver::writeOctet(pasynUser, value, maxChars, nActual);
1195  }
1196  cmdEnd();
1197  return status;
1198 }
1199 
1200 
1201 // maybe not call callParamCallbacks() ? for MPX_SINGLEACQCOMP as it might be at a very high rate
1202 // the value will get propagated when poller thread call callParamCallbacks()
1203 
1204 void pixelmanDriver::pixelmanEventCB(PixelmanCBEvent e, CBPARAM par, INTPTR userData)
1205 {
1206  eventCBInfo info(e, par, userData);
1207  m_eventCBQueue.send(&info, sizeof(eventCBInfo), 1.0);
1208 }
1209 
1210 
1211 void pixelmanDriver::pixelmanEventCBProcessC(void* arg)
1212 {
1213  pixelmanDriver* driver = (pixelmanDriver*)arg;
1214  driver->pixelmanEventCBProcess();
1215 }
1216 
1217 void pixelmanDriver::pixelmanEventCBProcess()
1218 {
1219  eventCBInfo info;
1220  epicsThreadSleep(1.0); // wait for constructor to finish
1221  while(m_eventCBQueue.receive(&info, sizeof(eventCBInfo)) > 0)
1222  {
1223  lock();
1224  switch(info.type)
1225  {
1226  case MPX_ACQPRESTART:
1227 // m_acqRunning = true;
1228  setIntegerParam(ADAcquire, 1);
1229  setIntegerParam(P_acqActive, 1);
1230  setIntegerParam(P_acqSActive, 1);
1231  break;
1232 
1233  case MPX_ACQSTART: // called for each single acquisition ?
1234 // m_acqRunning = true;
1235  setIntegerParam(ADAcquire, 1);
1236  setIntegerParam(P_acqActive, 1);
1237  setIntegerParam(P_acqSActive, 1);
1238  break;
1239 
1240  case MPX_SINGLEACQCOMP: // called for each single acquisition, each frame in frame mode
1241  setIntegerParam(P_acqSActive, 0);
1242  break;
1243 
1244  case MPX_SERIESACQCOMP: // called when acquisition ends (aborts)
1245  m_acqRunning = false;
1246  setIntegerParam(ADAcquire, 0);
1247  setIntegerParam(P_acqActive, 0);
1248  break;
1249 
1250  case MPX_FRAMENEW:
1251  m_acqRunning = true;
1252  m_currentFrameID = (FRAMEID)info.par;
1253  setIntegerParam(P_frameID, m_currentFrameID);
1254  break;
1255 
1256  default:
1257  break;
1258  }
1259  callParamCallbacks();
1260  unlock();
1261  }
1262 }
1263 
1264 void pixelmanDriver::acquisitionThreadC(void* arg)
1265 {
1266  AcquisitionThreadArgs* args = (AcquisitionThreadArgs*)arg;
1267  args->driver->acquisitionThread(args);
1268 }
1269 
1270 // acquisition commands block, so need to run in separate thread
1271 void pixelmanDriver::acquisitionThread(AcquisitionThreadArgs* args)
1272 {
1273  registerStructuredExceptionHandler();
1274  if (mgr == NULL)
1275  {
1276  errlogSevPrintf(errlogMajor, "acquisitionThread: pixelman not initialised\n");
1277  delete args;
1278  return;
1279  }
1280  int status;
1281  char buffer[256];
1282  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));
1283  debugOutput(buffer);
1284  try
1285  {
1286  switch(args->acq_type)
1287  {
1288  case ACQ_FRAME:
1289  if (m_acq_start_mutex.tryLock())
1290  {
1291 // epicsGuard<epicsMutex> _lock(m_acq_start_mutex);
1292  epicsTimeGetCurrent(&m_start_time);
1293  m_start_running = true;
1294  m_acqRunning = true;
1295  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);
1296  if ( (status = mgr->mpxCtrlPerformFrameAcq(getDevId(), args->numberOfAcq, args->timeOfEachAcq, args->fileFlags, args->fileName)) != MPXERR_NOERROR )
1297  {
1298  if (status != MPXERR_ACQABORTED)
1299  {
1300  errlogSevPrintf(errlogMajor, "Error from mpxCtrlPerformFrameAcq %d", status); // if we abort acquisition it is also an error
1301  }
1302  }
1303  else
1304  {
1305  mgr->logMsg(PLUGIN_NAME, "Frame acqusition complete", 0);
1306  }
1307  m_acqRunning = false;
1308  m_start_running = false;
1309  m_acq_start_mutex.unlock();
1310  }
1311  else
1312  {
1313  mgr->logMsg(PLUGIN_NAME, "Cannot start frame acqusition - already in progress", 0);
1314  debugOutput("Cannot start frame acqusition - already in progress\n");
1315  }
1316  break;
1317 
1318  case ACQ_INTEGRAL:
1319  if (m_acq_start_mutex.tryLock())
1320  {
1321 // epicsGuard<epicsMutex> _lock(m_acq_start_mutex);
1322  epicsTimeGetCurrent(&m_start_time);
1323  m_start_running = true;
1324  m_acqRunning = true;
1325  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);
1326  if ( (status = mgr->mpxCtrlPerformIntegralAcq(getDevId(), args->numberOfAcq, args->timeOfEachAcq, args->fileFlags, args->fileName)) != MPXERR_NOERROR)
1327  {
1328  if (status != MPXERR_ACQABORTED)
1329  {
1330  errlogSevPrintf(errlogInfo, "Error from mpxCtrlPerformIntegralAcq %d", status); // if we abort acquisition it is also an error
1331  }
1332  }
1333  else
1334  {
1335  mgr->logMsg(PLUGIN_NAME, "Integral acqusition complete", 0);
1336  }
1337  m_acqRunning = false;
1338  m_start_running = false;
1339  m_acq_start_mutex.unlock();
1340  }
1341  else
1342  {
1343  mgr->logMsg(PLUGIN_NAME, "Cannot start integral acqusition - already in progress", 0);
1344  debugOutput("Cannot start integral acqusition - already in progress\n");
1345  }
1346  break;
1347 
1348  case ACQ_ABORT:
1349  if (m_acq_abort_mutex.tryLock())
1350  {
1351 // epicsGuard<epicsMutex> _lock(m_acq_abort_mutex);
1352  epicsTimeGetCurrent(&m_abort_time);
1353  m_abort_running = true;
1354  if ( (status = mgr->mpxCtrlAbortOperation(getDevId())) == MPXERR_NOERROR )
1355  {
1356  m_acqRunning = false;
1357  mgr->logMsg(PLUGIN_NAME, "Acquisition Aborted", 0);
1358  }
1359  else
1360  {
1361  errlogSevPrintf(errlogMajor, "Error from mpxCtrlAbortOperation %d", status);
1362  mgr->logMsg(PLUGIN_NAME, "Error Aborting Acquisition", 0);
1363  }
1364  m_abort_running = false;
1365  m_acq_abort_mutex.unlock();
1366  }
1367  else
1368  {
1369  mgr->logMsg(PLUGIN_NAME, "Cannot abort acqusition - already in progress", 0);
1370  debugOutput("Cannot abort acqusition - already in progress\n");
1371  }
1372  break;
1373 
1374  default:
1375  mgr->logMsg(PLUGIN_NAME, "Unknown acqusition mode requested", 0);
1376  break;
1377 
1378  }
1379  }
1380  catch(const std::exception& ex)
1381  {
1382  errlogSevPrintf(errlogMajor, "Error from acquisitionThread %s", ex.what());
1383  }
1384  catch(...)
1385  {
1386  errlogSevPrintf(errlogMajor, "Error from acquisitionThread");
1387  }
1388  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));
1389  debugOutput(buffer);
1390  delete args;
1391 }
1392 
1393 void pixelmanDriver::getHwInfo(std::ostream& os)
1394 {
1395  int hwcount = 0;
1396  int status;
1397  DEVID devId = getDevId();
1398  mgr->mpxCtrlGetHwInfoCount(devId, &hwcount);
1399  int dataSize;
1400  HwInfoItem* infoItem;
1401  int allocDataSize = 1024;
1402 
1403  for(int i=0; i<hwcount; ++i)
1404  {
1405  infoItem = new HwInfoItem;
1406  infoItem->data = new char[allocDataSize];
1407  dataSize = allocDataSize;
1408  if ( (status = mgr->mpxCtrlGetHwInfoItem(devId, i, infoItem, &dataSize)) != MPXERR_NOERROR )
1409  {
1410  // we need more space, dataSize will now contain what we really need
1411  delete []((char*)infoItem->data);
1412  infoItem->data = new char[dataSize];
1413  status = mgr->mpxCtrlGetHwInfoItem(devId, i, infoItem, &dataSize);
1414  }
1415  if (status != MPXERR_NOERROR)
1416  {
1417  errlogSevPrintf(errlogMajor, "getHwInfo: error from mpxCtrlGetHwInfoItem %d", status);
1418  continue;
1419  }
1420  m_hwInfo[infoItem->name] = HwInfo(infoItem, i, dataSize);
1421  os << "HWINFO: Found " << nameofType[infoItem->type] << "[" << infoItem->count << "] \"" << infoItem->name << "\" (" << infoItem->descr << ")\n";
1422  }
1423 }
1424 
1425 void pixelmanDriver::getAllHwItems()
1426 {
1427  for(std::map<int,std::string>::const_iterator it = m_paramInfo.begin(); it != m_paramInfo.end(); ++it)
1428  {
1429  getHwItem(it->second, it->first);
1430  }
1431 }
1432 
1433 void pixelmanDriver::getHwItem(const std::string& name, int param)
1434 {
1435  if ( m_hwInfo.find(name) == m_hwInfo.end() )
1436  {
1437  return;
1438  }
1439  DEVID devId = getDevId();
1440  HwInfo& info = m_hwInfo[name];
1441  int dataSize = info.dataSize;
1442  asynStatus astatus = asynSuccess;
1443  int status = mgr->mpxCtrlGetHwInfoItem(devId, info.index, info.item, &dataSize);
1444  if (status != MPXERR_NOERROR)
1445  {
1446  delete []((char*)info.item->data);
1447  info.item->data = new char[dataSize];
1448  info.dataSize = dataSize;
1449  status = mgr->mpxCtrlGetHwInfoItem(devId, info.index, info.item, &dataSize);
1450  }
1451  if (status != MPXERR_NOERROR)
1452  {
1453  errlogSevPrintf(errlogMajor, "getHwItem: error %d for %s", status, name.c_str());
1454  return;
1455  }
1456  switch(info.item->type)
1457  {
1458  case TYPE_BOOL:
1459  case TYPE_I32:
1460  astatus = setIntegerParam(param, *(int*)info.item->data);
1461  break;
1462 
1463  case TYPE_U32:
1464  astatus = setIntegerParam(param, *(unsigned*)info.item->data);
1465  break;
1466 
1467  case TYPE_FLOAT:
1468  astatus = setDoubleParam(param, *(float*)info.item->data);
1469  break;
1470 
1471  case TYPE_DOUBLE:
1472  astatus = setDoubleParam(param, *(double*)info.item->data);
1473  break;
1474 
1475  case TYPE_I16:
1476  astatus = setIntegerParam(param, *(short*)info.item->data);
1477  break;
1478 
1479  case TYPE_U16:
1480  astatus = setIntegerParam(param, *(unsigned short*)info.item->data);
1481  break;
1482 
1483  case TYPE_BYTE:
1484  astatus = setIntegerParam(param, *(unsigned char*)info.item->data);
1485  break;
1486 
1487  case TYPE_CHAR:
1488  case TYPE_UCHAR:
1489  {
1490  std::string s((char*)info.item->data, info.item->count);
1491  astatus = setStringParam(param, s.c_str());
1492  }
1493  break;
1494 
1495  case TYPE_STRING:
1496  astatus = setStringParam(param, (char*)info.item->data);
1497  break;
1498 
1499  default:
1500  errlogSevPrintf(errlogMajor, "getHwItem: unknown item type %d for %s", info.item->type, name.c_str());
1501  break;
1502  }
1503  if (astatus != asynSuccess)
1504  {
1505  errlogSevPrintf(errlogMajor, "getHwItem: error setting asyn parameter for %s", name.c_str());
1506  }
1507 }
1508 
1510 void pixelmanDriver::setHwItem(const std::string& name, int param)
1511 {
1512  if ( m_hwInfo.find(name) == m_hwInfo.end() )
1513  {
1514  errlogSevPrintf(errlogMajor, "setHwItem: unknown item \"%s\"", name.c_str());
1515  return;
1516  }
1517  DEVID devId = getDevId();
1518  HwInfo& info = m_hwInfo[name];
1519  int status = 0;
1520  asynStatus astatus = asynSuccess;
1521  int ival;
1522  float fval;
1523  double dval;
1524  short sval;
1525  unsigned short usval;
1526  unsigned char bval;
1527  switch(info.item->type)
1528  {
1529  case TYPE_BOOL:
1530  case TYPE_I32:
1531  case TYPE_U32:
1532  if ( (astatus = getIntegerParam(param, &ival)) == asynSuccess )
1533  {
1534  status = mgr->mpxCtrlSetHwInfoItem(devId, info.index, (byte*)&ival, sizeof(ival));
1535  }
1536  break;
1537 
1538  case TYPE_FLOAT:
1539  if ( (astatus = getDoubleParam(param, &dval)) == asynSuccess )
1540  {
1541  fval = (float)dval;
1542  status = mgr->mpxCtrlSetHwInfoItem(devId, info.index, (byte*)&fval, sizeof(fval));
1543  }
1544  break;
1545 
1546  case TYPE_DOUBLE:
1547  if ( (astatus = getDoubleParam(param, &dval)) == asynSuccess )
1548  {
1549  status = mgr->mpxCtrlSetHwInfoItem(devId, info.index, (byte*)&dval, sizeof(dval));
1550  }
1551  break;
1552 
1553  case TYPE_I16:
1554  if ( (astatus = getIntegerParam(param, &ival)) == asynSuccess )
1555  {
1556  sval = ival;
1557  status = mgr->mpxCtrlSetHwInfoItem(devId, info.index, (byte*)&sval, sizeof(sval));
1558  }
1559  break;
1560 
1561  case TYPE_U16:
1562  if ( (astatus = getIntegerParam(param, &ival)) == asynSuccess )
1563  {
1564  usval = ival;
1565  status = mgr->mpxCtrlSetHwInfoItem(devId, info.index, (byte*)&usval, sizeof(usval));
1566  }
1567  break;
1568 
1569  case TYPE_BYTE:
1570  if ( (astatus = getIntegerParam(param, &ival)) == asynSuccess )
1571  {
1572  bval = ival;
1573  status = mgr->mpxCtrlSetHwInfoItem(devId, info.index, &bval, sizeof(bval));
1574  }
1575  break;
1576 
1577  case TYPE_CHAR:
1578  case TYPE_UCHAR:
1579  {
1580  int n = info.item->count;
1581  char* buffer = new char[n];
1582  memset(buffer, 0, n);
1583  if ( (astatus = getStringParam(param, n, buffer)) == asynSuccess )
1584  {
1585  status = mgr->mpxCtrlSetHwInfoItem(devId, info.index, (byte*)buffer, n);
1586  }
1587  delete []buffer;
1588  break;
1589  }
1590 
1591  case TYPE_STRING:
1592  {
1593  char* buffer = new char[info.dataSize];
1594  memset(buffer, 0, info.dataSize);
1595  if ( (astatus = getStringParam(param, info.dataSize, buffer)) == asynSuccess )
1596  {
1597  status = mgr->mpxCtrlSetHwInfoItem(devId, info.index, (byte*)buffer, info.dataSize);
1598  }
1599  delete []buffer;
1600  break;
1601  }
1602 
1603  default:
1604  errlogSevPrintf(errlogMajor, "setHwItem: unknown item type %d for %s", info.item->type, name.c_str());
1605  break;
1606  }
1607  if (astatus != asynSuccess)
1608  {
1609  errlogSevPrintf(errlogMajor, "setHwItem: error reading asyn parameter for %s", name.c_str());
1610  }
1611  if (status != MPXERR_NOERROR)
1612  {
1613  errlogSevPrintf(errlogMajor, "setHwItem: error %d for %s", status, name.c_str());
1614  }
1615 }
1616 
1617 pixelmanDriver::AcquisitionThreadArgs* pixelmanDriver::createAcquisitionThreadArgs(int at)
1618 {
1619  AcquisitionThreadArgs* args = new AcquisitionThreadArgs(this, at);
1620  memset(args->fileName, 0, sizeof(args->fileName));
1621  getIntegerParam(P_numberOfAcq, &(args->numberOfAcq));
1622  getIntegerParam(P_fileFlags, reinterpret_cast<int*>(&(args->fileFlags)));
1623  getDoubleParam(P_timeOfEachAcq, &(args->timeOfEachAcq));
1624  getStringParam(P_dataFileName, sizeof(args->fileName), args->fileName);
1625  return args;
1626 }
1627 
1628 // pixel mode = {p0, p1}; mode: 0 - medipix, 1 - TOT, 2 - Timepix 1-hit, 3 - Timepix
1629 void pixelmanDriver::setPixelMode(unsigned mode)
1630 {
1631  DEVID devId = getDevId();
1632  if (mode > 3)
1633  {
1634  errlogSevPrintf(errlogMajor, "setPixelMode: invalid mode");
1635  return;
1636  }
1637  if (m_devInfo.numberOfChips * MATRIX_SIZE != m_devInfo.pixCount)
1638  {
1639  errlogSevPrintf(errlogMajor, "setPixelMode: invalid number of pixels");
1640  return;
1641  }
1642  if (m_devInfo.mpxType != MPX_TPX)
1643  {
1644  errlogSevPrintf(errlogMajor, "setPixelMode: not timepix");
1645  return;
1646  }
1647  int npixels = m_devInfo.pixCount;
1648  TpxPixCfg* pixels(new TpxPixCfg[npixels]);
1649  if (mgr->mpxCtrlGetPixelsCfg(devId, reinterpret_cast<byte*>(pixels), npixels * sizeof(TpxPixCfg), ALLCHIPS) != MPXERR_NOERROR)
1650  {
1651  errlogSevPrintf(errlogMajor, "setPixelMode: mpxCtrlGetPixelsCfg failed");
1652  delete[] pixels;
1653  return;
1654  }
1655  for(int i=0; i<npixels; ++i)
1656  {
1657  pixels[i].mode = mode;
1658  }
1659  if (mgr->mpxCtrlSetPixelsCfg(devId, reinterpret_cast<byte*>(pixels), npixels * sizeof(TpxPixCfg), ALLCHIPS) != MPXERR_NOERROR)
1660  {
1661  errlogSevPrintf(errlogMajor, "setPixelMode: mpxCtrlSetPixelsCfg failed");
1662  delete[] pixels;
1663  return;
1664  }
1665  delete[] pixels;
1666  return;
1667 }
1668 
1669 void pixelmanDriver::printDevInfo(DevInfo* devInfo, std::ostream& os)
1670 {
1671  os << "Number of pixels: " << devInfo->pixCount << std::endl;
1672  os << "Row length: " << devInfo->rowLen << std::endl;
1673  os << "Number of chips: " << devInfo->numberOfChips << std::endl;
1674  os << "Number rows: " << devInfo->numberOfRows << std::endl;
1675  os << "Medipix type: " << devInfo->mpxType << std::endl;
1676  os << "Supported acq modes: " << devInfo->suppAcqModes << std::endl;
1677  os << "Support callbacks: " << devInfo->suppCallback << std::endl;
1678 }
1679 
1680 void pixelmanDriver::setADAcquire(int acquire)
1681 {
1682  int adstatus;
1683  int acquiring;
1684  int imageMode;
1685  asynStatus status = asynSuccess;
1686 
1687  /* Ensure that ADStatus is set correctly before we set ADAcquire.*/
1688  getIntegerParam(ADStatus, &adstatus);
1689  getIntegerParam(ADAcquire, &acquiring);
1690  getIntegerParam(ADImageMode, &imageMode);
1691  if (acquire && !acquiring) {
1692  setStringParam(ADStatusMessage, "Acquiring data");
1693  setIntegerParam(ADStatus, ADStatusAcquire);
1694  setIntegerParam(ADAcquire, 1);
1695  }
1696  if (!acquire && acquiring) {
1697  setIntegerParam(ADAcquire, 0);
1698  setStringParam(ADStatusMessage, "Acquisition stopped");
1699  if (imageMode == ADImageContinuous) {
1700  setIntegerParam(ADStatus, ADStatusIdle);
1701  } else {
1702  setIntegerParam(ADStatus, ADStatusAborted);
1703  }
1704  }
1705 }
1706 
1709 {
1710  int shutterMode;
1711 
1712  getIntegerParam(ADShutterMode, &shutterMode);
1713  if (shutterMode == ADShutterModeDetector) {
1714  /* Simulate a shutter by just changing the status readback */
1715  setIntegerParam(ADShutterStatus, open);
1716  } else {
1717  /* For no shutter or EPICS shutter call the base class method */
1718  ADDriver::setShutter(open);
1719  }
1720 }
1721 
1722 
1723 void pixelmanDriver::frameFilter(FRAMEID fID, ITEMID iID, INTPTR userData)
1724 {
1725  return; // not used or tested, but not needed at moment
1726 
1727  u32 refCount;
1728  double queue_timeout = 0.015; // Needs to be less than TS1 rep rate (20ms)
1729  FrameInfo info(fID, iID, userData);
1730  int stat = mgr->openFrame(fID, &refCount);
1731  if (stat == 0)
1732  {
1733  if (m_frameQueue.send(&info, sizeof(FrameInfo), queue_timeout) != 0)
1734  {
1735  stat = mgr->closeFrame(fID, &refCount); // unable to queue
1736  }
1737  }
1738 }
1739 
1740 // not used or tested, but not needed at moment
1741 void pixelmanDriver::frameProcess()
1742 {
1743  FrameInfo info;
1744  u32 refCount, width, height, byteSize;
1745  u32* buffer;
1746  int stat;
1747  Data_Types frame_type; //TYPE_I16, TYPE_U32, TYPE_DOUBLE
1748  while( m_frameQueue.receive(&info, sizeof(FrameInfo)) > 0 )
1749  {
1750  stat = mgr->getFrameType(info.fID, &frame_type);
1751  stat = mgr->getFrameSize(info.fID, &width, &height);
1752  buffer = new u32[width * height];
1753  byteSize = width * height * sizeof(u32) + 64; // +64 so we can test size after call
1754  stat = mgr->getFrameData(info.fID, (byte*)buffer, &byteSize, TYPE_U32);
1755  if (byteSize != width * height * sizeof(u32))
1756  {
1757  ;
1758  }
1759  delete[] buffer;
1760  stat = mgr->closeFrame(info.fID, &refCount);
1761  }
1762 }
1763 
1764 void pixelmanDriver::readFrame()
1765 {
1766  u32 refCount, width = 0, height = 0, byteSize;
1767  u32* buffer;
1768  int stat;
1769  FRAMEID FrameID = m_currentFrameID; // make copy as we release lock later
1770 // Data_Types frame_type; //TYPE_I16, TYPE_U32, TYPE_DOUBLE
1771  stat = mgr->openFrame(FrameID, &refCount);
1772  if (stat != 0)
1773  return;
1774 // stat = mgr->getFrameType(FrameID, &frame_type);
1775 // if (stat != 0)
1776 // return;
1777  stat = mgr->getFrameSize(FrameID, &width, &height);
1778  if (stat != 0 || width == 0 || height == 0)
1779  {
1780  mgr->closeFrame(FrameID, &refCount);
1781  return;
1782  }
1783  buffer = new u32[width * height];
1784  if (buffer == NULL)
1785  {
1786  mgr->closeFrame(FrameID, &refCount);
1787  return;
1788  }
1789  byteSize = width * height * sizeof(u32) + 64; // +64 so we can test size after call
1790  stat = mgr->getFrameData(FrameID, (byte*)buffer, &byteSize, TYPE_U32);
1791  mgr->closeFrame(FrameID, &refCount);
1792  if ( stat != 0 || byteSize != width * height * sizeof(u32) )
1793  {
1794  delete[] buffer;
1795  return;
1796  }
1797 // stat = mgr->mpxCtrlGetFrame32(m_devId, buffer, m_devInfo.numberOfChips * MATRIX_SIZE, 0);
1798  processFrame(buffer, width, height);
1799  delete[] buffer;
1800 }
1801 
1802 // already have lock
1803 // setIntegerParam(ADNumImagesCounter, 0);
1804 void pixelmanDriver::processFrame(u32* buffer, u32 width, u32 height)
1805 {
1806  static const char* functionName = "processFrame";
1807  int acquiring = 0;
1808  int status = asynSuccess;
1809  int imageCounter;
1810  int numImages, numImagesCounter;
1811  int imageMode;
1812  int arrayCallbacks;
1813  NDArray *pImage;
1814  double acquireTime, acquirePeriod, delay;
1815  epicsTimeStamp startTime, endTime;
1816  double elapsedTime;
1817 
1818  setIntegerParam(ADSizeX, width);
1819  setIntegerParam(ADSizeY, height);
1820  getIntegerParam(ADAcquire, &acquiring);
1821  getDoubleParam(ADAcquirePeriod, &acquirePeriod);
1822  setIntegerParam(ADStatus, ADStatusAcquire);
1823  epicsTimeGetCurrent(&startTime);
1824  getIntegerParam(ADImageMode, &imageMode);
1825 
1826  /* Get the exposure parameters */
1827  getDoubleParam(ADAcquireTime, &acquireTime); // not really used
1828 
1829  setShutter(ADShutterOpen);
1830  callParamCallbacks();
1831 
1832  /* Update the image */
1833  int maxval = 0;
1834  for(int i=0; i<width*height; ++i)
1835  {
1836  if (buffer[i] > maxval)
1837  {
1838  maxval = buffer[i];
1839  }
1840  }
1841  status = computeImage(buffer, width, height);
1842 // if (status) continue;
1843 
1844  // could sleep to make up to acquireTime
1845 
1846  /* Close the shutter */
1847  setShutter(ADShutterClosed);
1848 
1849  setIntegerParam(ADStatus, ADStatusReadout);
1850  /* Call the callbacks to update any changes */
1851  callParamCallbacks();
1852 
1853  pImage = this->pArrays[0];
1854 
1855  /* Get the current parameters */
1856  getIntegerParam(NDArrayCounter, &imageCounter);
1857  getIntegerParam(ADNumImages, &numImages);
1858  getIntegerParam(ADNumImagesCounter, &numImagesCounter);
1859  getIntegerParam(NDArrayCallbacks, &arrayCallbacks);
1860  imageCounter++;
1861  numImagesCounter++;
1862  setIntegerParam(NDArrayCounter, imageCounter);
1863  setIntegerParam(ADNumImagesCounter, numImagesCounter);
1864 
1865  /* Put the frame number and time stamp into the buffer */
1866  pImage->uniqueId = imageCounter;
1867  pImage->timeStamp = startTime.secPastEpoch + startTime.nsec / 1.e9;
1868  updateTimeStamp(&pImage->epicsTS);
1869 
1870  /* Get any attributes that have been defined for this driver */
1871  this->getAttributes(pImage->pAttributeList);
1872 
1873  if (arrayCallbacks) {
1874  /* Call the NDArray callback */
1875  /* Must release the lock here, or we can get into a deadlock, because we can
1876  * block on the plugin lock, and the plugin can be calling us */
1877  this->unlock();
1878  asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
1879  "%s:%s: calling imageData callback\n", driverName, functionName);
1880  doCallbacksGenericPointer(pImage, NDArrayData, 0);
1881  this->lock();
1882  }
1883 
1884  /* Call the callbacks to update any changes */
1885  callParamCallbacks();
1886  /* sleep for the acquire period minus elapsed time. */
1887  epicsTimeGetCurrent(&endTime);
1888  elapsedTime = epicsTimeDiffInSeconds(&endTime, &startTime);
1889  delay = acquirePeriod - elapsedTime;
1890  asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
1891  "%s:%s: delay=%f\n",
1892  driverName, functionName, delay);
1893 // if (delay >= 0.0) {
1894  // /* We set the status to waiting to indicate we are in the period delay */
1895 // setIntegerParam(ADStatus, ADStatusWaiting);
1896 // callParamCallbacks();
1897 // this->unlock();
1898 // epicsThreadSleep(delay);
1899 // this->lock();
1900 // setIntegerParam(ADStatus, ADStatusIdle);
1901 // callParamCallbacks();
1902 // }
1903 }
1904 
1906 int pixelmanDriver::computeImage(epicsUInt32 *value, u32 width, u32 height)
1907 {
1908  int status = asynSuccess;
1909  NDDataType_t dataType;
1910  int itemp;
1911  int binX, binY, minX, minY, sizeX, sizeY, reverseX, reverseY;
1912  int xDim=0, yDim=1, colorDim=-1;
1913  int maxSizeX, maxSizeY;
1914  int colorMode;
1915  int ndims=0;
1916  NDDimension_t dimsOut[3];
1917  size_t dims[3], dims2[2];
1918  NDArrayInfo_t arrayInfo;
1919  NDArray *pImage;
1920  const char* functionName = "computeImage";
1921 
1922  /* NOTE: The caller of this function must have taken the mutex */
1923 
1924  status |= getIntegerParam(ADBinX, &binX);
1925  status |= getIntegerParam(ADBinY, &binY);
1926  status |= getIntegerParam(ADMinX, &minX);
1927  status |= getIntegerParam(ADMinY, &minY);
1928  status |= getIntegerParam(ADSizeX, &sizeX);
1929  status |= getIntegerParam(ADSizeY, &sizeY);
1930  status |= getIntegerParam(ADReverseX, &reverseX);
1931  status |= getIntegerParam(ADReverseY, &reverseY);
1932  status |= getIntegerParam(ADMaxSizeX, &maxSizeX);
1933  status |= getIntegerParam(ADMaxSizeY, &maxSizeY);
1934  status |= getIntegerParam(NDColorMode, &colorMode);
1935  status |= getIntegerParam(NDDataType, &itemp);
1936  dataType = (NDDataType_t)itemp;
1937  if (status) asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
1938  "%s:%s: error getting parameters\n",
1939  driverName, functionName);
1940 
1941  /* Make sure parameters are consistent, fix them if they are not */
1942  if (binX < 1) {
1943  binX = 1;
1944  status |= setIntegerParam(ADBinX, binX);
1945  }
1946  if (binY < 1) {
1947  binY = 1;
1948  status |= setIntegerParam(ADBinY, binY);
1949  }
1950  if (minX < 0) {
1951  minX = 0;
1952  status |= setIntegerParam(ADMinX, minX);
1953  }
1954  if (minY < 0) {
1955  minY = 0;
1956  status |= setIntegerParam(ADMinY, minY);
1957  }
1958  if (minX > maxSizeX-1) {
1959  minX = maxSizeX-1;
1960  status |= setIntegerParam(ADMinX, minX);
1961  }
1962  if (minY > maxSizeY-1) {
1963  minY = maxSizeY-1;
1964  status |= setIntegerParam(ADMinY, minY);
1965  }
1966  if (minX+sizeX > maxSizeX) {
1967  sizeX = maxSizeX-minX;
1968  status |= setIntegerParam(ADSizeX, sizeX);
1969  }
1970  if (minY+sizeY > maxSizeY) {
1971  sizeY = maxSizeY-minY;
1972  status |= setIntegerParam(ADSizeY, sizeY);
1973  }
1974 
1975  switch (colorMode) {
1976  case NDColorModeMono:
1977  ndims = 2;
1978  xDim = 0;
1979  yDim = 1;
1980  break;
1981  case NDColorModeRGB1:
1982  ndims = 3;
1983  colorDim = 0;
1984  xDim = 1;
1985  yDim = 2;
1986  break;
1987  case NDColorModeRGB2:
1988  ndims = 3;
1989  colorDim = 1;
1990  xDim = 0;
1991  yDim = 2;
1992  break;
1993  case NDColorModeRGB3:
1994  ndims = 3;
1995  colorDim = 2;
1996  xDim = 0;
1997  yDim = 1;
1998  break;
1999  }
2000 
2001 // we could be more efficient
2002 // if (resetImage) {
2003  /* Free the previous raw buffer */
2004  if (m_pRaw) m_pRaw->release();
2005  /* Allocate the raw buffer we use to compute images. */
2006  dims[xDim] = sizeX;
2007  dims[yDim] = sizeY;
2008  size_t nelements = sizeX * sizeY;
2009  if (ndims > 2) dims[colorDim] = 3;
2010  m_pRaw = this->pNDArrayPool->alloc(ndims, dims, dataType, 0, NULL);
2011 
2012  if (!m_pRaw) {
2013  asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
2014  "%s:%s: error allocating raw buffer\n",
2015  driverName, functionName);
2016  return(status);
2017  }
2018 // }
2019 
2020  switch (dataType) {
2021  case NDInt8:
2022  status |= computeArray<epicsInt8>(value, nelements, sizeX, sizeY);
2023  break;
2024  case NDUInt8:
2025  status |= computeArray<epicsUInt8>(value, nelements, sizeX, sizeY);
2026  break;
2027  case NDInt16:
2028  status |= computeArray<epicsInt16>(value, nelements, sizeX, sizeY);
2029  break;
2030  case NDUInt16:
2031  status |= computeArray<epicsUInt16>(value, nelements, sizeX, sizeY);
2032  break;
2033  case NDInt32:
2034  status |= computeArray<epicsInt32>(value, nelements, sizeX, sizeY);
2035  break;
2036  case NDUInt32:
2037  status |= computeArray<epicsUInt32>(value, nelements, sizeX, sizeY);
2038  break;
2039  case NDFloat32:
2040  status |= computeArray<epicsFloat32>(value, nelements, sizeX, sizeY);
2041  break;
2042  case NDFloat64:
2043  status |= computeArray<epicsFloat64>(value, nelements, sizeX, sizeY);
2044  break;
2045  }
2046 
2047  /* Extract the region of interest with binning.
2048  * If the entire image is being used (no ROI or binning) that's OK because
2049  * convertImage detects that case and is very efficient */
2050  m_pRaw->initDimension(&dimsOut[xDim], sizeX);
2051  m_pRaw->initDimension(&dimsOut[yDim], sizeY);
2052  if (ndims > 2) m_pRaw->initDimension(&dimsOut[colorDim], 3);
2053  dimsOut[xDim].binning = binX;
2054  dimsOut[xDim].offset = minX;
2055  dimsOut[xDim].reverse = reverseX;
2056  dimsOut[yDim].binning = binY;
2057  dimsOut[yDim].offset = minY;
2058  dimsOut[yDim].reverse = reverseY;
2059  /* We save the most recent image buffer so it can be used in the read() function.
2060  * Now release it before getting a new version. */
2061  if (this->pArrays[0]) this->pArrays[0]->release();
2062  status = this->pNDArrayPool->convert(m_pRaw,
2063  &this->pArrays[0],
2064  dataType,
2065  dimsOut);
2066  if (status) {
2067  asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
2068  "%s:%s: error allocating buffer in convert()\n",
2069  driverName, functionName);
2070  return(status);
2071  }
2072  pImage = this->pArrays[0];
2073  pImage->getInfo(&arrayInfo);
2074  status = asynSuccess;
2075  status |= setIntegerParam(NDArraySize, (int)arrayInfo.totalBytes);
2076  status |= setIntegerParam(NDArraySizeX, (int)pImage->dims[xDim].size);
2077  status |= setIntegerParam(NDArraySizeY, (int)pImage->dims[yDim].size);
2078  if (status) asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
2079  "%s:%s: error setting parameters\n",
2080  driverName, functionName);
2081  return(status);
2082 }
2083 
2084 // supplied array of x,y,t
2085 template <typename epicsType>
2086 int pixelmanDriver::computeArray(epicsUInt32* value, size_t nelements, int sizeX, int sizeY)
2087 {
2088  epicsType *pMono=NULL, *pRed=NULL, *pGreen=NULL, *pBlue=NULL;
2089  int columnStep=0, rowStep=0, colorMode;
2090  int status = asynSuccess;
2091  double exposureTime;
2092  int i, j;
2093 
2094  status = getIntegerParam(NDColorMode, &colorMode);
2095  status = getDoubleParam (ADAcquireTime, &exposureTime);
2096 
2097  switch (colorMode) {
2098  case NDColorModeMono:
2099  pMono = (epicsType *)m_pRaw->pData;
2100  break;
2101  case NDColorModeRGB1:
2102  columnStep = 3;
2103  rowStep = 0;
2104  pRed = (epicsType *)m_pRaw->pData;
2105  pGreen = (epicsType *)m_pRaw->pData+1;
2106  pBlue = (epicsType *)m_pRaw->pData+2;
2107  break;
2108  case NDColorModeRGB2:
2109  columnStep = 1;
2110  rowStep = 2 * sizeX;
2111  pRed = (epicsType *)m_pRaw->pData;
2112  pGreen = (epicsType *)m_pRaw->pData + sizeX;
2113  pBlue = (epicsType *)m_pRaw->pData + 2*sizeX;
2114  break;
2115  case NDColorModeRGB3:
2116  columnStep = 1;
2117  rowStep = 0;
2118  pRed = (epicsType *)m_pRaw->pData;
2119  pGreen = (epicsType *)m_pRaw->pData + sizeX*sizeY;
2120  pBlue = (epicsType *)m_pRaw->pData + 2*sizeX*sizeY;
2121  break;
2122  }
2123  m_pRaw->pAttributeList->add("ColorMode", "Color mode", NDAttrInt32, &colorMode);
2124  memset(m_pRaw->pData, 0, m_pRaw->dataSize);
2125  for (i = sizeY-1; i>= 0; --i) {
2126  switch (colorMode) {
2127  case NDColorModeMono:
2128  for (j = 0; j<sizeX; j++) {
2129  *pMono = value[i*sizeX+j];
2130  ++pMono;
2131  }
2132  break;
2133  case NDColorModeRGB1:
2134  case NDColorModeRGB2:
2135  case NDColorModeRGB3:
2136  for (j = 0; j<sizeX; j++) {
2137  *pRed = value[i*sizeX + j];
2138  *pGreen = value[i*sizeX + j];
2139  *pBlue = value[i*sizeX + j];
2140  pRed += columnStep;
2141  pGreen += columnStep;
2142  pBlue += columnStep;
2143  }
2144  pRed += rowStep;
2145  pGreen += rowStep;
2146  pBlue += rowStep;
2147  break;
2148  }
2149  }
2150 
2151  return(status);
2152 }
2153 
2154 
2155 #if 0
2156 void pixelmanDriver::readFrame()
2157 {
2158  u32 refCount, width, height, byteSize;
2159  u32* buffer;
2160  int stat;
2161  u32 max;
2162  FRAMEID FrameID;
2163  Data_Types frame_type; //TYPE_I16, TYPE_U32, TYPE_DOUBLE
2164  buffer = new u32[m_devInfo.numberOfChips * MATRIX_SIZE];
2165  stat = mgr->mpxCtrlGetFrame32(m_devId, buffer, m_devInfo.numberOfChips * MATRIX_SIZE, 0);
2166  max = 0;
2167  for (int i = 0; i < m_devInfo.numberOfChips * MATRIX_SIZE; ++i)
2168  {
2169  max = (max > buffer[i] ? max : buffer[i]);
2170  }
2171  delete[]buffer;
2172  if (stat != 0)
2173  return;
2174  stat = mgr->mpxCtrlGetFrameID(m_devId, 0, &FrameID);
2175  if (stat != 0)
2176  return;
2177  stat = mgr->openFrame(FrameID, &refCount);
2178  if (stat != 0)
2179  return;
2180  stat = mgr->getFrameType(FrameID, &frame_type);
2181  if (stat != 0)
2182  return;
2183  stat = mgr->getFrameSize(FrameID, &width, &height);
2184  if (stat != 0)
2185  return;
2186  buffer = new u32[width * height];
2187  byteSize = width * height * sizeof(u32) + 64; // +64 so we can test size after call
2188  stat = mgr->getFrameData(FrameID, (byte*)buffer, &byteSize, TYPE_U32);
2189  if (byteSize != width * height * sizeof(u32))
2190  {
2191  ;
2192  }
2193  max = 0;
2194  for (int i = 0; i < width * height; ++i)
2195  {
2196  max = (max > buffer[i] ? max : buffer[i]);
2197  }
2198  delete[] buffer;
2199  stat = mgr->closeFrame(FrameID, &refCount);
2200 }
2201 
2202 
2203 #endif
start integral acquisition
camera not taking data
Header for pixelman EPICS plugin.
start frame acquisition
dbLoadDatabase(TOP)/dbd/pixelman.dbd"
Register all support components ;.
iocInit
ISIS common init ;.
Definition: pixelman.cmd:78
abort acquisition
virtual void setShutter(int open)
Controls the shutter.
pixelman asyn driver
pixelmanConfigure("MCP","$(PIXDET=dummy)")
&quot;BeARQuT&quot; is the real MCP detector, &quot;dummy&quot; is the simulation mode ; PIXDET variable normally set in ...
int computeImage(epicsUInt32 *value, u32 width, u32 height)
Computes the new image data.
dbLoadRecords("NDTransform.template","P=$(MYPVPREFIX),R=PIXELMAN:AD:rawimage1:,PORT=ADRawImage1,ADDR=0,TIMEOUT=1,NDARRAY_PORT=MCP,NDARRAY_ADDR=0,DATATYPE=4,ENABLED=1")
This waveform ; TYPE=Int8,FTVL=UCHAR for 8 bit integer ; TYPE=Int32,FTVL=LONG,DATATYPE=4 for 32 bit i...
Copyright © 2013 Science and Technology Facilities Council | Generated by   doxygen 1.8.5