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

stgmembs.c

Go to the documentation of this file.
00001 /*
00002  * stgmembs.cpp
00003  *
00004  * A part of the Windows 95 driver for Servo To Go, Incen.'s ISA Bus
00005  * servo I/O card.
00006  *
00007  * This file contains member functions for the ServoToGo class.
00008  *
00009  * This work, including the source code, documentation
00010  * and related data, is placed into the public domain.
00011  *
00012  * The orginal author is Don McLane, Servo To Go, Inc.
00013  *
00014  * THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY
00015  * OF ANY KIND, NOT EVEN THE IMPLIED WARRANTY OF
00016  * MERCHANTABILITY. THE AUTHOR OF THIS SOFTWARE,
00017  * ASSUMES _NO_ RESPONSIBILITY FOR ANY CONSEQUENCE
00018  * RESULTING FROM THE USE, MODIFICATION, OR
00019  * REDISTRIBUTION OF THIS SOFTWARE.
00020  *
00021  *
00022  */
00023 
00024 /* ident tag */
00025 #ifndef __GNUC__
00026 #ifndef __attribute__
00027 #define __attribute__(x)
00028 #endif
00029 #endif
00030 
00031 static char __attribute__((unused)) ident[] = "$Id: stgmembs.c,v 1.5 2001/11/05 16:59:55 wshackle Exp $";
00032 
00033 
00034 #include "locdefs.h"
00035 #define assert(a)
00036 
00037 #include "offsets.h"
00038 #include "stgdefs.h"
00039 #include "locsysio.h"
00040 
00041 
00042 inline void fOutP(unsigned short port, unsigned char data)
00043 {
00044   outb(data, port);
00045 }
00046 
00047 inline void fOutPW(unsigned short port, unsigned short data)
00048 {
00049   outw(data, port);
00050 }
00051 
00052 inline unsigned char fInP(unsigned short port)
00053 {
00054   return inb(port);
00055 }
00056 
00057 inline unsigned short fInPW(unsigned short port)
00058 {
00059   return inw(port);
00060 }
00061 
00062 static unsigned short wBaseAddress;
00063 static unsigned short wIrq;
00064 static unsigned short wModel;
00065 static unsigned short wNoBoardFlag;
00066 static unsigned short wAxesInSys;
00067 static unsigned short wSaveDirs;
00068 static unsigned char  byIndexPollAxis;
00069 static unsigned char  byIndexPulsePolarity;
00070 static long           lSimDac[MAX_AXIS];
00071 static long           lSimEnc[MAX_AXIS];
00072 
00073 static const int      aPortOffset_1[] = {DIO_A, DIO_B, DIO_C, DIO_D};
00074 static const int      aPortOffset_2[] = {PORT_A, PORT_B, PORT_C, PORT_D};
00075 
00076 static unsigned char  byEncHighByte[MAX_AXIS];
00077 static unsigned char  byOldByte2[MAX_AXIS];
00078 
00079 unsigned short BaseAddress(void)
00080 {
00081   return wBaseAddress;
00082 }
00083 
00084     unsigned short GetBoardPresence(void) {return wNoBoardFlag;};
00085     unsigned short GetAxes(void) {return wAxesInSys;};
00086     unsigned short GetIrq(void) {return wIrq;};
00087     unsigned short GetAddr(void) {return wBaseAddress;};
00088     unsigned short GetModel(void) {return wModel;};
00089 
00090 
00091 /***************************************************************************/
00092 /*                                                                         */
00093 /*                           Constructor                                   */
00094 /*                                                                         */
00095 /***************************************************************************/
00096 void
00097 ServoToGoConstructor(unsigned short wRequestedIrq)
00098 {
00099 #if defined ( STG_LINUX )
00100     iopl(3);  // get access to I/O ports, must be root.
00101 #endif
00102     wNoBoardFlag = NO_BOARD;
00103     Initialize(wRequestedIrq);   // figure out board address, init irq controller
00104     EncoderInit();
00105     SelectInterruptPeriod(_1_MILLISECOND);  // initialize timer
00106     byIndexPulsePolarity = 1;               // default active level high
00107     if (wModel == MODEL2)
00108         fOutP(wBaseAddress + CNTRL1, CNTRL1_NOT_SLAVE);
00109 };
00110 
00111 /***************************************************************************/
00112 /*                                                                         */
00113 /*                            Destructor                                   */
00114 /*                                                                         */
00115 /***************************************************************************/
00116 void
00117 ServoToGoDestructor(void)
00118 {
00119   unsigned short nAxis;
00120     StopInterrupts();
00121 
00122     // set all the DAC outputs to 0.
00123     for (nAxis = 0; nAxis < MAX_AXIS; nAxis++)
00124         RawDAC(nAxis, 0);
00125 
00126     // set all the digital I/O bits to input
00127     DioDirection2(0);
00128 }
00129 
00130 /***************************************************************************/
00131 /*                                                                         */
00132 /*                              SetIrq                                     */
00133 /*                                                                         */
00134 /***************************************************************************/
00135 void SetIrq(unsigned short wRequestedIrq)
00136 {
00137     unsigned char byIntReg;
00138 
00139     if (wNoBoardFlag == NO_BOARD)
00140         return;
00141 
00142     wIrq = wRequestedIrq;  // assume it's OK for now, check later
00143 
00144     if (wModel == MODEL1)
00145         byIntReg = 0x80;       // initial value for the high bits in the register
00146                                // sets auto zero off
00147     else   // MODEL2
00148         byIntReg = 0x88;       // cal high too, not calibrating ADC
00149 
00150     // now put low bits into byIntReg to select irq
00151 
00152     switch (wRequestedIrq)
00153     {
00154         case 3: break;      // add zero
00155 
00156         case 5: byIntReg |= 4;
00157                 break;
00158 
00159         case 7: byIntReg |= 2;
00160                 break;
00161 
00162         case 9: byIntReg |= 6;
00163                 break;
00164 
00165         case 10: byIntReg |= 5;
00166                  break;
00167 
00168         case 11: byIntReg |= 7;
00169                  break;
00170 
00171         case 12: byIntReg |= 3;
00172                  break;
00173 
00174         case 15: byIntReg |= 1;
00175                  break;
00176 
00177         default: wIrq = 5;      // ERROR, requested irq not valid, use 5
00178                  byIntReg |= 4; // There is no safe value, leaving zero
00179                                 // here would select IRQ 3 which is worse
00180                                 // than 5 because IRQ 3 is usually for COM 2
00181                  break;
00182     }
00183 
00184     if (wModel == MODEL1)
00185         fOutP(wBaseAddress + INTC, byIntReg);  // set irq
00186     else   // MODEL2
00187         fOutP(wBaseAddress + CNTRL0, byIntReg);
00188 }
00189 /***************************************************************************/
00190 /*                                                                         */
00191 /*                             BaseFind                                    */
00192 /*                                                                         */
00193 /***************************************************************************/
00194 
00195 // find the base address of the Servo To Go board
00196 
00197 unsigned short BaseFind(void)
00198 {
00199    short i;
00200    unsigned short io_add;
00201 
00202    for (i = 15; i >= 0; i--)                    // search all possible addresses
00203    {
00204        io_add = i * 0x20 + 0x200;
00205        if ( BrdtstOK(io_add) )
00206         return io_add;
00207    }
00208    return(0);
00209 }
00210 
00211 /***************************************************************************/
00212 /*                                                                         */
00213 /*                             BrdtstOK                                    */
00214 /*                                                                         */
00215 /***************************************************************************/
00216 
00217 // check the board tests register, figure out board model
00218 
00219 unsigned short BrdtstOK(unsigned short BaseAddress)
00220 {
00221     unsigned short BrdtstAddress;
00222     unsigned short SerSeq, HighNibble;
00223     int j;
00224 
00225     BrdtstAddress = BaseAddress + BRDTST;
00226 
00227     SerSeq = 0;
00228     for ( j = 7; j >= 0; j--)
00229     {
00230         HighNibble = fInP(BrdtstAddress) >> 4;
00231         if (HighNibble & 8)     // is SER set
00232         {
00233            // shift bit to position specifed by Q2, Q1, Q0
00234            // which are the lower three bits.  Put bit in SerSeq.
00235            SerSeq |= 1 << (HighNibble & 7);
00236         }
00237     }
00238     if (SerSeq == 0x75)        // SER sequence is 01110101
00239     {
00240         wModel = MODEL1;
00241         return 1;              //true
00242     }
00243     if (SerSeq == 0x74)        // SER sequence is 01110100
00244     {
00245         wModel = MODEL2;
00246         return 1;              // true
00247     }
00248 //    wModel = MODEL_NO_ID;
00249     return 0;  // false
00250 }
00251 
00252 /***************************************************************************/
00253 /*                                                                         */
00254 /*                             Initialize                                  */
00255 /*                                                                         */
00256 /***************************************************************************/
00257 void Initialize(unsigned short wRequestedIrq)
00258 {
00259   /*
00260    * First find the the base I/O address of the board.
00261    *
00262    * only do this in the DOS example.  It's dangerous under 95, and can't be
00263    * done under NT
00264    */
00265    wBaseAddress = BaseFind();
00266    if (wBaseAddress == 0)
00267    {
00268        wNoBoardFlag = NO_BOARD;
00269    }
00270    wNoBoardFlag = BOARD_PRESENT;
00271 
00272   /*
00273    * Initialize the interrupt controller
00274    */
00275    if (wModel == MODEL1)
00276    {
00277    fOutP(wBaseAddress + MIO_2, 0x92);  // initialize INTC as output reg.
00278                                        // sets port D to input since we have
00279                                        // to set it to something.
00280    SetIrq(wRequestedIrq);              // selects the IRQ in INTC. Now, if a stray
00281                                        // interrupt is issued (see below) it will
00282                                        // go to an interrupt that isn't enabled on
00283                                        // the motherboard yet (if your system is
00284                                        // set up correctly).
00285    fOutP( wBaseAddress + ICW1, 0x1a ); // initialize 82C59 as single chip,
00286                                        // level triggered
00287    fOutP( wBaseAddress + ICW2, 0x00 ); // icw2 - not used, must write
00288                                        // could issue stray interrupt here - danger!
00289    fOutP( wBaseAddress + OCW1, 0xff);  // mask off all interrupt sources (the
00290                                        // interrupt on the motherboard isn't
00291                                        // enabled yet, you do that when you install
00292                                        // your interrupt handler.).
00293    }
00294    else   // must be a Model 2
00295    {
00296    fOutP(wBaseAddress + MIO_2, 0x8b);  // initialize CNTRL0 as output reg.
00297                                        // BRDTST to input.
00298                                        // sets port D, high and low, to input
00299                                        // since we have to set it to something.
00300    SetIrq(wRequestedIrq);              // selects the IRQ in CNTRL0. Now, if a stray
00301                                        // interrupt is issued (see below) it will
00302                                        // go to an interrupt that isn't enabled on
00303                                        // the motherboard yet (if your system is
00304                                        // set up correctly).
00305    }
00306 };
00307 
00308 /***************************************************************************/
00309 /*                                                                         */
00310 /*                              StartADC                                   */
00311 /*                                                                         */
00312 /***************************************************************************/
00313 void StartADC(unsigned short wAxis)
00314 {
00315     if (wNoBoardFlag == NO_BOARD)
00316     {
00317         return;
00318     }
00319 
00320     if (wAxis > 7)
00321         return;
00322 
00323     if (wModel == MODEL1)
00324     {
00325         // do a dummy read from the ADC, just to set the input multiplexer to
00326         // the right channel
00327         fInPW(wBaseAddress + ADC_0 + (wAxis << 1));        //lint !e534
00328 
00329         // wait 4 uS for settling time on the multiplexer and ADC
00330         // you probably shouldn't really have a delay in
00331         // a driver.
00332         Timer2Delay(28);
00333 
00334         // now start conversion.
00335         fOutPW(wBaseAddress + ADC_0 + (wAxis << 1), 0);
00336     }
00337     else  // Model 2
00338     {
00339         unsigned char Cntrl0;
00340 
00341         Cntrl0 = fInP(wBaseAddress + CNTRL0) & 0x07;  // save irq
00342 
00343         Cntrl0 |= (wAxis << 4) | 0x88;  // shift bits to AD2, AD1, AD0
00344                                         // set bit 0x80 high for autozero
00345                                         // set bit 0x08 high, not calibrating
00346         fOutP(wBaseAddress + CNTRL0, Cntrl0);  // select ADC channel
00347 
00348         // don't have to do a dummy read for a model 2
00349 
00350         // wait 4 uS for settling time on the multiplexer and ADC
00351         // you probably shouldn't really have a delay in
00352         // a driver.
00353         Timer2Delay(28);
00354 
00355         // now start conversion.
00356         fOutPW(wBaseAddress + ADC, 0);
00357 
00358     }
00359 };
00360 
00361 /***************************************************************************/
00362 /*                                                                         */
00363 /*                               RawADC                                    */
00364 /*                                                                         */
00365 /***************************************************************************/
00366 short SpinReadADC(unsigned short wAxis)
00367 {
00368     short counts;
00369     short j;
00370 
00371     if (wNoBoardFlag == NO_BOARD)
00372     {
00373         return 0;
00374     }
00375 
00376     if (wAxis > 7)
00377          return -1;
00378 
00379     if (wModel == MODEL1)
00380     {
00381         // make sure conversion is done, assume polling delay is done.
00382         // EOC (End Of Conversion) is bit 0x08 in IIR (Interrupt Request
00383         // Register) of Interrupt Controller.  Don't wait forever though
00384         // bail out eventually.
00385 
00386         for ( j = 0; (!(CurrentIRR() & 0x08)) && (j < 10000); j++);
00387 
00388         counts = ( fInPW(wBaseAddress + ADC_0 + (wAxis << 1)) );
00389     }
00390     else
00391     {
00392         // is the conversion done?
00393         for ( j = 0; (fInP(wBaseAddress + BRDTST) & BRDTST_EOC) && (j < 10000); j++);
00394 
00395         // conversion is done, get counts.
00396         counts = fInPW(wBaseAddress + ADC);
00397     }
00398 
00399     if (counts & 0x1000)       // is sign bit negative?
00400         counts |= 0xf000;      // sign extend
00401     else
00402         counts &= 0xfff;       // make sure high order bits are zero.
00403 
00404     return counts;
00405 };
00406 
00407 long ReadADC(unsigned short wAxis, short *counts_ptr)
00408 {
00409   short counts;
00410   if(counts_ptr == 0)
00411     {
00412       return 0;
00413     }
00414   counts = *counts_ptr;
00415     if (wNoBoardFlag == NO_BOARD)
00416     {
00417         return STG_SUCCESS;
00418     }
00419 
00420     if (wAxis > 7)
00421          return STG_FAILURE;
00422 
00423     if (wModel == MODEL1)
00424     {
00425         if ( !(CurrentIRR() & 0x08) ) // is the conversion done?
00426             return STG_FAILURE;                  // no, return failure
00427 
00428         // conversion is done, get counts.
00429 //        counts = fInPW(wBaseAddress + ADC_0 + (wAxis << 1));
00430 //        counts = fInPW(wBaseAddress + ADC_1);  // debug
00431     }
00432     else  // Model 2
00433     {
00434         // is the conversion done?
00435         if ( fInP(wBaseAddress + BRDTST) & BRDTST_EOC )
00436             return STG_FAILURE;                 // no, return failure
00437 
00438         // conversion is done, get counts.
00439 //        counts = fInPW(wBaseAddress + ADC_1);
00440     }
00441 
00442     counts = fInPW(wBaseAddress + ADC_0 + (wAxis << 1));
00443 
00444     if (counts & 0x1000)       // is sign bit negative?
00445         counts |= 0xf000;      // sign extend
00446     else
00447         counts &= 0xfff;       // make sure high order bits are zero.
00448 
00449     *counts_ptr = counts;
00450     return STG_SUCCESS;
00451 
00452 };
00453 
00454 /***************************************************************************/
00455 /*                                                                         */
00456 /*                             EncoderInit                                 */
00457 /*                                                                         */
00458 /***************************************************************************/
00459 //
00460 // sets global variable: wAxesInSys
00461 //
00462 void EncoderInit(void)
00463 {
00464     LONGBYTE enc[8];
00465     unsigned short wAdd,wA;
00466     unsigned short const wTestPat = 0x5aa5;
00467     
00468     if (wNoBoardFlag == NO_BOARD)
00469     {
00470         wAxesInSys = MAX_AXIS;
00471         return;
00472     }
00473 
00474     // It is possible that the encoder counts are being held by battery
00475     // backup, so we'll read the encoders, and save the values
00476     // Then we'll initialize the encoder chips, since it's more likely that
00477     // the ecoders were not kept alive by battery and need to be initialized
00478 
00479     EncReadAll(enc);
00480 
00481     // probably the right thing is to sign extend the 24 bits, so, instead
00482     // of a 24 bit unsigned count, we have +/- 23 bits.
00483 
00484 //    for ( i = 0; i < 8; i++)
00485 //    {
00486 //        byEncHighByte[i] = enc[i].Byte[2] & 0x80 ? 0xff : 0;
00487 //        byOldByte2[i] = enc[i].Byte[2];
00488 //    }
00489 
00490     for (wAdd = wBaseAddress + CNT0_C;
00491                                  wAdd <= wBaseAddress + CNT6_C; wAdd +=4)
00492     {
00493         // we're going to be slick and do two chips at a time, that's why
00494         // the registers are arranged data, data, control, control.  You
00495         // can do two at a time, by using word operations, instead of
00496         // byte operations.  Not a big deal for initializing, but reading is
00497         // done pretty often.
00498 
00499         fOutPW(wAdd, 0x2020);   // master reset
00500 
00501         // Set Counter Command Register - Input Control, OL Load (P3),
00502         // and Enable Inputs A and B (INA/B).
00503 
00504         fOutPW(wAdd, 0x6868);
00505 
00506         // Set Counter Command Register - Output Control
00507 
00508         fOutPW(wAdd, 0x8080);
00509 
00510         // Set Counter Command Register - Quadrature
00511 
00512         fOutPW(wAdd, 0xc3c3);
00513 
00514         fOutPW(wAdd, 0x0404);  //reset counter to zero
00515     }
00516 
00517     //  Figure out how many axes are on the card
00518 
00519     for ( wA = wBaseAddress + CNT0_D; wA <= wBaseAddress + CNT6_D; wA +=4)
00520     {
00521 
00522         // reset address pointer
00523 
00524         fOutPW(wA + 2, 0x0101);
00525 
00526         // write a pattern to the preset register
00527 
00528         fOutPW(wA, wTestPat);
00529         fOutPW(wA, wTestPat);
00530         fOutPW(wA, wTestPat);
00531 
00532         // transfer the preset register to the count register
00533 
00534         fOutPW(wA + 2, 0x0909);
00535 
00536         // transfer counter to output latch
00537 
00538         fOutPW(wA + 2, 0x0202);
00539 
00540         // read the output latch and see if it matches
00541 
00542         if (fInPW(wA) != wTestPat)
00543             break;
00544         if (fInPW(wA) != wTestPat)
00545             break;
00546         if (fInPW(wA) != wTestPat)
00547             break;
00548 
00549         // now replace the values that you saved previously, in case the
00550         // encoder was battery backed up
00551 
00552         fOutP(wA, enc[wAxesInSys].Byte[0]);
00553         fOutP(wA, enc[wAxesInSys].Byte[1]);
00554         fOutP(wA, enc[wAxesInSys].Byte[2]);
00555 
00556         fOutP(wA + 1, enc[wAxesInSys + 1].Byte[0]);
00557         fOutP(wA + 1, enc[wAxesInSys + 1].Byte[1]);
00558         fOutP(wA + 1, enc[wAxesInSys + 1].Byte[2]);
00559 
00560         // transfer the preset register to the count register
00561 
00562         fOutPW(wA + 2, 0x0909);
00563 
00564         wAxesInSys += 2;
00565 
00566         // write zeros to preset register, we don't want to do a master reset
00567         // (MRST), because then we would need to re-initialize the counter
00568 
00569 //        fOutPW(wA, 0);
00570 //        fOutPW(wA, 0);
00571 //        fOutPW(wA, 0);
00572 
00573         // reset counter, BRW and CRY and address pointer (RADR)
00574 
00575 //        fOutPW(wA + 2, 0x0505);
00576     }
00577 };
00578 
00579 /***************************************************************************/
00580 /*                                                                         */
00581 /*                        SelectInterruptPeriod                            */
00582 /*                                                                         */
00583 /***************************************************************************/
00584 void SelectInterruptPeriod(long lPeriodSelect)
00585 {
00586    if (wNoBoardFlag == NO_BOARD)
00587    {
00588        return;
00589    }
00590 
00591    if (lPeriodSelect != MAX_PERIOD)
00592    {
00593        fOutP(wBaseAddress + TMRCMD, 0x56);   // timer 1, read/load LSB (MSB is 0)
00594                                              // mode 3 (square wave)
00595        fOutP(wBaseAddress + TIMER_1, 0xb4);  // 0xb4 = 180 -> 25 uSec period
00596    }
00597    else
00598    {
00599        fOutP(wBaseAddress + TMRCMD, 0x76);   // timer 1, read/load LSB then MSB
00600                                              // mode 3 (square wave)
00601        fOutP(wBaseAddress + TIMER_1, 0xff);  // LSB
00602        fOutP(wBaseAddress + TIMER_1, 0xff);  // MSB
00603    }
00604 
00605    switch (lPeriodSelect)
00606    {
00607         case _500_MICROSECONDS:
00608             fOutP(wBaseAddress + TMRCMD, 0x34);    // timer 0, read/load LSB followed by
00609                                                    // MSB, mode 2 (real-time interrupt)
00610             fOutP(wBaseAddress + TIMER_0, 0x14);   // 0x14 = 20 = .5 mS
00611             fOutP(wBaseAddress + TIMER_0, 0x00);
00612             break;
00613         case _1_MILLISECOND:
00614             fOutP(wBaseAddress + TMRCMD, 0x34);    // timer 0, read/load LSB followed by
00615                                                    // MSB, mode 2 (real-time interrupt)
00616             fOutP(wBaseAddress + TIMER_0, 0x28);   // 0x28 = 40 = 1 mS
00617             fOutP(wBaseAddress + TIMER_0, 0x00);
00618             break;
00619         case _2_MILLISECONDS:
00620             fOutP(wBaseAddress + TMRCMD, 0x34);    // timer 0, read/load LSB followed by
00621                                                    // MSB, mode 2 (real-time interrupt)
00622             fOutP(wBaseAddress + TIMER_0, 0x50);   // 0x50 = 80 = 2 mS
00623             fOutP(wBaseAddress + TIMER_0, 0x00);
00624             break;
00625         case _3_MILLISECONDS:
00626             fOutP(wBaseAddress + TMRCMD, 0x34);    // timer 0, read/load LSB followed by
00627                                                    // MSB, mode 2 (real-time interrupt)
00628             fOutP(wBaseAddress + TIMER_0, 0x78);   // 0x78 = 120 = 3 mS
00629             fOutP(wBaseAddress + TIMER_0, 0x00);
00630             break;
00631         case _4_MILLISECONDS:
00632             fOutP(wBaseAddress + TMRCMD, 0x34);    // timer 0, read/load LSB followed by
00633                                                    // MSB, mode 2 (real-time interrupt)
00634             fOutP(wBaseAddress + TIMER_0, 0xA0);   // 0xA0 = 160 = 4 mS
00635             fOutP(wBaseAddress + TIMER_0, 0x00);
00636             break;
00637         case _5_MILLISECONDS:
00638             fOutP(wBaseAddress + TMRCMD, 0x34);    // timer 0, read/load LSB followed by
00639                                                    // MSB, mode 2 (real-time interrupt)
00640             fOutP(wBaseAddress + TIMER_0, 0xC8);   // 0xC8 = 200 = 5 mS
00641             fOutP(wBaseAddress + TIMER_0, 0x00);
00642             break;
00643         case _10_MILLISECONDS:
00644             fOutP(wBaseAddress + TMRCMD, 0x34);    // timer 0, read/load LSB followed by
00645                                                    // MSB, mode 2 (real-time interrupt)
00646             fOutP(wBaseAddress + TIMER_0, 0x90);   // 0x0190 = 400 = 10 mS
00647             fOutP(wBaseAddress + TIMER_0, 0x01);
00648             break;
00649         case _100_MILLISECONDS:
00650             fOutP(wBaseAddress + TMRCMD, 0x34);    // timer 0, read/load LSB followed by
00651                                                    // MSB, mode 2 (real-time interrupt)
00652             fOutP(wBaseAddress + TIMER_0, 0xA0);   // 0x0FA0 = 4000 = 100 mS
00653             fOutP(wBaseAddress + TIMER_0, 0x0F);
00654             break;
00655         case _1_SECOND:
00656             fOutP(wBaseAddress + TMRCMD, 0x34);    // timer 0, read/load LSB followed by
00657                                                    // MSB, mode 2 (real-time interrupt)
00658             fOutP(wBaseAddress + TIMER_0, 0x40);   // 0x9C40 = 40000 = 1 S
00659             fOutP(wBaseAddress + TIMER_0, 0x9c);
00660             break;
00661         case MAX_PERIOD:
00662             fOutP(wBaseAddress + TMRCMD, 0x34);    // timer 0, read/load LSB followed by
00663                                                    // MSB, mode 2 (real-time interrupt)
00664             fOutP(wBaseAddress + TIMER_0, 0xff);   // LSB
00665             fOutP(wBaseAddress + TIMER_0, 0xff);   // MSB
00666             break;
00667         default:
00668             // wrong input? then don't change it
00669             break;
00670    }
00671 };
00672 
00673 /***************************************************************************/
00674 /*                                                                         */
00675 /*                               RawDAC                                    */
00676 /*                                                                         */
00677 /***************************************************************************/
00678 void RawDAC(unsigned short nAxis, long lCounts)
00679 {
00680     if (wNoBoardFlag == NO_BOARD)
00681     {
00682         return;
00683     }
00684 
00685     if ( nAxis > 7 )        // is axis within range?
00686        return;
00687 
00688     // input / output:
00689     //
00690     //    lCounts (decimal) ... -lCounts ... +0x1000 ... volts
00691     //
00692     //     0x1000  (4096)     0xfffff000           0       +10
00693     //          0                      0      0x1000         0
00694     // 0xfffff001 (-4095)          0xfff      0x1fff       -10
00695 
00696     // So, the domain might be different than you expected. I expected:
00697     //     0xf000 (-4096)  to  0xfff (4095), rather than
00698     //     0xf001 (-4095)  to 0x1000 (4096)
00699 
00700     // reverse slope so positive counts give positive voltage
00701     lCounts = - lCounts;
00702 
00703     // shift for DAC
00704     lCounts += 0x1000;
00705 
00706     if (lCounts > 0x1FFF)    // clamp + output
00707     {
00708         lCounts = 0x1FFF;
00709     }
00710     if (lCounts < 0)         // clamp - output
00711     {
00712         lCounts = 0;
00713     }
00714 
00715     if (wNoBoardFlag == NO_BOARD)      // are we simulating?
00716     {
00717         lSimDac[nAxis] = lCounts;
00718         return;
00719     }
00720 
00721 //    nCounts = (USHORT) (lCounts + 0x1000); // correct range for DAC
00722 
00723     fOutPW(wBaseAddress + DAC_0 + (nAxis << 1), (unsigned short)lCounts);
00724 };
00725 
00726 /***************************************************************************/
00727 /*                                                                         */
00728 /*                             EncReadAll                                  */
00729 /*                                                                         */
00730 /***************************************************************************/
00731 void EncReadAll(LONGBYTE *lbEnc)
00732 {
00733     WORDBYTE wbTransfer;
00734     unsigned short add;
00735     short i;
00736     int max_axes = wAxesInSys;
00737     unsigned short maxAdd;
00738     if(max_axes != 8)
00739       {
00740         max_axes = 4;
00741       }
00742 
00743 //    static unsigned char byOldByte2[MAX_AXIS];
00744 //    static unsigned char byEncHighByte[MAX_AXIS];
00745 
00746     if (wNoBoardFlag == NO_BOARD)
00747     {
00748         for (i = 0; i < 8; i++)
00749         {
00750             lbEnc[i].Long = lSimEnc[i];
00751         }
00752         return;
00753     }
00754 
00755     // Disable interrupts here?  No, the timer will latch new data in the
00756     // hardware anyway.  Maybe we should stop the timer?  In an interrupt
00757     // service routine, you're synchronized with the timer; so the readings
00758     // will never change while you're reading them.  If you're polling, you
00759     // would first latch the encoder counts with the EncoderLatch() function.
00760     // But, the timer could latch the counts again, in the middle of the read.
00761     // A critical section will help in some extreme cases.
00762 
00763     // reset counter internal addr ptr to point to first byte
00764     maxAdd = (wBaseAddress + ((max_axes>4)?CNT6_C:CNT2_D));
00765     for (add = wBaseAddress + CNT0_C; 
00766          add <= maxAdd;
00767          add +=4)
00768         fOutPW(add, 0x0101);
00769 
00770     for (i = 0; i < 3; i++)            // 24 bits means get 3 bytes each
00771     {
00772         wbTransfer.Word = fInPW(wBaseAddress + CNT0_D);
00773 
00774         lbEnc[0].Byte[i] = wbTransfer.Byte.high;
00775         lbEnc[1].Byte[i] = wbTransfer.Byte.low;
00776 
00777         wbTransfer.Word = fInPW(wBaseAddress + CNT2_D);
00778 
00779         lbEnc[2].Byte[i] = wbTransfer.Byte.high;
00780         lbEnc[3].Byte[i] = wbTransfer.Byte.low;
00781 
00782         if(max_axes >= 8)
00783           {
00784             wbTransfer.Word = fInPW(wBaseAddress + CNT4_D);
00785             
00786             lbEnc[4].Byte[i] = wbTransfer.Byte.high;
00787             lbEnc[5].Byte[i] = wbTransfer.Byte.low;
00788 
00789             wbTransfer.Word = fInPW(wBaseAddress + CNT6_D);
00790             
00791             lbEnc[6].Byte[i] = wbTransfer.Byte.high;
00792             lbEnc[7].Byte[i] = wbTransfer.Byte.low;
00793           }
00794     }
00795 
00796     // maintain the high byte, to extend the counter to 32 bits
00797     //
00798     // base decisions to increment or decrement the high byte
00799     // on the highest 2 bits of the 24 bit value.  To get the
00800     // highest 2 bits, use 0xc0 as a mask on byte [2] (the third
00801     // byte).
00802 
00803     for (i = 0; i < max_axes; i++)
00804     {
00805         // check for -1 to 0 transition
00806 
00807         if (    ( (byOldByte2[i]    & 0xc0) == 0xc0 ) // 11xxxxxx
00808              && ( (lbEnc[i].Byte[2] & 0xc0) == 0 )    // 00xxxxxx
00809            )
00810            byEncHighByte[i]++;
00811 
00812         // check for 0 to -1 transition
00813 
00814         if (    ( (byOldByte2[i]    & 0xc0) == 0 )    // 00xxxxxx
00815              && ( (lbEnc[i].Byte[2] & 0xc0) == 0xc0 ) // 11xxxxxx
00816            )
00817            byEncHighByte[i]--;
00818 
00819         lbEnc[i].Byte[3] = byEncHighByte[i];
00820         byOldByte2[i] = lbEnc[i].Byte[2];    // current byte 2 becomes old one
00821     }
00822 };
00823 
00824 /***************************************************************************/
00825 /*                                                                         */
00826 /*                          ResetIndexLatch(es)                            */
00827 /*                                                                         */
00828 /***************************************************************************/
00829 void ResetIndexLatch()
00830 {
00831     // routine for Model 1
00832 
00833     fInP(wBaseAddress + ODDRST);        //lint !e534 reset index pulse latch for ODD axis
00834     fInP(wBaseAddress + BRDTST);        //lint !e534 reset index pulse latch for EVEN axis
00835 }
00836 
00837 void ResetIndexLatches(unsigned char byLatchBits)
00838 {
00839     // routine for Model 2
00840     fOutP(wBaseAddress + IDL, byLatchBits);
00841 }
00842 
00843 /***************************************************************************/
00844 /*                                                                         */
00845 /*                          SelectIndexAxis                                */
00846 /*                       SelectIndexOrExtLatch                             */
00847 /*                                                                         */
00848 /***************************************************************************/
00849 void SelectIndexAxis(unsigned char byAxis)
00850 {
00851     // routine for Model 1
00852 
00853     // overloaded function.  Use this if you don't need to set polarity
00854 
00855     SelectIndexAxisWithPolarity(byAxis, byIndexPulsePolarity);
00856 }
00857 
00858 void SelectIndexAxisWithPolarity(unsigned char byAxis, unsigned char byPol)
00859 {
00860     // routine for Model 1
00861 
00862     //
00863     // initialize stuff to poll index pulse
00864     //
00865     unsigned char byIntc;
00866 
00867     byIndexPollAxis = byAxis;           // save axis to check later
00868     byIndexPulsePolarity = byPol;       // save polarity as new default
00869     byAxis &= 0x6;                      // ignore low bit, we check 2 axes at a time
00870     byAxis <<= 3;                       // shift into position for IXS1, IXS0
00871     byIntc = fInP(wBaseAddress + INTC); // get a copy of INTC, we'll change
00872                                         // some bits in it, not all
00873     byIntc &= ~(IXLVL | IXS1 | IXS0);   // zero bits for axis and polarity
00874     byIntc |= byAxis;                   // put axes address in INTC
00875     if (byPol != 0)                     // is index pulse active high?
00876         byIntc |= IXLVL;
00877     fOutP(wBaseAddress + INTC, byIntc);
00878 
00879     //    ResetIndexLatch();
00880 
00881     // The latched index pulse should be low now.  If it's not, either something's
00882     // wrong, or we happened to initialize it while the index pulse was active.
00883 }
00884 
00885 void SelectIndexOrExtLatch(unsigned char bySelectBits)
00886 {
00887     // routine for Model 2
00888 
00889     fOutP(wBaseAddress + SELDI, bySelectBits);
00890 }
00891 
00892 void EnableCounterLatchOnIndexOrExt(unsigned char bySelectBits)
00893 {
00894     // routine for Model 2
00895     fOutP(wBaseAddress + IDLEN, bySelectBits);
00896 }
00897 
00898 /***************************************************************************/
00899 /*                                                                         */
00900 /*                             CurrentIRR                                  */
00901 /*                                                                         */
00902 /***************************************************************************/
00903 unsigned char CurrentIRR(void)
00904 {
00905     fOutP(wBaseAddress + OCW3, 0x0a);           // IRR on next read
00906     return fInP(wBaseAddress + IRRreg);
00907 }
00908 
00909 /***************************************************************************/
00910 /*                                                                         */
00911 /*                        (Get)IndexPulseLatch(es)                         */
00912 /*                                                                         */
00913 /***************************************************************************/
00914 unsigned short IndexPulseLatch(void)
00915 {
00916     // routine for Model 1 board
00917 
00918     // poll the latched index pulse of the axis that was previously set up
00919 
00920     unsigned char byIRR, byAxisMask;
00921 
00922     byIRR = CurrentIRR();
00923     byAxisMask = (byIndexPollAxis & 1) ? LIXODD : LIXEVN;  // even or odd axis?
00924     if (byIRR & byAxisMask)                          // check latched index pulse
00925         return 1;
00926     return 0;
00927 
00928     //
00929     // a faster, but messier way
00930     //
00931     //fOutP(wBaseAddress + OCW3, 0x0a);           // IRR on next read
00932     //
00933     //return (   fInP(wBaseAddress + IRR)
00934     //         & ( (byIndexPollAxis & 1) ? LIXODD : LIXEVN ) // mask for even or odd
00935     //       );
00936 }
00937 
00938 unsigned char GetIndexLatches()
00939 {
00940     // routine for Model 2 board
00941 
00942     return fInP(wBaseAddress + IDL);
00943 }
00944 
00945 /***************************************************************************/
00946 /*                                                                         */
00947 /*                                RawDI                                    */
00948 /*                                                                         */
00949 /***************************************************************************/
00950 
00951 // some overloaded functions
00952 
00953 unsigned long RawDIAll()
00954 {
00955     IO32 xInBits;
00956 
00957     if (wNoBoardFlag == NO_BOARD)
00958     {
00959         xInBits.all = 0;
00960         return(xInBits.all);
00961     }
00962 
00963     if (wModel == MODEL1)
00964     {
00965         xInBits.port.A = fInP(wBaseAddress + DIO_A);
00966         xInBits.port.B = fInP(wBaseAddress + DIO_B);
00967         xInBits.port.C = fInP(wBaseAddress + DIO_C);
00968         xInBits.port.D = fInP(wBaseAddress + DIO_D);
00969     }
00970     else  // Model 2
00971     {
00972         xInBits.port.A = fInP(wBaseAddress + PORT_A);
00973         xInBits.port.B = fInP(wBaseAddress + PORT_B);
00974         xInBits.port.C = fInP(wBaseAddress + PORT_C);
00975         xInBits.port.D = fInP(wBaseAddress + PORT_D);
00976     }
00977     return (xInBits.all);
00978 };
00979 
00980 unsigned char RawDIBitPort(unsigned char byBitNumber, short nPort)
00981 {
00982     unsigned char nData;
00983 
00984     if (nPort > 3)
00985         return 0;
00986     if (wModel == MODEL1)
00987         nData = fInP(wBaseAddress + aPortOffset_1[nPort]);
00988     else // Model 2
00989         nData = fInP(wBaseAddress + aPortOffset_2[nPort]);
00990     return nData & (1 << byBitNumber);
00991 }
00992 
00993 unsigned char RawDIPort(short nPort)
00994 {
00995     if (nPort > 3)
00996         return 0;
00997 
00998     if (wModel == MODEL1)
00999         return fInP(wBaseAddress + aPortOffset_1[nPort]);
01000     else
01001         return fInP(wBaseAddress + aPortOffset_2[nPort]);
01002 }
01003 
01004 #if 0
01005 unsigned long RawDIPortBit(long lPort, long lBitNumber)
01006 {
01007     unsigned short wAddOff = 0;
01008     unsigned char bPortBits;
01009 
01010     switch (lPort)
01011     {
01012     case 0: wAddOff = DIO_A;
01013             break;
01014     case 1: wAddOff = DIO_B;
01015             break;
01016     case 2: wAddOff = DIO_C;
01017             break;
01018     case 3: if (wModel == MODEL1)
01019                 wAddOff = DIO_D;
01020             else
01021                 wAddOff = PORT_D;
01022             break;
01023     }
01024     bPortBits = fInP(wBaseAddress + wAddOff);
01025     if ( bPortBits & (1 << lBitNumber) )
01026         return 1;   // true
01027     return 0;       // false
01028 }
01029 #endif
01030 
01031 /***************************************************************************/
01032 /*                                                                         */
01033 /*                                RawDO                                    */
01034 /*                                                                         */
01035 /***************************************************************************/
01036 //
01037 // Overloaded functions:
01038 //    1) takes a 32 bit value and sets all 32 iobits
01039 //    2) takes which bit, which port, and what value, and sets only that bit
01040 //
01041 
01042 void RawDOAll(unsigned long lOutBits)
01043 {
01044     if (wNoBoardFlag == NO_BOARD)
01045     {
01046         return;
01047     }
01048     if (wModel == MODEL1)
01049     {
01050         fOutP(wBaseAddress + DIO_A, ((IO32 *)&lOutBits)->port.A);
01051         fOutP(wBaseAddress + DIO_B, ((IO32 *)&lOutBits)->port.B);
01052         fOutP(wBaseAddress + DIO_C, ((IO32 *)&lOutBits)->port.C);
01053         fOutP(wBaseAddress + DIO_D, ((IO32 *)&lOutBits)->port.D);
01054     }
01055     else  // Model 2
01056     {
01057         fOutP(wBaseAddress + PORT_A, ((IO32 *)&lOutBits)->port.A);
01058         fOutP(wBaseAddress + PORT_B, ((IO32 *)&lOutBits)->port.B);
01059         fOutP(wBaseAddress + PORT_C, ((IO32 *)&lOutBits)->port.C);
01060         fOutP(wBaseAddress + PORT_D, ((IO32 *)&lOutBits)->port.D);
01061     }
01062 };
01063 
01064 void RawDOBitValPort(unsigned char byBitNumber, unsigned char bySet0or1,
01065                       unsigned short nPort)
01066 {
01067     unsigned nOffset;
01068     unsigned char byData;
01069 
01070     if (wNoBoardFlag == NO_BOARD)
01071     {
01072         return;
01073     }
01074 
01075     if (nPort > 3)
01076         return;
01077 
01078     if (wModel == MODEL1)
01079         nOffset = aPortOffset_1[nPort];
01080     else  // Model 2
01081         nOffset = aPortOffset_2[nPort];
01082 
01083     byData = fInP(wBaseAddress + nOffset);
01084     if (bySet0or1 == 1)
01085         byData |= 1 << byBitNumber;
01086     else
01087         byData &= ~(1u << byBitNumber);
01088     fOutP(wBaseAddress + nOffset, byData);
01089 };
01090 
01091 void RawDOBytePort(unsigned char byData, short nPort)
01092 {
01093     if (wNoBoardFlag == NO_BOARD)
01094     {
01095         return;
01096     }
01097 
01098     if (nPort > 3)
01099         return;
01100 
01101     if (wModel == MODEL1)
01102         fOutP(wBaseAddress + aPortOffset_1[nPort], byData);
01103     else  // Model 2
01104         fOutP(wBaseAddress + aPortOffset_2[nPort], byData);
01105 };
01106 
01107 // these next functions use the same constant that the direction functions,
01108 // DioDirection(...) use.  These are prefered, since the same constant can
01109 // be used in both situations, hopefully simplifying the code.
01110 
01111 // helper function
01112 short PortBits2Index(short nPort)
01113 {
01114     int nPortIndex = 9;
01115 
01116     switch(nPort)
01117     {
01118     case STG_PORT_A:
01119         nPortIndex = 0;
01120         break;
01121     case STG_PORT_B:
01122         nPortIndex = 1;
01123         break;
01124     case STG_PORT_C_LO:
01125     case STG_PORT_C_HI:
01126     case STG_PORT_C:
01127         nPortIndex = 2;
01128         break;
01129     case STG_PORT_D_LO:
01130     case STG_PORT_D_HI:
01131     case STG_PORT_D:
01132         nPortIndex = 3;
01133         break;
01134     }
01135     return nPortIndex;
01136 }
01137 
01138 void DigitalOut1(unsigned char byData, short nPortBits)
01139 {
01140     RawDOBytePort(byData, PortBits2Index(nPortBits));
01141 }
01142 
01143 void DigitalOut2(unsigned char byBitNumber, unsigned char bySet0or1,
01144                       unsigned short nPortBits)
01145 {
01146     RawDOBitValPort(byBitNumber, bySet0or1, PortBits2Index(nPortBits));
01147 }
01148 
01149 /***************************************************************************/
01150 /*                                                                         */
01151 /*                            DioDirection                                 */
01152 /*                                                                         */
01153 /***************************************************************************/
01154 //
01155 // Two overloaded functions, the first takes a port and a direction, the
01156 // second takes a word with bits set for the direction of each port
01157 //
01158 void DioDirection1(unsigned short nPortBits, unsigned short nDirection)
01159 {
01160   unsigned short nSwDir;  
01161   // sometimes you want to set the direction of a port, but may not know
01162     // what direction other ports are.  Here we select the port (or ports)
01163     // that we want to set the direction of, in nPortBits.  Then the direction,
01164     // either input or output, with nDirection.
01165     //
01166 
01167     assert(nDirection <= 1);      // direction is either 0 or 1
01168     if (nDirection > 1)
01169         return;
01170 
01171     nSwDir = wSaveDirs;
01172 
01173     if (nDirection == STG_PORT_OUTPUT)
01174         nSwDir |= nPortBits;
01175     else
01176         nSwDir &= ~nPortBits;
01177 
01178     DioDirection2(nSwDir);
01179 }
01180 
01181 
01182 //                                        Don't care.
01183 //                                        |<------>|
01184 // bits in nSwDir set direction of ports: xxxxxxxxxxbbbbbb
01185 //                                                  ||||||
01186 //                                                  |||||Port A
01187 //       1 = Output                                 ||||PortB
01188 //       0 = Input                                  |||Port C, high nibble
01189 //                                                  ||Port C, low nibble
01190 //                                                  |Port D (port D, low nibble)
01191 //                                                  |(Port D, high nibble)
01192 
01193 void DioDirection2(const unsigned short nSwDir)
01194 {
01195     unsigned char byHwDir;                   // direction bits for hardware
01196     unsigned long lCurrentData;
01197 
01198     if (wNoBoardFlag == NO_BOARD)
01199     {
01200         return;
01201     }
01202 
01203     // get the current data in the I/O ports.  We'll replace it when we're
01204     // done.  When you change a port to output, it will start at what the
01205     // input was (usually high).  This way, bits won't change (except for a
01206     // glitch) when a port is set to output.
01207 
01208     lCurrentData = RawDIAll();
01209 
01210     byHwDir = 0x9b;                          // initially all ports input
01211 
01212     if (nSwDir & STG_PORT_A)                 // check the bit for A out
01213          byHwDir &= ~A_DIR_BIT;                  // if output, set bit to 0
01214     if (nSwDir & STG_PORT_B)
01215          byHwDir &= ~B_DIR_BIT;
01216     if (nSwDir & STG_PORT_C_LO)
01217          byHwDir &= ~C_LOW_DIR_BIT;
01218     if (nSwDir & STG_PORT_C_HI)
01219          byHwDir &= ~C_HI_DIR_BIT;
01220 
01221     fOutP(wBaseAddress + ABC_DIR, byHwDir); // set direction for A, B and C
01222 
01223     SetDDir(nSwDir);
01224     wSaveDirs = nSwDir;                     // save, mostly for other function
01225     RawDOAll(lCurrentData);
01226 }
01227 
01228 void SetDDir(unsigned short nSwDir)
01229 {
01230     unsigned char byHwDir;                   // direction bits for hardware
01231     unsigned char bySaveReg, bySaveIMR, bySaveCntrl1, bySaveCntrl0;
01232 
01233     if (wModel == MODEL1)
01234     {
01235         bySaveReg = fInP(wBaseAddress + INTC);   // INTC needs to be saved, because
01236                                                  // MIO_2 reinitializes the 8255 which
01237                                                  // implements the INTC register.
01238         byHwDir = 0x92;                          // initialize port D input
01239         if (nSwDir & STG_PORT_D)                 // is port D output?
01240              byHwDir &= ~D_DIR_BIT;              // if yes, set bit to 0,
01241         bySaveIMR = fInP(wBaseAddress + IMR);    // get the current interrupt mask
01242         fOutP(wBaseAddress + OCW1, 0xff);        // mask off all interrupts
01243         fOutP(wBaseAddress + MIO_2, byHwDir);    // set direction for port D
01244         fOutP(wBaseAddress + INTC, bySaveReg);   // restore interrupt control reg.
01245         fOutP(wBaseAddress + OCW1, bySaveIMR);   // restore interrupt mask
01246     }
01247     else  // Model 2
01248     {
01249         bySaveCntrl0 = fInP(wBaseAddress + CNTRL0); // CNTRL0 needs to be saved, because
01250                                                  // D_DIR reinitializes the 8255 which
01251                                                  // implements the CNTRL0 register.
01252         byHwDir = 0x8b;                          // initialize CNTRL0 as output reg.
01253                                                  // BRDTST to input.
01254                                                  // sets port D, high and low, to input
01255         if (nSwDir & STG_PORT_D_LO)              // low nibble
01256             byHwDir &= ~D_LOW_DIR_BIT;
01257         if (nSwDir & STG_PORT_D_HI)              // high nibble
01258             byHwDir &= ~D_HI_DIR_BIT;
01259 
01260         bySaveCntrl1 = fInP(wBaseAddress+CNTRL1);// save for interrupt enables
01261 
01262             // don't reset any latches; put in slave state;
01263             // disable interrupts, so the glitch in CTRL0 doesn't
01264             // cause an interrupt on wrong irq
01265         fOutP(wBaseAddress + CNTRL1, 0xf0);
01266 
01267         fOutP(wBaseAddress + D_DIR, byHwDir);    // set port D direction
01268 
01269             // restore CNTRL0, because it was re-initialized, which
01270             // lost any previous contents.
01271         fOutP(wBaseAddress + CNTRL0, bySaveCntrl0);
01272 
01273             // re-enable interrupts, and restore slave state, don't
01274             // reset any latches. (1111xxxx)
01275         fOutP(wBaseAddress+CNTRL1, (bySaveCntrl1 & 0x0f) | 0xf0);
01276     }
01277 };
01278 
01279 /***************************************************************************/
01280 /*                                                                         */
01281 /*                               MotSim                                    */
01282 /*                                                                         */
01283 /***************************************************************************/
01284 // a motor simulator
01285 //
01286 // takes it's input from lSimDac[]
01287 // writes it's output to lSimEnc[]
01288 //
01289 // This isn't used in the DOS program, it's only used in the Windows 95 driver
01290 
01291 void MotSim(void)
01292 {
01293     static long lState_1[MAX_AXIS] = {0};                    // state variables
01294     long lScaledUp;
01295     const short nScale = 10;
01296     int nAxis;
01297 
01298     for (nAxis = 0; nAxis < MAX_AXIS; nAxis++)
01299     {
01300         // The input is guaranteed to be +/- 12 bits
01301         // Scale up state so we don't loose resolution
01302         lScaledUp = lSimDac[nAxis] << nScale;
01303 
01304         // note: I assume right shift is sign preserving (for signed value)
01305 
01306         // lag
01307         lState_1[nAxis] += (lScaledUp - lState_1[nAxis]) >> (4 + nAxis); //lint !e704
01308                                                           //   ^^^^^^^ time constant
01309                                                           // is different for each axis
01310 
01311         // integrator (shift out the scale factor and then some)
01312         lSimEnc[nAxis] += lState_1[nAxis] >> (nScale + 1);               //lint !e704
01313     }
01314 }
01315 
01316 void AutoZeroAdc(void)
01317 {
01318     // set the Analog to Digital converter to autozero on each conversion
01319 
01320     if (wModel == MODEL1)
01321         fOutP(wBaseAddress + INTC, fInP(wBaseAddress + INTC) & ~AUTOZERO);
01322     else   // MODEL2
01323         fOutP(wBaseAddress + CNTRL0, fInP(wBaseAddress + CNTRL0) | CNTRL0_AZ);
01324 }
01325 
01326 void DontAutoZeroAdc(void)
01327 {
01328     // set the Analog to Digital converter to NOT autozero
01329 
01330     if (wModel == MODEL1)
01331         fOutP(wBaseAddress + INTC, fInP(wBaseAddress + INTC) | AUTOZERO);
01332     else   // MODEL2
01333         fOutP(wBaseAddress + CNTRL0, fInP(wBaseAddress + CNTRL0) & ~CNTRL0_AZ);
01334 }
01335 
01336 void CalADC(void)
01337 {
01338     // Start calibration cycle on ADC chip
01339 
01340     unsigned char Cntrl0;
01341 
01342     if (wModel == MODEL2)   // this function only in Model 2 board.
01343     {
01344         Cntrl0 = fInP(wBaseAddress + CNTRL0) & 0x07;       // save irq
01345         fOutP(wBaseAddress + CNTRL0, Cntrl0);              // cal is low
01346         // cal pulse should be 60 ns.  The ISA bus is 10 MHz. or 100 ns.
01347         // so we can just set it back high.
01348         fOutP(wBaseAddress + CNTRL0, Cntrl0 | 0x08);       // cal is high
01349     }
01350 }
01351 
01352 /***************************************************************************/
01353 /*                                                                         */
01354 /*                            SetEncoderCounts                             */
01355 /*                                                                         */
01356 /***************************************************************************/
01357 void SetEncoderCounts(unsigned short nAxis, long lCounts)
01358 {
01359     unsigned short wAddress;
01360     char *ByteUnion = (char *)&lCounts;  // get pointer to lCounts, so you
01361                                          // can take it apart byte by byte
01362 
01363     wAddress = wBaseAddress + CNT0_D;
01364     wAddress += (nAxis & 0x6) << 1; // shift to multiply by 2
01365                                     // pairs of data regs seperated by pairs
01366                                     // of control regs, skip over control.
01367     wAddress += nAxis & 1;
01368     fOutP(wAddress, ByteUnion[0]);
01369     fOutP(wAddress, ByteUnion[1]);
01370     fOutP(wAddress, ByteUnion[2]);
01371 
01372     // transfer the preset register to the count register
01373     fOutP(wAddress + 2, 0x09);
01374 
01375     // set things for the part that extends the 24 bit counter
01376     // to 32 bits.
01377     byEncHighByte[nAxis] = ByteUnion[3];
01378     byOldByte2[nAxis] = ByteUnion[2];
01379 }
01380 
01381 /***************************************************************************/
01382 /*                                                                         */
01383 /*                            EncoderLatch                                 */
01384 /*                                                                         */
01385 /***************************************************************************/
01386 void EncoderLatch(void)
01387 {
01388 #if 0
01389   unsigned short wAdd;
01390 #endif
01391     int max_axes = wAxesInSys;
01392     if (wNoBoardFlag == NO_BOARD)
01393     {
01394         return;
01395     }
01396     if(max_axes != 8)
01397       {
01398         max_axes = 4;
01399       }
01400 
01401    // normally you'll have the timer latch the data in hardware, but
01402    // if the timer isn't running, we need to latch it ourselves.
01403 #if 0
01404    for ( wAdd = wBaseAddress + CNT0_C; wAdd <= wBaseAddress + CNT6_C; wAdd +=4)
01405        fOutPW(wAdd, 0x0303);
01406 #endif
01407 
01408   /* BUG FIX-- don't go past 4 axes on 4 axis board */
01409   fOutPW(wBaseAddress + CNT0_C, 0x0303);
01410   fOutPW(wBaseAddress + CNT2_C, 0x0303);
01411   if (max_axes > 4) {
01412     fOutPW(wBaseAddress + CNT4_C, 0x0303);
01413     fOutPW(wBaseAddress + CNT6_C, 0x0303);
01414   }
01415 
01416 };
01417 
01418 /***************************************************************************/
01419 /*                                                                         */
01420 /*                          EncoderResetAddr                               */
01421 /*                                                                         */
01422 /***************************************************************************/
01423 void EncoderResetAddr(void)
01424 {
01425   unsigned short wAdd;
01426 
01427     if (wNoBoardFlag == NO_BOARD)
01428     {
01429         return;
01430     }
01431 
01432    // This function resets all the counter's internal address pointers to point
01433    // to the first byte in the 3 byte sequence
01434 
01435    for (wAdd = wBaseAddress + CNT0_C; wAdd <= wBaseAddress + CNT6_C; wAdd +=4)
01436        fOutPW(wAdd, 0x0101);
01437 };
01438 
01439 unsigned char GetSELDI()
01440 {
01441     return fInP(wBaseAddress + SELDI);
01442 }
01443 
01444 unsigned char GetIDLEN()
01445 {
01446     return fInP(wBaseAddress + IDLEN);
01447 }
01448 
01449 unsigned char GetCNTRL0()
01450 {
01451     return fInP(wBaseAddress + CNTRL0);
01452 }
01453 
01454 unsigned char GetCNTRL1()
01455 {
01456     return fInP(wBaseAddress + CNTRL1);
01457 }
01458 
01459 void ResetWatchdogLatch()
01460 {
01461     unsigned char byCntrl1 = fInP(wBaseAddress + CNTRL1);
01462     byCntrl1 &= ~CNTRL1_WDTOUT;                   //set bit low, to reset
01463     // don't reset other latches
01464     byCntrl1 |= CNTRL1_INT_G2 | CNTRL1_INT_T2 | CNTRL1_INT_T0;
01465     fOutP(wBaseAddress + CNTRL1, byCntrl1);
01466 }
01467 
01468 unsigned char GetBRDTST()
01469 {
01470     return fInP(wBaseAddress + BRDTST);
01471 }
01472 
01473 /***************************************************************************/
01474 /*                                                                         */
01475 /*                            IndexPulse                                   */
01476 /*                                                                         */
01477 /***************************************************************************/
01478 short IndexPulse(void)
01479 {
01480     // poll for the index pulse of the axis that was previously set up.
01481     // Normally you would look at the latched pulse.  This function will
01482     // probably only get used during testing.
01483 
01484     unsigned char byIRR, byAxisMask;
01485 
01486     byIRR = CurrentIRR();
01487     byAxisMask = (byIndexPollAxis & 1) ? IXODD : IXEVN;  // even or odd axis?
01488 
01489     // The raw index pulse isn't inverted by the hardware if the index pulse is
01490     // low active (only the latched pulse is).  For consistancy, we'll invert
01491     // the pulse in software.
01492 
01493     if (byIndexPulsePolarity == 0)                       // if pulse is low true
01494         byIRR ^= byAxisMask;                             // flip bit
01495 
01496     if (byIRR & byAxisMask)                              // check index pulse
01497         return 1;
01498     return 0;
01499 }
01500 
01501 /***************************************************************************/
01502 /*                                                                         */
01503 /*                             StopTimer                                   */
01504 /*                                                                         */
01505 /***************************************************************************/
01506 void StopTimer()
01507 {
01508     if (wNoBoardFlag == NO_BOARD)
01509     {
01510         return;
01511     }
01512 
01513     // stop the timer by putting it into one shot mode, it will never get
01514     // a trigger
01515 
01516     // bug bug this doesn't work
01517 
01518     fOutP(wBaseAddress + TMRCMD, 0x0a);    // timer 0, mode 1
01519 }
01520 
01521 /***************************************************************************/
01522 /*                                                                         */
01523 /*                           Timer2 functions                              */
01524 /*                                                                         */
01525 /***************************************************************************/
01526 void Timer2Delay(unsigned short counts)
01527 {
01528     if (wNoBoardFlag == NO_BOARD)
01529     {
01530         return;
01531     }
01532 
01533     StartTimer2TerminalCount(counts);
01534 
01535     while (PollTimer2());
01536 }
01537 
01538 void StartTimer2TerminalCount(unsigned short count)
01539 {
01540   char *pByte;
01541    if (wNoBoardFlag == NO_BOARD)
01542    {
01543        return;
01544    }
01545 
01546    pByte = (char *)&count;
01547    fOutP(wBaseAddress + TMRCMD, 0xb0);       // timer 2, read/load LSB followed
01548                                              // by MSB, mode 0 (terminal count)
01549    fOutP(wBaseAddress + TIMER_2, *pByte++);  // LSB (little endian)
01550    fOutP(wBaseAddress + TIMER_2, *pByte);    // MSB
01551 }
01552 
01553 void StartTimer2RTI(unsigned short count)
01554 {
01555   char *pByte;
01556    if (wNoBoardFlag == NO_BOARD)
01557    {
01558        return;
01559    }
01560 
01561    pByte = (char *)&count;
01562    fOutP(wBaseAddress + TMRCMD, 0xb4);       // timer 2, read/load LSB followed
01563                                              // by MSB, mode 2 (real time int).
01564    fOutP(wBaseAddress + TIMER_2, *pByte++);  // LSB (little endian)
01565    fOutP(wBaseAddress + TIMER_2, *pByte);    // MSB
01566 }
01567 
01568 unsigned short ReadTimer2TerminalCount(void)
01569 {
01570     unsigned short count;
01571     char *pByte = (char *)&count;
01572     fOutP(wBaseAddress + TMRCMD, 0x80);       // timer 2, latch
01573     *pByte++ = fInP(wBaseAddress + TIMER_2);  // LSB
01574     *pByte   = fInP(wBaseAddress + TIMER_2);  // MSB
01575     return count;
01576 }
01577 
01578 short PollTimer2(void)
01579 {
01580     if (wNoBoardFlag == NO_BOARD)
01581     {
01582         return 0;
01583     }
01584 
01585     if (wModel == MODEL1)
01586         return !(CurrentIRR() & TP2);  // mask selects bit for TP2
01587     else   // MODEL 2
01588     {
01589         unsigned char byRegCntrl1, byNewCntrl1;
01590 
01591         byRegCntrl1 = fInP(wBaseAddress + CNTRL1);
01592         if (byRegCntrl1 & CNTRL1_INT_T2)
01593         {
01594             // If it's set, we want to reset the latch, by writing a zero
01595             // to CNTRL1_INT_T2.
01596 
01597             // When we write to CNTRL1, we don't want to change SLAVE, IEN_G2
01598             // IEN_T2, or IEN_T0 -- the lower 4 bits.  So, we start with
01599 
01600             byNewCntrl1 = byRegCntrl1 & 0x0f;     // (0000xxxx)
01601 
01602             // We don't want to reset WDTOUT, INT_G2, or INT_T0--we only want
01603             // to reset ...T2. (1101xxxx)
01604 
01605             byNewCntrl1 |= CNTRL1_WDTOUT | CNTRL1_INT_G2 | CNTRL1_INT_T0;
01606 
01607             fOutP(wBaseAddress + CNTRL1, byNewCntrl1);  // reset bit
01608 
01609             return 1;  // true
01610         }
01611     }
01612     return 0;      // false
01613 }
01614 
01615 void MaskTimer2Interrupt()
01616 {
01617     if (wNoBoardFlag == NO_BOARD)
01618     {
01619         return;
01620     }
01621 
01622     if (wModel == MODEL1)
01623         fOutP(wBaseAddress + OCW1, CurrentIRR() | TP2);
01624     else   // Model 2
01625         // we want to save the state of the slave mode, and set the
01626         // high nibble bits high, so you don't reset any latches.
01627         // bit pattern: 1111x000  where x is don't change
01628         fOutP(wBaseAddress + CNTRL1,
01629             (fInP(wBaseAddress + CNTRL1) & CNTRL1_NOT_SLAVE) | 0xf0);
01630 }
01631 
01632 void UnMaskTimer2Interrupt()
01633 {
01634     if (wModel == MODEL1)
01635         fOutP(wBaseAddress + OCW1, CurrentIRR() & ~TP2);
01636     else   // Model 2
01637     {
01638         // we want to save the state of the slave mode, and set the
01639         // high nibble bits high, so you don't reset any latches.
01640         // bit pattern: 1111x010 where x is don't change
01641         fOutP(wBaseAddress + CNTRL1,
01642             (fInP(wBaseAddress + CNTRL1) & CNTRL1_NOT_SLAVE) | CNTRL1_IEN_T2);
01643     }
01644 }
01645 
01646 /***************************************************************************/
01647 /*                                                                         */
01648 /*                           StartInterrupts                               */
01649 /*                                                                         */
01650 /***************************************************************************/
01651 void StartInterrupts(void)
01652 {
01653     if (wNoBoardFlag == NO_BOARD)
01654     {
01655         return;
01656     }
01657     if (wModel == MODEL1)
01658         fOutP(wBaseAddress + OCW1, ~0x04);   // enable interrupt for timer 0
01659     else  // MODEL2
01660         // we want to save the state of the slave mode, and set the
01661         // high nibble bits high, so you don't reset any latches.
01662         // 1111x001, where x means don't change
01663     {
01664         fOutP(wBaseAddress + CNTRL1, CNTRL1_IEN_T0 | CNTRL1_NOT_SLAVE);
01665     }
01666 };
01667 
01668 /***************************************************************************/
01669 /*                                                                         */
01670 /*                           StopInterrupts                                */
01671 /*                                                                         */
01672 /***************************************************************************/
01673 void  StopInterrupts(void)
01674 {
01675     if (wNoBoardFlag == NO_BOARD)
01676     {
01677         return;
01678     }
01679     if (wModel == MODEL1)
01680         fOutP(wBaseAddress + OCW1, 0xff);     // disable all interrupts
01681     else  // MODEL2
01682         // we want to save the state of the slave mode, and set the
01683         // high nibble bits high, so you don't reset any latches.
01684         // disable all interrupts, since only one can be enabled at
01685         // a time (currently).  If more than one was enabled, it's
01686         // an error (currently).
01687         // 1111x000, where x means not changed.
01688         fOutP(wBaseAddress + CNTRL1,
01689             (fInP(wBaseAddress + CNTRL1) & CNTRL1_NOT_SLAVE) | 0xf0);
01690 };
01691 
01692 

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