Main Page   Class Hierarchy   Alphabetical List   Data Structures   File List   Data Fields   Globals  

stg.c

Go to the documentation of this file.
00001 /*
00002   stg.c
00003 
00004   Servo To Go board functions
00005 
00006   Modification history:
00007 
00008   2-Aug-2001  FMP added stgAdcStart,Wait,Read functions
00009   30-Jul-2001  FMP fixed bug in poll loop in RawADC so that it stops polling
00010   when EOC is 1, per Scott Shamblin's bug fix.
00011   19-Jun-2001  FMP changed typo #ifdef STG_8_AXIS to the proper STG_8_AXES,
00012   in three places where the limit and home switches were read, as reported
00013   by Scott Shamblin at U Fl. Nothing like having a real machine to work with.
00014   15-Jun-2000 WPS changed include asm/io.h to sys/io.h for rtlinux_2_2.
00015   13-Mar-2000 WPS eliminate compiler warning MODULE redefined.
00016   28-Oct-1999  FMP added EncoderLatch() function and call to it in
00017   stgEncoderReadAll()
00018   22-Oct-1999  FMP added MODULE_PARM() macro for exporting STG_BASE_ADDRESS
00019   16-Aug-1999  FMP didn't error out if axis was outside range-- just
00020   zeroed if appropriate, or ignored
00021   31-Mar-1998  FMP added analog and digital IO stuff
00022   26-Mar-1998  FMP added STG_BASE_ADDRESS decl
00023   8-Jan-1998  FMP took out amp disable on init, quit since we don't know
00024   the polarity
00025   15-Nov-1997 FMP removed debounce here. Solution to debounce problem
00026   is to use 5V pullups on STG digital IO. I'll add generic debounce code
00027   later.
00028   5-Nov-1997  FMP added stgAmpFault()
00029   10-Oct-1997  FMP added 0-ing, disabling of DACs, amps on extInit,quit
00030   8-Oct-1997  FMP added debounce to switch reading code
00031   25-Sep-1997  FMP added digital IO stuff
00032   19-Sep-1997  FMP used #defines for base address, number of axes
00033   18-Sep-1997  FMP removed piezo hack; changed loops in EncoderInit() and
00034   EncReadAll() to run 4 axis checks instead of doing all 8 always
00035   19-Aug-1997  PJM Added offset to volts in extDACwrite()
00036   01-Aug-1997  FMP changed encoder counts from int to double
00037   31-Jul-1997  FMP added StartADC, RawADC; changed sign of lCounts in
00038   RawDAC since the polarity was reversed
00039   28-Jul-1997  FMP added extLimitSwitchRead()
00040   1-Jul-1997  FMP added wait to extInit() to fix problem with
00041   extEncoderReadAll() returning garbage immediately after an init
00042   20-Jun-1997  FMP added exintf.h generic defs
00043   10-Jun-1997  FMP created
00044   */
00045 
00046 /* ident tag */
00047 #ifndef __GNUC__
00048 #ifndef __attribute__
00049 #define __attribute__(x)
00050 #endif
00051 #endif
00052 
00053 static char __attribute__((unused)) ident[] = "$Id: stg.c,v 1.13 2001/10/30 23:31:03 paul_c Exp $";
00054 
00055 #include "stg.h"                /* these decls */
00056 #include "extintf.h"            /* EXT_ENCODER_INDEX_MODEL */
00057 
00058 /* base address-- override default at compile time in stg.h,
00059    or at module load time with STG_BASE_ADDRESS=value */
00060 unsigned short STG_BASE_ADDRESS = DEFAULT_STG_BASE_ADDRESS;
00061 int FIND_STG_BASE_ADDRESS=0;
00062 
00063 #ifdef STG_8_AXES
00064 #define STG_MAX_AXIS 8
00065 #else
00066 #define STG_MAX_AXIS 4
00067 #endif
00068 
00069 #if defined(rtlinux) || defined(rtai)
00070 #ifndef MODULE
00071 #define MODULE
00072 #endif
00073 #define DO_IT
00074 #endif
00075 
00076 #ifdef LINUX
00077 #define DO_IT
00078 /*
00079   Compiling this for LINUX (not RTLINUX) means linking this into a Linux
00080   process, running non-real-time in user space. This is useful for debugging.
00081   If this is done, then the following stuff needs to be done to access the
00082   IO space.
00083   */
00084 
00085 #ifdef DEFINE_EXTERN_BEFORE_IO
00086 /*
00087   Because of a limitation in gcc (present at least in 2.7.2.1 and below), you
00088   _have to_ compile any source code that uses these routines with optimisation
00089   turned on (gcc -O1 or higher), or alternatively #define extern to be
00090   empty before #including <asm/io.h>.
00091 
00092   Otherwise, you'll get errors at link time like:
00093 
00094   stg.c:475: undefined reference to `__inbc'
00095  */
00096 #define extern
00097 #endif
00098 
00099 /*
00100   Need to access ports in range 0x200-0x21F and 0x600-0x61F, for default
00101   STG base address. ioperm() only enables up to 0x3FF, so we need to use
00102   iopl() to grant full access to IO space.
00103   */
00104 #include <sys/types.h>
00105 #include <unistd.h>             /* iopl() */
00106 
00107 #endif /* LINUX  */
00108 
00109 #ifdef DO_IT
00110 
00111 #if defined(__KERNEL__) && defined(linux)
00112 #include <linux/kernel.h>
00113 #if !defined(rtai)
00114 /* P.C.  These two headers cause a bunch of compiler errors on
00115    a RH7.1 system using 2.4.9-rtai
00116    */
00117 #include <linux/types.h>
00118 #include <linux/fs.h>
00119 #endif
00120 #endif
00121 
00122 #if defined(linux) || defined(rtlinux) || defined(rtai)
00123 #include <sys/io.h>             /* ioperm() */
00124 #endif
00125 
00126 
00127 /* Linux or RT-Linux use io ports */
00128 #ifndef LINUX_VERSION_CODE
00129 #include <linux/version.h>
00130 #endif
00131 
00132 #ifndef __GLIBC__
00133 #include <features.h>           /* __GLIBC__  */
00134 #endif
00135 
00136 // Pre 2.2 kernels don't seem to have the KERNEL_VERSION macro.
00137 #ifndef KERNEL_VERSION
00138 #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
00139 #endif
00140 
00141 /* Only include this for systems with an old version of glibc or an
00142  old version of the linux kernel.  Othewise it is not needed and results
00143  in a bunch of redefined symbol warnings/errors.
00144 */
00145 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0) || !defined(__GLIBC__) || __GLIBC__ < 2
00146 #include <asm/io.h>             /* outw, inw */
00147 #endif
00148 
00149 #else
00150 
00151 /* otherwise do nothing */
00152 
00153 #include <stdio.h>
00154 
00155 static int iopl(int level)
00156 {
00157   return 0;
00158 }
00159 
00160 static unsigned char inb(unsigned int port)
00161 {
00162   if (port >= STG_BASE_ADDRESS &&
00163       port <= STG_BASE_ADDRESS + 0x1f)
00164     {
00165       return 0;
00166     }
00167 
00168   if (port >= STG_BASE_ADDRESS + 0x400 &&
00169       port <= STG_BASE_ADDRESS + 0x400 + 0x1f)
00170     {
00171       return 0;
00172     }
00173 
00174   printf("inb: address out of bounds: %X\n", port);
00175   return 0;
00176 }
00177 
00178 static void outb(unsigned char byte, unsigned int port)
00179 {
00180   /* allow writes to 0x80 for 1 msec delay */
00181   if (port == 0x80)
00182     {
00183       return;
00184     }
00185 
00186   if (port >= STG_BASE_ADDRESS &&
00187       port <= STG_BASE_ADDRESS + 0x1f)
00188     {
00189       return;
00190     }
00191 
00192   if (port >= STG_BASE_ADDRESS + 0x400 &&
00193       port <= STG_BASE_ADDRESS + 0x400 + 0x1f)
00194     {
00195       return;
00196     }
00197 
00198   printf("outb: address out of bounds: %X\n", port);
00199 }
00200 
00201 static unsigned short inw(unsigned int port)
00202 {
00203   if (port % 2)
00204     {
00205       printf("inw: alignment error: %X\n", port);
00206       return 0;
00207     }
00208 
00209   if (port >= STG_BASE_ADDRESS &&
00210       port <= STG_BASE_ADDRESS + 0x1e)
00211     {
00212       return 0;
00213     }
00214 
00215   if (port >= STG_BASE_ADDRESS + 0x400 &&
00216       port <= STG_BASE_ADDRESS + 0x400 + 0x1e)
00217     {
00218       return 0;
00219     }
00220 
00221   printf("inw: address out of bounds: %X\n", port);
00222   return 0;
00223 }
00224 
00225 static void outw(unsigned short word, unsigned int port)
00226 {
00227   if (port % 2)
00228     {
00229       printf("outw: alignment error: %X\n", port);
00230       return;
00231     }
00232 
00233   if (port >= STG_BASE_ADDRESS &&
00234       port <= STG_BASE_ADDRESS + 0x1e)
00235     {
00236       return;
00237     }
00238 
00239   if (port >= STG_BASE_ADDRESS + 0x400 &&
00240       port <= STG_BASE_ADDRESS + 0x400 + 0x1e)
00241     {
00242       return;
00243     }
00244 
00245   printf("outw: address out of bounds: %X\n", port);
00246   return;
00247 }
00248 
00249 #endif /* don't DO_IT */
00250 
00251 /* map DOS funcs to Linux */
00252 #define _outp(port,val) outb(val,port)
00253 #define outp(port,val) outb(val,port)
00254 #define _inp(port) inb(port)
00255 #define inp(port) inb(port)
00256 #define _inpw(port) inw(port)
00257 #define _outpw(port,val) outw(val,port)
00258 
00259 static short int nIrq;
00260 
00261 void SetIrq(short nRequestedIrq)
00262 {
00263   unsigned char byIntReg;
00264 
00265   nIrq = nRequestedIrq;  /* assume it's OK for now, check later */
00266 
00267   byIntReg = 0x80;       /* initial value for the high bits in the register */
00268   /* sets auto zero on the ADC.  Maybe this should */
00269   /* be a parameter if we want to do something different */
00270 
00271   /* now put low bits into byIntReg to select irq */
00272 
00273   switch (nRequestedIrq)
00274     {
00275     case 3: break;      /* add zero */
00276 
00277     case 5: byIntReg |= 4;
00278       break;
00279 
00280     case 7: byIntReg |= 2;
00281       break;
00282 
00283     case 9: byIntReg |= 6;
00284       break;
00285 
00286     case 10: byIntReg |= 5;
00287       break;
00288 
00289     case 11: byIntReg |= 7;
00290       break;
00291 
00292     case 12: byIntReg |= 3;
00293       break;
00294 
00295     case 15: byIntReg |= 1;
00296       break;
00297 
00298     default: nIrq = 5;      /* ERROR, requested irq not valid, use 5 */
00299       byIntReg |= 4; /* There is no safe value, leaving zero */
00300       /* here would select IRQ 3 which is worse */
00301       /* than 5 because IRQ 3 is usually for COM 2 */
00302       break;
00303     }
00304 
00305   _outp(STG_BASE_ADDRESS + INTC, byIntReg);  /* set irq */
00306 }
00307 
00308 unsigned short BaseFind()
00309 {
00310   short i, j, k, l, ofs;
00311   unsigned short io_add;
00312 
00313   for (i = 15; i >= 0; i--)     /* search all possible addresses */
00314     {
00315       io_add = i * 0x20 + 0x200;
00316       if ((_inp(io_add + BRDTST) & 0x0f) == i) /* does jumper = i? */
00317         {
00318           k = 0;
00319           for (j = 7; j >= 0; j--)
00320             {
00321               ofs = (_inp(io_add + BRDTST) & 0xf0) / 16;
00322               l = 0;
00323               if (ofs > 7)                     /* is SER set?  */
00324                 l = 1;
00325               ofs = ofs & 7;                   /* mask for Q2,Q1,Q0 */
00326               if (l == 1)
00327                 k += (1 << ofs);             /* shift bit into position */
00328             }
00329           if (k == 0x75) return io_add;        /* SER sequence is 01110101 */
00330         }
00331     }
00332   return(0);
00333 }
00334 
00335 short int Initialize(short int nRequestedIrq)
00336 {
00337   /*
00338    * Initialize the interrupt controller
00339    */
00340   _outp(STG_BASE_ADDRESS + MIO_2, 0x92);  /* initialize INTC as output reg. */
00341   /* sets port D to input since we have */
00342   /* to set it to something. */
00343   SetIrq(nRequestedIrq);        /* selects the IRQ in INTC. Now, if a stray */
00344   /* interrupt is issued (see below) it will */
00345   /* go to an interrupt that isn't enabled on */
00346   /* the motherboard yet (if your system is */
00347   /* set up correctly). */
00348   _outp( STG_BASE_ADDRESS + ICW1, 0x1a ); /* initialize 82C59 as single chip, */
00349   /* level triggered */
00350   _outp( STG_BASE_ADDRESS + ICW2, 0x00 ); /* icw2 - not used, must write */
00351   /* could issue stray interrupt here - danger! */
00352   _outp( STG_BASE_ADDRESS + OCW1, 0xff);  /* mask off all interrupt sources (the */
00353   /* interrupt on the motherboard isn't */
00354   /* enabled yet, you do that when you install */
00355   /* your interrupt handler.). */
00356   return 0;
00357 }
00358 
00359 int StartADC(unsigned short wAxis)
00360 {
00361   if (wAxis > 7) {
00362     return -1;
00363   }
00364 
00365   /* do a dummy read from the ADC, just to set the input multiplexer to
00366      the right channel */
00367   _inpw(STG_BASE_ADDRESS + ADC_0 + (wAxis << 1));
00368 
00369   /* wait 4 uS for settling time on the multiplexer and ADC. You probably
00370      shouldn't really have a delay in a driver */
00371   _outp(0x80, 0);
00372   _outp(0x80, 0);
00373   _outp(0x80, 0);
00374   _outp(0x80, 0);
00375 
00376   /* now start conversion */
00377   _outpw(STG_BASE_ADDRESS + ADC_0 + (wAxis << 1), 0);
00378 
00379   return 0;
00380 };
00381 
00382 short RawADC(unsigned short wAxis)
00383 {
00384   short ret;
00385   short j;
00386 
00387   if (wAxis > 7)
00388     return -1;
00389 
00390   /*
00391     there must have been a delay between StartADC() and RawADC(),
00392     of 19 usec if autozeroing (we are), 4 uses otherwise. In code
00393     that calls this, make sure you split these calls up with some
00394     intervening code
00395     */
00396 
00397   /* make sure conversion is done, assume polling delay is done.
00398      EOC (End Of Conversion) is bit 0x08 in IIR (Interrupt Request
00399      Register) of Interrupt Controller.  Don't wait forever though
00400      bail out eventually. */
00401 
00402   for (j = 0; !(_inp(STG_BASE_ADDRESS + IRR) & 0x08) && (j < 1000); j++);
00403 
00404   ret = _inpw(STG_BASE_ADDRESS + ADC_0 + (wAxis << 1));
00405 
00406   if (ret & 0x1000)       /* is sign bit negative? */
00407     ret |= 0xf000;      /* sign extend */
00408   else
00409     ret &= 0xfff;       /* make sure high order bits are zero. */
00410 
00411   return ret;
00412 };
00413 
00414 void EncoderInit()
00415 {
00416   unsigned int wAdd;
00417   unsigned int wAddTop;
00418 
00419 #ifdef STG_8_AXES
00420   wAddTop = STG_BASE_ADDRESS + CNT6_C;
00421 #else
00422   wAddTop = STG_BASE_ADDRESS + CNT2_C;
00423 #endif
00424 
00425   for (wAdd = STG_BASE_ADDRESS + CNT0_C; wAdd <= wAddTop; wAdd +=4)
00426     {
00427       /* Set Counter Command Register - Master Control, Master Reset (MRST), */
00428       /* and Reset address pointer (RADR). */
00429 
00430       _outpw(wAdd, 0x2323);
00431 
00432       /* Set Counter Command Register - Input Control, OL Load (P3), */
00433       /* and Enable Inputs A and B (INA/B). */
00434 
00435       _outpw(wAdd, 0x6868);
00436 
00437       /* Set Counter Command Register - Output Control */
00438 
00439       _outpw(wAdd, 0x8080);
00440 
00441       /* Set Counter Command Register - Quadrature */
00442 
00443       _outpw(wAdd, 0xc3c3);
00444     }
00445 }
00446 
00447 void SelectInterruptPeriod(long lPeriodSelect)
00448 {
00449   _outp(STG_BASE_ADDRESS + TMRCMD, 0x56);   /* timer 1, read/load LSB (MSB is 0) */
00450   /* mode 3 (square wave) */
00451   _outp(STG_BASE_ADDRESS + TIMER_1, 0xb4);  /* 0xb4 = 180 -> 25 uSec period */
00452 
00453   switch (lPeriodSelect)
00454     {
00455     case _500_MICROSECONDS:
00456       _outp(STG_BASE_ADDRESS + TMRCMD, 0x34);    /* timer 0, read/load LSB followed by */
00457       /* MSB, mode 2 (real-time interrupt) */
00458       _outp(STG_BASE_ADDRESS + TIMER_0, 0x14);   /* 0x14 = 20 = .5 mS */
00459       _outp(STG_BASE_ADDRESS + TIMER_0, 0x00);
00460       break;
00461     case _1_MILLISECOND:
00462       _outp(STG_BASE_ADDRESS + TMRCMD, 0x34);    /* timer 0, read/load LSB followed by */
00463       /* MSB, mode 2 (real-time interrupt) */
00464       _outp(STG_BASE_ADDRESS + TIMER_0, 0x28);   /* 0x28 = 40 = 1 mS */
00465       _outp(STG_BASE_ADDRESS + TIMER_0, 0x00);
00466       break;
00467     case _2_MILLISECONDS:
00468       _outp(STG_BASE_ADDRESS + TMRCMD, 0x34);    /* timer 0, read/load LSB followed by */
00469       /* MSB, mode 2 (real-time interrupt) */
00470       _outp(STG_BASE_ADDRESS + TIMER_0, 0x50);   /* 0x50 = 80 = 2 mS */
00471       _outp(STG_BASE_ADDRESS + TIMER_0, 0x00);
00472       break;
00473     case _3_MILLISECONDS:
00474       _outp(STG_BASE_ADDRESS + TMRCMD, 0x34);    /* timer 0, read/load LSB followed by */
00475       /* MSB, mode 2 (real-time interrupt) */
00476       _outp(STG_BASE_ADDRESS + TIMER_0, 0x78);   /* 0x78 = 120 = 3 mS */
00477       _outp(STG_BASE_ADDRESS + TIMER_0, 0x00);
00478       break;
00479     case _4_MILLISECONDS:
00480       _outp(STG_BASE_ADDRESS + TMRCMD, 0x34);    /* timer 0, read/load LSB followed by */
00481       /* MSB, mode 2 (real-time interrupt) */
00482       _outp(STG_BASE_ADDRESS + TIMER_0, 0xA0);   /* 0xA0 = 160 = 4 mS */
00483       _outp(STG_BASE_ADDRESS + TIMER_0, 0x00);
00484       break;
00485     case _5_MILLISECONDS:
00486       _outp(STG_BASE_ADDRESS + TMRCMD, 0x34);    /* timer 0, read/load LSB followed by */
00487       /* MSB, mode 2 (real-time interrupt) */
00488       _outp(STG_BASE_ADDRESS + TIMER_0, 0xC8);   /* 0xC8 = 200 = 5 mS */
00489       _outp(STG_BASE_ADDRESS + TIMER_0, 0x00);
00490       break;
00491     case _10_MILLISECONDS:
00492       _outp(STG_BASE_ADDRESS + TMRCMD, 0x34);    /* timer 0, read/load LSB followed by */
00493       /* MSB, mode 2 (real-time interrupt) */
00494       _outp(STG_BASE_ADDRESS + TIMER_0, 0x90);   /* 0x0190 = 400 = 10 mS */
00495       _outp(STG_BASE_ADDRESS + TIMER_0, 0x01);
00496       break;
00497     case _100_MILLISECONDS:
00498       _outp(STG_BASE_ADDRESS + TMRCMD, 0x34);    /* timer 0, read/load LSB followed by */
00499       /* MSB, mode 2 (real-time interrupt) */
00500       _outp(STG_BASE_ADDRESS + TIMER_0, 0xA0);   /* 0x0FA0 = 4000 = 100 mS */
00501       _outp(STG_BASE_ADDRESS + TIMER_0, 0x0F);
00502       break;
00503     case _1_SECOND:
00504       _outp(STG_BASE_ADDRESS + TMRCMD, 0x34);    /* timer 0, read/load LSB followed by */
00505       /* MSB, mode 2 (real-time interrupt) */
00506       _outp(STG_BASE_ADDRESS + TIMER_0, 0x40);   /* 0x9C40 = 40000 = 1 S */
00507       _outp(STG_BASE_ADDRESS + TIMER_0, 0x9c);
00508       break;
00509     default:
00510       /* wrong input? then don't change it */
00511       break;
00512     }
00513 };
00514 
00515 /*
00516   output to DAC word works like:
00517 
00518   0x0000 -> +10 V
00519   0x1000 ->   0 V
00520   0x1FFF -> -10 V
00521   */
00522 int RawDAC(short nAxis, double volts)
00523 {
00524   short nCounts;
00525 
00526   if ( (nAxis > 7) || (nAxis < 0) )        /* is axis within range? */
00527     return -1;
00528 
00529   /* convert -10.0 -> 10.0 to 0x1FFF -> 0x0000 */
00530   nCounts = (short) ((10.0 - volts) / 20.0 * 0x1FFF);
00531 
00532   if (nCounts > 0x1FFF)
00533     {
00534       nCounts = 0x1FFF;
00535     }
00536   if (nCounts < 0)
00537     {
00538       nCounts = 0;
00539     }
00540 
00541   _outpw(STG_BASE_ADDRESS + DAC_0 + (nAxis << 1), nCounts);
00542 
00543   return 0;
00544 };
00545 
00546 int EncoderLatch()
00547 {
00548   unsigned short wAdd;
00549   unsigned short wAddTop;
00550 
00551 #ifdef STG_8_AXES
00552   wAddTop = STG_BASE_ADDRESS + CNT6_C;
00553 #else
00554   wAddTop = STG_BASE_ADDRESS + CNT2_C;
00555 #endif
00556 
00557   for (wAdd = STG_BASE_ADDRESS + CNT0_C; wAdd <= wAddTop; wAdd +=4)
00558     {
00559       _outpw(wAdd, 0x0303);
00560     }
00561 
00562   return 0;
00563 }
00564 
00565 int EncReadAll(LONGBYTE * lbEnc)
00566 {
00567   WORDBYTE wbTransfer;
00568   static unsigned char byOldByte2[STG_MAX_AXIS];
00569   static unsigned char byEncHighByte[STG_MAX_AXIS];
00570   short i;
00571   unsigned int wAdd;
00572   unsigned int wAddTop;
00573 
00574   /* Disable interrupts here?  No, the timer will latch new data in the */
00575   /* hardware anyway.  Maybe we should stop the timer?  In an interrupt */
00576   /* service routine, you're synchronized with the timer; so the readings */
00577   /* will never change while you're reading them.  If you're polling, you */
00578   /* would first latch the encoder counts with the EncoderLatch() function. */
00579   /* But, the timer could latch the counts again, in the middle of the read. */
00580 
00581 #ifdef STG_8_AXES
00582   wAddTop = STG_BASE_ADDRESS + CNT6_C;
00583 #else
00584   wAddTop = STG_BASE_ADDRESS + CNT2_C;
00585 #endif
00586 
00587   /* reset counter internal addr ptr to point to first byte */
00588   for (wAdd = STG_BASE_ADDRESS + CNT0_C; wAdd <= wAddTop; wAdd +=4)
00589     {
00590       _outpw(wAdd, 0x0101);
00591     }
00592 
00593   for (i = 0; i < 3; i++)            /* 24 bits means get 3 bytes each */
00594     {
00595       wbTransfer.Word = _inpw(STG_BASE_ADDRESS + CNT0_D);
00596 
00597       lbEnc[0].Byte[i] = wbTransfer.Byte.high;
00598       lbEnc[1].Byte[i] = wbTransfer.Byte.low;
00599 
00600       wbTransfer.Word = _inpw(STG_BASE_ADDRESS + CNT2_D);
00601 
00602       lbEnc[2].Byte[i] = wbTransfer.Byte.high;
00603       lbEnc[3].Byte[i] = wbTransfer.Byte.low;
00604 
00605 #ifdef STG_8_AXES
00606       wbTransfer.Word = _inpw(STG_BASE_ADDRESS + CNT4_D);
00607 
00608       lbEnc[4].Byte[i] = wbTransfer.Byte.high;
00609       lbEnc[5].Byte[i] = wbTransfer.Byte.low;
00610 
00611       wbTransfer.Word = _inpw(STG_BASE_ADDRESS + CNT6_D);
00612 
00613       lbEnc[6].Byte[i] = wbTransfer.Byte.high;
00614       lbEnc[7].Byte[i] = wbTransfer.Byte.low;
00615 #endif
00616     }
00617 
00618   /* code to sign extend the 24 bit value */
00619   /* but we won't do this. */
00620   /*for ( i = 0; i < 8; i++) */
00621   /*  lbEnc[i].Byte[3] = lbEnc[i].Byte[2] & 0x80 ? 0xff : 0; */
00622 
00623   /* maintain the high byte, to extend the counter to 32 bits */
00624   /* */
00625   /* base decisions to increment or decrement the high byte */
00626   /* on the highest 2 bits of the 24 bit value.  To get the */
00627   /* highest 2 bits, use 0xc0 as a mask on byte [2] (the third */
00628   /* byte). */
00629 
00630   for (i = 0; i < STG_MAX_AXIS; i++)
00631     {
00632       /* check for -1 to 0 transition */
00633 
00634       if (    ( (byOldByte2[i]    & 0xc0) == 0xc0 ) /* 11xxxxxx */
00635               && ( (lbEnc[i].Byte[2] & 0xc0) == 0 ) /* 00xxxxxx */
00636               )
00637         byEncHighByte[i]++;
00638 
00639       /* check for 0 to -1 transition */
00640 
00641       if (    ( (byOldByte2[i]    & 0xc0) == 0 ) /* 00xxxxxx */
00642               && ( (lbEnc[i].Byte[2] & 0xc0) == 0xc0 ) /* 11xxxxxx */
00643               )
00644         byEncHighByte[i]--;
00645 
00646       lbEnc[i].Byte[3] = byEncHighByte[i];
00647       byOldByte2[i] = lbEnc[i].Byte[2]; /* current byte 2 becomes old one */
00648     }
00649 
00650   return 0;
00651 }
00652 
00653 void ResetIndexLatch()
00654 {
00655   _inp(STG_BASE_ADDRESS + ODDRST);        /* reset index pulse latch for ODD axis */
00656   _inp(STG_BASE_ADDRESS + BRDTST);        /* reset index pulse latch for EVEN axis */
00657 }
00658 
00659 static unsigned char byIndexPollAxis = 0;
00660 static unsigned char byIndexPulsePolarity = 1;
00661 
00662 void SelectIndexAxis(unsigned char byAxis, unsigned char byPol)
00663 {
00664   /* */
00665   /* initialize stuff to poll index pulse */
00666   /* */
00667   unsigned char byIntc;
00668 
00669   byIndexPollAxis = byAxis;           /* save axis to check later */
00670   byIndexPulsePolarity = byPol;       /* save polarity as new default */
00671   byAxis &= 0x6;                      /* ignore low bit, we check 2 axes at a time */
00672   byAxis <<= 3;                       /* shift into position for IXS1, IXS0 */
00673   byIntc = _inp(STG_BASE_ADDRESS + INTC); /* get a copy of INTC, we'll change */
00674   /* some bits in it, not all */
00675   byIntc &= ~(IXLVL | IXS1 | IXS0);   /* zero bits for axis and polarity */
00676   byIntc |= byAxis;                   /* put axes address in INTC */
00677   if (byPol != 0)                     /* is index pulse active high? */
00678     byIntc |= IXLVL;
00679   _outp(STG_BASE_ADDRESS + INTC, byIntc);
00680   ResetIndexLatch();
00681 
00682   /* The latched index pulse should be low now.  If it's not, either something's */
00683   /* wrong, or we happened to initialize it while the index pulse was active. */
00684 }
00685 
00686 unsigned char CurrentIRR()
00687 {
00688   outp(STG_BASE_ADDRESS + OCW3, 0x0a);           /* IRR on next read */
00689   return inp(STG_BASE_ADDRESS + IRR);
00690 }
00691 
00692 int IndexPulseLatch()
00693 {
00694   /* poll the latched index pulse of the axis that was previously set up */
00695 
00696   unsigned char byIRR, byAxisMask;
00697 
00698   byIRR = CurrentIRR();
00699   byAxisMask = (byIndexPollAxis & 1) ? LIXODD : LIXEVN;  /* even or odd axis? */
00700   if (byIRR & byAxisMask)       /* check latched index pulse */
00701     return 1;
00702   return 0;
00703 }
00704 
00705 long RawDI()
00706 {
00707   IO32 xInBits;
00708 
00709   xInBits.port.A = _inp(STG_BASE_ADDRESS + DIO_A);
00710   xInBits.port.B = _inp(STG_BASE_ADDRESS + DIO_B);
00711   xInBits.port.C = _inp(STG_BASE_ADDRESS + DIO_C);
00712   xInBits.port.D = _inp(STG_BASE_ADDRESS + DIO_D);
00713 
00714   return xInBits.all;
00715 };
00716 
00717 void RawDO(unsigned char byBitNumber, unsigned char by0or1, unsigned short nPort)
00718 {
00719   unsigned nOffset;
00720   unsigned char byData;
00721 
00722   switch (nPort)
00723     {
00724     case 0:
00725       nOffset = DIO_A;
00726       break;
00727     case 1:
00728       nOffset = DIO_B;
00729       break;
00730     case 2:
00731       nOffset = DIO_C;
00732       break;
00733     case 3:
00734       nOffset = DIO_D;
00735       break;
00736     default:
00737       return;
00738     }
00739   byData = _inp(STG_BASE_ADDRESS + nOffset);
00740   if (by0or1 == 1)
00741     byData |= 1 << byBitNumber;
00742   else
00743     byData &= ~(1 << byBitNumber);
00744   _outp(STG_BASE_ADDRESS + nOffset, byData);
00745 };
00746 
00747 void RawDOAll(IO32 xOutBits)
00748 {
00749   _outp(STG_BASE_ADDRESS + DIO_A, xOutBits.port.A);
00750   _outp(STG_BASE_ADDRESS + DIO_B, xOutBits.port.B);
00751   _outp(STG_BASE_ADDRESS + DIO_C, xOutBits.port.C);
00752   _outp(STG_BASE_ADDRESS + DIO_D, xOutBits.port.D);
00753 };
00754 
00755 /*
00756   nSwDir is bitmask for directions, ports A-D
00757   Bit = 1 means output, bit = 0 means input
00758 
00759   Looks like:
00760 
00761   MSB                               LSB
00762   v---------------v-------------------v
00763   |   |   |   | D | CHI | CLO | B | A |
00764   ^---------------^-------------------^
00765 
00766   */
00767 void DIOdirection(short nSwDir)
00768 {
00769   unsigned char byHwDir;        /* direction bits for hardware */
00770   unsigned char bySaveIntc, bySaveIMR;
00771 
00772   byHwDir = 0x9b;               /* initially all ports input */
00773 
00774   if (nSwDir & 0x01)            /* check the bit for A out */
00775     byHwDir &= ~A_OUT;          /* if output, set bit to 0 */
00776   if (nSwDir & 0x02)
00777     byHwDir &= ~B_OUT;
00778   if (nSwDir & 0x04)
00779     byHwDir &= ~C_LOW_OUT;
00780   if (nSwDir & 0x08)
00781     byHwDir &= ~C_HI_OUT;
00782   _outp(STG_BASE_ADDRESS + MIO_1, byHwDir); /* set direction for A, B and C */
00783 
00784   bySaveIntc = _inp(STG_BASE_ADDRESS + INTC); /* INTC needs to be saved, because */
00785   /* MIO_2 reinitializes the 8255 which */
00786   /* implements the INTC register. */
00787   byHwDir = 0x92;               /* initialize port D input */
00788   if (nSwDir & 0x10)            /* is port D output? */
00789     byHwDir &= ~D_OUT;          /* if yes, set bit to 0,  */
00790   bySaveIMR = _inp(STG_BASE_ADDRESS + IMR); /* get the current interrupt mask */
00791   _outp(STG_BASE_ADDRESS + OCW1, 0xff); /* mask off all interrupts */
00792   _outp(STG_BASE_ADDRESS + MIO_2, byHwDir); /* set direction for port D */
00793   _outp(STG_BASE_ADDRESS + INTC, bySaveIntc); /* restore interrupt control reg. */
00794   _outp(STG_BASE_ADDRESS + OCW1, bySaveIMR); /* restore interrupt mask */
00795 };
00796 
00797 /* Implementations of external functions */
00798 
00799 /* saved outputs, for stgAioCheck(), since we can't really read outputs */
00800 static double checkedOutputs[STG_MAX_AXIS];
00801 
00802 #define STG_INIT_WAIT 1000      /* usecs to wait after stgMotInit() */
00803 
00804 int stgMotInit(const char * stuff)
00805 {
00806   int t;
00807 
00808 #ifdef LINUX
00809   /* enable port programming */
00810   if (-1 == iopl(3))
00811     {
00812       return -1;
00813     }
00814 #endif
00815 
00816   Initialize(5);
00817   EncoderInit();
00818 
00819   /* output 0's to amps */
00820   for (t = 0; t < STG_MAX_AXIS; t++)
00821     {
00822       /* write 0 to DACs */
00823       stgDacWrite(t, 0.0);
00824     }
00825 
00826   /* init digital IO directions */
00827   stgDioInit(0);
00828 
00829   /* need to force a wait here-- calls to stgEncoderReadAll()
00830      immediately after this return garbage. Is there status to
00831      poll on for 'ready'? */
00832   for (t = 0; t < STG_INIT_WAIT; t++)
00833     {
00834       /* do a dummy 1 usec write */
00835       _outp(0x80, 0);
00836     }
00837 
00838   return 0;
00839 }
00840 
00841 int stgMotQuit()
00842 {
00843   int t;
00844 
00845   for (t = 0; t < STG_MAX_AXIS; t++)
00846     {
00847       /* write 0's to DACs */
00848       stgDacWrite(t, 0.0);
00849     }
00850 
00851   return 0;
00852 }
00853 
00854 int stgAdcNum(void)
00855 {
00856   return STG_MAX_AXIS;
00857 }
00858 
00859 int stgAdcStart(int adc)
00860 {
00861   if (adc < 0 ||
00862       adc >= STG_MAX_AXIS) {
00863     return 0;                 /* don't care */
00864   }
00865 
00866   StartADC((unsigned short) adc);
00867 
00868   return 0;
00869 }
00870 
00871 #define STG_ADC_WAIT_USEC 20    /* microsecs to wait for conversion */
00872 
00873 void stgAdcWait(void)
00874 {
00875   int t;
00876 
00877   for (t = 0; t < STG_ADC_WAIT_USEC; t++) {
00878     _outp(0x80, 0);             /* 0x80 is historical dummy, 1 usec write */
00879   }
00880 }
00881 
00882 int stgAdcRead(int adc, double * volts)
00883 {
00884   if (adc < 0 ||
00885       adc >= STG_MAX_AXIS) {
00886     return 0;                 /* don't care */
00887   }
00888 
00889   *volts = (double) RawADC((unsigned short) adc);
00890 
00891   return 0;
00892 }
00893 
00894 int stgDacNum()
00895 {
00896   return STG_MAX_AXIS;
00897 }
00898 
00899 int stgDacWrite(int dac, double volts)
00900 {
00901   if (dac < 0 ||
00902       dac >= STG_MAX_AXIS) {
00903     return 0;                 /* don't care */
00904   }
00905 
00906   checkedOutputs[dac] = volts;
00907 
00908   return RawDAC(dac, volts);
00909 }
00910 
00911 int stgDacWriteAll(int max, double * volts)
00912 {
00913   int t;
00914   int smax;
00915 
00916   /* clip smax to max supported-- if they want more, ignore */
00917   if (max > STG_MAX_AXIS) {
00918     smax = STG_MAX_AXIS;
00919   }
00920   else {
00921     smax = max;
00922   }
00923 
00924   for (t = 0; t < smax; t++) {
00925     if (0 != stgDacWrite(t, volts[t])){
00926       return -1;
00927     }
00928   }
00929 
00930   return 0;
00931 }
00932 
00933 unsigned int stgEncoderIndexModel(void)
00934 {
00935   return EXT_ENCODER_INDEX_MODEL_MANUAL;
00936 }
00937 
00938 int stgEncoderSetIndexModel(unsigned int model)
00939 {
00940   if (model != EXT_ENCODER_INDEX_MODEL_MANUAL)
00941     {
00942       return -1;
00943     }
00944 
00945   return 0;
00946 }
00947 
00948 int stgEncoderNum()
00949 {
00950   return STG_MAX_AXIS;
00951 }
00952 
00953 int stgEncoderRead(int encoder, double * counts)
00954 {
00955   double allCounts[STG_MAX_AXIS];
00956 
00957   if (encoder < 0 ||
00958       encoder >= STG_MAX_AXIS) {
00959     *counts = 0.0;
00960     return 0;
00961   }
00962 
00963   stgEncoderReadAll(encoder + 1, allCounts);
00964 
00965   *counts = allCounts[encoder];
00966 
00967   return 0;
00968 }
00969 
00970 int stgEncoderReadAll(int max, double * counts)
00971 {
00972   LONGBYTE lbEnc[STG_MAX_AXIS];
00973   int t;
00974   int smax;                     /* how many we actually have */
00975 
00976   /* clip smax to max supported-- if they want more, give
00977      them zeros */
00978   if (max > STG_MAX_AXIS) {
00979     smax = STG_MAX_AXIS;
00980   }
00981   else {
00982     smax = max;
00983   }
00984 
00985   EncoderLatch();
00986   EncReadAll(lbEnc);
00987 
00988   /* fill ours with the actual values */
00989   for (t = 0; t < smax; t++) {
00990     counts[t] = (double) lbEnc[t].Long;
00991   }
00992   /* and fill the rest with zeros */
00993   for (t = smax; t < max; t++) {
00994     counts[t] = 0.0;
00995   }
00996 
00997   return 0;
00998 }
00999 
01000 int stgEncoderResetIndex(int encoder)
01001 {
01002   if (encoder < 0 ||
01003       encoder >= STG_MAX_AXIS)
01004     {
01005       return 0;
01006     }
01007 
01008   SelectIndexAxis(encoder, 1);
01009 
01010   return 0;
01011 }
01012 
01013 int stgEncoderReadLatch(int encoder, int * flag)
01014 {
01015   *flag = IndexPulseLatch();
01016 
01017   return 0;
01018 }
01019 
01020 /* basically same code as IndexPulseLatch() except mask is 2 bits higher */
01021 int stgEncoderReadLevel(int encoder, int * flag)
01022 {
01023   unsigned char byIRR, byAxisMask;
01024 
01025   byIRR = CurrentIRR();
01026   byAxisMask = (byIndexPollAxis & 1) ? IXODD : IXEVN;
01027 
01028   if (byIRR & byAxisMask)
01029     {
01030       *flag = 1;
01031     }
01032   else
01033     {
01034       *flag = 0;
01035     }
01036 
01037   return 0;
01038 }
01039 
01040 /* Note: board only supports 6 axes max of digital in, out for limit and
01041    home switches, amp enables  */
01042 
01043 /* digital input bit masks, 32-bit word */
01044 /* maps to ports A and B */
01045 #define HOME_0    0x00000001
01046 #define MIN_LIM_0 0x00000002
01047 #define MAX_LIM_0 0x00000004
01048 #define FAULT_0   0x00000008
01049 #define HOME_1    0x00000010
01050 #define MIN_LIM_1 0x00000020
01051 #define MAX_LIM_1 0x00000040
01052 #define FAULT_1   0x00000080
01053 #define HOME_2    0x00000100
01054 #define MIN_LIM_2 0x00000200
01055 #define MAX_LIM_2 0x00000400
01056 #define FAULT_2   0x00000800
01057 #define HOME_3    0x00001000
01058 #define MIN_LIM_3 0x00002000
01059 #define MAX_LIM_3 0x00004000
01060 #define FAULT_3   0x00008000
01061 
01062 #ifdef STG_8_AXES
01063 /* skip C, maps to port D */
01064 #define HOME_4    0x01000000
01065 #define MIN_LIM_4 0x02000000
01066 #define MAX_LIM_4 0x04000000
01067 #define FAULT_4   0x08000000
01068 #define HOME_5    0x10000000
01069 #define MIN_LIM_5 0x20000000
01070 #define MAX_LIM_5 0x40000000
01071 #define FAULT_5   0x80000000
01072 
01073 #endif
01074 
01075 /* no space for axes 7 and 8, so these won't go through */
01076 int stgMaxLimitSwitchRead(int axis, int * flag)
01077 {
01078   long bits;
01079   int retval = 0;
01080 
01081   bits = RawDI();
01082   *flag = 0;
01083 
01084   switch (axis)
01085     {
01086     case 0:
01087       if (bits & MAX_LIM_0)
01088         {
01089           *flag = 1;
01090         }
01091       break;
01092 
01093     case 1:
01094       if (bits & MAX_LIM_1)
01095         {
01096           *flag = 1;
01097         }
01098       break;
01099 
01100     case 2:
01101       if (bits & MAX_LIM_2)
01102         {
01103           *flag = 1;
01104         }
01105       break;
01106 
01107     case 3:
01108       if (bits & MAX_LIM_3)
01109         {
01110           *flag = 1;
01111         }
01112       break;
01113 
01114 #ifdef STG_8_AXES
01115     case 4:
01116       if (bits & MAX_LIM_4)
01117         {
01118           *flag = 1;
01119         }
01120       break;
01121 
01122     case 5:
01123       if (bits & MAX_LIM_5)
01124         {
01125           *flag = 1;
01126         }
01127       break;
01128 
01129 #endif
01130 
01131     default:
01132       retval = -1;
01133       break;
01134     }
01135 
01136   return retval;
01137 }
01138 
01139 
01140 /* no space for axes 7 and 8, so these won't go through */
01141 int stgMinLimitSwitchRead(int axis, int * flag)
01142 {
01143   long bits;
01144   int retval = 0;
01145 
01146   bits = RawDI();
01147   *flag = 0;
01148 
01149   switch (axis)
01150     {
01151     case 0:
01152       if (bits & MIN_LIM_0)
01153         {
01154           *flag = 1;
01155         }
01156       break;
01157 
01158     case 1:
01159       if (bits & MIN_LIM_1)
01160         {
01161           *flag = 1;
01162         }
01163       break;
01164 
01165     case 2:
01166       if (bits & MIN_LIM_2)
01167         {
01168           *flag = 1;
01169         }
01170       break;
01171 
01172     case 3:
01173       if (bits & MIN_LIM_3)
01174         {
01175           *flag = 1;
01176         }
01177       break;
01178 
01179 #ifdef STG_8_AXES
01180     case 4:
01181       if (bits & MIN_LIM_4)
01182         {
01183           *flag = 1;
01184         }
01185       break;
01186 
01187     case 5:
01188       if (bits & MIN_LIM_5)
01189         {
01190           *flag = 1;
01191         }
01192       break;
01193 
01194 #endif
01195 
01196     default:
01197       retval = -1;
01198       break;
01199     }
01200 
01201   return retval;
01202 }
01203 
01204 /* no space for axes 7 and 8, so these won't go through */
01205 int stgHomeSwitchRead(int axis, int *flag)
01206 {
01207   long bits;
01208   int retval = 0;
01209 
01210   bits = RawDI();
01211   *flag = 0;
01212 
01213   switch (axis)
01214     {
01215     case 0:
01216       if (bits & HOME_0)
01217         {
01218           *flag = 1;
01219         }
01220       break;
01221 
01222     case 1:
01223       if (bits & HOME_1)
01224         {
01225           *flag = 1;
01226         }
01227       break;
01228 
01229     case 2:
01230       if (bits & HOME_2)
01231         {
01232           *flag = 1;
01233         }
01234       break;
01235 
01236     case 3:
01237       if (bits & HOME_3)
01238         {
01239           *flag = 1;
01240         }
01241       break;
01242 
01243 #ifdef STG_8_AXES
01244     case 4:
01245       if (bits & HOME_4)
01246         {
01247           *flag = 1;
01248         }
01249       break;
01250 
01251     case 5:
01252       if (bits & HOME_5)
01253         {
01254           *flag = 1;
01255         }
01256       break;
01257 
01258 #endif
01259 
01260     default:
01261       retval = -1;
01262       break;
01263     }
01264 
01265   return retval;
01266 }
01267 
01268 /* there is space for axes 7 and 8, so these will go through */
01269 int stgAmpEnable(int axis, int enable)
01270 {
01271   if (axis < 0 || axis >= STG_MAX_AXIS)
01272     {
01273       return 0;
01274     }
01275 
01276   RawDO(axis, (unsigned char) enable, 2); /* 2 is port C */
01277 
01278   return 0;
01279 }
01280 
01281 /* no space for axes 7 and 8, so these won't go through */
01282 int stgAmpFault(int axis, int * flag)
01283 {
01284   long bits;
01285   int retval = 0;
01286 
01287   bits = RawDI();
01288   *flag = 0;
01289 
01290   switch (axis)
01291     {
01292     case 0:
01293       if (bits & FAULT_0)
01294         {
01295           *flag = 1;
01296         }
01297       break;
01298 
01299     case 1:
01300       if (bits & FAULT_1)
01301         {
01302           *flag = 1;
01303         }
01304       break;
01305 
01306     case 2:
01307       if (bits & FAULT_2)
01308         {
01309           *flag = 1;
01310         }
01311       break;
01312 
01313     case 3:
01314       if (bits & FAULT_3)
01315         {
01316           *flag = 1;
01317         }
01318       break;
01319 
01320 #ifdef STG_8_AXES
01321     case 4:
01322       if (bits & FAULT_4)
01323         {
01324           *flag = 1;
01325         }
01326       break;
01327 
01328     case 5:
01329       if (bits & FAULT_5)
01330         {
01331           *flag = 1;
01332         }
01333       break;
01334 
01335 #endif
01336 
01337     default:
01338       retval = -1;
01339       break;
01340     }
01341 
01342   return retval;
01343 }
01344 
01345 /*
01346   Analog and Digital IO
01347 
01348   Analog and digital IO are mapped directly onto the board with no care
01349   that they don't collide with axes functions above. This is good in the
01350   sense that you can effect motion, bad in the same sense. This means that
01351   you should leave indices 0..axis-1 alone and use the higher indices for
01352   general-purpose IO. For example, if you have a 4-axis board and only
01353   3 real axes, you can use digital input at indices 12..15 for anything.
01354 
01355   Analog input is an option for the board. There are 8 inputs, which
01356   don't collide with any motion IO so you can use indices 0..7
01357   regardless of how many motion axes you have.
01358 
01359   If you have an 8 axis board, only 6 axis can be fully used for motion
01360   since there is not enough digital input for all the home and limit switches.
01361 
01362   For a 4-axis board, there are:
01363   24 digital inputs (includes limit switches and amp faults at 0..15)
01364   8 digital outputs (includes amp enables at 0..3)
01365   8 analog inputs (with option)
01366   4 analog outputs (includes amp outputs at 0..3)
01367 
01368   For an 8-axis board (6 motion axes max), there are:
01369   24 digital inputs (includes limit switches and amp faults at 0..23)
01370   8 digital outputs (includes amp enables at 0..5)
01371   8 analog inputs (with option)
01372   8 analog outputs (includes amp outputs at 0..5)
01373 
01374   Here's the actual map. If you aren't using some axes then their
01375   slots are up for grabs.
01376 
01377   DIGITAL INPUT
01378   -------------
01379   Index   Function      Connector/Pin
01380   -----   --------      -------------
01381   00      X home sw     P1/47
01382   01      X +lim sw     P1/45
01383   02      X -lim sw     P1/43
01384   03      X amp fault   P1/41
01385   04      Y home sw     P1/39
01386   05      Y +lim sw     P1/37
01387   06      Y -lim sw     P1/35
01388   07      Y amp fault   P1/33
01389   08      Z home sw     P1/31
01390   09      Z +lim sw     P1/29
01391   10      Z -lim sw     P1/27
01392   11      Z amp fault   P1/25
01393   12      U home sw     P1/23
01394   13      U +lim sw     P1/21
01395   14      U -lim sw     P1/19
01396   15      U amp fault   P1/17
01397   16      V home sw     P2/31
01398   17      V +lim sw     P2/29
01399   18      V -lim sw     P2/27
01400   19      V amp fault   P2/25
01401   20      W home sw     P2/23
01402   21      W +lim sw     P2/21
01403   22      W -lim sw     P2/19
01404   23      W amp fault   P2/17
01405 
01406   DIGITAL OUTPUT
01407   -------------
01408   Index   Function      Connector/Pin
01409   -----   --------      -------------
01410   00      X amp enable  P1/15
01411   01      Y amp enable  P1/13
01412   02      Z amp enable  P1/11
01413   03      U amp enable  P1/9
01414   04      V amp enable  P1/7
01415   05      W amp enable  P1/5
01416   06      (none)        P1/3
01417   07      (none)        P1/1
01418 
01419   ANALOG INPUT
01420   -------------
01421   Index   Function      Connector/Pin
01422   -----   --------      -------------
01423   00*     (none)        P2/1
01424   01*     (none)        P2/3
01425   02*     (none)        P2/5
01426   03*     (none)        P2/7
01427   04*     (none)        P2/9
01428   05*     (none)        P2/11
01429   06*     (none)        P2/13
01430   07*     (none)        P2/15
01431 
01432   ANALOG OUTPUT
01433   -------------
01434   Index   Function      Connector/Pin
01435   -----   --------      -------------
01436   00      X amp ref     P3/2
01437   01      Y amp ref     P3/8
01438   02      Z amp ref     P3/5
01439   03      U amp ref     P3/11
01440   04**    V amp ref     P4/2
01441   05**    W amp ref     P4/8
01442   06**    (none)        P4/5
01443   07**    (none)        P4/11
01444 
01445   * = only available as option
01446   ** = only available for 8-axis boards, with STG_8_AXES defined
01447 
01448   */
01449 
01450 int stgDioInit(const char * stuff)
01451 {
01452   /* set digital IO bits for A,B input, C output */
01453   DIOdirection(0x0C);
01454 
01455   return 0;
01456 }
01457 
01458 int stgDioQuit()
01459 {
01460   return 0;
01461 }
01462 
01463 int stgDioMaxInputs()
01464 {
01465   return 24;
01466 }
01467 
01468 int stgDioMaxOutputs()
01469 {
01470   return 24;
01471 }
01472 
01473 int stgDioRead(int index, int *value)
01474 {
01475   unsigned char byte;
01476   unsigned char mask;
01477 
01478   mask = 1 << (index % 8);
01479 
01480   /* try A */
01481   if (index >= 0 && index < 8)
01482     {
01483       byte = _inp(STG_BASE_ADDRESS + DIO_A);
01484       *value = (byte & mask ? 1 : 0);
01485       return 0;
01486     }
01487 
01488   /* try B */
01489   if (index >= 8 && index < 16)
01490     {
01491       byte = _inp(STG_BASE_ADDRESS + DIO_B);
01492       *value = (byte & mask ? 1 : 0);
01493       return 0;
01494     }
01495 
01496   /* try D */
01497   if (index >= 16 && index < 24)
01498     {
01499       byte = _inp(STG_BASE_ADDRESS + DIO_D);
01500       *value = (byte & mask ? 1 : 0);
01501       return 0;
01502     }
01503 
01504   /* bad index */
01505   *value = 0;
01506   return -1;
01507 }
01508 
01509 /* writes go to the C register */
01510 int stgDioWrite(int index, int value)
01511 {
01512   if (index < 0 || index >= 8)
01513     {
01514       return -1;
01515     }
01516 
01517   RawDO(index, (unsigned char) value, 2); /* 2 is port C */
01518 
01519   return 0;
01520 }
01521 
01522 /* we can really read the outputs in the C register */
01523 int stgDioCheck(int index, int *value)
01524 {
01525   unsigned char byte;
01526   unsigned char mask;
01527 
01528   if (index < 0 || index >= 8)
01529     {
01530       *value = 0;
01531       return -1;
01532     }
01533 
01534   byte = _inp(STG_BASE_ADDRESS + DIO_C);
01535   mask = 1 << index;
01536 
01537   *value = (byte & mask ? 1 : 0);
01538 
01539   return 0;
01540 }
01541 
01542 /* can read bytes 0..2 */
01543 int stgDioByteRead(int index, unsigned char *byte)
01544 {
01545   if (index == 0)
01546     {
01547       *byte = _inp(STG_BASE_ADDRESS + DIO_A);
01548       return 0;
01549     }
01550 
01551   if (index == 1)
01552     {
01553       *byte = _inp(STG_BASE_ADDRESS + DIO_B);
01554       return 0;
01555     }
01556 
01557   if (index == 2)
01558     {
01559       *byte = _inp(STG_BASE_ADDRESS + DIO_D);
01560       return 0;
01561     }
01562 
01563   *byte = 0;
01564   return -1;
01565 }
01566 
01567 /* can read shorts 0..1, 0 is BA, 1 is 0D */
01568 int stgDioShortRead(int index, unsigned short *sh)
01569 {
01570   unsigned char lo, hi;
01571 
01572   if (index == 0)
01573     {
01574       lo = _inp(STG_BASE_ADDRESS + DIO_A);
01575       hi = _inp(STG_BASE_ADDRESS + DIO_B);
01576 
01577       *sh = (hi << 8) + lo;
01578       return 0;
01579     }
01580 
01581   if (index == 1)
01582     {
01583       lo = _inp(STG_BASE_ADDRESS + DIO_D);
01584 
01585       *sh = lo;
01586       return 0;
01587     }
01588 
01589   *sh = 0;
01590   return -1;
01591 }
01592 
01593 /* can only read 1 word, and this is 0DBA */
01594 int stgDioWordRead(int index, unsigned int *word)
01595 {
01596   if (index != 0)
01597     {
01598       *word = 0;
01599       return -1;
01600     }
01601 
01602   *word = _inp(STG_BASE_ADDRESS + DIO_D) << 16;
01603   *word += _inp(STG_BASE_ADDRESS + DIO_B) << 8;
01604   *word += _inp(STG_BASE_ADDRESS + DIO_A);
01605 
01606   return 0;
01607 }
01608 
01609 /* index is 0 only for port C */
01610 int stgDioByteWrite(int index, unsigned char byte)
01611 {
01612   if (index == 0)
01613     {
01614       _outp(STG_BASE_ADDRESS + DIO_C, byte);
01615       return 0;
01616     }
01617 
01618   return -1;
01619 }
01620 
01621 /* can't do a short write-- only 1 byte of digital out */
01622 int stgDioShortWrite(int index, unsigned short sh)
01623 {
01624   return -1;
01625 }
01626 
01627 /* can't do a word write-- only 1 byte of digital out */
01628 int stgDioWordWrite(int index, unsigned int word)
01629 {
01630   return -1;
01631 }
01632 
01633 /* can do a byte check on output C register */
01634 int stgDioByteCheck(int index, unsigned char *byte)
01635 {
01636   if (index == 0)
01637     {
01638       *byte = _inp(STG_BASE_ADDRESS + DIO_C);
01639       return 0;
01640     }
01641 
01642   *byte = 0;
01643   return -1;
01644 }
01645 
01646 /* can't read a short-- only 8 bits of digital out */
01647 int stgDioShortCheck(int index, unsigned short *sh)
01648 {
01649   *sh = 0;
01650   return -1;
01651 }
01652 
01653 /* cant' read a word-- only 8 bits of digital out */
01654 int stgDioWordCheck(int index, unsigned int *word)
01655 {
01656   *word = 0;
01657   return -1;
01658 }
01659 
01660 int stgAioInit(const char * stuff)
01661 {
01662   /* nothing need be done */
01663   return 0;
01664 }
01665 
01666 int stgAioQuit()
01667 {
01668   return 0;
01669 }
01670 
01671 int stgAioMaxInputs()
01672 {
01673   return 8;                     /* make sure you have this option */
01674 }
01675 
01676 int stgAioMaxOutputs()
01677 {
01678   return STG_MAX_AXIS;
01679 }
01680 
01681 int stgAioStart(int index)
01682 {
01683   return stgAdcStart(index);
01684 }
01685 
01686 void stgAioWait(void)
01687 {
01688   stgAdcWait();
01689 }
01690 
01691 int stgAioRead(int index, double *volts)
01692 {
01693   return stgAdcRead(index, volts);
01694 }
01695 
01696 int stgAioWrite(int index, double volts)
01697 {
01698   return stgDacWrite(index, volts);
01699 }
01700 
01701 int stgAioCheck(int index, double *volts)
01702 {
01703   if (index < 0 || index >= STG_MAX_AXIS) {
01704     *volts = 0.0;
01705     return 0;
01706   }
01707 
01708   /* can't read outputs directly, so return stored value */
01709   *volts = checkedOutputs[index];
01710   return 0;
01711 }
01712 
01713 int stgModel()
01714 {
01715   return 1;
01716 }

Generated on Sun Dec 2 15:27:43 2001 for EMC by doxygen1.2.11.1 written by Dimitri van Heesch, © 1997-2001