1 /****************************************************************/
\r
3 * Description: API layer for TEDIA PCD-7004 card. *
\r
4 * Dependency: Windows 32, Windows 64 or Linux *
\r
5 * Copyright 2009-2010 Jaroslav Fojtik *
\r
6 ****************************************************************/
\r
8 #if defined(_WIN32) || defined(_WIN64)
\r
16 #include "hudaqlib.h"
\r
17 #include "hudaq_internal.h"
\r
20 #define DI_CHANNELS 4 ///< Amount of Digital Outputs
\r
21 #define DO_CHANNELS 4 ///< Amount of Digital Inputs
\r
22 #define DA_CHANNELS 0 ///< Amount of Analog Outputs
\r
23 #define AD_CHANNELS 0 ///< Amount of Analog Inputs
\r
24 #define ENC_CHANNELS 0 ///< Amount of Encoders
\r
25 #define CTR_CHANNELS 1 ///< Amount of counters
\r
26 #define STEP_CHANNELS 0 ///< Amount of steppers
\r
29 #define MASTERFREQUENCY 1000 ///< Internal oscillator frequency is 1kHz
\r
32 /** Cache of PCD-7004 state */
\r
35 UserDataHeader Hdr; ///< General device setup
\r
37 unsigned __int8 DIOReg[4]; ///< Port configuration register
\r
38 unsigned __int8 DIOCfgReg;
\r
39 unsigned __int8 IRQCfgReg;
\r
40 unsigned __int8 INTEnReg;
\r
41 unsigned __int8 TimerReg;
\r
45 /** Symbolic aliases for available registers inside BADR4 read. */
\r
55 IRQCfgReg = 0x200/4, // WR only
\r
56 IRQStatusReg = 0x200/4, // RD only
\r
57 IRQClrReg = 0x204/4, // WR only
\r
59 TimerReg = 0x208/4, // RW
\r
64 static __int8 Ports[DI_CHANNELS] = {DIOReg0, DIOReg1, DIOReg2, DIOReg3};
\r
67 /** write to memory mapped device byte wise, bytes are stored on every 4th position. */
\r
68 static __inline void StoreByte(size_t Ptr, int Offset, unsigned __int8 value)
\r
70 ((volatile unsigned __int8 *)(Ptr))[4*Offset] = value;
\r
73 /** write to memory mapped device byte wise through cache. */
\r
74 static __inline void StoreCachedByte(size_t Ptr, int Offset, unsigned __int8 value, unsigned __int8 *CachedValue)
\r
76 if (*CachedValue != value)
\r
78 *CachedValue = value;
\r
79 StoreByte(Ptr,Offset,value);
\r
84 /** This inline is used for reading tightly packed OX9162 local configuration registers. */
\r
85 static __inline unsigned __int8 GetBytePlain(size_t Ptr, int Offset)
\r
87 return ((volatile unsigned __int8 *)(Ptr))[4*Offset];
\r
91 /****************************************************************
\r
93 * DIGITAL INPUTS & OUTPUTS *
\r
95 ****************************************************************/
\r
98 /** Get data from digital input. */
\r
99 static int PCD7004DIRead(const DeviceRecord *DevRecord, unsigned channel)
\r
101 if (channel>=DI_CHANNELS) return HUDAQBADARG;
\r
102 return GetBytePlain(DevRecord->DrvRes.Resources.MemResources[1].Base,Ports[channel]);
\r
106 /** Write data to digital output. */
\r
107 static HUDAQSTATUS PCD7004DOWrite(const DeviceRecord *DevRecord, unsigned channel, unsigned value)
\r
109 if (channel>=DO_CHANNELS) return HUDAQBADARG;
\r
110 StoreCachedByte(DevRecord->DrvRes.Resources.MemResources[1].Base, Ports[channel], value,
\r
111 &((PCD_7004_Private *)(DevRecord->DrvRes.DriverData))->DIOReg[channel] );
\r
112 return HUDAQSUCCESS;
\r
116 static HUDAQSTATUS PCD7004DIReadMultiple(const DeviceRecord *DevRecord, unsigned number, const unsigned *channels, unsigned *values)
\r
118 unsigned FlagX = 0;
\r
121 unsigned __int8 Cache[DI_CHANNELS+1]; //allocate more bytes for padding ind
\r
123 if (number==0 || channels==NULL || values==NULL) return HUDAQBADARG;
\r
124 if(DevRecord->pCT->HudaqDIRead==NULL) return HUDAQFAILURE;
\r
126 Base = DevRecord->DrvRes.Resources.MemResources[1].Base;
\r
128 /* Schedule what to read. */
\r
129 for(i=0; i<number; i++)
\r
131 if (channels[i]<DI_CHANNELS)
\r
133 FlagX |= 1<<(channels[i]);
\r
142 /* Read isolated DIs */
\r
143 for(i=0; i<DI_CHANNELS; i++)
\r
147 Cache[i] = GetBytePlain(Base,Ports[i]);
\r
151 /* Final store of numbers read. */
\r
152 for(i=0; i<number; i++)
\r
154 if(channels[i]<DI_CHANNELS)
\r
156 values[i] = Cache[channels[i]];
\r
160 if(FlagX == 0x8000) return HUDAQFAILURE; //no valid value returned
\r
161 if(FlagX & 0x8000) return HUDAQPARTIAL; //several values are valid and several are not
\r
162 return HUDAQSUCCESS; //all values are valid (or no channel asked)
\r
166 static HUDAQSTATUS PCD7004DOWriteMultiple(const DeviceRecord *DevRecord, unsigned number, const unsigned *channels, const unsigned *values)
\r
168 unsigned FlagX = 0;
\r
171 unsigned __int8 *Cache;
\r
173 if (number==0 || channels==NULL || values==NULL) return HUDAQBADARG;
\r
174 if(DevRecord->pCT->HudaqDIRead==NULL) return HUDAQFAILURE;
\r
176 Base = DevRecord->DrvRes.Resources.MemResources[1].Base;
\r
177 Cache = ((PCD_7004_Private *)(DevRecord->DrvRes.DriverData))->DIOReg;
\r
179 /* schedule what to write */
\r
180 for(i=0; i<number; i++)
\r
182 if (channels[i]<DI_CHANNELS)
\r
184 if(Cache[i] != values[i])
\r
186 FlagX |= 1<<(channels[i]);
\r
187 Cache[i] = values[i];
\r
196 /* Final store of DOs */
\r
197 for(i=0; i<DI_CHANNELS; i++)
\r
201 StoreByte(Base, Ports[i], Cache[i]);
\r
205 if(FlagX == 0x8000) return HUDAQFAILURE; //no valid value returned
\r
206 if(FlagX & 0x8000) return HUDAQPARTIAL; //several values are valid and several are not
\r
207 return HUDAQSUCCESS; //all values are valid (or no channel asked)
\r
211 /** Write one bit to digital output. */
\r
212 static void PCD7004DOWriteBit(const DeviceRecord *DevRecord, unsigned channel, unsigned bit, int value)
\r
216 if (channel>=DO_CHANNELS) return;
\r
217 if (bit>=8) return; /* There are only 8 bits available in PCD7004. */
\r
219 DoutByte = (((PCD_7004_Private *)(DevRecord->DrvRes.DriverData))->DIOReg[channel]);
\r
220 if (value) DoutByte |= (1<<bit);
\r
221 else DoutByte &= ~(1<<bit);
\r
223 StoreCachedByte(DevRecord->DrvRes.Resources.MemResources[1].Base, Ports[channel], DoutByte,
\r
224 & ((PCD_7004_Private *)(DevRecord->DrvRes.DriverData))->DIOReg[channel]);
\r
228 static void PCD7004DOWriteMultipleBits(const DeviceRecord *DevRecord, unsigned channel, unsigned mask, unsigned value)
\r
232 if (channel>=DO_CHANNELS) return;
\r
234 DoutByte = (((PCD_7004_Private *)(DevRecord->DrvRes.DriverData))->DIOReg[channel]);
\r
235 DoutByte = (DoutByte & ~mask) | (value & mask);
\r
237 StoreCachedByte(DevRecord->DrvRes.Resources.MemResources[1].Base, Ports[channel], DoutByte,
\r
238 & ((PCD_7004_Private *)(DevRecord->DrvRes.DriverData))->DIOReg[channel] );
\r
242 static double PCD7004DIOGetParameter(unsigned channel, HudaqParameter param)
\r
246 case HudaqDINUMBITS:
\r
247 return (channel<DI_CHANNELS) ? 8 : WRONG_VALUE;
\r
248 case HudaqDONUMBITS:
\r
249 return (channel<DO_CHANNELS) ? 8 : WRONG_VALUE;
\r
250 case HudaqDINUMCHANNELS:
\r
251 return DI_CHANNELS;
\r
252 case HudaqDONUMCHANNELS:
\r
253 return DO_CHANNELS;
\r
256 return WRONG_VALUE;
\r
260 static HUDAQSTATUS PCD7004DIOSetParameter(const DeviceRecord *DevRecord, unsigned channel, HudaqParameter param, int value)
\r
262 unsigned __int8 chval;
\r
266 case HudaqDINUMBITS:
\r
267 if(channel>=DI_CHANNELS) return WRONG_VALUE;
\r
268 return (value==8) ? 0 : WRONG_VALUE;
\r
269 case HudaqDONUMBITS:
\r
270 if(channel>=DI_CHANNELS) return WRONG_VALUE;
\r
271 return (value==8) ? 0 : WRONG_VALUE;
\r
272 case HudaqDINUMCHANNELS:
\r
273 return DI_CHANNELS;
\r
274 case HudaqDONUMCHANNELS:
\r
275 return DO_CHANNELS;
\r
277 if(channel>=DO_CHANNELS) return WRONG_VALUE;
\r
278 chval = ((PCD_7004_Private *)(DevRecord->DrvRes.DriverData))->DIOCfgReg;
\r
279 //printf("chval = %d\n",chval);
\r
283 case 0: if(value==1) chval &= ~0x1;
\r
284 if(value==0) chval |= 0x1;
\r
286 case 1: if(value==1) chval &= ~0x02;
\r
287 if(value==0) chval |= 0x02;
\r
289 case 2: if(value==1) chval &= ~0x04;
\r
290 if(value==0) chval |= 0x04;
\r
292 case 3: if(value==1) chval &= ~0x08;
\r
293 if(value==0) chval |= 0x08;
\r
296 StoreCachedByte(DevRecord->DrvRes.Resources.MemResources[1].Base, DIOCfgReg, chval,
\r
297 & ((PCD_7004_Private *)(DevRecord->DrvRes.DriverData))->DIOCfgReg );
\r
298 return HUDAQSUCCESS;
\r
301 return WRONG_VALUE;
\r
305 /****************************************************************
\r
307 * COUNTERS PWM + Count + Step *
\r
309 ****************************************************************/
\r
311 static HUDAQSTATUS PCD7004PWMWrite(const DeviceRecord *DevRecord, unsigned channel, double frequency, double dutycycle)
\r
314 HUDAQSTATUS ret = HUDAQSUCCESS;
\r
316 if (channel>=CTR_CHANNELS) return HUDAQBADARG;
\r
318 if (frequency<=0) return HUDAQBADARG; //Allow duty cycle 0 and 1 for f=0.
\r
320 T = MASTERFREQUENCY/frequency;
\r
323 StoreCachedByte(DevRecord->DrvRes.Resources.MemResources[1].Base, TimerReg, 1,
\r
324 & ((PCD_7004_Private *)(DevRecord->DrvRes.DriverData))->TimerReg);
\r
325 return HUDAQPARTIAL;
\r
329 StoreCachedByte(DevRecord->DrvRes.Resources.MemResources[1].Base, TimerReg, 255,
\r
330 & ((PCD_7004_Private *)(DevRecord->DrvRes.DriverData))->TimerReg);
\r
331 return HUDAQPARTIAL;
\r
334 StoreCachedByte(DevRecord->DrvRes.Resources.MemResources[1].Base, TimerReg,
\r
335 (unsigned __int8)T,
\r
336 &((PCD_7004_Private *)(DevRecord->DrvRes.DriverData))->TimerReg);
\r
338 return HUDAQSUCCESS;
\r
342 static HUDAQSTATUS PCD7004CtrReset(const DeviceRecord *DevRecord, unsigned channel)
\r
344 if (channel>=CTR_CHANNELS) return HUDAQBADARG;
\r
345 StoreCachedByte(DevRecord->DrvRes.Resources.MemResources[1].Base, TimerReg,
\r
346 0, &((PCD_7004_Private *)(DevRecord->DrvRes.DriverData))->TimerReg);
\r
347 return HUDAQSUCCESS;
\r
351 static int PCD7004CtrRead(const DeviceRecord *DevRecord, unsigned channel)
\r
353 if (channel>=CTR_CHANNELS) return 0;
\r
354 return GetBytePlain(DevRecord->DrvRes.Resources.MemResources[1].Base, TimerReg);
\r
361 /********************************************************************/
\r
363 /* Initialization procedure for PCD-7004 card. */
\r
364 static int InitPCD7004(DeviceRecord *DevRecord, int IniOptions)
\r
366 PCD_7004_Private *Cache;
\r
370 if (DevRecord==NULL) return -1;
\r
372 if (DevRecord->DrvRes.Resources.NumMemResources<2) return -2; //insufficient amount of resources
\r
373 Cache = DevRecord->DrvRes.DriverData;
\r
374 if (Cache==NULL) return -3;
\r
375 if (DevRecord->DrvRes.DriverDataSize<sizeof(PCD_7004_Private)) return -4;
\r
377 DevRecord->pCT = &CTPCD7004;
\r
379 if ((IniOptions & HudaqOpenNOINIT)==0)
\r
380 { //initialize hardware only if no other application is running
\r
381 Base = DevRecord->DrvRes.Resources.MemResources[1].Base;
\r
383 /* disable interrupts */
\r
384 Cache->INTEnReg = 0;
\r
385 StoreByte(Base, INTEnReg, 0);
\r
387 /* Initialization of DI and DO. */
\r
390 Cache->DIOReg[i] = 0;
\r
391 StoreByte(Base, Ports[i], 0);
\r
394 Cache->DIOCfgReg = 0;
\r
395 StoreByte(Base, DIOCfgReg, 0);
\r
397 Cache->IRQCfgReg = 0;
\r
398 StoreByte(Base, IRQCfgReg, 0);
\r
400 Cache->TimerReg = 0;
\r
401 StoreByte(Base, TimerReg, 0); /* Stop timer. */
\r
404 return 1; //success
\r
408 /** Internal cleanup procedure for PCD7004 */
\r
409 static void DonePCD7004(DeviceRecord *DevRecord)
\r
411 if (DevRecord==NULL) return;
\r
413 DevRecord->pCT = &CtDummy;
\r
418 /****************************************************************
\r
420 * GET/SET PARAMETERS *
\r
422 ****************************************************************/
\r
425 static HUDAQSTATUS PCD7004IRQSetParameter(const DeviceRecord *DevRecord, unsigned channel, HudaqParameter param, int value)
\r
429 Base = DevRecord->DrvRes.Resources.MemResources[1].Base;
\r
437 StoreCachedByte(Base, IRQCfgReg, 1, &((PCD_7004_Private *)DevRecord->DrvRes.DriverData)->IRQCfgReg);
\r
438 StoreByte(Base, IRQClrReg, 0xFF);
\r
439 StoreCachedByte(Base, INTEnReg, 0x80, &((PCD_7004_Private *)DevRecord->DrvRes.DriverData)->INTEnReg);
\r
443 StoreCachedByte(DevRecord->DrvRes.Resources.MemResources[1].Base, INTEnReg, 0,
\r
444 &((PCD_7004_Private *)DevRecord->DrvRes.DriverData)->INTEnReg);
\r
445 StoreCachedByte(DevRecord->DrvRes.Resources.MemResources[1].Base, IRQCfgReg, 0,
\r
446 &((PCD_7004_Private *)DevRecord->DrvRes.DriverData)->IRQCfgReg);
\r
448 return HUDAQSUCCESS;
\r
451 return HUDAQSUCCESS;
\r
454 return WRONG_VALUE;
\r
458 static double PCD7004IRQGetParameter(const DeviceRecord *DevRecord, unsigned channel, HudaqParameter param)
\r
463 return ((PCD_7004_Private *)DevRecord->DrvRes.DriverData)->Hdr.IRQcounter;
\r
465 return GetBytePlain(DevRecord->DrvRes.Resources.MemResources[1].Base,IRQStatusReg);
\r
467 return WRONG_VALUE;
\r
471 static HUDAQSTATUS PCD7004SetParameter(const DeviceRecord *DevRecord, unsigned channel, HudaqParameter param, double value)
\r
473 switch(param & HudaqSubsystemMASK)
\r
476 case HudaqDO: return PCD7004DIOSetParameter(DevRecord,channel,param,(int)value);
\r
483 case HudaqIRQ: return PCD7004IRQSetParameter(DevRecord,channel,param,(int)value);
\r
485 return HUDAQNOTSUPPORTED;
\r
488 static double PCD7004GetParameter(const DeviceRecord *DevRecord, unsigned channel, HudaqParameter param)
\r
490 switch(param & HudaqSubsystemMASK)
\r
493 case HudaqDO: return PCD7004DIOGetParameter(channel,param);
\r
500 case HudaqIRQ: return PCD7004IRQGetParameter(DevRecord,channel,param);
\r
502 return WRONG_VALUE;
\r
506 const CallTable CTPCD7004 =
\r
508 "PCD7004", 0x1760, 0x0101,
\r
512 PCD7004SetParameter,
\r
513 PCD7004GetParameter,
\r
516 // INITIALIZE DI callers
\r
518 GenericDIReadBit, //Generic implementation
\r
519 PCD7004DIReadMultiple,
\r
520 // INITIALIZE DO callers
\r
523 PCD7004DOWriteMultipleBits,
\r
524 PCD7004DOWriteMultiple,
\r
525 // INITIALIZE AI callers
\r
528 // INITIALIZE AO callers
\r
531 // INITIALIZE Enc callers
\r
532 NULL, // Not available
\r
534 // INITIALIZE Ctr callers
\r
537 // INITIALIZE PWM callers
\r
539 NULL, // Not available
\r
541 // INITIALIZE Step callers
\r
542 NULL, // Not available
\r