]> rtime.felk.cvut.cz Git - mf6xx.git/blobdiff - src/HuLinux-2.4.3/PCD7004.c
Merge branch 'hudaqlib_mf614_uio'
[mf6xx.git] / src / HuLinux-2.4.3 / PCD7004.c
diff --git a/src/HuLinux-2.4.3/PCD7004.c b/src/HuLinux-2.4.3/PCD7004.c
new file mode 100644 (file)
index 0000000..84d4bb9
--- /dev/null
@@ -0,0 +1,544 @@
+/****************************************************************/\r
+/**@file PCD7004.c:\r
+ * Description: API layer for TEDIA PCD-7004 card.              *\r
+ * Dependency: Windows 32, Windows 64 or Linux                  *\r
+ *                Copyright 2009-2010 Jaroslav Fojtik           *\r
+ ****************************************************************/\r
+\r
+#if defined(_WIN32) || defined(_WIN64)\r
+#include <windows.h>\r
+#else\r
+#include <sys/io.h>\r
+#endif\r
+#include <malloc.h>\r
+#include <math.h>\r
+\r
+#include "hudaqlib.h"\r
+#include "hudaq_internal.h"\r
+\r
+\r
+#define DI_CHANNELS   4                ///< Amount of Digital Outputs\r
+#define DO_CHANNELS   4                ///< Amount of Digital Inputs\r
+#define DA_CHANNELS   0         ///< Amount of Analog Outputs\r
+#define AD_CHANNELS   0         ///< Amount of Analog Inputs\r
+#define ENC_CHANNELS  0         ///< Amount of Encoders\r
+#define CTR_CHANNELS  1         ///< Amount of counters\r
+#define STEP_CHANNELS 0         ///< Amount of steppers\r
+\r
+\r
+#define MASTERFREQUENCY 1000        ///< Internal oscillator frequency is 1kHz\r
+\r
+\r
+/** Cache of PCD-7004 state */\r
+typedef struct\r
+{\r
+       UserDataHeader Hdr;                   ///< General device setup\r
+\r
+       unsigned __int8 DIOReg[4];              ///< Port configuration register\r
+       unsigned __int8 DIOCfgReg;\r
+       unsigned __int8 IRQCfgReg;\r
+       unsigned __int8 INTEnReg;\r
+       unsigned __int8 TimerReg;\r
+} PCD_7004_Private;\r
+\r
+\r
+/** Symbolic aliases for available registers inside BADR4 read. */\r
+typedef enum\r
+{\r
+       DIOReg0    = 0,\r
+       DIOReg1    = 1, //4\r
+       DIOReg2    = 2, //8,\r
+       DIOReg3    = 3, //0xC,\r
+\r
+       DIOCfgReg  = 0x80/4,\r
+\r
+       IRQCfgReg  = 0x200/4,           // WR only\r
+       IRQStatusReg = 0x200/4, // RD only\r
+       IRQClrReg =  0x204/4,           // WR only\r
+\r
+       TimerReg =  0x208/4,            // RW\r
+       INTEnReg =  0x20C/4,\r
+\r
+} MEM4IO;\r
+\r
+static __int8 Ports[DI_CHANNELS] = {DIOReg0, DIOReg1, DIOReg2, DIOReg3};\r
+\r
+\r
+/** write to memory mapped device byte wise, bytes are stored on every 4th position. */\r
+static __inline void StoreByte(size_t Ptr, int Offset, unsigned __int8 value)\r
+{\r
+       ((volatile unsigned __int8 *)(Ptr))[4*Offset] = value;\r
+}\r
+\r
+/** write to memory mapped device byte wise through cache. */\r
+static __inline void StoreCachedByte(size_t Ptr, int Offset, unsigned __int8 value, unsigned __int8 *CachedValue)\r
+{\r
+       if (*CachedValue != value)\r
+       {\r
+               *CachedValue = value;\r
+               StoreByte(Ptr,Offset,value);\r
+       }\r
+}\r
+\r
+\r
+/** This inline is used for reading tightly packed OX9162 local configuration registers. */\r
+static __inline unsigned __int8 GetBytePlain(size_t Ptr, int Offset)\r
+{\r
+       return ((volatile unsigned __int8 *)(Ptr))[4*Offset];\r
+}\r
+\r
+\r
+/****************************************************************\r
+ *                                                              *\r
+ *                 DIGITAL INPUTS & OUTPUTS                     *\r
+ *                                                              *\r
+ ****************************************************************/\r
+\r
+\r
+/** Get data from digital input. */\r
+static int PCD7004DIRead(const DeviceRecord *DevRecord, unsigned channel)\r
+{\r
+       if (channel>=DI_CHANNELS) return HUDAQBADARG;\r
+       return GetBytePlain(DevRecord->DrvRes.Resources.MemResources[1].Base,Ports[channel]);\r
+}\r
+\r
+\r
+/** Write data to digital output. */\r
+static HUDAQSTATUS PCD7004DOWrite(const DeviceRecord *DevRecord, unsigned channel, unsigned value)\r
+{\r
+       if (channel>=DO_CHANNELS) return HUDAQBADARG;\r
+       StoreCachedByte(DevRecord->DrvRes.Resources.MemResources[1].Base, Ports[channel], value,\r
+                       &((PCD_7004_Private *)(DevRecord->DrvRes.DriverData))->DIOReg[channel] );\r
+       return HUDAQSUCCESS;\r
+}\r
+\r
+\r
+static HUDAQSTATUS PCD7004DIReadMultiple(const DeviceRecord *DevRecord, unsigned number, const unsigned *channels, unsigned *values)\r
+{\r
+       unsigned FlagX = 0;\r
+       unsigned i;\r
+       size_t Base;\r
+       unsigned __int8 Cache[DI_CHANNELS+1];  //allocate more bytes for padding ind\r
+\r
+       if (number==0 || channels==NULL || values==NULL) return HUDAQBADARG;\r
+       if(DevRecord->pCT->HudaqDIRead==NULL) return HUDAQFAILURE;\r
+\r
+       Base = DevRecord->DrvRes.Resources.MemResources[1].Base;\r
+\r
+       /* Schedule what to read. */\r
+       for(i=0; i<number; i++)\r
+       {\r
+               if (channels[i]<DI_CHANNELS)\r
+               {\r
+                       FlagX |= 1<<(channels[i]);\r
+               }\r
+               else\r
+               {\r
+                       values[i] = 0;\r
+                       FlagX |= 0x8000;\r
+               }\r
+       }\r
+\r
+       /* Read isolated DIs */\r
+       for(i=0; i<DI_CHANNELS; i++)\r
+       {\r
+               if(FlagX & (1<<i))\r
+               {\r
+                       Cache[i] = GetBytePlain(Base,Ports[i]);\r
+               }\r
+       }  \r
+\r
+       /* Final store of numbers read. */\r
+       for(i=0; i<number; i++)\r
+       {\r
+               if(channels[i]<DI_CHANNELS)\r
+               {\r
+                       values[i] = Cache[channels[i]];\r
+               }\r
+       }      \r
+\r
+       if(FlagX == 0x8000) return HUDAQFAILURE;        //no valid value returned\r
+       if(FlagX & 0x8000) return HUDAQPARTIAL; //several values are valid and several are not\r
+       return HUDAQSUCCESS;                    //all values are valid (or no channel asked)\r
+}\r
+\r
+\r
+static HUDAQSTATUS PCD7004DOWriteMultiple(const DeviceRecord *DevRecord, unsigned number, const unsigned *channels, const unsigned *values)\r
+{\r
+       unsigned FlagX = 0;\r
+       unsigned i;\r
+       size_t Base;\r
+       unsigned __int8 *Cache;\r
+\r
+       if (number==0 || channels==NULL || values==NULL) return HUDAQBADARG;\r
+       if(DevRecord->pCT->HudaqDIRead==NULL) return HUDAQFAILURE;\r
+\r
+       Base = DevRecord->DrvRes.Resources.MemResources[1].Base;\r
+       Cache = ((PCD_7004_Private *)(DevRecord->DrvRes.DriverData))->DIOReg;\r
+\r
+       /* schedule what to write */\r
+       for(i=0; i<number; i++)\r
+       {\r
+               if (channels[i]<DI_CHANNELS)\r
+               {\r
+                       if(Cache[i] != values[i])\r
+                       {\r
+                               FlagX |= 1<<(channels[i]);\r
+                               Cache[i] = values[i];\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       FlagX |= 0x8000;\r
+               }\r
+       }\r
+\r
+       /* Final store of DOs */\r
+       for(i=0; i<DI_CHANNELS; i++)\r
+       {\r
+               if(FlagX & (1<<i))\r
+               {\r
+                       StoreByte(Base, Ports[i], Cache[i]);\r
+               }\r
+       }  \r
+\r
+       if(FlagX == 0x8000) return HUDAQFAILURE;        //no valid value returned\r
+       if(FlagX & 0x8000) return HUDAQPARTIAL; //several values are valid and several are not\r
+       return HUDAQSUCCESS;                    //all values are valid (or no channel asked)\r
+}\r
+\r
+\r
+/** Write one bit to digital output. */\r
+static void PCD7004DOWriteBit(const DeviceRecord *DevRecord, unsigned channel, unsigned bit, int value)\r
+{\r
+       __int8 DoutByte;\r
+\r
+       if (channel>=DO_CHANNELS) return;\r
+       if (bit>=8) return;             /* There are only 8 bits available in PCD7004. */\r
+\r
+       DoutByte = (((PCD_7004_Private *)(DevRecord->DrvRes.DriverData))->DIOReg[channel]);\r
+       if (value) DoutByte |= (1<<bit);\r
+       else DoutByte &= ~(1<<bit);\r
+\r
+       StoreCachedByte(DevRecord->DrvRes.Resources.MemResources[1].Base, Ports[channel], DoutByte,\r
+                       & ((PCD_7004_Private *)(DevRecord->DrvRes.DriverData))->DIOReg[channel]);\r
+}\r
+\r
+\r
+static void PCD7004DOWriteMultipleBits(const DeviceRecord *DevRecord, unsigned channel, unsigned mask, unsigned value)\r
+{\r
+       __int8 DoutByte;\r
+\r
+       if (channel>=DO_CHANNELS) return;\r
+\r
+       DoutByte = (((PCD_7004_Private *)(DevRecord->DrvRes.DriverData))->DIOReg[channel]);\r
+       DoutByte = (DoutByte & ~mask) | (value & mask);\r
+\r
+       StoreCachedByte(DevRecord->DrvRes.Resources.MemResources[1].Base, Ports[channel], DoutByte,\r
+                       & ((PCD_7004_Private *)(DevRecord->DrvRes.DriverData))->DIOReg[channel] );\r
+}\r
+\r
+\r
+static double PCD7004DIOGetParameter(unsigned channel, HudaqParameter param)\r
+{\r
+       switch((int)param)\r
+       {\r
+               case HudaqDINUMBITS:\r
+                       return (channel<DI_CHANNELS) ? 8 : WRONG_VALUE;\r
+               case HudaqDONUMBITS:\r
+                       return (channel<DO_CHANNELS) ? 8 : WRONG_VALUE;\r
+               case HudaqDINUMCHANNELS:\r
+                       return DI_CHANNELS;\r
+               case HudaqDONUMCHANNELS:\r
+                       return DO_CHANNELS;\r
+       }\r
+\r
+       return WRONG_VALUE;\r
+}\r
+\r
+\r
+static HUDAQSTATUS PCD7004DIOSetParameter(const DeviceRecord *DevRecord, unsigned channel, HudaqParameter param, int value)\r
+{\r
+       unsigned __int8 chval;\r
+\r
+       switch((int)param)\r
+       {\r
+               case HudaqDINUMBITS:\r
+                       if(channel>=DI_CHANNELS) return WRONG_VALUE;\r
+                       return (value==8) ? 0 : WRONG_VALUE;\r
+               case HudaqDONUMBITS:\r
+                       if(channel>=DI_CHANNELS) return WRONG_VALUE;\r
+                       return (value==8) ? 0 : WRONG_VALUE;\r
+               case HudaqDINUMCHANNELS:\r
+                       return DI_CHANNELS;\r
+               case HudaqDONUMCHANNELS:\r
+                       return DO_CHANNELS;\r
+               case HudaqDOMODE:\r
+                       if(channel>=DO_CHANNELS) return WRONG_VALUE;\r
+                       chval = ((PCD_7004_Private *)(DevRecord->DrvRes.DriverData))->DIOCfgReg;\r
+                       //printf("chval =  %d\n",chval);          \r
+\r
+                       switch(channel)\r
+                       {\r
+                               case 0: if(value==1) chval &= ~0x1;\r
+                                               if(value==0) chval |= 0x1;\r
+                                       break;\r
+                               case 1: if(value==1) chval &= ~0x02;\r
+                                               if(value==0) chval |= 0x02;\r
+                                       break;\r
+                               case 2: if(value==1) chval &= ~0x04;\r
+                                               if(value==0) chval |= 0x04;\r
+                                       break;\r
+                               case 3: if(value==1) chval &= ~0x08;\r
+                                               if(value==0) chval |= 0x08;\r
+                                       break;\r
+                       }\r
+                       StoreCachedByte(DevRecord->DrvRes.Resources.MemResources[1].Base, DIOCfgReg, chval,\r
+                                       & ((PCD_7004_Private *)(DevRecord->DrvRes.DriverData))->DIOCfgReg );\r
+                       return HUDAQSUCCESS;\r
+       }\r
+\r
+       return WRONG_VALUE;\r
+}\r
+\r
+\r
+/****************************************************************\r
+ *                                                              *\r
+ *                COUNTERS PWM + Count + Step                   *\r
+ *                                                              *\r
+ ****************************************************************/\r
+\r
+static HUDAQSTATUS PCD7004PWMWrite(const DeviceRecord *DevRecord, unsigned channel, double frequency, double dutycycle)\r
+{\r
+       double T;\r
+       HUDAQSTATUS ret = HUDAQSUCCESS;\r
+\r
+       if (channel>=CTR_CHANNELS) return HUDAQBADARG;\r
+\r
+       if (frequency<=0) return HUDAQBADARG; //Allow duty cycle 0 and 1 for f=0.\r
+\r
+       T = MASTERFREQUENCY/frequency;\r
+       if(T<1) \r
+       {\r
+               StoreCachedByte(DevRecord->DrvRes.Resources.MemResources[1].Base, TimerReg, 1,\r
+                               & ((PCD_7004_Private *)(DevRecord->DrvRes.DriverData))->TimerReg);\r
+               return HUDAQPARTIAL;\r
+       }\r
+       if(T>255)\r
+       {\r
+               StoreCachedByte(DevRecord->DrvRes.Resources.MemResources[1].Base, TimerReg, 255,\r
+                               & ((PCD_7004_Private *)(DevRecord->DrvRes.DriverData))->TimerReg);\r
+               return HUDAQPARTIAL;\r
+       }\r
+\r
+       StoreCachedByte(DevRecord->DrvRes.Resources.MemResources[1].Base, TimerReg, \r
+                       (unsigned __int8)T,\r
+                       &((PCD_7004_Private *)(DevRecord->DrvRes.DriverData))->TimerReg);\r
+\r
+       return HUDAQSUCCESS;\r
+}\r
+\r
+\r
+static HUDAQSTATUS PCD7004CtrReset(const DeviceRecord *DevRecord, unsigned channel)\r
+{\r
+       if (channel>=CTR_CHANNELS) return HUDAQBADARG;\r
+       StoreCachedByte(DevRecord->DrvRes.Resources.MemResources[1].Base, TimerReg, \r
+                       0, &((PCD_7004_Private *)(DevRecord->DrvRes.DriverData))->TimerReg);\r
+       return HUDAQSUCCESS;\r
+}\r
+\r
+\r
+static int PCD7004CtrRead(const DeviceRecord *DevRecord, unsigned channel)\r
+{\r
+       if (channel>=CTR_CHANNELS) return 0;\r
+       return GetBytePlain(DevRecord->DrvRes.Resources.MemResources[1].Base, TimerReg);\r
+}\r
+\r
+\r
+\r
+\r
+\r
+/********************************************************************/\r
+\r
+/* Initialization procedure for PCD-7004 card. */\r
+static int InitPCD7004(DeviceRecord *DevRecord, int IniOptions)\r
+{\r
+       PCD_7004_Private *Cache;\r
+       int i;\r
+       size_t Base;\r
+\r
+       if (DevRecord==NULL) return -1;\r
+\r
+       if (DevRecord->DrvRes.Resources.NumMemResources<2) return -2;  //insufficient amount of resources\r
+       Cache = DevRecord->DrvRes.DriverData;\r
+       if (Cache==NULL) return -3;\r
+       if (DevRecord->DrvRes.DriverDataSize<sizeof(PCD_7004_Private)) return -4;\r
+\r
+       DevRecord->pCT = &CTPCD7004;\r
+\r
+       if ((IniOptions & HudaqOpenNOINIT)==0)\r
+       {                           //initialize hardware only if no other application is running\r
+               Base = DevRecord->DrvRes.Resources.MemResources[1].Base;\r
+\r
+               /* disable interrupts */\r
+               Cache->INTEnReg = 0;\r
+               StoreByte(Base, INTEnReg, 0);\r
+\r
+               /* Initialization of DI and DO. */\r
+               for(i=0; i<4; i++)\r
+               {\r
+                       Cache->DIOReg[i] = 0;\r
+                       StoreByte(Base, Ports[i], 0);\r
+               }\r
+\r
+               Cache->DIOCfgReg = 0;\r
+               StoreByte(Base, DIOCfgReg, 0);\r
+\r
+               Cache->IRQCfgReg = 0;\r
+               StoreByte(Base, IRQCfgReg, 0);\r
+\r
+               Cache->TimerReg = 0;\r
+               StoreByte(Base, TimerReg, 0);   /* Stop timer. */\r
+       }\r
+\r
+       return 1; //success\r
+}\r
+\r
+\r
+/** Internal cleanup procedure for PCD7004 */\r
+static void DonePCD7004(DeviceRecord *DevRecord)\r
+{\r
+       if (DevRecord==NULL) return;\r
+\r
+       DevRecord->pCT = &CtDummy;\r
+}\r
+\r
+\r
+\r
+/****************************************************************\r
+ *                                                              *\r
+ *                    GET/SET PARAMETERS                        *\r
+ *                                                              *\r
+ ****************************************************************/\r
+\r
+\r
+static HUDAQSTATUS PCD7004IRQSetParameter(const DeviceRecord *DevRecord, unsigned channel, HudaqParameter param, int value)\r
+{\r
+       size_t Base;\r
+\r
+       Base = DevRecord->DrvRes.Resources.MemResources[1].Base;\r
+\r
+       switch((int)param)\r
+       {\r
+               case HudaqIRQ+0:\r
+                       {\r
+                               if(value)\r
+                               {\r
+                                       StoreCachedByte(Base, IRQCfgReg, 1, &((PCD_7004_Private *)DevRecord->DrvRes.DriverData)->IRQCfgReg);\r
+                                       StoreByte(Base, IRQClrReg, 0xFF);\r
+                                       StoreCachedByte(Base, INTEnReg, 0x80, &((PCD_7004_Private *)DevRecord->DrvRes.DriverData)->INTEnReg);\r
+                               }\r
+                               else\r
+                               { \r
+                                       StoreCachedByte(DevRecord->DrvRes.Resources.MemResources[1].Base, INTEnReg, 0,\r
+                                                       &((PCD_7004_Private *)DevRecord->DrvRes.DriverData)->INTEnReg);\r
+                                       StoreCachedByte(DevRecord->DrvRes.Resources.MemResources[1].Base, IRQCfgReg, 0,\r
+                                                       &((PCD_7004_Private *)DevRecord->DrvRes.DriverData)->IRQCfgReg);\r
+                               }\r
+                               return HUDAQSUCCESS;\r
+                       }\r
+               case HudaqIRQ+1:\r
+                       return HUDAQSUCCESS;\r
+       }\r
+\r
+       return WRONG_VALUE;\r
+}\r
+\r
+\r
+static double PCD7004IRQGetParameter(const DeviceRecord *DevRecord, unsigned channel, HudaqParameter param)\r
+{\r
+       switch((int)param)\r
+       {\r
+               case HudaqIRQ+0: \r
+                       return ((PCD_7004_Private *)DevRecord->DrvRes.DriverData)->Hdr.IRQcounter;\r
+               case HudaqIRQ+1:\r
+                       return GetBytePlain(DevRecord->DrvRes.Resources.MemResources[1].Base,IRQStatusReg);\r
+       }\r
+       return WRONG_VALUE;\r
+}\r
+\r
+\r
+static HUDAQSTATUS PCD7004SetParameter(const DeviceRecord *DevRecord, unsigned channel, HudaqParameter param, double value)\r
+{\r
+       switch(param & HudaqSubsystemMASK)\r
+       {\r
+               case HudaqDI:\r
+               case HudaqDO:  return PCD7004DIOSetParameter(DevRecord,channel,param,(int)value);\r
+                              //  case HudaqAI:  \r
+                              //  case HudaqAO:  \r
+                              //  case HudaqEnc: \r
+                              //  case HudaqPWM:\r
+                              //  case HudaqCtr: \r
+                              //  case HudaqStep:\r
+               case HudaqIRQ: return PCD7004IRQSetParameter(DevRecord,channel,param,(int)value);\r
+       }\r
+       return HUDAQNOTSUPPORTED;\r
+}\r
+\r
+static double PCD7004GetParameter(const DeviceRecord *DevRecord, unsigned channel, HudaqParameter param)\r
+{\r
+       switch(param & HudaqSubsystemMASK)\r
+       {\r
+               case HudaqDI:\r
+               case HudaqDO:  return PCD7004DIOGetParameter(channel,param);\r
+                              //case HudaqAI:  \r
+                              //case HudaqAO:  \r
+                              //case HudaqEnc:\r
+                              //case HudaqPWM:\r
+                              //case HudaqCtr:\r
+                              //case HudaqStep:\r
+               case HudaqIRQ: return PCD7004IRQGetParameter(DevRecord,channel,param);\r
+       }\r
+       return WRONG_VALUE;\r
+}\r
+\r
+\r
+const CallTable CTPCD7004 =\r
+{\r
+       "PCD7004", 0x1760, 0x0101,\r
+       InitPCD7004,\r
+       DonePCD7004,\r
+\r
+       PCD7004SetParameter,\r
+       PCD7004GetParameter,\r
+       NULL,\r
+\r
+       // INITIALIZE DI callers\r
+       PCD7004DIRead,\r
+       GenericDIReadBit,           //Generic implementation\r
+       PCD7004DIReadMultiple,\r
+       // INITIALIZE DO callers\r
+       PCD7004DOWrite,\r
+       PCD7004DOWriteBit,\r
+       PCD7004DOWriteMultipleBits,\r
+       PCD7004DOWriteMultiple,\r
+       // INITIALIZE AI callers\r
+       NULL,\r
+       NULL,\r
+       // INITIALIZE AO callers\r
+       NULL,\r
+       NULL,\r
+       // INITIALIZE Enc callers\r
+       NULL,                       // Not available\r
+       NULL,\r
+       // INITIALIZE Ctr callers\r
+       PCD7004CtrRead,\r
+       PCD7004CtrReset,\r
+       // INITIALIZE PWM callers\r
+       PCD7004PWMWrite,            \r
+       NULL,                   // Not available\r
+       NULL,\r
+       // INITIALIZE Step callers\r
+       NULL,                       // Not available\r
+};\r
+\r