PageRenderTime 64ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/ATF2/control-software/epics-3.14.10/support/asyn/4-14/asyn/miscellaneous/asynPortDriver.cpp

http://atf2flightsim.googlecode.com/
C++ | 1544 lines | 1008 code | 163 blank | 373 comment | 205 complexity | 3159591f8aec13e341d01859f360ce38 MD5 | raw file
Possible License(s): BSD-2-Clause, LGPL-2.0, IPL-1.0, BSD-3-Clause
  1. /*
  2. * asynPortDriver.cpp
  3. *
  4. * Base class that implements methods for asynStandardInterfaces with a parameter library.
  5. *
  6. * Author: Mark Rivers
  7. *
  8. * Created April 27, 2008
  9. */
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <stdio.h>
  13. #include <errno.h>
  14. #include <epicsString.h>
  15. #include <epicsMutex.h>
  16. #include <epicsThread.h>
  17. #include <cantProceed.h>
  18. /* NOTE: This is needed for interruptAccept */
  19. #include <dbAccess.h>
  20. #include <asynStandardInterfaces.h>
  21. #include "asynPortDriver.h"
  22. static const char *driverName = "asynPortDriver";
  23. /* I thought this would be a temporary fix until EPICS supported PINI after interruptAccept, which would then be used
  24. * for input records that need callbacks after output records that also have PINI and that could affect them. But this
  25. * does not work with asyn device support because of the ring buffer. Records with SCAN=I/O Intr must not processed
  26. * for any other reason, including PINI, or the ring buffer can get out of sync. */
  27. static void callbackTaskC(void *drvPvt)
  28. {
  29. asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
  30. pPvt->callbackTask();
  31. }
  32. void asynPortDriver::callbackTask()
  33. {
  34. int addr;
  35. while(!interruptAccept) epicsThreadSleep(0.1);
  36. epicsMutexLock(this->mutexId);
  37. for (addr=0; addr<this->maxAddr; addr++) {
  38. callParamCallbacks(addr, addr);
  39. }
  40. epicsMutexUnlock(this->mutexId);
  41. }
  42. /** Constructor for paramList class.
  43. * \param[in] nVals Number of parameters in the list.
  44. * \param[in] pasynInterfaces Pointer to asynStandardInterfaces structure, used for callbacks */
  45. paramList::paramList(int nVals, asynStandardInterfaces *pasynInterfaces)
  46. : nextParam(0), nVals(nVals), nFlags(0), pasynInterfaces(pasynInterfaces)
  47. {
  48. vals = (paramVal *) calloc(nVals, sizeof(paramVal));
  49. flags = (int *) calloc(nVals, sizeof(int));
  50. }
  51. /** Destructor for paramList class; frees resources allocated in constructor */
  52. paramList::~paramList()
  53. {
  54. free(vals);
  55. free(flags);
  56. }
  57. asynStatus paramList::setFlag(int index)
  58. {
  59. int i;
  60. if (index < 0 || index >= this->nVals) return asynParamBadIndex;
  61. /* See if we have already set the flag for this parameter */
  62. for (i=0; i<this->nFlags; i++) if (this->flags[i] == index) break;
  63. /* If not found add a flag */
  64. if (i == this->nFlags) this->flags[this->nFlags++] = index;
  65. return asynSuccess;
  66. }
  67. /** Adds a new parameter to the parameter library.
  68. * \param[in] name The name of this parameter
  69. * \param[in] type The type of this parameter
  70. * \param[out] index The parameter number
  71. * \return Returns asynParamAlreadyExists if the parameter already exists, or asynBadParamIndex if
  72. * adding this parameter would exceed the size of the parameter list. */
  73. asynStatus paramList::createParam(const char *name, asynParamType type, int *index)
  74. {
  75. if (this->findParam(name, index) == asynSuccess) return asynParamAlreadyExists;
  76. *index = this->nextParam++;
  77. if (*index < 0 || *index >= this->nVals) return asynParamBadIndex;
  78. this->vals[*index].name = epicsStrDup(name);
  79. this->vals[*index].type = type;
  80. this->vals[*index].valueDefined = 0;
  81. return asynSuccess;
  82. }
  83. /** Finds a parameter in the parameter library.
  84. * \param[in] name The name of this parameter
  85. * \param[out] index The parameter number
  86. * \return Returns asynParamNotFound if name is not found in the parameter list. */
  87. asynStatus paramList::findParam(const char *name, int *index)
  88. {
  89. for (*index=0; *index<this->nVals; (*index)++) {
  90. if (name && this->vals[*index].name && (epicsStrCaseCmp(name, this->vals[*index].name) == 0)) return asynSuccess;
  91. }
  92. return asynParamNotFound;
  93. }
  94. /** Sets the value for an integer in the parameter library.
  95. * \param[in] index The parameter number
  96. * \param[in] value Value to set.
  97. * \return Returns asynParamBadIndex if the index is not valid or asynParamWrongType if the parametertype is not asynParamInt32. */
  98. asynStatus paramList::setInteger(int index, int value)
  99. {
  100. if (index < 0 || index >= this->nVals) return asynParamBadIndex;
  101. if (this->vals[index].type != asynParamInt32) return asynParamWrongType;
  102. if ((!this->vals[index].valueDefined) || (this->vals[index].data.ival != value))
  103. {
  104. this->vals[index].valueDefined = 1;
  105. setFlag(index);
  106. this->vals[index].data.ival = value;
  107. }
  108. return asynSuccess;
  109. }
  110. /** Sets the value for an integer in the parameter library.
  111. * \param[in] index The parameter number
  112. * \param[in] value Value to set.
  113. * \param[in] mask Mask to use when setting the value.
  114. * \return Returns asynParamBadIndex if the index is not valid or asynParamWrongType if the parameter type is not asynParamUInt32Digital. */
  115. asynStatus paramList::setUInt32(int index, epicsUInt32 value, epicsUInt32 mask)
  116. {
  117. if (index < 0 || index >= this->nVals) return asynParamBadIndex;
  118. if (this->vals[index].type != asynParamUInt32Digital) return asynParamWrongType;
  119. if ((!this->vals[index].valueDefined) || (this->vals[index].data.uival != value))
  120. {
  121. this->vals[index].valueDefined = 1;
  122. setFlag(index);
  123. /* Set any bits that are set in the value and the mask */
  124. this->vals[index].data.uival |= (value & mask);
  125. /* Clear bits that are clear in the value and set in the mask */
  126. this->vals[index].data.uival &= (value | ~mask);
  127. }
  128. return asynSuccess;
  129. }
  130. /** Sets the value for a double in the parameter library.
  131. * \param[in] index The parameter number
  132. * \param[in] value Value to set.
  133. * \return Returns asynParamBadIndex if the index is not valid or asynParamWrongType if the parameter type is not asynParamFloat64. */
  134. asynStatus paramList::setDouble(int index, double value)
  135. {
  136. if (index < 0 || index >= this->nVals) return asynParamBadIndex;
  137. if (this->vals[index].type != asynParamFloat64) return asynParamWrongType;
  138. if ((!this->vals[index].valueDefined) || (this->vals[index].data.dval != value))
  139. {
  140. this->vals[index].valueDefined = 1;
  141. setFlag(index);
  142. this->vals[index].data.dval = value;
  143. }
  144. return asynSuccess;
  145. }
  146. /** Sets the value for a string in the parameter library.
  147. * \param[in] index The parameter number
  148. * \param[out] value Address of value to set.
  149. * \return Returns asynParamBadIndex if the index is not valid or asynParamWrongType if the parameter type is not asynParamOctet. */
  150. asynStatus paramList::setString(int index, const char *value)
  151. {
  152. if (index < 0 || index >= this->nVals) return asynParamBadIndex;
  153. if (this->vals[index].type != asynParamOctet) return asynParamWrongType;
  154. if ((!this->vals[index].valueDefined) || (strcmp(this->vals[index].data.sval, value)))
  155. {
  156. this->vals[index].valueDefined = 1;
  157. setFlag(index);
  158. free(this->vals[index].data.sval);
  159. this->vals[index].data.sval = epicsStrDup(value);
  160. }
  161. return asynSuccess;
  162. }
  163. /** Returns the value for an integer from the parameter library.
  164. * \param[in] index The parameter number
  165. * \param[out] value Address of value to get.
  166. * \return Returns asynParamBadIndex if the index is not valid, asynParamWrongType if the parameter type is not asynParamInt32,
  167. * or asynParamUndefined if the value has not been defined. */
  168. asynStatus paramList::getInteger(int index, int *value)
  169. {
  170. if (index < 0 || index >= this->nVals) return asynParamBadIndex;
  171. if (this->vals[index].type != asynParamInt32) return asynParamWrongType;
  172. if (!this->vals[index].valueDefined) return asynParamUndefined;
  173. *value = this->vals[index].data.ival;
  174. return asynSuccess;
  175. }
  176. /** Returns the value for an integer from the parameter library.
  177. * \param[in] index The parameter number
  178. * \param[out] value Address of value to get.
  179. * \param[in] mask The mask to use when getting the value.
  180. * \return Returns asynParamBadIndex if the index is not valid, asynParamWrongType if the parameter type is not asynParamUInt32Digital,
  181. * or asynParamUndefined if the value has not been defined. */
  182. asynStatus paramList::getUInt32(int index, epicsUInt32 *value, epicsUInt32 mask)
  183. {
  184. if (index < 0 || index >= this->nVals) return asynParamBadIndex;
  185. if (this->vals[index].type != asynParamUInt32Digital) return asynParamWrongType;
  186. if (!this->vals[index].valueDefined) return asynParamUndefined;
  187. *value = this->vals[index].data.uival & mask;
  188. return asynSuccess;
  189. }
  190. /** Returns the value for a double from the parameter library.
  191. * \param[in] index The parameter number
  192. * \param[out] value Address of value to get.
  193. * \return Returns asynParamBadIndex if the index is not valid, asynParamWrongType if the parameter type is not asynParamFloat64,
  194. * or asynParamUndefined if the value has not been defined. */
  195. asynStatus paramList::getDouble(int index, double *value)
  196. {
  197. if (index < 0 || index >= this->nVals) return asynParamBadIndex;
  198. if (this->vals[index].type != asynParamFloat64) return asynParamWrongType;
  199. if (!this->vals[index].valueDefined) return asynParamUndefined;
  200. *value = this->vals[index].data.dval;
  201. return asynSuccess;
  202. }
  203. /** Sets the value of the UInt32Interrupt in the parameter library.
  204. * \param[in] index The parameter number
  205. * \param[in] mask The interrupt mask.
  206. * \param[in] reason The interrupt reason.
  207. * \return Returns asynParamBadIndex if the index is not valid,
  208. * or asynParamWrongType if the parameter type is not asynParamUInt32Digital */
  209. asynStatus paramList::setUInt32Interrupt(int index, epicsUInt32 mask, interruptReason reason)
  210. {
  211. if (index < 0 || index >= this->nVals) return asynParamBadIndex;
  212. if (this->vals[index].type != asynParamUInt32Digital) return asynParamWrongType;
  213. this->vals[index].uInt32InterruptMask = mask;
  214. this->vals[index].uInt32InterruptReason = reason;
  215. return asynSuccess;
  216. }
  217. /** Clears the UInt32Interrupt in the parameter library.
  218. * \param[in] index The parameter number
  219. * \param[in] mask The interrupt mask.
  220. * \return Returns asynParamBadIndex if the index is not valid,
  221. * or asynParamWrongType if the parameter type is not asynParamUInt32Digital */
  222. asynStatus paramList::clearUInt32Interrupt(int index, epicsUInt32 mask)
  223. {
  224. if (index < 0 || index >= this->nVals) return asynParamBadIndex;
  225. if (this->vals[index].type != asynParamUInt32Digital) return asynParamWrongType;
  226. this->vals[index].uInt32InterruptMask = mask;
  227. return asynSuccess;
  228. }
  229. /** Returns the UInt32Interrupt from the parameter library.
  230. * \param[in] index The parameter number
  231. * \param[out] mask The address of the interrupt mask to return.
  232. * \param[in] reason The interrupt reason.
  233. * \return Returns asynParamBadIndex if the index is not valid,
  234. * or asynParamWrongType if the parameter type is not asynParamUInt32Digital */
  235. asynStatus paramList::getUInt32Interrupt(int index, epicsUInt32 *mask, interruptReason reason)
  236. {
  237. if (index < 0 || index >= this->nVals) return asynParamBadIndex;
  238. if (this->vals[index].type != asynParamUInt32Digital) return asynParamWrongType;
  239. *mask = this->vals[index].uInt32InterruptMask;
  240. return asynSuccess;
  241. }
  242. /** Returns the value for a string from the parameter library.
  243. * \param[in] index The parameter number
  244. * \param[in] maxChars Maximum number of characters to return.
  245. * \param[out] value Address of value to get.
  246. * \return Returns asynParamBadIndex if the index is not valid, asynParamWrongType if the parameter type is not asynParamOctet,
  247. * or asynParamUndefined if the value has not been defined. */
  248. asynStatus paramList::getString(int index, int maxChars, char *value)
  249. {
  250. if (index < 0 || index >= this->nVals) return asynParamBadIndex;
  251. if (this->vals[index].type != asynParamOctet) return asynParamWrongType;
  252. if (!this->vals[index].valueDefined) return asynParamUndefined;
  253. if (maxChars > 0) {
  254. strncpy(value, this->vals[index].data.sval, maxChars-1);
  255. value[maxChars-1] = '\0';
  256. }
  257. return asynSuccess;
  258. }
  259. /** Returns the name of a parameter from the parameter library.
  260. * \param[in] index The parameter number
  261. * \param[out] value Address of pointer that will contain name string pointer.
  262. * \return Returns asynParamBadIndex if the index is not valid */
  263. asynStatus paramList::getName(int index, const char **value)
  264. {
  265. if (index < 0 || index >= this->nVals) return asynParamBadIndex;
  266. *value = (const char *)this->vals[index].name;
  267. return asynSuccess;
  268. }
  269. /** Calls the registered asyn callback functions for all clients for an integer parameter */
  270. asynStatus paramList::int32Callback(int command, int addr, epicsInt32 value)
  271. {
  272. ELLLIST *pclientList;
  273. interruptNode *pnode;
  274. asynStandardInterfaces *pInterfaces = this->pasynInterfaces;
  275. int address;
  276. /* Pass int32 interrupts */
  277. if (!pInterfaces->int32InterruptPvt) return(asynParamNotFound);
  278. pasynManager->interruptStart(pInterfaces->int32InterruptPvt, &pclientList);
  279. pnode = (interruptNode *)ellFirst(pclientList);
  280. while (pnode) {
  281. asynInt32Interrupt *pInterrupt = (asynInt32Interrupt *) pnode->drvPvt;
  282. pasynManager->getAddr(pInterrupt->pasynUser, &address);
  283. /* If this is not a multi-device then address is -1, change to 0 */
  284. if (address == -1) address = 0;
  285. if ((command == pInterrupt->pasynUser->reason) &&
  286. (address == addr)) {
  287. pInterrupt->callback(pInterrupt->userPvt,
  288. pInterrupt->pasynUser,
  289. value);
  290. }
  291. pnode = (interruptNode *)ellNext(&pnode->node);
  292. }
  293. pasynManager->interruptEnd(pInterfaces->int32InterruptPvt);
  294. return(asynSuccess);
  295. }
  296. /** Calls the registered asyn callback functions for all clients for an UInt32 parameter */
  297. asynStatus paramList::uint32Callback(int command, int addr, epicsUInt32 value, epicsUInt32 interruptMask)
  298. {
  299. ELLLIST *pclientList;
  300. interruptNode *pnode;
  301. asynStandardInterfaces *pInterfaces = this->pasynInterfaces;
  302. int address;
  303. /* Pass UInt32Digital interrupts */
  304. if (!pInterfaces->uInt32DigitalInterruptPvt) return(asynParamNotFound);
  305. pasynManager->interruptStart(pInterfaces->uInt32DigitalInterruptPvt, &pclientList);
  306. pnode = (interruptNode *)ellFirst(pclientList);
  307. while (pnode) {
  308. asynUInt32DigitalInterrupt *pInterrupt = (asynUInt32DigitalInterrupt *) pnode->drvPvt;
  309. pasynManager->getAddr(pInterrupt->pasynUser, &address);
  310. /* If this is not a multi-device then address is -1, change to 0 */
  311. if (address == -1) address = 0;
  312. if ((command == pInterrupt->pasynUser->reason) &&
  313. (address == addr) &&
  314. (pInterrupt->mask & interruptMask)) {
  315. pInterrupt->callback(pInterrupt->userPvt,
  316. pInterrupt->pasynUser,
  317. pInterrupt->mask & value);
  318. }
  319. pnode = (interruptNode *)ellNext(&pnode->node);
  320. }
  321. pasynManager->interruptEnd(pInterfaces->uInt32DigitalInterruptPvt);
  322. return(asynSuccess);
  323. }
  324. /** Calls the registered asyn callback functions for all clients for a double parameter */
  325. asynStatus paramList::float64Callback(int command, int addr, epicsFloat64 value)
  326. {
  327. ELLLIST *pclientList;
  328. interruptNode *pnode;
  329. asynStandardInterfaces *pInterfaces = this->pasynInterfaces;
  330. int address;
  331. /* Pass float64 interrupts */
  332. if (!pInterfaces->float64InterruptPvt) return(asynParamNotFound);
  333. pasynManager->interruptStart(pInterfaces->float64InterruptPvt, &pclientList);
  334. pnode = (interruptNode *)ellFirst(pclientList);
  335. while (pnode) {
  336. asynFloat64Interrupt *pInterrupt = (asynFloat64Interrupt *) pnode->drvPvt;
  337. pasynManager->getAddr(pInterrupt->pasynUser, &address);
  338. /* If this is not a multi-device then address is -1, change to 0 */
  339. if (address == -1) address = 0;
  340. if ((command == pInterrupt->pasynUser->reason) &&
  341. (address == addr)) {
  342. pInterrupt->callback(pInterrupt->userPvt,
  343. pInterrupt->pasynUser,
  344. value);
  345. }
  346. pnode = (interruptNode *)ellNext(&pnode->node);
  347. }
  348. pasynManager->interruptEnd(pInterfaces->float64InterruptPvt);
  349. return(asynSuccess);
  350. }
  351. /** Calls the registered asyn callback functions for all clients for a string parameter */
  352. asynStatus paramList::octetCallback(int command, int addr, char *value)
  353. {
  354. ELLLIST *pclientList;
  355. interruptNode *pnode;
  356. asynStandardInterfaces *pInterfaces = this->pasynInterfaces;
  357. int address;
  358. /* Pass octet interrupts */
  359. if (!pInterfaces->octetInterruptPvt) return(asynParamNotFound);
  360. pasynManager->interruptStart(pInterfaces->octetInterruptPvt, &pclientList);
  361. pnode = (interruptNode *)ellFirst(pclientList);
  362. while (pnode) {
  363. asynOctetInterrupt *pInterrupt = (asynOctetInterrupt *) pnode->drvPvt;
  364. pasynManager->getAddr(pInterrupt->pasynUser, &address);
  365. /* If this is not a multi-device then address is -1, change to 0 */
  366. if (address == -1) address = 0;
  367. if ((command == pInterrupt->pasynUser->reason) &&
  368. (address == addr)) {
  369. pInterrupt->callback(pInterrupt->userPvt,
  370. pInterrupt->pasynUser,
  371. value, strlen(value), ASYN_EOM_END);
  372. }
  373. pnode = (interruptNode *)ellNext(&pnode->node);
  374. }
  375. pasynManager->interruptEnd(pInterfaces->octetInterruptPvt);
  376. return(asynSuccess);
  377. }
  378. /** Calls the registered asyn callback functions for all clients for any parameters that have changed
  379. * since the last time this function was called.
  380. * \param[in] addr A client will be called if addr matches the asyn address registered for that client.
  381. *
  382. * Don't do anything if interruptAccept=0.
  383. * There is a thread that will do all callbacks once when interruptAccept goes to 1.
  384. */
  385. asynStatus paramList::callCallbacks(int addr)
  386. {
  387. int i, index;
  388. asynStatus status = asynSuccess;
  389. if (!interruptAccept) return(asynSuccess);
  390. for (i = 0; i < this->nFlags; i++)
  391. {
  392. index = this->flags[i];
  393. if (!this->vals[index].valueDefined) return(status);
  394. switch(this->vals[index].type) {
  395. case asynParamInt32:
  396. status = int32Callback(index, addr, this->vals[index].data.ival);
  397. break;
  398. case asynParamUInt32Digital:
  399. status = uint32Callback(index, addr, this->vals[index].data.uival, this->vals[index].uInt32InterruptMask);
  400. break;
  401. case asynParamFloat64:
  402. status = float64Callback(index, addr, this->vals[index].data.dval);
  403. break;
  404. case asynParamOctet:
  405. status = octetCallback(index, addr, this->vals[index].data.sval);
  406. break;
  407. default:
  408. break;
  409. }
  410. }
  411. this->nFlags=0;
  412. return(status);
  413. }
  414. asynStatus paramList::callCallbacks()
  415. {
  416. return(callCallbacks(0));
  417. }
  418. /** Reports on status of the paramList
  419. * \param[in] fp The file pointer on which report information will be written
  420. * \param[in] details The level of report detail desired. Prints the number of parameters in the list,
  421. * and if details >1 also prints the index, data type, name, and value of each parameter.
  422. */
  423. void paramList::report(FILE *fp, int details)
  424. {
  425. int i;
  426. printf( "Number of parameters is: %d\n", this->nVals );
  427. if (details <= 1) return;
  428. for (i=0; i<this->nVals; i++)
  429. {
  430. switch (this->vals[i].type)
  431. {
  432. case asynParamInt32:
  433. if (this->vals[i].valueDefined)
  434. fprintf(fp, "Parameter %d type=asynInt32, name=%s, value=%d\n", i, this->vals[i].name, this->vals[i].data.ival );
  435. else
  436. fprintf(fp, "Parameter %d type=asynInt32, name=%s, value is undefined\n", i, this->vals[i].name);
  437. break;
  438. case asynParamUInt32Digital:
  439. if (this->vals[i].valueDefined)
  440. fprintf(fp, "Parameter %d type=asynUInt32Digital, name=%s, value=%u, mask=%u\n", i, this->vals[i].name,
  441. this->vals[i].data.uival, this->vals[i].uInt32Mask );
  442. else
  443. fprintf(fp, "Parameter %d type=asynUInt32Digital, name=%s, value is undefined\n", i, this->vals[i].name);
  444. break;
  445. case asynParamFloat64:
  446. if (this->vals[i].valueDefined)
  447. fprintf(fp, "Parameter %d type=asynFloat64, name=%s, value=%f\n", i, this->vals[i].name, this->vals[i].data.dval );
  448. else
  449. fprintf(fp, "Parameter %d type=asynFloat64, name=%s, value is undefined\n", i, this->vals[i].name);
  450. break;
  451. case asynParamOctet:
  452. if (this->vals[i].valueDefined)
  453. fprintf(fp, "Parameter %d type=string, name=%s, value=%s\n", i, this->vals[i].name, this->vals[i].data.sval );
  454. else
  455. fprintf(fp, "Parameter %d type=string, name=%s, value is undefined\n", i, this->vals[i].name);
  456. break;
  457. case asynParamInt8Array:
  458. if (this->vals[i].valueDefined)
  459. fprintf(fp, "Parameter %d type=asynInt8Array, name=%s, value=%p\n", i, this->vals[i].name, this->vals[i].data.pi8 );
  460. else
  461. fprintf(fp, "Parameter %d type=asynInt8Array, name=%s, value is undefined\n", i, this->vals[i].name);
  462. break;
  463. case asynParamInt16Array:
  464. if (this->vals[i].valueDefined)
  465. fprintf(fp, "Parameter %d type=asynInt16Array, name=%s, value=%p\n", i, this->vals[i].name, this->vals[i].data.pi16 );
  466. else
  467. fprintf(fp, "Parameter %d type=asynInt16Array, name=%s, value is undefined\n", i, this->vals[i].name);
  468. break;
  469. case asynParamInt32Array:
  470. if (this->vals[i].valueDefined)
  471. fprintf(fp, "Parameter %d type=asynInt32Array, name=%s, value=%p\n", i, this->vals[i].name, this->vals[i].data.pi32 );
  472. else
  473. fprintf(fp, "Parameter %d type=asynInt32Array, name=%s, value is undefined\n", i, this->vals[i].name);
  474. break;
  475. case asynParamFloat32Array:
  476. if (this->vals[i].valueDefined)
  477. fprintf(fp, "Parameter %d type=asynFloat32Array, name=%s, value=%p\n", i, this->vals[i].name, this->vals[i].data.pf32 );
  478. else
  479. fprintf(fp, "Parameter %d type=asynFloat32Array, name=%s, value is undefined\n", i, this->vals[i].name);
  480. break;
  481. case asynParamFloat64Array:
  482. if (this->vals[i].valueDefined)
  483. fprintf(fp, "Parameter %d type=asynFloat64Array, name=%s, value=%p\n", i, this->vals[i].name, this->vals[i].data.pf64 );
  484. else
  485. fprintf(fp, "Parameter %d type=asynFloat64Array, name=%s, value is undefined\n", i, this->vals[i].name);
  486. break;
  487. default:
  488. fprintf(fp, "Parameter %d is undefined, name=%s\n", i, this->vals[i].name);
  489. break;
  490. }
  491. }
  492. }
  493. /** Locks the driver to prevent multiple threads from accessing memory at the same time.
  494. * This function is called whenever asyn clients call the functions on the asyn interfaces.
  495. * Drivers with their own background threads must call lock() to protect conflicts with
  496. * asyn clients. They can call unlock() to permit asyn clients to run during times that the driver
  497. * thread is idle or is performing compute bound work that does not access memory also accessible by clients. */
  498. asynStatus asynPortDriver::lock()
  499. {
  500. int status;
  501. status = epicsMutexLock(this->mutexId);
  502. if (status) return(asynError);
  503. else return(asynSuccess);
  504. }
  505. /** Unocks the driver; called when an asyn client or driver is done accessing common memory. */
  506. asynStatus asynPortDriver::unlock()
  507. {
  508. epicsMutexUnlock(this->mutexId);
  509. return(asynSuccess);
  510. }
  511. /** Creates a parameter in the parameter library.
  512. * Calls paramList::createParam (list, name, index) for all parameters lists.
  513. * \param[in] name Parameter name
  514. * \param[in] type Parameter type
  515. * \param[out] index Parameter number */
  516. asynStatus asynPortDriver::createParam(const char *name, asynParamType type, int *index)
  517. {
  518. int list;
  519. asynStatus status;
  520. /* All parameters lists support the same parameters, so add the parameter name to all lists */
  521. for (list=0; list<this->maxAddr; list++) {
  522. status = createParam(list, name, type, index);
  523. if (status) return asynError;
  524. }
  525. return asynSuccess;
  526. }
  527. /** Creates a parameter in the parameter library.
  528. * Calls paramList::addParam (name, index) for the parameter list indexed by list.
  529. * \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
  530. * \param[in] name Parameter name
  531. * \param[in] type Parameter type
  532. * \param[out] index Parameter number */
  533. asynStatus asynPortDriver::createParam(int list, const char *name, asynParamType type, int *index)
  534. {
  535. asynStatus status;
  536. int itemp;
  537. static const char *functionName = "createParam";
  538. status = this->params[list]->findParam(name, &itemp);
  539. if (status == asynParamAlreadyExists) {
  540. asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
  541. "%s:%s: port=%s error adding parameter %s to list %d, parameter already exists.\n",
  542. driverName, functionName, portName, name, list);
  543. return(asynError);
  544. }
  545. status = this->params[list]->createParam(name, type, index);
  546. if (status == asynParamBadIndex) {
  547. asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
  548. "%s:%s: port=%s error adding parameter %s to list %d, too many parameters\n",
  549. driverName, functionName, portName, name, list);
  550. return(asynError);
  551. }
  552. return asynSuccess;
  553. }
  554. /** Finds a parameter in the parameter library.
  555. * Calls findParam(0, name, index), i.e. for parameter list 0.
  556. * \param[in] name Parameter name
  557. * \param[out] index Parameter number */
  558. asynStatus asynPortDriver::findParam(const char *name, int *index)
  559. {
  560. return this->findParam(0, name, index);
  561. }
  562. /** Finds a parameter in the parameter library.
  563. * Calls paramList::findParam (name, index) for the parameter list indexed by list.
  564. * \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
  565. * \param[in] name Parameter name
  566. * \param[out] index Parameter number */
  567. asynStatus asynPortDriver::findParam(int list, const char *name, int *index)
  568. {
  569. return this->params[list]->findParam(name, index);
  570. }
  571. /** Returns the name of a parameter in the parameter library.
  572. * Calls getParamName(0, index, name) i.e. for parameter list 0.
  573. * \param[in] index Parameter number
  574. * \param[out] name Parameter name */
  575. asynStatus asynPortDriver::getParamName(int index, const char **name)
  576. {
  577. return this->getParamName(0, index, name);
  578. }
  579. /** Returns the name of a parameter in the parameter library.
  580. * Calls paramList::getName (index, name) for the parameter list indexed by list.
  581. * \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
  582. * \param[in] index Parameter number
  583. * \param[out] name Parameter name */
  584. asynStatus asynPortDriver::getParamName(int list, int index, const char **name)
  585. {
  586. return this->params[list]->getName(index, name);
  587. }
  588. /** Reports errors when setting parameters.
  589. * \param[in] status The error status.
  590. * \param[in] index The parameter number
  591. * \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
  592. * \param[in] functionName The name of the function that generated the error */
  593. void asynPortDriver::reportSetParamErrors(asynStatus status, int index, int list, const char *functionName)
  594. {
  595. if (status == asynParamBadIndex) {
  596. asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
  597. "%s:%s: port=%s error setting parameter %d in list %d, bad index\n",
  598. driverName, functionName, portName, index, list);
  599. }
  600. if (status == asynParamWrongType) {
  601. asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
  602. "%s:%s: port=%s error setting parameter %d in list %d, wrong type\n",
  603. driverName, functionName, portName, index, list);
  604. }
  605. }
  606. /** Sets the value for an integer in the parameter library.
  607. * Calls setIntegerParam(0, index, value) i.e. for parameter list 0.
  608. * \param[in] index The parameter number
  609. * \param[in] value Value to set. */
  610. asynStatus asynPortDriver::setIntegerParam(int index, int value)
  611. {
  612. return this->setIntegerParam(0, index, value);
  613. }
  614. /** Sets the value for an integer in the parameter library.
  615. * Calls paramList::setInteger (index, value) for the parameter list indexed by list.
  616. * \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
  617. * \param[in] index The parameter number
  618. * \param[in] value Value to set. */
  619. asynStatus asynPortDriver::setIntegerParam(int list, int index, int value)
  620. {
  621. asynStatus status;
  622. static const char *functionName = "setIntegerParam";
  623. status = this->params[list]->setInteger(index, value);
  624. if (status) reportSetParamErrors(status, index, list, functionName);
  625. return(status);
  626. }
  627. /** Sets the value for a UInt32Digital in the parameter library.
  628. * Calls setUIntDigitalParam(0, index, value) i.e. for parameter list 0.
  629. * \param[in] index The parameter number
  630. * \param[in] value Value to set.
  631. * \param[in] mask The mask to use when setting the value. */
  632. asynStatus asynPortDriver::setUIntDigitalParam(int index, epicsUInt32 value, epicsUInt32 mask)
  633. {
  634. return this->setUIntDigitalParam(0, index, value, mask);
  635. }
  636. /** Sets the value for a UInt32Digital in the parameter library.
  637. * Calls paramList::setInteger (index, value) for the parameter list indexed by list.
  638. * \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
  639. * \param[in] index The parameter number
  640. * \param[in] value Value to set.
  641. * \param[in] mask The mask to use when setting the value. */
  642. asynStatus asynPortDriver::setUIntDigitalParam(int list, int index, epicsUInt32 value, epicsUInt32 mask)
  643. {
  644. asynStatus status;
  645. static const char *functionName = "setUIntDigitalParam";
  646. status = this->params[list]->setUInt32(index, value, mask);
  647. if (status) reportSetParamErrors(status, index, list, functionName);
  648. return(status);
  649. }
  650. /** Sets the value for a double in the parameter library.
  651. * Calls setDoubleParam(0, index, value) i.e. for parameter list 0.
  652. * \param[in] index The parameter number
  653. * \param[in] value Value to set. */
  654. asynStatus asynPortDriver::setDoubleParam(int index, double value)
  655. {
  656. return this->setDoubleParam(0, index, value);
  657. }
  658. /** Sets the value for a double in the parameter library.
  659. * Calls paramList::setDouble (index, value) for the parameter list indexed by list.
  660. * \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
  661. * \param[in] index The parameter number
  662. * \param[in] value Value to set. */
  663. asynStatus asynPortDriver::setDoubleParam(int list, int index, double value)
  664. {
  665. asynStatus status;
  666. static const char *functionName = "setDoubleParam";
  667. status = this->params[list]->setDouble(index, value);
  668. if (status) reportSetParamErrors(status, index, list, functionName);
  669. return(status);
  670. }
  671. /** Sets the value for a string in the parameter library.
  672. * Calls setStringParam(0, index, value) i.e. for parameter list 0.
  673. * \param[in] index The parameter number
  674. * \param[in] value Address of value to set. */
  675. asynStatus asynPortDriver::setStringParam(int index, const char *value)
  676. {
  677. return this->setStringParam(0, index, value);
  678. }
  679. /** Sets the value for a string in the parameter library.
  680. * Calls paramList::setString (index, value) for the parameter list indexed by list.
  681. * \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
  682. * \param[in] index The parameter number
  683. * \param[in] value Address of value to set. */
  684. asynStatus asynPortDriver::setStringParam(int list, int index, const char *value)
  685. {
  686. asynStatus status;
  687. static const char *functionName = "setStringParam";
  688. status = this->params[list]->setString(index, value);
  689. if (status) reportSetParamErrors(status, index, list, functionName);
  690. return(status);
  691. }
  692. /** Reports errors when getting parameters.
  693. * asynParamBadIndex and asynParamWrongType are printed with ASYN_TRACE_ERROR because they should never happen.
  694. * asynParamUndefined is printed with ASYN_TRACE_FLOW because it is an expected error if the value is read before it
  695. * is defined, which device support can do.
  696. * \param[in] status The error status.
  697. * \param[in] index The parameter number
  698. * \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
  699. * \param[in] functionName The name of the function that generated the error */
  700. void asynPortDriver::reportGetParamErrors(asynStatus status, int index, int list, const char *functionName)
  701. {
  702. if (status == asynParamBadIndex) {
  703. asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
  704. "%s:%s: port=%s error getting parameter %d in list %d, bad index\n",
  705. driverName, functionName, portName, index, list);
  706. }
  707. if (status == asynParamWrongType) {
  708. asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
  709. "%s:%s: port=%s error getting parameter %d in list %d, wrong type\n",
  710. driverName, functionName, portName, index, list);
  711. }
  712. if (status == asynParamUndefined) {
  713. asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
  714. "%s:%s: port=%s error getting parameter %d in list %d, value undefined\n",
  715. driverName, functionName, portName, index, list);
  716. }
  717. }
  718. /** Returns the value for an integer from the parameter library.
  719. * Calls getIntegerParam(0, index, value) i.e. for parameter list 0.
  720. * \param[in] index The parameter number
  721. * \param[out] value Address of value to get. */
  722. asynStatus asynPortDriver::getIntegerParam(int index, int *value)
  723. {
  724. return this->getIntegerParam(0, index, value);
  725. }
  726. /** Returns the value for an integer from the parameter library.
  727. * Calls paramList::getInteger (index, value) for the parameter list indexed by list.
  728. * \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
  729. * \param[in] index The parameter number
  730. * \param[out] value Address of value to get. */
  731. asynStatus asynPortDriver::getIntegerParam(int list, int index, int *value)
  732. {
  733. asynStatus status;
  734. static const char *functionName = "getIntegerParam";
  735. status = this->params[list]->getInteger(index, value);
  736. if (status) reportGetParamErrors(status, index, list, functionName);
  737. return(status);
  738. }
  739. /** Returns the value for an UInt32Digital parameter from the parameter library.
  740. * Calls getUIntDigitalParam(0, index, value, mask) i.e. for parameter list 0.
  741. * \param[in] index The parameter number
  742. * \param[out] value Address of value to get.
  743. * \param[in] mask The mask to apply when getting the value */
  744. asynStatus asynPortDriver::getUIntDigitalParam(int index, epicsUInt32 *value, epicsUInt32 mask)
  745. {
  746. return this->getUIntDigitalParam(0, index, value, mask);
  747. }
  748. /** Returns the value for an UInt32Digital parameter from the parameter library.
  749. * Calls paramList::getUInt32 (index, value, mask) for the parameter list indexed by list.
  750. * \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
  751. * \param[in] index The parameter number
  752. * \param[out] value Address of value to get.
  753. * \param[in] mask The mask to apply when getting the value. */
  754. asynStatus asynPortDriver::getUIntDigitalParam(int list, int index, epicsUInt32 *value, epicsUInt32 mask)
  755. {
  756. asynStatus status;
  757. static const char *functionName = "getUIntDigitalParam";
  758. status = this->params[list]->getUInt32(index, value, mask);
  759. if (status) reportGetParamErrors(status, index, list, functionName);
  760. return(status);
  761. }
  762. /** Returns the value for a double from the parameter library.
  763. * Calls getDoubleParam(0, index, value) i.e. for parameter list 0.
  764. * \param[in] index The parameter number
  765. * \param[out] value Address of value to get. */
  766. asynStatus asynPortDriver::getDoubleParam(int index, double *value)
  767. {
  768. return this->getDoubleParam(0, index, value);
  769. }
  770. /** Returns the value for a double from the parameter library.
  771. * Calls paramList::getDouble (index, value) for the parameter list indexed by list.
  772. * \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
  773. * \param[in] index The parameter number
  774. * \param[out] value Address of value to get. */
  775. asynStatus asynPortDriver::getDoubleParam(int list, int index, double *value)
  776. {
  777. asynStatus status;
  778. static const char *functionName = "getDoubleParam";
  779. status = this->params[list]->getDouble(index, value);
  780. if (status) reportGetParamErrors(status, index, list, functionName);
  781. return(status);
  782. }
  783. /** Returns the value for a string from the parameter library.
  784. * Calls getStringParam(0, index, maxChars, value) i.e. for parameter list 0.
  785. * \param[in] index The parameter number
  786. * \param[in] maxChars Maximum number of characters to return.
  787. * \param[out] value Address of value to get. */
  788. asynStatus asynPortDriver::getStringParam(int index, int maxChars, char *value)
  789. {
  790. return this->getStringParam(0, index, maxChars, value);
  791. }
  792. /** Returns the value for a string from the parameter library.
  793. * Calls paramList::getString (index, maxChars, value) for the parameter list indexed by list.
  794. * \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
  795. * \param[in] index The parameter number
  796. * \param[in] maxChars Maximum number of characters to return.
  797. * \param[out] value Address of value to get. */
  798. asynStatus asynPortDriver::getStringParam(int list, int index, int maxChars, char *value)
  799. {
  800. asynStatus status;
  801. static const char *functionName = "getStringParam";
  802. status = this->params[list]->getString(index, maxChars, value);
  803. if (status) reportGetParamErrors(status, index, list, functionName);
  804. return(status);
  805. }
  806. /** Calls callParamCallbacks(0, 0) i.e. with both list and asyn address. */
  807. asynStatus asynPortDriver::callParamCallbacks()
  808. {
  809. return this->callParamCallbacks(0, 0);
  810. }
  811. /** Calls callParamCallbacks(addr, addr) i.e. with list=addr, which is normal. */
  812. asynStatus asynPortDriver::callParamCallbacks(int addr)
  813. {
  814. return this->callParamCallbacks(addr, addr);
  815. }
  816. /** Calls paramList::callCallbacks(addr) for a specific parameter list.
  817. * \param[in] list The parameter list number. Must be < maxAddr passed to asynPortDriver::asynPortDriver.
  818. * \param[in] addr The asyn address to be used in the callback. Typically the same value as list. */
  819. asynStatus asynPortDriver::callParamCallbacks(int list, int addr)
  820. {
  821. return this->params[list]->callCallbacks(addr);
  822. }
  823. /** Calls paramList::report(fp, details) for each parameter list that the driver supports.
  824. * \param[in] fp The file pointer on which report information will be written
  825. * \param[in] details The level of report detail desired. */
  826. void asynPortDriver::reportParams(FILE *fp, int details)
  827. {
  828. int i;
  829. for (i=0; i<this->maxAddr; i++) {
  830. fprintf(fp, "Parameter list %d\n", i);
  831. this->params[i]->report(fp, details);
  832. }
  833. }
  834. template <typename epicsType>
  835. asynStatus readArray(asynUser *pasynUser, epicsType *value, size_t nElements, size_t *nIn)
  836. {
  837. epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
  838. "%s:readArray not implemented", driverName);
  839. return(asynError);
  840. }
  841. template <typename epicsType>
  842. asynStatus writeArray(asynUser *pasynUser, epicsType *value, size_t nElements)
  843. {
  844. epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
  845. "%s:writeArray not implemented", driverName);
  846. return(asynError);
  847. }
  848. template <typename epicsType, typename interruptType>
  849. asynStatus doCallbacksArray(epicsType *value, size_t nElements,
  850. int reason, int address, void *interruptPvt)
  851. {
  852. ELLLIST *pclientList;
  853. interruptNode *pnode;
  854. int addr;
  855. pasynManager->interruptStart(interruptPvt, &pclientList);
  856. pnode = (interruptNode *)ellFirst(pclientList);
  857. while (pnode) {
  858. interruptType *pInterrupt = (interruptType *)pnode->drvPvt;
  859. pasynManager->getAddr(pInterrupt->pasynUser, &addr);
  860. /* If this is not a multi-device then address is -1, change to 0 */
  861. if (addr == -1) addr = 0;
  862. if ((pInterrupt->pasynUser->reason == reason) &&
  863. (address == addr)) {
  864. pInterrupt->callback(pInterrupt->userPvt,
  865. pInterrupt->pasynUser,
  866. value, nElements);
  867. }
  868. pnode = (interruptNode *)ellNext(&pnode->node);
  869. }
  870. pasynManager->interruptEnd(interruptPvt);
  871. return(asynSuccess);
  872. }
  873. template <typename interruptType>
  874. void reportInterrupt(FILE *fp, void *interruptPvt, const char *interruptTypeString)
  875. {
  876. ELLLIST *pclientList;
  877. interruptNode *pnode;
  878. if (interruptPvt) {
  879. pasynManager->interruptStart(interruptPvt, &pclientList);
  880. pnode = (interruptNode *)ellFirst(pclientList);
  881. while (pnode) {
  882. interruptType *pInterrupt = (interruptType *)pnode->drvPvt;
  883. fprintf(fp, " %s callback client address=%p, addr=%d, reason=%d, userPvt=%p\n",
  884. interruptTypeString, pInterrupt->callback, pInterrupt->addr,
  885. pInterrupt->pasynUser->reason, pInterrupt->userPvt);
  886. pnode = (interruptNode *)ellNext(&pnode->node);
  887. }
  888. pasynManager->interruptEnd(interruptPvt);
  889. }
  890. }
  891. /** Returns the asyn address associated with a pasynUser structure.
  892. * Derived classes rarely need to reimplement this function.
  893. * \param[in] pasynUser pasynUser structure that encodes the reason and address.
  894. * \param[out] address Returned address.
  895. * \return Returns asynError if the address is > maxAddr value passed to asynPortDriver::asynPortDriver. */
  896. asynStatus asynPortDriver::getAddress(asynUser *pasynUser, int *address)
  897. {
  898. static const char *functionName = "getAddress";
  899. pasynManager->getAddr(pasynUser, address);
  900. /* If this is not a multi-device then address is -1, change to 0 */
  901. if (*address == -1) *address = 0;
  902. if (*address > this->maxAddr-1) {
  903. asynPrint(pasynUser, ASYN_TRACE_ERROR,
  904. "%s:%s: %s invalid address=%d, max=%d\n",
  905. driverName, functionName, portName, *address, this->maxAddr-1);
  906. return(asynError);
  907. }
  908. return(asynSuccess);
  909. }
  910. /* asynInt32 interface methods */
  911. extern "C" {static asynStatus readInt32(void *drvPvt, asynUser *pasynUser,
  912. epicsInt32 *value)
  913. {
  914. asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
  915. asynStatus status;
  916. pPvt->lock();
  917. status = pPvt->readInt32(pasynUser, value);
  918. pPvt->unlock();
  919. return(status);
  920. }}
  921. /** Called when asyn clients call pasynInt32->read().
  922. * The base class implementation simply returns the value from the parameter library.
  923. * Derived classes rarely need to reimplement this function.
  924. * \param[in] pasynUser pasynUser structure that encodes the reason and address.
  925. * \param[out] value Address of the value to read. */
  926. asynStatus asynPortDriver::readInt32(asynUser *pasynUser, epicsInt32 *value)
  927. {
  928. int function = pasynUser->reason;
  929. int addr=0;
  930. asynStatus status = asynSuccess;
  931. const char *functionName = "readInt32";
  932. status = getAddress(pasynUser, &addr); if (status != asynSuccess) return(status);
  933. /* We just read the current value of the parameter from the parameter library.
  934. * Those values are updated whenever anything could cause them to change */
  935. status = (asynStatus) getIntegerParam(addr, function, value);
  936. if (status)
  937. epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
  938. "%s:%s: status=%d, function=%d, value=%d",
  939. driverName, functionName, status, function, *value);
  940. else
  941. asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
  942. "%s:%s: function=%d, value=%d\n",
  943. driverName, functionName, function, *value);
  944. return(status);
  945. }
  946. extern "C" {static asynStatus writeInt32(void *drvPvt, asynUser *pasynUser,
  947. epicsInt32 value)
  948. {
  949. asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
  950. asynStatus status;
  951. pPvt->lock();
  952. status = pPvt->writeInt32(pasynUser, value);
  953. pPvt->unlock();
  954. return(status);
  955. }}
  956. /** Called when asyn clients call pasynInt32->write().
  957. * The base class implementation simply sets the value in the parameter library and
  958. * calls any registered callbacks for this pasynUser->reason and address.
  959. * Derived classes will reimplement this function if they need to perform an action when an
  960. * asynInt32 value is written.
  961. * \param[in] pasynUser pasynUser structure that encodes the reason and address.
  962. * \param[in] value Value to write. */
  963. asynStatus asynPortDriver::writeInt32(asynUser *pasynUser, epicsInt32 value)
  964. {
  965. int function = pasynUser->reason;
  966. int addr=0;
  967. asynStatus status = asynSuccess;
  968. const char* functionName = "writeInt32";
  969. status = getAddress(pasynUser, &addr); if (status != asynSuccess) return(status);
  970. /* Set the parameter in the parameter library. */
  971. status = (asynStatus) setIntegerParam(addr, function, value);
  972. /* Do callbacks so higher layers see any changes */
  973. status = (asynStatus) callParamCallbacks(addr, addr);
  974. if (status)
  975. epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
  976. "%s:%s: status=%d, function=%d, value=%d",
  977. driverName, functionName, status, function, value);
  978. else
  979. asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
  980. "%s:%s: function=%d, value=%d\n",
  981. driverName, functionName, function, value);
  982. return status;
  983. }
  984. extern "C" {static asynStatus getBounds(void *drvPvt, asynUser *pasynUser,
  985. epicsInt32 *low, epicsInt32 *high)
  986. {
  987. asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
  988. asynStatus status;
  989. pPvt->lock();
  990. status = pPvt->getBounds(pasynUser, low, high);
  991. pPvt->unlock();
  992. return(status);
  993. }}
  994. /** Called when asyn clients call pasynInt32->getBounds(), returning the bounds on the asynInt32 interface
  995. * for drivers that use raw units.
  996. * Device support uses these values for unit conversion.
  997. * The base class implementation simply returns low=0, high=65535.
  998. * Derived classes can reimplement this function if they support raw units with different limits.
  999. * \param[in] pasynUser pasynUser structure that encodes the reason and address.
  1000. * \param[out] low Address of the low limit.
  1001. * \param[out] high Address of the high limit. */
  1002. asynStatus asynPortDriver::getBounds(asynUser *pasynUser,
  1003. epicsInt32 *low, epicsInt32 *high)
  1004. {
  1005. /* This is only needed for the asynInt32 interface when the device uses raw units.
  1006. Our interface is using engineering units. */
  1007. *low = 0;
  1008. *high = 65535;
  1009. asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
  1010. "%s::getBounds,low=%d, high=%d\n",
  1011. driverName, *low, *high);
  1012. return(asynSuccess);
  1013. }
  1014. /* asynUInt32Digital interface methods */
  1015. extern "C" {static asynStatus readUInt32Digital(void *drvPvt, asynUser *pasynUser,
  1016. epicsUInt32 *value, epicsUInt32 mask)
  1017. {
  1018. asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
  1019. asynStatus status;
  1020. pPvt->lock();
  1021. status = pPvt->readUInt32Digital(pasynUser, value, mask);
  1022. pPvt->unlock();
  1023. return(status);
  1024. }}
  1025. /** Called when asyn clients call pasynUInt32Digital->read().
  1026. * The base class implementation simply returns the value from the parameter library.
  1027. * Derived classes rarely need to reimplement this function.
  1028. * \param[in] pasynUser pasynUser structure that encodes the reason and address.
  1029. * \param[out] value Address of the value to read.
  1030. * \param[in] mask Mask value to use when reading the value. */
  1031. asynStatus asynPortDriver::readUInt32Digital(asynUser *pasynUser, epicsUInt32 *value, epicsUInt32 mask)
  1032. {
  1033. int function = pasynUser->reason;
  1034. int addr=0;
  1035. asynStatus status = asynSuccess;
  1036. const char *functionName = "readUInt32Digital";
  1037. status = getAddress(pasynUser, &addr); if (status != asynSuccess) return(status);
  1038. /* We just read the current value of the parameter from the parameter library.
  1039. * Those values are updated whenever anything could cause them to change */
  1040. status = (asynStatus) getUIntDigitalParam(addr, function, value, mask);
  1041. if (status)
  1042. epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
  1043. "%s:%s: status=%d, function=%d, value=%u mask=%u",
  1044. driverName, functionName, status, function, *value, mask);
  1045. else
  1046. asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
  1047. "%s:%s: function=%d, value=%u, mask=%u\n",
  1048. driverName, functionName, function, *value, mask);
  1049. return(status);
  1050. }
  1051. extern "C" {static asynStatus writeUInt32Digital(void *drvPvt, asynUser *pasynUser,
  1052. epicsUInt32 value, epicsUInt32 mask)
  1053. {
  1054. asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
  1055. asynStatus status;
  1056. pPvt->lock();
  1057. status = pPvt->writeUInt32Digital(pasynUser, value, mask);
  1058. pPvt->unlock();
  1059. return(status);
  1060. }}
  1061. /** Called when asyn clients call pasynUInt32Digital->write().
  1062. * The base class implementation simply sets the value in the parameter library and
  1063. * calls any registered callbacks for this pasynUser->reason and address.
  1064. * Derived classes will reimplement this function if they need to perform an action when an
  1065. * asynInt32 value is written.
  1066. * \param[in] pasynUser pasynUser structure that encodes the reason and address.
  1067. * \param[in] value Value to write.
  1068. * \param[in] mask Mask value to use when writinging the value. */
  1069. asynStatus asynPortDriver::writeUInt32Digital(asynUser *pasynUser, epicsUInt32 value, epicsUInt32 mask)
  1070. {
  1071. int function = pasynUser->reason;
  1072. int addr=0;
  1073. asynStatus status = asynSuccess;
  1074. const char* functionName = "writeUInt32Digital";
  1075. status = getAddress(pasynUser, &addr); if (status != asynSuccess) return(status);
  1076. /* Set the parameter in the parameter library. */
  1077. status = (asynStatus) setUIntDigitalParam(addr, function, value, mask);
  1078. /* Do callbacks so higher layers see any changes */
  1079. status = (asynStatus) callParamCallbacks(addr, addr);
  1080. if (status)
  1081. epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
  1082. "%s:%s: status=%d, function=%d, value=%u, mask=%u",
  1083. driverName, functionName, status, function, value, mask);
  1084. else
  1085. asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
  1086. "%s:%s: function=%d, value=%d, mask=%u\n",
  1087. driverName, functionName, function, value, mask);
  1088. return status;
  1089. }
  1090. extern "C" {static asynStatus setInterruptUInt32Digital(void *drvPvt, asynUser *pasynUser, epicsUInt32 mask, interruptReason reason)
  1091. {
  1092. asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
  1093. asynStatus status;
  1094. pPvt->lock();
  1095. status = pPvt->setInterruptUInt32Digital(pasynUser, mask, reason);
  1096. pPvt->unlock();
  1097. return(status);
  1098. }}
  1099. /** Called when asyn clients call pasynUInt32Digital->setInterrupt().
  1100. * The base class implementation simply sets the value in the parameter library.
  1101. * Derived classes will reimplement this function if they need to perform an action when an
  1102. * setInterrupt is called.
  1103. * \param[in] pasynUser pasynUser structure that encodes the reason and address.
  1104. * \param[in] mask Interrupt mask.
  1105. * \param[in] reason Interrupt reason. */
  1106. asynStatus asynPortDriver::setInterruptUInt32Digital(asynUser *pasynUser, epicsUInt32 mask, interruptReason reason)
  1107. {
  1108. int function = pasynUser->reason;
  1109. int addr=0;
  1110. asynStatus status = asynSuccess;
  1111. const char* functionName = "setInterruptUInt32Digital";
  1112. status = getAddress(pasynUser, &addr); if (status != asynSuccess) return(status);
  1113. /* Set the parameters in the parameter library. */
  1114. status = this->params[addr]->setUInt32Interrupt(function, mask, reason);
  1115. if (status)
  1116. epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
  1117. "%s:%s: status=%d, function=%d, mask=%u, reason=%d",
  1118. driverName, functionName, status, function, mask, reason);
  1119. else
  1120. asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
  1121. "%s:%s: function=%d, mask=%u, reason=%d\n",
  1122. driverName, functionName, function, mask, reason);
  1123. return status;
  1124. }
  1125. extern "C" {static asynStatus clearInterruptUInt32Digital(void *drvPvt, asynUser *pasynUser, epicsUInt32 mask)
  1126. {
  1127. asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
  1128. asynStatus status;
  1129. pPvt->lock();
  1130. status = pPvt->clearInterruptUInt32Digital(pasynUser, mask);
  1131. pPvt->unlock();
  1132. return(status);
  1133. }}
  1134. /** Called when asyn clients call pasynUInt32Digital->clearInterrupt().
  1135. * The base class implementation simply sets the value in the parameter library.
  1136. * Derived classes will reimplement this function if they need to perform an action when an
  1137. * clearInterrupt is called.
  1138. * \param[in] pasynUser pasynUser structure that encodes the reason and address.
  1139. * \param[in] mask Interrupt mask. */
  1140. asynStatus asynPortDriver::clearInterruptUInt32Digital(asynUser *pasynUser, epicsUInt32 mask)
  1141. {
  1142. int function = pasynUser->reason;
  1143. int addr=0;
  1144. asynStatus status = asynSuccess;
  1145. const char* functionName = "clearInterruptUInt32Digital";
  1146. status = getAddress(pasynUser, &addr); if (status != asynSuccess) return(status);
  1147. /* Set the parameters in the parameter library. */
  1148. status = this->params[addr]->clearUInt32Interrupt(function, mask);
  1149. if (status)
  1150. epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
  1151. "%s:%s: status=%d, function=%d, mask=%u",
  1152. driverName, functionName, status, function, mask);
  1153. else
  1154. asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
  1155. "%s:%s: function=%d, mask=%u\n",
  1156. driverName, functionName, function, mask);
  1157. return status;
  1158. }
  1159. extern "C" {static asynStatus getInterruptUInt32Digital(void *drvPvt, asynUser *pasynUser, epicsUInt32 *mask, interruptReason reason)
  1160. {
  1161. asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
  1162. asynStatus status;
  1163. pPvt->lock();
  1164. status = pPvt->getInterruptUInt32Digital(pasynUser, mask, reason);
  1165. pPvt->unlock();
  1166. return(status);
  1167. }}
  1168. /** Called when asyn clients call pasynUInt32Digital->getInterrupt().
  1169. * The base class implementation simply returns the value from the parameter library.
  1170. * Derived classes rarely need to reimplement this function.
  1171. * \param[in] pasynUser pasynUser structure that encodes the reason and address.
  1172. * \param[out] mask Interrupt mask address.
  1173. * \param[in] reason Interrupt reason. */
  1174. asynStatus asynPortDriver::getInterruptUInt32Digital(asynUser *pasynUser, epicsUInt32 *mask, interruptReason reason)
  1175. {
  1176. int function = pasynUser->reason;
  1177. int addr=0;
  1178. asynStatus status = asynSuccess;
  1179. const char* functionName = "getInterruptUInt32Digital";
  1180. status = getAddress(pasynUser, &addr); if (status != asynSuccess) return(status);
  1181. /* Get the parameters in the parameter library. */
  1182. status = this->params[addr]->getUInt32Interrupt(function, mask, reason);
  1183. if (status)
  1184. epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
  1185. "%s:%s: status=%d, function=%d, mask=%u, reason=%d",
  1186. driverName, functionName, status, function, *mask, reason);
  1187. else
  1188. asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
  1189. "%s:%s: function=%d, mask=%u, reason=%d\n",
  1190. driverName, functionName, function, *mask, reason);
  1191. return status;
  1192. }
  1193. /* asynFloat64 interface methods */
  1194. extern "C" {static asynStatus readFloat64(void *drvPvt, asynUser *pasynUser,
  1195. epicsFloat64 *value)
  1196. {
  1197. asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
  1198. asynStatus status;
  1199. pPvt->lock();
  1200. status = pPvt->readFloat64(pasynUser, value);
  1201. pPvt->unlock();
  1202. return(status);
  1203. }}
  1204. /** Called when asyn clients call pasynFloat64->read().
  1205. * The base class implementation simply returns the value from the parameter library.
  1206. * Derived classes rarely need to reimplement this function.
  1207. * \param[in] pasynUser pasynUser structure that encodes the reason and address.
  1208. * \param[in] value Address of the value to read. */
  1209. asynStatus asynPortDriver::readFloat64(asynUser *pasynUser, epicsFloat64 *value)
  1210. {
  1211. int function = pasynUser->reason;
  1212. int addr=0;
  1213. asynStatus status = asynSuccess;
  1214. const char *functionName = "readFloat64";
  1215. status = getAddress(pasynUser, &addr); if (status != asynSuccess) return(status);
  1216. /* We just read the current value of the parameter from the parameter library.
  1217. * Those values are updated whenever anything could cause them to change */
  1218. status = (asynStatus) getDoubleParam(addr, function, value);
  1219. if (status)
  1220. epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
  1221. "%s:%s: status=%d, function=%d, value=%f",
  1222. driverName, functionName, status, function, *value);
  1223. else
  1224. asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
  1225. "%s:%s: function=%d, value=%f\n",
  1226. driverName, functionName, function, *value);
  1227. return(status);
  1228. }
  1229. extern "C" {static asynStatus writeFloat64(void *drvPvt, asynUser *pasynUser,
  1230. epicsFloat64 value)
  1231. {
  1232. asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
  1233. asynStatus status;
  1234. pPvt->lock();
  1235. status = pPvt->writeFloat64(pasynUser, value);
  1236. pPvt->unlock();
  1237. return(status);
  1238. }}
  1239. /** Called when asyn clients call pasynFloat64->write().
  1240. * The base class implementation simply sets the value in the parameter library and
  1241. * calls any registered callbacks for this pasynUser->reason and address.
  1242. * Derived classes will reimplement this function if they need to perform an action when an
  1243. * asynFloat64 value is written.
  1244. * \param[in] pasynUser pasynUser structure that encodes the reason and address.
  1245. * \param[in] value Value to write. */
  1246. asynStatus asynPortDriver::writeFloat64(asynUser *pasynUser, epicsFloat64 value)
  1247. {
  1248. int function = pasynUser->reason;
  1249. asynStatus status = asynSuccess;
  1250. int addr=0;
  1251. const char *functionName = "writeFloat64";
  1252. status = getAddress(pasynUser, &addr); if (status != asynSuccess) return(status);
  1253. /* Set the parameter and readback in the parameter library. */
  1254. status = setDoubleParam(addr, function, value);
  1255. /* Do callbacks so higher layers see any changes */
  1256. callParamCallbacks(addr, addr);
  1257. if (status)
  1258. asynPrint(pasynUser, ASYN_TRACE_ERROR,
  1259. "%s:%s: error, status=%d function=%d, value=%f\n",
  1260. driverName, functionName, status, function, value);
  1261. else
  1262. asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
  1263. "%s:%s: function=%d, value=%f\n",
  1264. driverName, functionName, function, value);
  1265. return status;
  1266. }
  1267. /* asynOctet interface methods */
  1268. extern "C" {static asynStatus readOctet(void *drvPvt, asynUser *pasynUser,
  1269. char *value, size_t maxChars, size_t *nActual,
  1270. int *eomReason)
  1271. {
  1272. asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
  1273. asynStatus status;
  1274. pPvt->lock();
  1275. status = pPvt->readOctet(pasynUser, value, maxChars, nActual, eomReason);
  1276. pPvt->unlock();
  1277. return(status);
  1278. }}
  1279. /** Called when asyn clients call pasynOctet->read().
  1280. * The base class implementation simply returns the value from the parameter library.
  1281. * Derived classes rarely need to reimplement this function.
  1282. * \param[in] pasynUser pasynUser structure that encodes the reason and address.
  1283. * \param[in] value Address of the string to read.
  1284. * \param[in] maxChars Maximum number of characters to read.
  1285. * \param[out] nActual Number of characters actually read. Base class sets this to strlen(value).
  1286. * \param[out] eomReason Reason that read terminated. Base class sets this to ASYN_EOM_END. */
  1287. asynStatus asynPortDriver::readOctet(asynUser *pasynUser,
  1288. char *value, size_t maxChars, size_t *nActual,
  1289. int *eomReason)
  1290. {
  1291. int function = pasynUser->reason;
  1292. int addr=0;
  1293. asynStatus status = asynSuccess;
  1294. const char *functionName = "readOctet";
  1295. status = getAddress(pasynUser, &addr); if (status != asynSuccess) return(status);
  1296. /* We just read the current value of the parameter from the parameter library.
  1297. * Those values are updated whenever anything could cause them to change */
  1298. status = (asynStatus)getStringParam(addr, function, maxChars, value);
  1299. if (status)
  1300. epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
  1301. "%s:%s: status=%d, function=%d, value=%s",
  1302. driverName, functionName, status, function, value);
  1303. else
  1304. asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
  1305. "%s:%s: function=%d, value=%s\n",
  1306. driverName, functionName, function, value);
  1307. if (eomReason) *eomReason = ASYN_EOM_END;
  1308. *nActual = strlen(value);
  1309. return(status);
  1310. }
  1311. extern "C" {static asynStatus writeOctet(void *drvPvt, asynUser *pasynUser,
  1312. const char *value, size_t maxChars, size_t *nActual)
  1313. {
  1314. asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
  1315. asynStatus status;
  1316. pPvt->lock();
  1317. status = pPvt->writeOctet(pasynUser, value, maxChars, nActual);
  1318. pPvt->unlock();
  1319. return(status);
  1320. }}
  1321. /** Called when asyn clients call pasynOctet->write().
  1322. * The base class implementation simply sets the value in the parameter library and
  1323. * calls any registered callbacks for this pasynUser->reason and address.
  1324. * Derived classes will reimplement this function if they need to perform an action when an
  1325. * asynOctet value is written.
  1326. * \param[in] pasynUser pasynUser structure that encodes the reason and address.
  1327. * \param[in] value Address of the string to write.
  1328. * \param[in] nChars Number of characters to write.
  1329. * \param[out] nActual Number of characters actually written. */
  1330. asynStatus asynPortDriver::writeOctet(asynUser *pasynUser, const char *value,
  1331. size_t nChars, size_t *nActual)
  1332. {
  1333. int addr=0;
  1334. int function = pasynUser->reason;
  1335. asynStatus status = asynSuccess;
  1336. const char *functionName = "writeOctet";
  1337. status = getAddress(pasynUser, &addr); if (status != asynSuccess) return(status);
  1338. /* Set the parameter in the parameter library. */
  1339. status = (asynStatus)setStringParam(addr, function, (char *)value);
  1340. /* Do callbacks so higher layers see any changes */
  1341. status = (asynStatus)callParamCallbacks(addr, addr);
  1342. if (status)
  1343. epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
  1344. "%s:%s: status=%d, function=%d, value=%s",
  1345. driverName, functionName, status, function, value);
  1346. else
  1347. asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
  1348. "%s:%s: function=%d, value=%s\n",
  1349. driverName, functionName, function, value);
  1350. *nActual = nChars;
  1351. return status;
  1352. }
  1353. /* asynInt8Array interface methods */
  1354. extern "C" {static asynStatus readInt8Array(void *drvPvt, asynUser *pasynUser, epicsInt8 *value,
  1355. size_t nElements, size_t *nIn)
  1356. {
  1357. asynPortDriver *pPvt = (asynPortDriver *)drvPvt;
  1358. asynStatus status;
  1359. pPvt->lock();
  1360. status = pPvt->readInt8Array(pasynUser, value, nElements, nIn);
  1361. pPvt->unlock();
  1362. return(status);
  1363. }}
  1364. /** Called when asyn clients call pasynInt8Array->read().
  1365. * The base class implementation simply prints an error message.
  1366. * Derived classes may reimplement this function if required.
  1367. * \param[in] pasynUser pasynUser structure that encodes the reason and address.
  1368. * \param[in] value Pointer to the array to read.
  1369. * \param[in] nElements Number of elements to read.
  1370. * \param[out] nIn Number of elements actually read. */
  1371. asynStatus asynPortDriver::readInt8Array(asynUser *pasynUser, epicsInt8 *value,
  1372. size_t nElements, size_t *nIn)
  1373. {
  1374. return(readArray<epicsInt8>(pasynUser, value, nElements, nIn));
  1375. }
  1376. extern "C" {static asynStatus writeInt8Array(void *drvPvt, asynUser *pasynUser, epicsInt8 *value,
  1377. size_t nE