1 /****************************************************************/
\r
3 * Description: API layer for Advantech PCI1753 card. *
\r
4 * Dependency: Windows 32 or Linux *
\r
5 * Copyright 2006-2009 Jaroslav Fojtik *
\r
6 * Note: Windows 64 will not work *
\r
7 ****************************************************************/
\r
9 #if defined(_WIN32) || defined(_WIN64)
\r
10 #include <windows.h>
\r
12 #define outb(Port,Data) __outbyte(Port,Data)
\r
13 #define outw(Port,Data) __outword(Port,Data)
\r
14 #define inb(Port) __inbyte(Port)
\r
21 #include "hudaqlib.h"
\r
22 #include "hudaq_internal.h"
\r
25 #define DI_CHANNELS 12 ///< Amount of Digital Outputs
\r
26 #define DO_CHANNELS 12 ///< Amount of Digital Inputs
\r
27 #define DA_CHANNELS 0 ///< Amount of Analog Outputs
\r
28 #define AD_CHANNELS 0 ///< Amount of Analog Inputs
\r
29 #define ENC_CHANNELS 0 ///< Amount of Encoders
\r
30 #define CTR_CHANNELS 0 ///< Amount of counters
\r
31 #define STEP_CHANNELS 0 ///< Amount of steppers
\r
34 /** Cache of PCI1753 state */
\r
37 UserDataHeader Hdr; ///< General device setup
\r
39 unsigned __int8 pconfig[4]; ///< Port configuration register
\r
40 __int8 InterruptControl[4];
\r
41 unsigned __int8 DoutCache[DO_CHANNELS];
\r
42 __int8 PatternMatch;
\r
43 __int8 PatternEnable;
\r
44 __int8 ChangeEnableState;
\r
48 /** Symbolic aliases for available registers inside BADR0 read. */
\r
73 static __int8 Ports[DI_CHANNELS] = {A0, B0, C0, A1, B1, C1, A2, B2, C2, A3, B3, C3};
\r
76 /** write to memory mapped device byte wise, bytes are stored on every 4th position. */
\r
77 static __inline void StoreByte(size_t Ptr, int Offset, unsigned __int8 value)
\r
79 //printf("%X %X\n",Ptr+Offset, value);
\r
80 outb(value, Ptr+Offset);
\r
83 /** write to IO device byte through cache. */
\r
84 static __inline void StoreCachedByte(size_t Ptr, int Offset, unsigned __int8 value, unsigned __int8 *CachedValue)
\r
86 if (*CachedValue != value)
\r
88 *CachedValue = value;
\r
89 StoreByte(Ptr,Offset,value);
\r
93 /** Read from memory mapped device byte wise, bytes are stored on every 4th position. */
\r
94 static __inline unsigned __int8 GetByte(size_t Ptr, int Offset)
\r
96 return inb(Ptr+Offset);
\r
100 /****************************************************************
\r
102 * DIGITAL INPUTS & OUTPUTS *
\r
104 ****************************************************************/
\r
107 /** Get data from digital input. */
\r
108 static int PCI1753DIRead(const DeviceRecord *DevRecord, unsigned channel)
\r
110 if (channel>=DI_CHANNELS) return HUDAQBADARG;
\r
111 return GetByte(DevRecord->DrvRes.Resources.IOResources[0].Base,Ports[channel]);
\r
115 /** Write data to digital output. */
\r
116 static HUDAQSTATUS PCI1753DOWrite(const DeviceRecord *DevRecord, unsigned channel, unsigned value)
\r
118 if (channel>=DO_CHANNELS) return HUDAQBADARG;
\r
119 StoreCachedByte(DevRecord->DrvRes.Resources.IOResources[0].Base, Ports[channel], value,
\r
120 & ((PCI1753_Private *)(DevRecord->DrvRes.DriverData))->DoutCache[channel] );
\r
121 return HUDAQSUCCESS;
\r
125 static HUDAQSTATUS PCI1753DIReadMultiple(const DeviceRecord *DevRecord, unsigned number, const unsigned *channels, unsigned *values)
\r
127 unsigned FlagX = 0;
\r
130 unsigned __int8 Cache[DI_CHANNELS+1]; //allocate more bytes for padding ind
\r
132 if (number==0 || channels==NULL || values==NULL) return HUDAQBADARG;
\r
133 if(DevRecord->pCT->HudaqDIRead==NULL) return HUDAQFAILURE;
\r
135 Base = DevRecord->DrvRes.Resources.IOResources[0].Base;
\r
137 /* schedule what to read */
\r
138 for(i=0; i<number; i++)
\r
140 if (channels[i]<DI_CHANNELS)
\r
142 FlagX |= 1<<(channels[i]);
\r
151 /* Read isolated DIs */
\r
152 for(i=0; i<DI_CHANNELS; i++)
\r
156 Cache[i] = GetByte(Base,Ports[i]);
\r
160 /* Final store od numbers read */
\r
161 for(i=0; i<number; i++)
\r
163 if(channels[i]<DI_CHANNELS)
\r
165 values[i] = Cache[channels[i]];
\r
169 if(FlagX == 0x8000) return HUDAQFAILURE; //no valid value returned
\r
170 if(FlagX & 0x8000) return HUDAQPARTIAL; //several values are valid and several are not
\r
171 return HUDAQSUCCESS; //all values are valid (or no channel asked)
\r
175 static HUDAQSTATUS PCI1753DOWriteMultiple(const DeviceRecord *DevRecord, unsigned number, const unsigned *channels, const unsigned *values)
\r
177 unsigned FlagX = 0;
\r
180 unsigned __int8 *Cache;
\r
182 if (number==0 || channels==NULL || values==NULL) return HUDAQBADARG;
\r
183 if(DevRecord->pCT->HudaqDIRead==NULL) return HUDAQFAILURE;
\r
185 Base = DevRecord->DrvRes.Resources.IOResources[0].Base;
\r
186 Cache = ((PCI1753_Private *)(DevRecord->DrvRes.DriverData))->DoutCache;
\r
188 /* schedule what to write */
\r
189 for(i=0; i<number; i++)
\r
191 if (channels[i]<DI_CHANNELS)
\r
193 if(Cache[i] != values[i])
\r
195 FlagX |= 1<<(channels[i]);
\r
196 Cache[i] = values[i];
\r
205 /* Write DOs couples */
\r
206 for(i=0; i<12; i=i+3)
\r
209 if((FlagX & j) == j)
\r
211 outw(*(__int16 *)&(Cache[i]), Base+Ports[i]);
\r
216 /* Final store of DOs */
\r
217 for(i=0; i<DI_CHANNELS; i++)
\r
221 StoreByte(Base, Ports[i], Cache[i]);
\r
225 if(FlagX == 0x8000) return HUDAQFAILURE; //no valid value returned
\r
226 if(FlagX & 0x8000) return HUDAQPARTIAL; //several values are valid and several are not
\r
227 return HUDAQSUCCESS; //all values are valid (or no channel asked)
\r
231 /** Write one bit to digital output. */
\r
232 static void PCI1753DOWriteBit(const DeviceRecord *DevRecord, unsigned channel, unsigned bit, int value)
\r
236 if (channel>=DO_CHANNELS) return; /* HUDAQBADARG */
\r
237 if (bit>=8) return; //there are only 8 bits available in each channel in PCI1753
\r
239 DoutByte = (((PCI1753_Private *)(DevRecord->DrvRes.DriverData))->DoutCache[channel]);
\r
240 if (value) DoutByte |= (1<<bit);
\r
241 else DoutByte &= ~(1<<bit);
\r
243 StoreCachedByte(DevRecord->DrvRes.Resources.IOResources[0].Base, Ports[channel], DoutByte,
\r
244 & ((PCI1753_Private *)(DevRecord->DrvRes.DriverData))->DoutCache[channel] );
\r
248 static void PCI1753DOWriteMultipleBits(const DeviceRecord *DevRecord, unsigned channel, unsigned mask, unsigned value)
\r
252 if (channel>=DO_CHANNELS) return;
\r
254 DoutByte = (((PCI1753_Private *)(DevRecord->DrvRes.DriverData))->DoutCache[channel]);
\r
255 DoutByte = (DoutByte & ~mask) | (value & mask);
\r
257 StoreCachedByte(DevRecord->DrvRes.Resources.IOResources[0].Base, Ports[channel], DoutByte,
\r
258 & ((PCI1753_Private *)(DevRecord->DrvRes.DriverData))->DoutCache[channel] );
\r
262 static double PCI1753DIOGetParameter(unsigned channel, HudaqParameter param)
\r
266 case HudaqDINUMBITS:
\r
267 return (channel<DI_CHANNELS) ? 8 : WRONG_VALUE;
\r
268 case HudaqDONUMBITS:
\r
269 return (channel<DO_CHANNELS) ? 8 : WRONG_VALUE;
\r
270 case HudaqDINUMCHANNELS:
\r
271 return DI_CHANNELS;
\r
272 case HudaqDONUMCHANNELS:
\r
273 return DO_CHANNELS;
\r
276 return WRONG_VALUE;
\r
280 static HUDAQSTATUS PCI1753DIOSetParameter(const DeviceRecord *DevRecord, unsigned channel, HudaqParameter param, int value)
\r
282 unsigned __int8 chval;
\r
286 case HudaqDINUMBITS:
\r
287 if(channel>=DI_CHANNELS) return WRONG_VALUE;
\r
288 return (value==8) ? 0 : WRONG_VALUE;
\r
289 case HudaqDONUMBITS:
\r
290 if(channel>=DI_CHANNELS) return WRONG_VALUE;
\r
291 return (value==8) ? 0 : WRONG_VALUE;
\r
292 case HudaqDINUMCHANNELS:
\r
293 return DI_CHANNELS;
\r
294 case HudaqDONUMCHANNELS:
\r
295 return DO_CHANNELS;
\r
297 if(channel>=DO_CHANNELS) return WRONG_VALUE;
\r
298 chval = ((PCI1753_Private *)(DevRecord->DrvRes.DriverData))->pconfig[channel/3];
\r
299 //printf("chval = %d\n",chval);
\r
302 case 0: if(value==1) chval &= ~0x10;
\r
303 if(value==0) chval |= 0x10;
\r
305 case 1: if(value==1) chval &= ~0x02;
\r
306 if(value==0) chval |= 0x02;
\r
308 case 2: if(value==1) chval &= ~0x0A;
\r
309 if(value==0) chval |= 0x0A;
\r
312 StoreCachedByte(DevRecord->DrvRes.Resources.IOResources[0].Base, Cfg0+4*(channel/3), chval,
\r
313 & ((PCI1753_Private *)(DevRecord->DrvRes.DriverData))->pconfig[channel/3] );
\r
314 return HUDAQSUCCESS;
\r
317 return WRONG_VALUE;
\r
320 /********************************************************************/
\r
322 /* Initialization procedure for AD612 card. */
\r
323 static int InitPCI1753(DeviceRecord *DevRecord, int IniOptions)
\r
325 PCI1753_Private *Cache;
\r
328 if (DevRecord==NULL) return -1;
\r
330 if (DevRecord->DrvRes.Resources.NumIOResources<1) return -2; //insufficient amount of resources
\r
331 Cache = DevRecord->DrvRes.DriverData;
\r
332 if (Cache==NULL) return -3;
\r
333 if (DevRecord->DrvRes.DriverDataSize<sizeof(PCI1753_Private)) return -4;
\r
335 DevRecord->pCT = &CTPCI1753;
\r
337 if ((IniOptions & HudaqOpenNOINIT)==0)
\r
338 { //initialize hardware only if no other application is running
\r
339 /* Initialization of DI and DO. */
\r
340 Cache->InterruptControl[0] = 0x8A; /* Clear ISRs */
\r
341 Cache->InterruptControl[1] = 0x80;
\r
342 Cache->InterruptControl[2] = 0x80;
\r
343 Cache->InterruptControl[3] = 0x80;
\r
345 StoreByte(DevRecord->DrvRes.Resources.IOResources[0].Base, IrqCtrR+i, Cache->InterruptControl[i]);
\r
349 Cache->pconfig[i] = 0x1B;
\r
350 StoreByte(DevRecord->DrvRes.Resources.IOResources[0].Base, Cfg0+4*i, Cache->pconfig[i]);
\r
353 Cache->PatternMatch = 0;
\r
354 StoreByte(DevRecord->DrvRes.Resources.IOResources[0].Base, PatternMatch, Cache->PatternMatch);
\r
355 Cache->PatternEnable = 0;
\r
356 StoreByte(DevRecord->DrvRes.Resources.IOResources[0].Base, PatternEnable, Cache->PatternEnable);
\r
357 Cache->ChangeEnableState = 0;
\r
358 StoreByte(DevRecord->DrvRes.Resources.IOResources[0].Base, ChEnableState, Cache->ChangeEnableState);
\r
361 return 1; //success
\r
364 /** Internal cleanup procedure for PCI1753 */
\r
365 static void DonePCI1753(DeviceRecord *DevRecord)
\r
367 if (DevRecord==NULL) return;
\r
369 DevRecord->pCT = &CtDummy;
\r
374 /****************************************************************
\r
376 * GET/SET PARAMETERS *
\r
378 ****************************************************************/
\r
380 static HUDAQSTATUS PCI1753SetParameter(const DeviceRecord *DevRecord, unsigned channel, HudaqParameter param, double value)
\r
382 switch(param & HudaqSubsystemMASK)
\r
385 case HudaqDO: return PCI1753DIOSetParameter(DevRecord,channel,param,value);
\r
393 return HUDAQNOTSUPPORTED;
\r
396 static double PCI1753GetParameter(const DeviceRecord *DevRecord, unsigned channel, HudaqParameter param)
\r
398 switch(param & HudaqSubsystemMASK)
\r
401 case HudaqDO: return PCI1753DIOGetParameter(channel,param);
\r
409 return WRONG_VALUE;
\r
413 const CallTable CTPCI1753 =
\r
415 "PCI1753", 0x13FE, 0x1753,
\r
419 PCI1753SetParameter,
\r
420 PCI1753GetParameter,
\r
423 // INITIALIZE DI callers
\r
425 GenericDIReadBit, //Generic implementation
\r
426 PCI1753DIReadMultiple,
\r
427 // INITIALIZE DO callers
\r
430 PCI1753DOWriteMultipleBits,
\r
431 PCI1753DOWriteMultiple,
\r
432 // INITIALIZE AI callers
\r
435 // INITIALIZE AO callers
\r
438 // INITIALIZE Enc callers
\r
439 NULL, // Not available
\r
441 // INITIALIZE Ctr callers
\r
442 NULL, // Not available
\r
444 // INITIALIZE PWM callers
\r
445 NULL, // Not available
\r
448 // INITIALIZE Step callers
\r
449 NULL, // Not available
\r