|
1 /* |
|
2 Description |
|
3 This module provides support for a multiple device port driver. To |
|
4 initialize the driver, the method drvAsynKeithley6485() is called from the |
|
5 startup script with the following calling sequence. |
|
6 |
|
7 drvAsynKeithley6485(myport,ioport,ioaddr) |
|
8 |
|
9 Where: |
|
10 myport - Keithley6485 Asyn interface port driver name (i.e. "EP0" ) |
|
11 ioport - Communication port driver name (i.e. "S0" ) |
|
12 ioaddr - Communication port device addr |
|
13 |
|
14 The method dbior can be called from the IOC shell to display the current |
|
15 status of the driver. |
|
16 */ |
|
17 |
|
18 |
|
19 /* System related include files */ |
|
20 #include <math.h> |
|
21 #include <stdio.h> |
|
22 #include <stdlib.h> |
|
23 #include <string.h> |
|
24 |
|
25 |
|
26 /* EPICS system related include files */ |
|
27 #include <iocsh.h> |
|
28 #include <epicsStdio.h> |
|
29 #include <cantProceed.h> |
|
30 #include <epicsString.h> |
|
31 #include <epicsExport.h> |
|
32 #include <errlog.h> |
|
33 |
|
34 /* EPICS synApps/Asyn related include files */ |
|
35 #include <asynDriver.h> |
|
36 #include <asynDrvUser.h> |
|
37 #include <asynInt32.h> |
|
38 #include <asynFloat64.h> |
|
39 #include <asynOctet.h> |
|
40 #include <asynOctetSyncIO.h> |
|
41 #include <asynStandardInterfaces.h> |
|
42 |
|
43 /* Define symbolic constants */ |
|
44 #define TIMEOUT (5.0) |
|
45 #define BUFFER_SIZE (100) |
|
46 |
|
47 |
|
48 typedef enum {Octet=1, Float64=2, Int32=3} Type; |
|
49 |
|
50 static const char *driver = "drvAsynKeithley648x"; /* String for asynPrint */ |
|
51 |
|
52 |
|
53 /* Declare port driver structure */ |
|
54 struct Port |
|
55 { |
|
56 int devtype; // 1:6485, 2:6487 |
|
57 char* myport; |
|
58 char* ioport; |
|
59 int ioaddr; |
|
60 |
|
61 int init; // really needed?? |
|
62 |
|
63 char model[BUFFER_SIZE+1], *serial, *dig_rev, *disp_rev, *brd_rev; |
|
64 |
|
65 struct |
|
66 { |
|
67 int ioErrors; |
|
68 int writeReads; |
|
69 int writeOnlys; |
|
70 } stats; |
|
71 |
|
72 struct |
|
73 { |
|
74 double reading; |
|
75 int timestamp; |
|
76 union |
|
77 { |
|
78 int raw; |
|
79 struct |
|
80 { |
|
81 unsigned int overflow : 1; |
|
82 unsigned int filter_enabled : 1; |
|
83 unsigned int math_enabled : 1; |
|
84 unsigned int null_enabled : 1; |
|
85 unsigned int limit_test : 1; |
|
86 unsigned int limit_result : 2; |
|
87 unsigned int overvoltage : 1; |
|
88 unsigned int padding : 1; |
|
89 unsigned int zero_check_enabled : 1; |
|
90 unsigned int zero_correct_enabled : 1; |
|
91 } bits; |
|
92 } status; |
|
93 /* |
|
94 Bits: |
|
95 0 (OFLO) — Set to 1 if measurement performed while in over-range |
|
96 (overflowed reading). |
|
97 1 (Filter) — Set to 1 when measurement performed with the averaging |
|
98 filter enabled. |
|
99 2 (Math) — Set to 1 when measurement performed with CALC1 enabled. |
|
100 3 (Null) — Set to 1 if null for CALC2 is enabled. |
|
101 4 (Limits) — Set to 1 if a limit test (CALC2) is enabled. |
|
102 5 & 6 (Limit Results) — Provides limit test results: |
|
103 Bit 6 Bit 5 |
|
104 0 0 All limit tests passed |
|
105 0 1 CALC2:LIM1 test failed |
|
106 1 0 CALC2:LIM2 test failed |
|
107 7 (Overvoltage) — Set to 1 if measurement performed with an |
|
108 overvoltage condition on the input. |
|
109 9 (Zero Check) — Set to 1 when zero check is enabled. |
|
110 10 (Zero Correct) — Set to 1 when zero correct is enabled. |
|
111 */ |
|
112 int eom; |
|
113 } data; |
|
114 |
|
115 /* Asyn info */ |
|
116 asynUser *pasynUser; |
|
117 asynUser *pasynUserTrace; /* asynUser for asynTrace on this port */ |
|
118 asynStandardInterfaces asynStdInterfaces; |
|
119 }; |
|
120 |
|
121 |
|
122 struct Command |
|
123 { |
|
124 const char *tag; |
|
125 int dev; |
|
126 int type; |
|
127 int id; |
|
128 }; |
|
129 |
|
130 |
|
131 /* Declare command structure */ |
|
132 struct GenCommand |
|
133 { |
|
134 asynStatus (*readFunc)(int which, Port *pport, void* data, Type Iface, |
|
135 size_t *length, int *eom); |
|
136 asynStatus (*writeFunc)(int which, Port *pport, void* data, Type Iface); |
|
137 }; |
|
138 |
|
139 struct SimpleCommand |
|
140 { |
|
141 int type; |
|
142 const char *cmd_str; |
|
143 }; |
|
144 |
|
145 /* Public interface forward references */ |
|
146 int drvAsynKeithley648x(const char* myport,const char* ioport, int ioaddr); |
|
147 |
|
148 |
|
149 /* Forward references for asynCommon methods */ |
|
150 static void report(void* ppvt,FILE* fp,int details); |
|
151 static asynStatus connect(void* ppvt,asynUser* pasynUser); |
|
152 static asynStatus disconnect(void* ppvt,asynUser* pasynUser); |
|
153 static asynCommon ifaceCommon = {report,connect,disconnect}; |
|
154 |
|
155 /* Forward references for asynDrvUser methods */ |
|
156 static asynStatus create(void* ppvt,asynUser* pasynUser,const char* drvInfo, |
|
157 const char** pptypeName,size_t* psize); |
|
158 static asynStatus destroy(void* ppvt,asynUser* pasynUser); |
|
159 static asynStatus gettype(void* ppvt,asynUser* pasynUser, |
|
160 const char** pptypeName,size_t* psize); |
|
161 static asynDrvUser ifaceDrvUser = {create,gettype,destroy}; |
|
162 |
|
163 /* Forward references for asynFloat64 methods */ |
|
164 static asynStatus readFloat64(void* ppvt,asynUser* pasynUser, |
|
165 epicsFloat64* value); |
|
166 static asynStatus writeFloat64(void* ppvt,asynUser* pasynUser, |
|
167 epicsFloat64 value); |
|
168 static asynFloat64 ifaceFloat64 = {writeFloat64, readFloat64}; |
|
169 |
|
170 /* Forward references for asynInt32 methods */ |
|
171 static asynStatus readInt32(void* ppvt,asynUser* pasynUser,epicsInt32* value); |
|
172 static asynStatus writeInt32(void* ppvt,asynUser* pasynUser,epicsInt32 value); |
|
173 static asynInt32 ifaceInt32 = {writeInt32, readInt32}; |
|
174 |
|
175 /* Forward references for asynOctet methods */ |
|
176 static asynStatus flushOctet( void* ppvt, asynUser* pasynUser); |
|
177 static asynStatus writeOctet( void* ppvt, asynUser* pasynUser, const char *data, |
|
178 size_t numchars, size_t* nbytes); |
|
179 static asynStatus readOctet( void* ppvt, asynUser* pasynUser, char* data, |
|
180 size_t maxchars, size_t *nbytes, int *eom); |
|
181 static asynOctet ifaceOctet = { writeOctet, readOctet, flushOctet}; |
|
182 |
|
183 |
|
184 /* Forward references for external asynOctet interface */ |
|
185 static asynStatus writeOnly(Port* pport, const char* outBuf); |
|
186 static asynStatus writeRead(Port* pport, const char* outBuf, char* inpBuf, |
|
187 int inputSize, int *eomReason); |
|
188 |
|
189 |
|
190 static asynStatus readDummy(int which, Port *pport, void *data, Type Iface, |
|
191 size_t *length, int *eom); |
|
192 static asynStatus writeDummy(int which, Port *pport, void* data, Type Iface); |
|
193 |
|
194 static asynStatus readSimpleData( int which, Port *pport, void *data, |
|
195 Type Iface, size_t *length, int *eom); |
|
196 static asynStatus writeSimpleData( int which, Port *pport, void *data, |
|
197 Type Iface); |
|
198 |
|
199 static asynStatus readCache(int which, Port *pport, void *data, |
|
200 Type Iface, size_t *length, int *eom); |
|
201 |
|
202 static asynStatus readSensorReading(int which, Port *pport, void* data, |
|
203 Type Iface, size_t *length, int *eom); |
|
204 static asynStatus readRange(int which, Port *pport, void* data, |
|
205 Type Iface, size_t *length, int *eom); |
|
206 static asynStatus writeRange(int which, Port *pport, void* data, Type Iface); |
|
207 static asynStatus readRate(int which, Port *pport, void* data, |
|
208 Type Iface, size_t *length, int *eom); |
|
209 static asynStatus writeRate(int which, Port *pport, void* data, Type Iface); |
|
210 static asynStatus readVoltageSettings(int which, Port *pport, void* data, |
|
211 Type Iface, size_t *length, int *eom); |
|
212 static asynStatus writeVoltageSettings(int which, Port *pport, void* data, |
|
213 Type Iface); |
|
214 static asynStatus readCommon(int which, Port *pport, void* data, |
|
215 Type Iface, size_t *length, int *eom); |
|
216 static asynStatus writeCommon(int which, Port *pport, void* data, Type Iface); |
|
217 |
|
218 |
|
219 |
|
220 |
|
221 // General commands that need special attention go here |
|
222 enum { VOID_CMD, READ_CMD, RANGE_CMD, RANGE_AUTO_ULIMIT_CMD, |
|
223 RANGE_AUTO_LLIMIT_CMD, RATE_CMD, DIGITAL_FILTER_CONTROL_CMD, |
|
224 VOLTAGE_RANGE_CMD, VOLTAGE_CURRENT_LIMIT_CMD, GEN_CMD_NUMBER }; |
|
225 static GenCommand genCommandTable[GEN_CMD_NUMBER] = |
|
226 { |
|
227 { readDummy, writeDummy}, // VOID |
|
228 { readSensorReading, writeDummy}, // READ |
|
229 { readRange, writeRange}, // RANGE |
|
230 { readRange, writeRange}, // RANGE_AUTO_ULIMIT |
|
231 { readRange, writeRange}, // RANGE_AUTO_LLIMIT |
|
232 { readRate, writeRate}, // RATE |
|
233 { readCommon, writeCommon}, // DIGITAL_FILTER_CONTROL |
|
234 { readVoltageSettings, writeVoltageSettings}, // VOLTAGE_RANGE_COMMAND |
|
235 { readVoltageSettings, writeVoltageSettings}, // VOLTAGE_CURRENT_LIMIT_COMMAND |
|
236 }; |
|
237 |
|
238 // commands that are very simple-minded go here |
|
239 enum { RESET_CMD, RANGE_AUTO_CMD, |
|
240 ZERO_CHECK_CMD, ZERO_CORRECT_CMD, ZERO_CORRECT_ACQUIRE_CMD, |
|
241 MEDIAN_FILTER_CMD, MEDIAN_FILTER_RANK_CMD, |
|
242 DIGITAL_FILTER_CMD, DIGITAL_FILTER_COUNT_CMD, |
|
243 VOLTAGE_CMD, VOLTAGE_STATE_CMD, VOLTAGE_10V_INTERLOCK_CMD, VOLTAGE_INTERLOCK_STATUS_CMD, |
|
244 SIMPLE_CMD_NUMBER}; |
|
245 |
|
246 enum { SIMPLE_TRIGGER=0, SIMPLE_OCTET=Octet, SIMPLE_FLOAT64=Float64, |
|
247 SIMPLE_INT32=Int32 }; |
|
248 static SimpleCommand simpleCommandTable[SIMPLE_CMD_NUMBER] = |
|
249 { |
|
250 { SIMPLE_TRIGGER, "*RST"}, // RESET DEVICE |
|
251 |
|
252 { SIMPLE_INT32, ":RANGE:AUTO"}, // RANGE_AUTO |
|
253 |
|
254 { SIMPLE_INT32, "SYST:ZCH"}, // ZERO CHECK |
|
255 { SIMPLE_INT32, "SYST:ZCOR"}, // ZERO CORRECT |
|
256 { SIMPLE_TRIGGER, "SYST:ZCOR:ACQ"}, // ZERO CORRECT ACQUIRE |
|
257 |
|
258 { SIMPLE_INT32, "MED"}, // MEDIAN FILTER |
|
259 { SIMPLE_INT32, "MED:RANK"}, // MEDIAN FILTER RANK |
|
260 |
|
261 { SIMPLE_INT32, "AVER"}, // DIGITAL FILTER |
|
262 { SIMPLE_INT32, "AVER:COUN"}, // DIGITAL FILTER COUNT |
|
263 |
|
264 { SIMPLE_FLOAT64, "SOUR:VOLT"}, // VOLTAGE |
|
265 { SIMPLE_INT32, "SOUR:VOLT:STAT"}, // VOLTAGE STATE |
|
266 { SIMPLE_INT32, "SOUR:VOLT:INT"}, // VOLTAGE 10V INTERLOCK |
|
267 { SIMPLE_INT32, "SOUR:VOLT:INT:FAIL"}, // VOLTAGE INTERLOCK STATUS |
|
268 |
|
269 // { SIMPLE_INT32, "AVER:"}, // |
|
270 // { SIMPLE_INT32, "AVER:"}, // |
|
271 }; |
|
272 |
|
273 |
|
274 enum { TIMESTAMP_CMD, STATUS_RAW_CMD, STATUS_OVERFLOW_CMD, STATUS_FILTER_CMD, |
|
275 STATUS_MATH_CMD, STATUS_NULL_CMD, STATUS_LIMITS_CMD, |
|
276 STATUS_OVERVOLTAGE_CMD, STATUS_ZERO_CHECK_CMD, STATUS_ZERO_CORRECT_CMD, |
|
277 MODEL_CMD, SERIAL_CMD, DIG_REV_CMD, DISP_REV_CMD, BRD_REV_CMD, |
|
278 CACHE_CMD_NUMBER }; |
|
279 |
|
280 #define COMMAND_NUMBER (GEN_CMD_NUMBER + SIMPLE_CMD_NUMBER + CACHE_CMD_NUMBER) |
|
281 |
|
282 enum { CMD_GEN, CMD_SIMPLE, CMD_CACHE }; |
|
283 enum { DEV_ALL, DEV_6485, DEV_6487}; |
|
284 static Command commandTable[ COMMAND_NUMBER ] = |
|
285 { |
|
286 { "VOID", DEV_ALL, CMD_GEN, VOID_CMD }, |
|
287 { "READ", DEV_ALL, CMD_GEN, READ_CMD }, |
|
288 { "RANGE", DEV_ALL, CMD_GEN, RANGE_CMD }, |
|
289 { "RANGE_AUTO_ULIMIT", DEV_ALL, CMD_GEN, RANGE_AUTO_ULIMIT_CMD }, |
|
290 { "RANGE_AUTO_LLIMIT", DEV_ALL, CMD_GEN, RANGE_AUTO_LLIMIT_CMD }, |
|
291 { "RATE", DEV_ALL, CMD_GEN, RATE_CMD }, |
|
292 { "DIGITAL_FILTER_CONTROL", DEV_ALL, CMD_GEN, DIGITAL_FILTER_CONTROL_CMD }, |
|
293 { "VOLTAGE_RANGE", DEV_6487, CMD_GEN, VOLTAGE_RANGE_CMD }, |
|
294 { "VOLTAGE_CURRENT_LIMIT", DEV_6487, CMD_GEN, VOLTAGE_CURRENT_LIMIT_CMD }, |
|
295 { "RESET", DEV_ALL, CMD_SIMPLE, RESET_CMD }, |
|
296 { "RANGE_AUTO", DEV_ALL, CMD_SIMPLE, RANGE_AUTO_CMD }, |
|
297 { "ZERO_CHECK", DEV_ALL, CMD_SIMPLE, ZERO_CHECK_CMD }, |
|
298 { "ZERO_CORRECT", DEV_ALL, CMD_SIMPLE, ZERO_CORRECT_CMD }, |
|
299 { "ZERO_CORRECT_ACQUIRE", DEV_ALL, CMD_SIMPLE, ZERO_CORRECT_ACQUIRE_CMD }, |
|
300 { "MEDIAN_FILTER", DEV_ALL, CMD_SIMPLE, MEDIAN_FILTER_CMD }, |
|
301 { "MEDIAN_FILTER_RANK", DEV_ALL, CMD_SIMPLE, MEDIAN_FILTER_RANK_CMD }, |
|
302 { "DIGITAL_FILTER", DEV_ALL, CMD_SIMPLE, DIGITAL_FILTER_CMD }, |
|
303 { "DIGITAL_FILTER_COUNT", DEV_ALL, CMD_SIMPLE, DIGITAL_FILTER_COUNT_CMD }, |
|
304 { "VOLTAGE", DEV_6487, CMD_SIMPLE, VOLTAGE_CMD }, |
|
305 { "VOLTAGE_STATE", DEV_6487, CMD_SIMPLE, VOLTAGE_STATE_CMD }, |
|
306 { "VOLTAGE_TENV_INTERLOCK", DEV_6487, CMD_SIMPLE, VOLTAGE_10V_INTERLOCK_CMD }, |
|
307 { "VOLTAGE_INTERLOCK_STATUS", DEV_6487, CMD_SIMPLE, VOLTAGE_INTERLOCK_STATUS_CMD }, |
|
308 { "MODEL", DEV_ALL, CMD_CACHE, MODEL_CMD }, |
|
309 { "SERIAL", DEV_ALL, CMD_CACHE, SERIAL_CMD }, |
|
310 { "DIG_REV", DEV_ALL, CMD_CACHE, DIG_REV_CMD }, |
|
311 { "DISP_REV", DEV_ALL, CMD_CACHE, DISP_REV_CMD }, |
|
312 { "BRD_REV", DEV_ALL, CMD_CACHE, BRD_REV_CMD }, |
|
313 { "TIMESTAMP", DEV_ALL, CMD_CACHE, TIMESTAMP_CMD }, |
|
314 { "STATUS_RAW", DEV_ALL, CMD_CACHE, STATUS_RAW_CMD }, |
|
315 { "STATUS_OVERFLOW", DEV_ALL, CMD_CACHE, STATUS_OVERFLOW_CMD }, |
|
316 { "STATUS_FILTER", DEV_ALL, CMD_CACHE, STATUS_FILTER_CMD }, |
|
317 { "STATUS_MATH", DEV_ALL, CMD_CACHE, STATUS_MATH_CMD }, |
|
318 { "STATUS_NULL", DEV_ALL, CMD_CACHE, STATUS_NULL_CMD }, |
|
319 { "STATUS_LIMITS", DEV_ALL, CMD_CACHE, STATUS_LIMITS_CMD }, |
|
320 { "STATUS_OVERVOLTAGE", DEV_ALL, CMD_CACHE, STATUS_OVERVOLTAGE_CMD }, |
|
321 { "STATUS_ZERO_CHECK", DEV_ALL, CMD_CACHE, STATUS_ZERO_CHECK_CMD }, |
|
322 { "STATUS_ZERO_CORRECT", DEV_ALL, CMD_CACHE, STATUS_ZERO_CORRECT_CMD }, |
|
323 }; |
|
324 |
|
325 |
|
326 |
|
327 /**************************************************************************** |
|
328 * Define public interface methods |
|
329 ****************************************************************************/ |
|
330 int drvAsynKeithley648x(const char *type, const char *myport, |
|
331 const char *ioport, int ioaddr) |
|
332 { |
|
333 int status = asynSuccess; |
|
334 Port* pport; |
|
335 // int i; |
|
336 asynStandardInterfaces *pInterfaces; |
|
337 |
|
338 char inpBuf[BUFFER_SIZE]; |
|
339 int eomReason; |
|
340 |
|
341 pport = (Port*)callocMustSucceed(1,sizeof(Port),"drvAsynKeithley6485"); |
|
342 pport->myport = epicsStrDup(myport); |
|
343 pport->ioport = epicsStrDup(ioport); |
|
344 pport->ioaddr = ioaddr; |
|
345 |
|
346 pport->devtype = DEV_ALL; |
|
347 if( !strcmp("6485", type)) |
|
348 pport->devtype = DEV_6485; |
|
349 if( !strcmp("6487", type)) |
|
350 pport->devtype = DEV_6487; |
|
351 if(pport->devtype == DEV_ALL) // DEV_ALL is not a real device |
|
352 { |
|
353 errlogPrintf("%s::drvAsynKeithley6485 type has to be " |
|
354 "either \'6485\' or \'6487\'.\n", driver); |
|
355 return asynError; |
|
356 } |
|
357 |
|
358 |
|
359 status = pasynOctetSyncIO->connect(ioport,ioaddr,&pport->pasynUser,NULL); |
|
360 if (status != asynSuccess) |
|
361 { |
|
362 errlogPrintf("%s::drvAsynKeithley6485 port %s can't connect " |
|
363 "to asynCommon on Octet server %s address %d.\n", |
|
364 driver, myport, ioport, ioaddr); |
|
365 return asynError; |
|
366 } |
|
367 |
|
368 /* Create asynUser for asynTrace */ |
|
369 pport->pasynUserTrace = pasynManager->createAsynUser(0, 0); |
|
370 pport->pasynUserTrace->userPvt = pport; |
|
371 |
|
372 status = pasynManager->registerPort(myport,ASYN_CANBLOCK,1,0,0); |
|
373 if( status != asynSuccess) |
|
374 { |
|
375 errlogPrintf("%s::drvAsynKeithley6485 port %s can't register port\n", |
|
376 driver, myport); |
|
377 return asynError; |
|
378 } |
|
379 |
|
380 pInterfaces = &pport->asynStdInterfaces; |
|
381 |
|
382 /* Initialize interface pointers */ |
|
383 pInterfaces->common.pinterface = (void *)&ifaceCommon; |
|
384 pInterfaces->drvUser.pinterface = (void *)&ifaceDrvUser; |
|
385 pInterfaces->octet.pinterface = (void *)&ifaceOctet; |
|
386 pInterfaces->int32.pinterface = (void *)&ifaceInt32; |
|
387 pInterfaces->float64.pinterface = (void *)&ifaceFloat64; |
|
388 |
|
389 status = pasynStandardInterfacesBase->initialize(myport, pInterfaces, |
|
390 pport->pasynUserTrace, |
|
391 pport); |
|
392 if (status != asynSuccess) |
|
393 { |
|
394 errlogPrintf("%s::drvAsynKeithley6485 port %s" |
|
395 " can't register standard interfaces: %s\n", |
|
396 driver, myport, pport->pasynUserTrace->errorMessage); |
|
397 return asynError; |
|
398 } |
|
399 |
|
400 #ifdef vxWorks |
|
401 /* Send a sacrificial clear status to vxworks device (i.e. VME)*/ |
|
402 /* This fixes a problem with *IDN? call when starting from a cold boot */ |
|
403 /* with the SBS IP-Octal hardware. */ |
|
404 if( writeOnly(pport,"") ) |
|
405 { |
|
406 errlogPrintf("%s::drvAsynKeithley6485 port %s failed to write\n", |
|
407 driver, myport); |
|
408 return asynError; |
|
409 } |
|
410 #endif |
|
411 |
|
412 /* Reset device */ |
|
413 if( writeOnly(pport,"*CLS") ) |
|
414 { |
|
415 errlogPrintf("%s::drvAsynKeithley6485 port %s failed to clear\n", |
|
416 driver, myport); |
|
417 return asynError; |
|
418 } |
|
419 |
|
420 |
|
421 /* Identification query */ |
|
422 if( writeRead(pport,"*IDN?",inpBuf,sizeof(inpBuf),&eomReason) ) |
|
423 { |
|
424 errlogPrintf("%s::drvAsynKeithley6485 port %s failed to " |
|
425 "acquire identification\n", driver, myport); |
|
426 return asynError; |
|
427 } |
|
428 strcpy(pport->model,inpBuf); |
|
429 // char *model, *serial, *dig_rev, *disp_rev, *brd_rev; |
|
430 pport->serial = strchr( pport->model, ','); |
|
431 pport->serial = strchr( pport->serial + 1, ','); |
|
432 *(pport->serial) = '\0'; |
|
433 pport->serial++; |
|
434 pport->dig_rev = strchr( pport->serial, ','); |
|
435 *(pport->dig_rev) = '\0'; |
|
436 pport->dig_rev++; |
|
437 pport->disp_rev = strchr( pport->dig_rev, '/'); |
|
438 *(pport->disp_rev) = '\0'; |
|
439 pport->disp_rev++; |
|
440 pport->brd_rev = strchr( pport->disp_rev, '/'); |
|
441 *(pport->brd_rev) = '\0'; |
|
442 pport->brd_rev++; |
|
443 |
|
444 /* Complete initialization */ |
|
445 pport->init=1; |
|
446 |
|
447 pport->data.reading = 0.0; |
|
448 pport->data.timestamp = 0; |
|
449 pport->data.status.raw = 0; |
|
450 |
|
451 return asynSuccess; |
|
452 } |
|
453 |
|
454 |
|
455 |
|
456 |
|
457 /**************************************************************************** |
|
458 * Define private read and write parameter methods |
|
459 ****************************************************************************/ |
|
460 |
|
461 static asynStatus readDummy(int which, Port *pport, void *data, Type Iface, |
|
462 size_t *length, int *eom) |
|
463 { |
|
464 return asynSuccess; |
|
465 } |
|
466 |
|
467 static asynStatus writeDummy(int which, Port *pport, void *data, Type Iface) |
|
468 { |
|
469 return asynSuccess; |
|
470 } |
|
471 |
|
472 /// |
|
473 |
|
474 static asynStatus readSimpleData( int which, Port *pport, void *data, |
|
475 Type Iface, size_t *length, int *eom) |
|
476 { |
|
477 asynStatus status; |
|
478 char outBuf[BUFFER_SIZE]; |
|
479 char inpBuf[BUFFER_SIZE]; |
|
480 |
|
481 int len; |
|
482 |
|
483 // Trigger will automatically not work |
|
484 if( simpleCommandTable[which].type != Iface) |
|
485 return asynSuccess; |
|
486 |
|
487 sprintf( outBuf, "%s?", simpleCommandTable[which].cmd_str); |
|
488 |
|
489 status = writeRead( pport, outBuf, inpBuf, BUFFER_SIZE, &pport->data.eom); |
|
490 if( status != asynSuccess) |
|
491 return status; |
|
492 |
|
493 switch( Iface) |
|
494 { |
|
495 case Float64: |
|
496 *((epicsFloat64 *) data) = atof(inpBuf); |
|
497 break; |
|
498 case Int32: |
|
499 *((epicsInt32 *) data) = atoi(inpBuf); |
|
500 break; |
|
501 case Octet: |
|
502 len = strlen( inpBuf); |
|
503 if( len > 39) |
|
504 inpBuf[39] = '\0'; |
|
505 strcpy( (char *) data, inpBuf); |
|
506 break; |
|
507 } |
|
508 |
|
509 return asynSuccess; |
|
510 } |
|
511 |
|
512 static asynStatus writeSimpleData( int which, Port *pport, void *data, |
|
513 Type Iface) |
|
514 { |
|
515 char outBuf[BUFFER_SIZE]; |
|
516 |
|
517 if( simpleCommandTable[which].type == SIMPLE_TRIGGER ) |
|
518 sprintf( outBuf, "%s", simpleCommandTable[which].cmd_str); |
|
519 else |
|
520 { |
|
521 if( simpleCommandTable[which].type != Iface ) |
|
522 return asynSuccess; |
|
523 |
|
524 switch( simpleCommandTable[which].type & Iface) |
|
525 { |
|
526 case Float64: |
|
527 sprintf( outBuf, "%s %g", simpleCommandTable[which].cmd_str, |
|
528 *((epicsFloat64*) data) ); |
|
529 break; |
|
530 case Int32: |
|
531 sprintf( outBuf, "%s %d", simpleCommandTable[which].cmd_str, |
|
532 *((epicsInt32*) data) ); |
|
533 break; |
|
534 case Octet: |
|
535 sprintf( outBuf, "%s %s", simpleCommandTable[which].cmd_str, |
|
536 ((char *) data) ); |
|
537 break; |
|
538 } |
|
539 } |
|
540 |
|
541 return writeOnly( pport, outBuf); |
|
542 } |
|
543 |
|
544 //// |
|
545 |
|
546 static asynStatus readCache(int which, Port *pport, void *data, |
|
547 Type Iface, size_t *length, int *eom) |
|
548 { |
|
549 char *char_cache = NULL; |
|
550 int len; |
|
551 |
|
552 switch( Iface) |
|
553 { |
|
554 case Octet: |
|
555 switch(which) |
|
556 { |
|
557 case MODEL_CMD: |
|
558 char_cache = pport->model; |
|
559 break; |
|
560 case SERIAL_CMD: |
|
561 char_cache = pport->serial; |
|
562 break; |
|
563 case DIG_REV_CMD: |
|
564 char_cache = pport->dig_rev; |
|
565 break; |
|
566 case DISP_REV_CMD: |
|
567 char_cache = pport->disp_rev; |
|
568 break; |
|
569 case BRD_REV_CMD: |
|
570 char_cache = pport->brd_rev; |
|
571 break; |
|
572 } |
|
573 len = strlen(char_cache); |
|
574 if( len < 40) |
|
575 strcpy( (char *) data, char_cache); |
|
576 else // just in case string will overflow the EPICS string size of 40 |
|
577 { |
|
578 len = 39; |
|
579 memcpy( (char *) data, char_cache, len); |
|
580 ((char *) data)[len] = '\0'; |
|
581 } |
|
582 *length = len; |
|
583 *eom = 0; |
|
584 break; |
|
585 case Float64: |
|
586 // switch( which) |
|
587 // { |
|
588 // } |
|
589 break; |
|
590 case Int32: |
|
591 switch( which) |
|
592 { |
|
593 case TIMESTAMP_CMD: |
|
594 *(epicsInt32*)data = pport->data.timestamp; |
|
595 break; |
|
596 case STATUS_RAW_CMD: |
|
597 *(epicsInt32*) data = pport->data.status.raw; |
|
598 break; |
|
599 case STATUS_OVERFLOW_CMD: |
|
600 *(epicsInt32*) data = pport->data.status.bits.overflow; |
|
601 break; |
|
602 case STATUS_FILTER_CMD: |
|
603 *(epicsInt32*) data = pport->data.status.bits.filter_enabled; |
|
604 break; |
|
605 case STATUS_MATH_CMD: |
|
606 *(epicsInt32*) data = pport->data.status.bits.math_enabled; |
|
607 break; |
|
608 case STATUS_NULL_CMD: |
|
609 *(epicsInt32*) data = pport->data.status.bits.null_enabled; |
|
610 break; |
|
611 case STATUS_LIMITS_CMD: |
|
612 if( pport->data.status.bits.limit_test) |
|
613 *(epicsInt32*) data = pport->data.status.bits.limit_result; |
|
614 else |
|
615 *(epicsInt32*) data = 3; |
|
616 break; |
|
617 case STATUS_OVERVOLTAGE_CMD: |
|
618 *(epicsInt32*) data = pport->data.status.bits.overvoltage; |
|
619 break; |
|
620 case STATUS_ZERO_CHECK_CMD: |
|
621 *(epicsInt32*) data = pport->data.status.bits.zero_check_enabled; |
|
622 break; |
|
623 case STATUS_ZERO_CORRECT_CMD: |
|
624 *(epicsInt32*) data = pport->data.status.bits.zero_correct_enabled; |
|
625 break; |
|
626 } |
|
627 break; |
|
628 } |
|
629 |
|
630 return asynSuccess; |
|
631 } |
|
632 |
|
633 |
|
634 static asynStatus readSensorReading(int which, Port *pport, void *data, |
|
635 Type Iface, size_t *length, int *eom) |
|
636 { |
|
637 asynStatus status; |
|
638 char inpBuf[BUFFER_SIZE]; |
|
639 |
|
640 char *str, *token[3], *saveptr; |
|
641 int pass; |
|
642 |
|
643 status = writeRead( pport, "READ?", inpBuf, BUFFER_SIZE, &pport->data.eom); |
|
644 if( status != asynSuccess) |
|
645 return status; |
|
646 |
|
647 str = inpBuf; |
|
648 for( pass = 0; pass < 3; pass++, str = NULL) |
|
649 { |
|
650 token[pass] = epicsStrtok_r(str, ",", &saveptr); |
|
651 if (token == NULL) |
|
652 break; |
|
653 } |
|
654 if( pass != 3) |
|
655 return asynError; |
|
656 |
|
657 pport->data.reading = atof( token[0]); |
|
658 pport->data.timestamp = (int) atof( token[1]); |
|
659 pport->data.status.raw = (int) atof( token[2]); |
|
660 |
|
661 switch( Iface ) |
|
662 { |
|
663 case Octet: |
|
664 // only print current value |
|
665 *length = sprintf( (char *) data, "%s", token[0]); |
|
666 *eom = pport->data.eom; |
|
667 break; |
|
668 case Float64: |
|
669 *(epicsFloat64*)data = pport->data.reading; |
|
670 break; |
|
671 case Int32: |
|
672 break; |
|
673 } |
|
674 |
|
675 return asynSuccess; |
|
676 } |
|
677 |
|
678 static asynStatus readRange(int which, Port *pport, void *data, |
|
679 Type Iface, size_t *length, int *eom) |
|
680 { |
|
681 asynStatus status; |
|
682 char inpBuf[BUFFER_SIZE]; |
|
683 |
|
684 if( Iface == Octet) |
|
685 return asynSuccess; |
|
686 |
|
687 switch( which) |
|
688 { |
|
689 case RANGE_CMD: |
|
690 status = writeRead( pport, ":RANGE?", inpBuf, BUFFER_SIZE, |
|
691 &pport->data.eom); |
|
692 break; |
|
693 case RANGE_AUTO_ULIMIT_CMD: |
|
694 status = writeRead( pport, ":RANGE:AUTO:ULIM?", inpBuf, BUFFER_SIZE, |
|
695 &pport->data.eom); |
|
696 break; |
|
697 case RANGE_AUTO_LLIMIT_CMD: |
|
698 status = writeRead( pport, ":RANGE:AUTO:LLIM?", inpBuf, BUFFER_SIZE, |
|
699 &pport->data.eom); |
|
700 break; |
|
701 default: |
|
702 return asynError; |
|
703 } |
|
704 if( status != asynSuccess) |
|
705 return status; |
|
706 |
|
707 if( Iface == Float64) |
|
708 { |
|
709 double val; |
|
710 |
|
711 val = atof( inpBuf); |
|
712 if( val == 0.0) |
|
713 return asynError; |
|
714 |
|
715 *(epicsFloat64*) data = val; |
|
716 } |
|
717 else if( Iface == Int32) |
|
718 { |
|
719 char *p; |
|
720 |
|
721 p = strchr( inpBuf, 'E'); |
|
722 if(p == NULL) |
|
723 return asynError; |
|
724 p++; |
|
725 *(epicsInt32*) data = 9 + atoi(p) ; |
|
726 } |
|
727 |
|
728 return asynSuccess; |
|
729 } |
|
730 |
|
731 |
|
732 static asynStatus writeRange( int which, Port *pport, void *data, Type Iface) |
|
733 { |
|
734 char outBuf[BUFFER_SIZE]; |
|
735 int value; |
|
736 |
|
737 if( Iface != Int32) |
|
738 return asynSuccess; |
|
739 |
|
740 value = *((epicsInt32*) data); |
|
741 if( (value < 0) || (value > 7) ) |
|
742 return asynError; |
|
743 |
|
744 switch( which) |
|
745 { |
|
746 case RANGE_CMD: |
|
747 sprintf( outBuf, ":RANGE 2.0e%d", -9 + value ); |
|
748 break; |
|
749 case RANGE_AUTO_ULIMIT_CMD: |
|
750 sprintf( outBuf, ":RANGE:AUTO:ULIM 2.0e%d", -9 + value ); |
|
751 break; |
|
752 case RANGE_AUTO_LLIMIT_CMD: |
|
753 sprintf( outBuf, ":RANGE:AUTO:LLIM 2.0e%d", -9 + value ); |
|
754 break; |
|
755 default: |
|
756 return asynError; |
|
757 } |
|
758 |
|
759 return writeOnly( pport, outBuf); |
|
760 } |
|
761 |
|
762 |
|
763 static asynStatus readRate(int which, Port *pport, void *data, |
|
764 Type Iface, size_t *length, int *eom) |
|
765 { |
|
766 asynStatus status; |
|
767 char inpBuf[BUFFER_SIZE]; |
|
768 |
|
769 double val; |
|
770 int rate; |
|
771 |
|
772 if( Iface != Int32) |
|
773 return asynSuccess; |
|
774 |
|
775 status = writeRead( pport, ":NPLC?", inpBuf, BUFFER_SIZE, &pport->data.eom); |
|
776 if( status != asynSuccess) |
|
777 return status; |
|
778 |
|
779 val = atof( inpBuf); |
|
780 if( val > 1.0) |
|
781 rate = 0; // SLOW |
|
782 else if( val > 0.1) |
|
783 rate = 1; // MEDIUM |
|
784 else |
|
785 rate = 2; // FAST |
|
786 |
|
787 *((epicsInt32*) data) = rate; |
|
788 |
|
789 return asynSuccess; |
|
790 } |
|
791 |
|
792 |
|
793 static asynStatus writeRate( int which, Port *pport, void *data, Type Iface) |
|
794 { |
|
795 char outBuf[BUFFER_SIZE]; |
|
796 int rate; |
|
797 double val; |
|
798 |
|
799 if( Iface != Int32) |
|
800 return asynSuccess; |
|
801 |
|
802 rate = *((epicsInt32*) data); |
|
803 if( (rate < 0) || (rate > 2) ) |
|
804 return asynError; |
|
805 |
|
806 switch( rate) |
|
807 { |
|
808 case 0: |
|
809 val = 6.0; |
|
810 break; |
|
811 case 1: |
|
812 val = 1.0; |
|
813 break; |
|
814 case 2: |
|
815 val = 0.1; |
|
816 break; |
|
817 default: |
|
818 val = 1.0; |
|
819 break; |
|
820 } |
|
821 |
|
822 sprintf( outBuf, ":NPLC %g", val ); |
|
823 return writeOnly( pport, outBuf); |
|
824 } |
|
825 |
|
826 |
|
827 static asynStatus readVoltageSettings(int which, Port *pport, void *data, Type Iface, |
|
828 size_t *length, int *eom) |
|
829 { |
|
830 asynStatus status; |
|
831 char inpBuf[BUFFER_SIZE]; |
|
832 |
|
833 double val; |
|
834 |
|
835 if(( which != VOLTAGE_RANGE_CMD) && ( which != VOLTAGE_CURRENT_LIMIT_CMD)) |
|
836 return asynError; |
|
837 if( Iface == Octet) |
|
838 return asynSuccess; |
|
839 |
|
840 if( which == VOLTAGE_RANGE_CMD) |
|
841 status = writeRead( pport, "SOUR:VOLT:RANGE?", inpBuf, BUFFER_SIZE, |
|
842 &pport->data.eom); |
|
843 else |
|
844 status = writeRead( pport, "SOUR:VOLT:ILIM?", inpBuf, BUFFER_SIZE, |
|
845 &pport->data.eom); |
|
846 if( status != asynSuccess) |
|
847 return status; |
|
848 |
|
849 val = atof( inpBuf); |
|
850 if( val == 0.0) |
|
851 return asynError; |
|
852 |
|
853 if( Iface == Float64) |
|
854 { |
|
855 *((epicsFloat64*) data) = val; |
|
856 } |
|
857 else if( Iface == Int32) |
|
858 { |
|
859 if( which == VOLTAGE_RANGE_CMD) |
|
860 { |
|
861 if( val == 10.0) |
|
862 *((epicsInt32*) data) = 0; |
|
863 else if( val == 50.0) |
|
864 *((epicsInt32*) data) = 1; |
|
865 else if( val == 500.0) |
|
866 *((epicsInt32*) data) = 2; |
|
867 } |
|
868 else |
|
869 { |
|
870 if( val == 2.5e-5) |
|
871 *((epicsInt32*) data) = 0; |
|
872 else if( val == 2.5e-4) |
|
873 *((epicsInt32*) data) = 1; |
|
874 else if( val == 2.5e-3) |
|
875 *((epicsInt32*) data) = 2; |
|
876 else if( val == 2.5e-2) |
|
877 *((epicsInt32*) data) = 3; |
|
878 } |
|
879 } |
|
880 |
|
881 return asynSuccess; |
|
882 } |
|
883 |
|
884 |
|
885 static asynStatus writeVoltageSettings( int which, Port *pport, void *data, Type Iface) |
|
886 { |
|
887 char outBuf[BUFFER_SIZE]; |
|
888 int value; |
|
889 |
|
890 if(( which != VOLTAGE_RANGE_CMD) && ( which != VOLTAGE_CURRENT_LIMIT_CMD)) |
|
891 return asynError; |
|
892 if( Iface != Int32) |
|
893 return asynSuccess; |
|
894 |
|
895 value = *((epicsInt32*) data); |
|
896 if( which == VOLTAGE_RANGE_CMD) |
|
897 { |
|
898 if( (value < 0) || (value > 2) ) |
|
899 return asynError; |
|
900 |
|
901 if( value == 0) |
|
902 value = 10; |
|
903 else if( value == 1) |
|
904 value = 50; |
|
905 else |
|
906 value = 500; |
|
907 |
|
908 sprintf( outBuf, "SOUR:VOLT:RANGE %d", value ); |
|
909 } |
|
910 else |
|
911 { |
|
912 if( (value < 0) || (value > 3) ) |
|
913 return asynError; |
|
914 |
|
915 sprintf( outBuf, "SOUR:VOLT:ILIM 2.5e%d", value - 5 ); |
|
916 } |
|
917 |
|
918 return writeOnly( pport, outBuf); |
|
919 } |
|
920 |
|
921 |
|
922 static asynStatus readCommon(int which, Port *pport, void *data, |
|
923 Type Iface, size_t *length, int *eom) |
|
924 { |
|
925 asynStatus status; |
|
926 char inpBuf[BUFFER_SIZE]; |
|
927 |
|
928 int val = 0; |
|
929 |
|
930 if( Iface != Int32) |
|
931 return asynSuccess; |
|
932 |
|
933 switch(which) |
|
934 { |
|
935 case DIGITAL_FILTER_CONTROL_CMD: |
|
936 status = writeRead( pport, "AVER:TCON?", inpBuf, BUFFER_SIZE, |
|
937 &pport->data.eom); |
|
938 |
|
939 if( status != asynSuccess) |
|
940 return status; |
|
941 if( !strcmp( "MOV", inpBuf) ) |
|
942 val = 0; |
|
943 else if( !strcmp( "REP", inpBuf) ) |
|
944 val = 1; |
|
945 else |
|
946 return asynError; |
|
947 break; |
|
948 } |
|
949 |
|
950 *((epicsInt32*) data) = val; |
|
951 |
|
952 return asynSuccess; |
|
953 } |
|
954 |
|
955 |
|
956 static asynStatus writeCommon( int which, Port *pport, void *data, Type Iface) |
|
957 { |
|
958 char outBuf[BUFFER_SIZE]; |
|
959 int val; |
|
960 |
|
961 if( Iface != Int32) |
|
962 return asynSuccess; |
|
963 |
|
964 val = *((epicsInt32*) data); |
|
965 switch( which) |
|
966 { |
|
967 case DIGITAL_FILTER_CONTROL_CMD: |
|
968 if( !val) |
|
969 sprintf( outBuf, "AVER:TCON MOV" ); |
|
970 else if(val == 1) |
|
971 sprintf( outBuf, "AVER:TCON REP" ); |
|
972 else |
|
973 return asynError; |
|
974 break; |
|
975 } |
|
976 |
|
977 return writeOnly( pport, outBuf); |
|
978 } |
|
979 |
|
980 |
|
981 /**************************************************************************** |
|
982 * Define private interface asynCommon methods |
|
983 ****************************************************************************/ |
|
984 static void report(void* ppvt,FILE* fp,int details) |
|
985 { |
|
986 // int i; |
|
987 Port* pport = (Port*)ppvt; |
|
988 |
|
989 fprintf( fp, "Keithley648x port: %s\n", pport->myport); |
|
990 if( details) |
|
991 { |
|
992 fprintf( fp, " server: %s\n", pport->ioport); |
|
993 fprintf( fp, " address: %d\n", pport->ioaddr); |
|
994 fprintf( fp, " ioErrors: %d\n", pport->stats.ioErrors); |
|
995 fprintf( fp, " writeReads: %d\n", pport->stats.writeReads); |
|
996 fprintf( fp, " writeOnlys: %d\n", pport->stats.writeOnlys); |
|
997 fprintf( fp, " support %s initialized\n",(pport->init)?"IS":"IS NOT"); |
|
998 } |
|
999 |
|
1000 } |
|
1001 |
|
1002 static asynStatus connect(void* ppvt,asynUser* pasynUser) |
|
1003 { |
|
1004 pasynManager->exceptionConnect(pasynUser); |
|
1005 return asynSuccess; |
|
1006 } |
|
1007 |
|
1008 static asynStatus disconnect(void* ppvt,asynUser* pasynUser) |
|
1009 { |
|
1010 pasynManager->exceptionDisconnect(pasynUser); |
|
1011 return asynSuccess; |
|
1012 } |
|
1013 |
|
1014 |
|
1015 /**************************************************************************** |
|
1016 * Define private interface asynDrvUser methods |
|
1017 ****************************************************************************/ |
|
1018 static asynStatus create(void* ppvt, asynUser *pasynUser, const char *drvInfo, |
|
1019 const char **pptypeName, size_t *psize) |
|
1020 { |
|
1021 Port* pport=(Port*)ppvt; |
|
1022 |
|
1023 int i; |
|
1024 |
|
1025 for(i = 0; i < COMMAND_NUMBER; i++) |
|
1026 if( !epicsStrCaseCmp( drvInfo, commandTable[i].tag) ) |
|
1027 { |
|
1028 if( (commandTable[i].dev != DEV_ALL) && |
|
1029 (commandTable[i].dev != pport->devtype) ) |
|
1030 { |
|
1031 errlogPrintf("%s::create port %s failed as tag %s is for different " |
|
1032 "device\n", driver, pport->myport, drvInfo); |
|
1033 pasynUser->reason = 0; |
|
1034 return asynError; |
|
1035 } |
|
1036 pasynUser->reason = i; |
|
1037 break; |
|
1038 } |
|
1039 if( i == COMMAND_NUMBER ) |
|
1040 { |
|
1041 errlogPrintf("%s::create port %s failed to find tag %s\n", |
|
1042 driver, pport->myport, drvInfo); |
|
1043 pasynUser->reason = 0; |
|
1044 return asynError; |
|
1045 } |
|
1046 |
|
1047 return asynSuccess; |
|
1048 } |
|
1049 |
|
1050 static asynStatus gettype(void* ppvt,asynUser* pasynUser, |
|
1051 const char** pptypeName,size_t* psize) |
|
1052 { |
|
1053 if( pptypeName ) |
|
1054 *pptypeName = NULL; |
|
1055 if( psize ) |
|
1056 *psize = 0; |
|
1057 |
|
1058 return asynSuccess; |
|
1059 } |
|
1060 |
|
1061 static asynStatus destroy(void* ppvt,asynUser* pasynUser) |
|
1062 { |
|
1063 return asynSuccess; |
|
1064 } |
|
1065 |
|
1066 |
|
1067 /**************************************************************************** |
|
1068 * Define private interface asynFloat64 methods |
|
1069 ****************************************************************************/ |
|
1070 static asynStatus writeFloat64(void* ppvt,asynUser* pasynUser, |
|
1071 epicsFloat64 value) |
|
1072 { |
|
1073 Port* pport=(Port*)ppvt; |
|
1074 int which = pasynUser->reason; |
|
1075 |
|
1076 int id; |
|
1077 id = commandTable[which].id; |
|
1078 |
|
1079 if( pport->init == 0) |
|
1080 return asynError; |
|
1081 |
|
1082 switch( commandTable[which].type ) |
|
1083 { |
|
1084 case CMD_GEN: |
|
1085 return genCommandTable[id].writeFunc(id, pport, &value, Float64); |
|
1086 break; |
|
1087 case CMD_SIMPLE: |
|
1088 return writeSimpleData( id, pport, &value, Float64); |
|
1089 break; |
|
1090 } |
|
1091 |
|
1092 return asynSuccess; |
|
1093 } |
|
1094 |
|
1095 static asynStatus readFloat64(void* ppvt,asynUser* pasynUser, |
|
1096 epicsFloat64* value) |
|
1097 { |
|
1098 Port* pport=(Port*)ppvt; |
|
1099 int which = pasynUser->reason; |
|
1100 |
|
1101 int id; |
|
1102 id = commandTable[which].id; |
|
1103 |
|
1104 if( pport->init == 0) |
|
1105 return asynError; |
|
1106 |
|
1107 switch( commandTable[which].type ) |
|
1108 { |
|
1109 case CMD_GEN: |
|
1110 return genCommandTable[id].readFunc(id, pport, value, Float64, |
|
1111 NULL, NULL); |
|
1112 break; |
|
1113 case CMD_SIMPLE: |
|
1114 return readSimpleData( id, pport, value, Float64, NULL, NULL); |
|
1115 break; |
|
1116 case CMD_CACHE: |
|
1117 return readCache(id, pport, value, Float64, NULL, NULL); |
|
1118 break; |
|
1119 } |
|
1120 |
|
1121 return asynSuccess; |
|
1122 } |
|
1123 |
|
1124 |
|
1125 /**************************************************************************** |
|
1126 * Define private interface asynInt32 methods |
|
1127 ****************************************************************************/ |
|
1128 static asynStatus writeInt32(void *ppvt, asynUser *pasynUser, epicsInt32 value) |
|
1129 { |
|
1130 Port* pport=(Port*)ppvt; |
|
1131 int which = pasynUser->reason; |
|
1132 |
|
1133 int id; |
|
1134 id = commandTable[which].id; |
|
1135 |
|
1136 if( pport->init == 0) |
|
1137 return asynError; |
|
1138 |
|
1139 switch( commandTable[which].type ) |
|
1140 { |
|
1141 case CMD_GEN: |
|
1142 return genCommandTable[id].writeFunc(id, pport, &value, Int32); |
|
1143 break; |
|
1144 case CMD_SIMPLE: |
|
1145 return writeSimpleData( id, pport, (void *) &value, Int32); |
|
1146 break; |
|
1147 } |
|
1148 |
|
1149 return asynSuccess; |
|
1150 } |
|
1151 |
|
1152 static asynStatus readInt32(void *ppvt, asynUser *pasynUser, epicsInt32 *value) |
|
1153 { |
|
1154 Port* pport=(Port*)ppvt; |
|
1155 int which = pasynUser->reason; |
|
1156 |
|
1157 int id; |
|
1158 id = commandTable[which].id; |
|
1159 |
|
1160 if( pport->init == 0) |
|
1161 return asynError; |
|
1162 |
|
1163 switch( commandTable[which].type ) |
|
1164 { |
|
1165 case CMD_GEN: |
|
1166 return genCommandTable[id].readFunc(id, pport, value, Int32, |
|
1167 NULL, NULL); |
|
1168 break; |
|
1169 case CMD_SIMPLE: |
|
1170 return readSimpleData( id, pport, value, Int32, NULL, NULL); |
|
1171 break; |
|
1172 case CMD_CACHE: |
|
1173 return readCache(id, pport, value, Int32, NULL, NULL); |
|
1174 break; |
|
1175 } |
|
1176 |
|
1177 return asynSuccess; |
|
1178 } |
|
1179 |
|
1180 |
|
1181 /**************************************************************************** |
|
1182 * Define private interface asynOctet methods |
|
1183 ****************************************************************************/ |
|
1184 static asynStatus flushOctet(void *ppvt, asynUser* pasynUser) |
|
1185 { |
|
1186 return asynSuccess; |
|
1187 } |
|
1188 |
|
1189 static asynStatus writeOctet(void *ppvt, asynUser *pasynUser, const char *data, |
|
1190 size_t numchars, size_t *nbytes) |
|
1191 { |
|
1192 Port* pport=(Port*)ppvt; |
|
1193 int which = pasynUser->reason; |
|
1194 |
|
1195 int id; |
|
1196 id = commandTable[which].id; |
|
1197 |
|
1198 if( pport->init == 0) |
|
1199 return asynError; |
|
1200 |
|
1201 switch( commandTable[which].type ) |
|
1202 { |
|
1203 case CMD_GEN: |
|
1204 *nbytes=strlen(data); |
|
1205 return genCommandTable[id].writeFunc(id, pport, (void *) data, Octet); |
|
1206 break; |
|
1207 case CMD_SIMPLE: |
|
1208 *nbytes=strlen(data); |
|
1209 return writeSimpleData( id, pport, &data, Octet); |
|
1210 break; |
|
1211 } |
|
1212 |
|
1213 return asynSuccess; |
|
1214 } |
|
1215 |
|
1216 static asynStatus readOctet(void* ppvt, asynUser* pasynUser, char* data, |
|
1217 size_t maxchars,size_t* nbytes,int* eom) |
|
1218 { |
|
1219 Port* pport=(Port*)ppvt; |
|
1220 int which = pasynUser->reason; |
|
1221 |
|
1222 int id; |
|
1223 id = commandTable[which].id; |
|
1224 |
|
1225 if( pport->init == 0) |
|
1226 return asynError; |
|
1227 |
|
1228 switch( commandTable[which].type ) |
|
1229 { |
|
1230 case CMD_GEN: |
|
1231 return genCommandTable[id].readFunc(id, pport, (void *) data, Octet, |
|
1232 nbytes, eom); |
|
1233 break; |
|
1234 case CMD_SIMPLE: |
|
1235 return readSimpleData( id, pport, data, Octet, nbytes, eom); |
|
1236 break; |
|
1237 case CMD_CACHE: |
|
1238 return readCache(id, pport, (void *) data, Octet, nbytes, eom); |
|
1239 break; |
|
1240 } |
|
1241 |
|
1242 return asynSuccess; |
|
1243 } |
|
1244 |
|
1245 |
|
1246 /**************************************************************************** |
|
1247 * Define private Keithley648x external interface asynOctet methods |
|
1248 ****************************************************************************/ |
|
1249 static asynStatus writeOnly(Port *pport, const char *outBuf) |
|
1250 { |
|
1251 asynStatus status; |
|
1252 size_t nActual, nRequested; |
|
1253 |
|
1254 nRequested=strlen(outBuf); |
|
1255 status = |
|
1256 pasynOctetSyncIO->write(pport->pasynUser,outBuf,nRequested,TIMEOUT,&nActual); |
|
1257 if( nActual!=nRequested ) |
|
1258 status = asynError; |
|
1259 |
|
1260 if( status!=asynSuccess ) |
|
1261 { |
|
1262 pport->stats.ioErrors++; |
|
1263 asynPrint(pport->pasynUserTrace,ASYN_TRACE_ERROR, |
|
1264 "%s writeOnly: error %d wrote \"%s\"\n", |
|
1265 pport->myport,status,outBuf); |
|
1266 } |
|
1267 else |
|
1268 pport->stats.writeOnlys++; |
|
1269 |
|
1270 asynPrint(pport->pasynUserTrace, ASYN_TRACEIO_FILTER, |
|
1271 "%s writeOnly: wrote \"%s\"\n", |
|
1272 pport->myport,outBuf); |
|
1273 |
|
1274 return status; |
|
1275 } |
|
1276 |
|
1277 static asynStatus writeRead(Port *pport, const char *outBuf, char *inpBuf, |
|
1278 int inputSize, int *eomReason) |
|
1279 { |
|
1280 asynStatus status; |
|
1281 size_t nWrite, nRead, nWriteRequested; |
|
1282 |
|
1283 nWriteRequested=strlen(outBuf); |
|
1284 status = pasynOctetSyncIO->writeRead(pport->pasynUser,outBuf, |
|
1285 nWriteRequested,inpBuf,inputSize-1, |
|
1286 TIMEOUT,&nWrite,&nRead,eomReason); |
|
1287 if( nWrite!=nWriteRequested ) |
|
1288 status = asynError; |
|
1289 |
|
1290 if( status!=asynSuccess ) |
|
1291 { |
|
1292 pport->stats.ioErrors++; |
|
1293 asynPrint(pport->pasynUserTrace,ASYN_TRACE_ERROR, |
|
1294 "%s writeRead: error %d wrote \"%s\"\n", |
|
1295 pport->myport,status,outBuf); |
|
1296 } |
|
1297 else |
|
1298 { |
|
1299 inpBuf[nRead]='\0'; |
|
1300 pport->stats.writeReads++; |
|
1301 } |
|
1302 |
|
1303 asynPrint(pport->pasynUserTrace,ASYN_TRACEIO_FILTER, |
|
1304 "%s writeRead: wrote \"%s\" read \"%s\"\n", |
|
1305 pport->myport,outBuf,inpBuf); |
|
1306 |
|
1307 return status; |
|
1308 } |
|
1309 |
|
1310 |
|
1311 /**************************************************************************** |
|
1312 * Register public methods |
|
1313 ****************************************************************************/ |
|
1314 |
|
1315 /* Initialization method definitions */ |
|
1316 static const iocshArg arg0 = {"type",iocshArgString}; |
|
1317 static const iocshArg arg1 = {"myport",iocshArgString}; |
|
1318 static const iocshArg arg2 = {"ioport",iocshArgString}; |
|
1319 static const iocshArg arg3 = {"ioaddr",iocshArgInt}; |
|
1320 static const iocshArg* args[]= {&arg0,&arg1,&arg2,&arg3}; |
|
1321 static const iocshFuncDef drvAsynKeithley648xFuncDef = |
|
1322 {"drvAsynKeithley648x",4,args}; |
|
1323 static void drvAsynKeithley648xCallFunc(const iocshArgBuf* args) |
|
1324 { |
|
1325 drvAsynKeithley648x(args[0].sval,args[1].sval,args[2].sval,args[3].ival); |
|
1326 } |
|
1327 |
|
1328 /* Registration method */ |
|
1329 static void drvAsynKeithley648xRegister(void) |
|
1330 { |
|
1331 static int firstTime = 1; |
|
1332 |
|
1333 if( firstTime ) |
|
1334 { |
|
1335 firstTime = 0; |
|
1336 iocshRegister( &drvAsynKeithley648xFuncDef,drvAsynKeithley648xCallFunc ); |
|
1337 } |
|
1338 } |
|
1339 epicsExportRegistrar( drvAsynKeithley648xRegister ); |