1 /****************************************************************/
\r
3 * Description: API layer for TEDIA PCT-7303B card. *
\r
4 * Dependency: Windows 32, Windows 64 or Linux *
\r
5 * Copyright 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 1 ///< Amount of Digital Outputs
\r
21 #define DO_CHANNELS 1 ///< 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 3 ///< 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
31 #define IrcResetCounter 2 ///< Binary flag for IrcOptions
\r
34 /** Cache of PCT-7303B state */
\r
37 UserDataHeader Hdr; ///< General device setup
\r
39 int EncOptions[ENC_CHANNELS]; ///< Bit options for encoders
\r
41 unsigned __int8 DOReg; ///< Port configuration register
\r
42 unsigned __int8 IRQCfgReg;
\r
43 unsigned __int8 INTEnReg;
\r
44 unsigned __int8 TimerReg;
\r
45 unsigned __int8 CNTEnReg;
\r
46 } PCT_7303B_Private;
\r
49 /** Symbolic aliases for available registers inside BADR1 read. */
\r
52 DINReg = 0, // RD only
\r
53 DOUTReg = 4, // WR only
\r
55 IRQCfgReg = 0x180, // WR only
\r
56 IRQStatusReg = 0x180, // RD only
\r
57 IRQClrReg = 0x184, // WR only
\r
59 TimerReg = 0x3F0, // RW
\r
60 INTEnReg = 0x18C, // WR only
\r
62 CNT0SetReg = 0x200, // RW
\r
63 CNT1SetReg = 0x204, // RW
\r
64 CNT2SetReg = 0x208, // RW
\r
66 CNTEnReg = 0x380, // WR only
\r
67 CNTCtrReg= 0x384, // WR only
\r
69 } MEM_BAR1; // Memory space #0 on F1
\r
72 /** write to memory mapped device byte wise, bytes are stored on every 4th position. */
\r
73 static __inline void StoreByte(size_t Ptr, int Offset, unsigned __int8 value)
\r
75 ((volatile unsigned __int8 *)(Ptr))[Offset] = value;
\r
78 static __inline void StoreDword(size_t Ptr, int Offset, unsigned __int32 value)
\r
80 ((volatile unsigned __int32 *)(Ptr))[Offset] = value;
\r
84 /** write to memory mapped device byte wise through cache. */
\r
85 static __inline void StoreCachedByte(size_t Ptr, int Offset, unsigned __int8 value, unsigned __int8 *CachedValue)
\r
87 if (*CachedValue != value)
\r
89 *CachedValue = value;
\r
90 StoreByte(Ptr,Offset,value);
\r
95 /** This inline is used for reading tightly packed OX9162 local configuration registers. */
\r
96 static __inline unsigned __int8 GetBytePlain(size_t Ptr, int Offset)
\r
98 return ((volatile unsigned __int8 *)(Ptr))[Offset];
\r
102 /****************************************************************
\r
104 * DIGITAL INPUTS & OUTPUTS *
\r
106 ****************************************************************/
\r
109 /** Get data from digital input. */
\r
110 static int PCT7303DIRead(const DeviceRecord *DevRecord, unsigned channel)
\r
112 if (channel>=DI_CHANNELS) return HUDAQBADARG;
\r
113 return GetBytePlain(DevRecord->DrvRes.Resources.MemResources[0].Base,DINReg);
\r
117 /** Write data to digital output. */
\r
118 static HUDAQSTATUS PCT7303DOWrite(const DeviceRecord *DevRecord, unsigned channel, unsigned value)
\r
120 if (channel>=DO_CHANNELS) return HUDAQBADARG;
\r
121 StoreCachedByte(DevRecord->DrvRes.Resources.MemResources[0].Base, DOUTReg, value,
\r
122 &((PCT_7303B_Private *)(DevRecord->DrvRes.DriverData))->DOReg);
\r
123 return HUDAQSUCCESS;
\r
127 /** Write one bit to digital output. */
\r
128 static void PCT7303DOWriteBit(const DeviceRecord *DevRecord, unsigned channel, unsigned bit, int value)
\r
132 if (channel>=DO_CHANNELS) return;
\r
133 if (bit>=8) return; //there are only 8 bits available in PCT7303
\r
135 DoutByte = (((PCT_7303B_Private *)(DevRecord->DrvRes.DriverData))->DOReg);
\r
136 if (value) DoutByte |= (1<<bit);
\r
137 else DoutByte &= ~(1<<bit);
\r
139 StoreCachedByte(DevRecord->DrvRes.Resources.MemResources[0].Base, DOUTReg, DoutByte,
\r
140 & ((PCT_7303B_Private *)(DevRecord->DrvRes.DriverData))->DOReg);
\r
144 static void PCT7303DOWriteMultipleBits(const DeviceRecord *DevRecord, unsigned channel, unsigned mask, unsigned value)
\r
148 if (channel>=DO_CHANNELS) return;
\r
150 DoutByte = (((PCT_7303B_Private *)(DevRecord->DrvRes.DriverData))->DOReg);
\r
151 DoutByte = (DoutByte & ~mask) | (value & mask);
\r
153 StoreCachedByte(DevRecord->DrvRes.Resources.MemResources[0].Base, DOUTReg, DoutByte,
\r
154 &((PCT_7303B_Private *)(DevRecord->DrvRes.DriverData))->DOReg);
\r
158 static double PCT7303DIOGetParameter(unsigned channel, HudaqParameter param)
\r
162 case HudaqDINUMBITS:
\r
163 return (channel<DI_CHANNELS) ? 8 : WRONG_VALUE;
\r
164 case HudaqDONUMBITS:
\r
165 return (channel<DO_CHANNELS) ? 8 : WRONG_VALUE;
\r
166 case HudaqDINUMCHANNELS:
\r
167 return DI_CHANNELS;
\r
168 case HudaqDONUMCHANNELS:
\r
169 return DO_CHANNELS;
\r
172 return WRONG_VALUE;
\r
176 static HUDAQSTATUS PCT7303DIOSetParameter(const DeviceRecord *DevRecord, unsigned channel, HudaqParameter param, int value)
\r
181 case HudaqDINUMBITS:
\r
182 if(channel>=DI_CHANNELS) return WRONG_VALUE;
\r
183 return (value==8) ? 0 : WRONG_VALUE;
\r
184 case HudaqDONUMBITS:
\r
185 if(channel>=DI_CHANNELS) return WRONG_VALUE;
\r
186 return (value==8) ? 0 : WRONG_VALUE;
\r
187 case HudaqDINUMCHANNELS:
\r
188 return DI_CHANNELS;
\r
189 case HudaqDONUMCHANNELS:
\r
190 return DO_CHANNELS;
\r
192 if(channel>=DO_CHANNELS) return WRONG_VALUE;
\r
193 return HUDAQSUCCESS;
\r
196 return WRONG_VALUE;
\r
200 /****************************************************************
\r
204 ****************************************************************/
\r
206 static double PCT7303BEncGetParameter(const DeviceRecord *DevRecord, unsigned channel, HudaqParameter param)
\r
209 PCT_7303B_Private *Cache;
\r
211 Cache = (PCT_7303B_Private *)DevRecord->DrvRes.DriverData;
\r
212 if (channel>=ENC_CHANNELS) return WRONG_VALUE;
\r
216 case HudaqEncRESETONREAD:
\r
217 return(Cache->EncOptions[channel] & IrcResetCounter);
\r
221 pCTRi = (IRC_Control *)&(((char *)&(Cache->EncCache))[channel]);
\r
222 return(pCTRi->IRC_MODE);
\r
223 case HudaqEncCOUNTCONTROL:
\r
224 pCTRi = (IRC_Control *)&(((char *)&(Cache->EncCache))[channel]);
\r
225 return(pCTRi->BLOCK_MODE);
\r
226 case HudaqEncRESETMODE:
\r
227 pCTRi = (IRC_Control *)&(((char *)&(Cache->EncCache))[channel]);
\r
228 return(pCTRi->RESET_MODE);
\r
230 *(__int32 *)IrcValue = GetDword(DevRecord->DrvRes.Resources.MemResources[0].Base, IRCSTATUS);
\r
231 return(IrcValue[channel]);
\r
233 case HudaqEncNUMCHANNELS:
\r
234 return ENC_CHANNELS;
\r
237 return WRONG_VALUE;
\r
241 static HUDAQSTATUS PCT7303BEncSetParameter(const DeviceRecord *DevRecord, unsigned channel, HudaqParameter param, double value)
\r
244 PCT_7303B_Private *Cache;
\r
246 Cache = (PCT_7303B_Private *)DevRecord->DrvRes.DriverData;
\r
247 if (channel>=ENC_CHANNELS) return HUDAQBADARG;
\r
248 Ptr1 = DevRecord->DrvRes.Resources.MemResources[0].Base;
\r
252 case HudaqEncRESETONREAD:
\r
254 Cache->EncOptions[channel] |= IrcResetCounter;
\r
256 Cache->EncOptions[channel] &= ~IrcResetCounter;
\r
257 return HUDAQSUCCESS;
\r
261 if (value<0 || value>=4) return HUDAQBADARG;
\r
262 *(unsigned __int32 *)&IrcValue = Cache->EncCache;
\r
263 pCTRi = (IRC_Control *)&IrcValue[channel];
\r
265 pCTRi->IRC_MODE = (int)value;
\r
266 StoreCachedDword(Ptr2, IRCCTRL, *(unsigned __int32 *)&IrcValue, &Cache->EncCache);
\r
267 return HUDAQSUCCESS;
\r
269 case HudaqEncRESETMODE:
\r
270 if (value<0 || value>=7) return HUDAQBADARG;
\r
271 *(unsigned __int32 *)&IrcValue = Cache->EncCache;
\r
272 pCTRi = (IRC_Control *)&IrcValue[channel];
\r
274 pCTRi->RESET_MODE = (int)value;
\r
275 StoreCachedDword(Ptr2, IRCCTRL, *(unsigned __int32 *)&IrcValue, &Cache->EncCache);
\r
276 return HUDAQSUCCESS;
\r
278 case HudaqEncCOUNTCONTROL:
\r
279 if (value<0 || value>=4) return HUDAQBADARG;
\r
280 *(unsigned __int32 *)&IrcValue = Cache->EncCache;
\r
281 pCTRi = (IRC_Control *)&IrcValue[channel];
\r
283 pCTRi->BLOCK_MODE = (int)value;
\r
284 StoreCachedDword(Ptr2, IRCCTRL, *(unsigned __int32 *)&IrcValue, &Cache->EncCache);
\r
285 return HUDAQSUCCESS;
\r
289 return HUDAQNOTSUPPORTED;
\r
293 /* static HUDAQSTATUS PCT7303BEncReset(const DeviceRecord *DevRecord, unsigned channel)
\r
296 MF624_Private *Cache;
\r
297 __int8 IrcValue[ENC_CHANNELS];
\r
298 IRC_Control *pCTRi;
\r
301 Cache = (MF624_Private *)DevRecord->DrvRes.DriverData;
\r
302 if (channel>=ENC_CHANNELS) return HUDAQBADARG;
\r
303 Ptr2 = DevRecord->DrvRes.Resources.MemResources[0].Base;
\r
305 *(unsigned __int32*)&IrcValue = Cache->EncCache;
\r
306 pCTRi = (IRC_Control *)&IrcValue[channel];
\r
308 OldResetMode = pCTRi->RESET_MODE; //store original reset mode
\r
309 pCTRi->RESET_MODE = 1; //reset encoder
\r
310 StoreDword(Ptr2, IRCCTRL, *(unsigned __int32 *)&IrcValue);
\r
311 pCTRi->RESET_MODE = OldResetMode; //enable counting
\r
312 StoreDword(Ptr2, IRCCTRL, *(unsigned __int32 *)&IrcValue);
\r
313 return HUDAQSUCCESS;
\r
317 static int PCT7303BEncRead(const DeviceRecord *DevRecord, unsigned channel)
\r
321 PCT_7303B_Private *Cache;
\r
323 if (channel>=ENC_CHANNELS) return 0;
\r
324 Cache = (PCT_7303B_Private *)DevRecord->DrvRes.DriverData;
\r
325 Ptr1 = DevRecord->DrvRes.Resources.MemResources[0].Base;
\r
327 // read a value from encoder
\r
328 StoreByte(Ptr1, CNTCtrReg, 1<<channel);
\r
329 RetVal = GetBytePlain(Ptr1,CNT0SetReg) +
\r
330 0x100 * GetBytePlain(Ptr1,CNT1SetReg) +
\r
331 0x10000 * GetBytePlain(Ptr1,CNT2SetReg);
\r
333 if(Cache->EncOptions[channel] & IrcResetCounter) //RESET counter on every read
\r
335 StoreByte(Ptr1, CNT0SetReg, 0);
\r
336 StoreByte(Ptr1, CNT1SetReg, 0);
\r
337 StoreByte(Ptr1, CNT2SetReg, 0);
\r
338 StoreByte(Ptr1, CNTCtrReg, 0x10<<channel);
\r
345 /****************************************************************
\r
347 * COUNTERS PWM + Count + Step *
\r
349 ****************************************************************/
\r
351 static HUDAQSTATUS PCT7303BPWMWrite(const DeviceRecord *DevRecord, unsigned channel, double frequency, double dutycycle)
\r
355 if (channel>=CTR_CHANNELS) return HUDAQBADARG;
\r
357 if (frequency<=0) return HUDAQBADARG; //Allow duty cycle 0 and 1 for f=0.
\r
359 T = MASTERFREQUENCY/frequency;
\r
362 StoreCachedByte(DevRecord->DrvRes.Resources.MemResources[0].Base, TimerReg, 1,
\r
363 & ((PCT_7303B_Private *)(DevRecord->DrvRes.DriverData))->TimerReg);
\r
364 return HUDAQPARTIAL;
\r
368 StoreCachedByte(DevRecord->DrvRes.Resources.MemResources[0].Base, TimerReg, 255,
\r
369 & ((PCT_7303B_Private *)(DevRecord->DrvRes.DriverData))->TimerReg);
\r
370 return HUDAQPARTIAL;
\r
373 StoreCachedByte(DevRecord->DrvRes.Resources.MemResources[0].Base, TimerReg,
\r
374 (unsigned __int8)T,
\r
375 &((PCT_7303B_Private *)(DevRecord->DrvRes.DriverData))->TimerReg);
\r
377 return HUDAQSUCCESS;
\r
381 static HUDAQSTATUS PCT7303BCtrReset(const DeviceRecord *DevRecord, unsigned channel)
\r
383 StoreCachedByte(DevRecord->DrvRes.Resources.MemResources[0].Base, TimerReg,
\r
384 0, &((PCT_7303B_Private *)(DevRecord->DrvRes.DriverData))->TimerReg);
\r
385 return HUDAQSUCCESS;
\r
389 static int PCT7303BCtrRead(const DeviceRecord *DevRecord, unsigned channel)
\r
391 if (channel>=CTR_CHANNELS) return 0;
\r
392 return GetBytePlain(DevRecord->DrvRes.Resources.MemResources[0].Base, TimerReg);
\r
397 /********************************************************************/
\r
399 /* Initialization procedure for PCT-7303B card. */
\r
400 static int InitPCT7303(DeviceRecord *DevRecord, int IniOptions)
\r
402 PCT_7303B_Private *Cache;
\r
405 if (DevRecord==NULL) return -1;
\r
407 if (DevRecord->DrvRes.Resources.NumMemResources<2) return -2; //insufficient amount of resources
\r
408 Cache = DevRecord->DrvRes.DriverData;
\r
409 if (Cache==NULL) return -3;
\r
410 if (DevRecord->DrvRes.DriverDataSize<sizeof(PCT_7303B_Private)) return -4;
\r
412 DevRecord->pCT = &CTPCT7303;
\r
414 if ((IniOptions & HudaqOpenNOINIT)==0)
\r
415 { //initialize hardware only if no other application is running
\r
416 Base = DevRecord->DrvRes.Resources.MemResources[0].Base;
\r
418 /* Disable interrupts */
\r
419 Cache->IRQCfgReg = 0;
\r
420 StoreByte(Base, IRQCfgReg, 0);
\r
421 Cache->INTEnReg = 0; /* Clear interrupt logic. */
\r
422 StoreByte(Base, INTEnReg, 0);
\r
424 /* Initialization of DI and DO. */
\r
426 StoreByte(Base, DOUTReg, 0);
\r
428 /* Initialization of internal timer/counter. */
\r
429 Cache->TimerReg = 0;
\r
430 StoreByte(Base, TimerReg, 0); /* Stop timer. */
\r
432 /* Initialization of encoders. */
\r
433 Cache->CNTEnReg = 0;
\r
434 StoreByte(Base, CNTEnReg, 0); /* Stop encoders. */
\r
437 return 1; //success
\r
441 /** Internal cleanup procedure for PCT7303B */
\r
442 static void DonePCT7303(DeviceRecord *DevRecord)
\r
444 if (DevRecord==NULL) return;
\r
446 DevRecord->pCT = &CtDummy;
\r
451 /****************************************************************
\r
453 * GET/SET PARAMETERS *
\r
455 ****************************************************************/
\r
458 static HUDAQSTATUS PCT7303IRQSetParameter(const DeviceRecord *DevRecord, unsigned channel, HudaqParameter param, int value)
\r
462 Base = DevRecord->DrvRes.Resources.MemResources[0].Base;
\r
471 StoreCachedByte(Base, IRQCfgReg, 1, &((PCT_7303B_Private *)DevRecord->DrvRes.DriverData)->IRQCfgReg);
\r
472 StoreByte(Base, IRQClrReg, 0xFF);
\r
473 StoreCachedByte(Base, INTEnReg, 0x80, &((PCT_7303B_Private *)DevRecord->DrvRes.DriverData)->INTEnReg);
\r
477 StoreCachedByte(DevRecord->DrvRes.Resources.MemResources[0].Base, INTEnReg, 0,
\r
478 &((PCT_7303B_Private *)DevRecord->DrvRes.DriverData)->INTEnReg);
\r
479 StoreCachedByte(DevRecord->DrvRes.Resources.MemResources[0].Base, IRQCfgReg, 0,
\r
480 &((PCT_7303B_Private *)DevRecord->DrvRes.DriverData)->IRQCfgReg);
\r
482 return HUDAQSUCCESS;
\r
485 return HUDAQSUCCESS;
\r
489 return WRONG_VALUE;
\r
493 static double PCT7303IRQGetParameter(const DeviceRecord *DevRecord, unsigned channel, HudaqParameter param)
\r
498 return ((PCT_7303B_Private *)DevRecord->DrvRes.DriverData)->Hdr.IRQcounter;
\r
500 return WRONG_VALUE;
\r
504 static HUDAQSTATUS PCT7303SetParameter(const DeviceRecord *DevRecord, unsigned channel, HudaqParameter param, double value)
\r
506 switch(param & HudaqSubsystemMASK)
\r
509 case HudaqDO: return PCT7303DIOSetParameter(DevRecord,channel,param,(int)value);
\r
512 case HudaqEnc: return PCT7303BEncSetParameter(DevRecord,channel,param,(int)value);
\r
516 case HudaqIRQ: return PCT7303IRQSetParameter(DevRecord,channel,param,(int)value);
\r
518 return HUDAQNOTSUPPORTED;
\r
521 static double PCT7303GetParameter(const DeviceRecord *DevRecord, unsigned channel, HudaqParameter param)
\r
523 switch(param & HudaqSubsystemMASK)
\r
526 case HudaqDO: return PCT7303DIOGetParameter(channel,param);
\r
529 case HudaqEnc: return PCT7303BEncGetParameter(DevRecord,channel,param);
\r
533 case HudaqIRQ: return PCT7303IRQGetParameter(DevRecord,channel,param);
\r
535 return WRONG_VALUE;
\r
539 const CallTable CTPCT7303 =
\r
541 "PCT7303B", 0x1760, 0x0201,
\r
545 PCT7303SetParameter,
\r
546 PCT7303GetParameter,
\r
549 // INITIALIZE DI callers
\r
551 GenericDIReadBit, //Generic implementation
\r
552 GenericOneDIReadMultiple,
\r
553 // INITIALIZE DO callers
\r
556 PCT7303DOWriteMultipleBits,
\r
557 GenericDOWriteMultiple,
\r
558 // INITIALIZE AI callers
\r
561 // INITIALIZE AO callers
\r
562 NULL, // Not available
\r
564 // INITIALIZE Enc callers
\r
567 // INITIALIZE Ctr callers
\r
570 // INITIALIZE PWM callers
\r
572 NULL, // Not available
\r
574 // INITIALIZE Step callers
\r
575 NULL, // Not available
\r