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

pmac.cc

Go to the documentation of this file.
00001 
00002 static char sccsid[] = "@(#) pmac.c 1.32@(#)";
00003 
00004 /*
00005   Utility functions for reading and writing PMAC dual-ported RAM.
00006   This code is intended for use with 386/486 PC's and a POSIX OS,
00007   such as Lynx.  The code assumes 4-byte integers in Intel format.
00008 
00009   Modification history:
00010 
00011    6-Nov-1996 WPS edited to shorten startup time on Windows NT.
00012   27-Sep-1996  FMP added write_pmac_uint32 (it was left out)
00013   20-Jun-1996  Fred Proctor changed return val in pmac_writemsg debug
00014   from 0 to PMAC_ACK.
00015   14-Nov-1995  Fred Proctor added probing code
00016   13-Nov-1995  Fred Proctor reworked for 8 axes with better DPRAM mapping
00017   6-Oct-1995  Fred Proctor added TBUF transformation initialization
00018   to pmac_program().
00019   28-Jul-1995  Fred Proctor took out val = -val, for pmac_spindle_speed()
00020   20-Jul-1995  Fred Proctor added pmac_target_pos()
00021   18-Jul-1995  Fred Proctor added pmac_reset()
00022   24-Mar-1995 Sandor Szabo added pmac.c specific macros from pmac.h
00023   into pmac.c.  This will minimize recompiles to *.cc files when low
00024   level changes made to pmac.c (e.g., changing PMAC_IO_ADDR).
00025   Added newer DP RAM messaging code.
00026   22-Mar-1995  Fred Proctor added $$$ to pmac_exit(), in order to clear
00027   out any lingering effects of the controller on the PMAC
00028   15-Mar-1995  Fred Proctor out pmac_enable,disable_spindle() in;
00029   upped rotary buffer size to 8192
00030   26-Feb-1995  Fred Proctor changed DEBUG to DEBUG_PMAC
00031   15-Feb-1995  Fred Proctor added pmac_print_error()
00032   10-Feb-1995  Fred Proctor 10x'ed TIMEOUT for pmac waits-- the
00033   time appeared to need increasing with the ICS backplane and CPU.
00034   26-Jan-1995  Fred Proctor ifdef DEBUG'ed out all pmac dpram calls,
00035   so that everything will compile in DEBUG mode. Checked 'pmac' ptr
00036   for non-NULL at every access, so that it will automatically init
00037   itself-- now calls to pmac_init() need not appear in user code.
00038   21-Dec-1994  Fred Proctor removed pcioInit() call
00039   23-Sep-1994  Fred Proctor moved utility functions for program running,
00040   etc. (pmac_sendstring() and all functions after that) into this file,
00041   from hme and servo. Added debug flag so that this code can now be
00042   used in non-Lynx programs (functions that require the PMAC hardware,
00043   e.g., pmac_read/write*, aren't provided for debug).
00044   */
00045 
00046 #ifndef rtlinux
00047 #include "rcs.hh"               /* WIN32, class PHYSMEM_HANDLE, rcs_print_error */
00048 #else
00049 
00050 #include "physmem.hh"
00051 
00052 
00053 #endif
00054 
00055 
00056 
00057 
00058 
00059 #include "pmac.h"
00060 
00061 #ifdef lynxosPC
00062 extern "C" {
00063 #include "pcioDrv.h"            // inportb, outportb
00064 }
00065 #endif
00066 
00067 #ifdef linux
00068 #include <asm/io.h>             // inb, outb
00069 #endif
00070 
00071 /* #define PMAC_PROM_V1_13 1     uncomment to run old version pmac proms */
00072 
00073 #ifndef PMAC_PROM_V1_13
00074 #define PMAC_MSG_BASE 0x600     /* base location in dpram for ascii com */
00075 #endif
00076 
00077 static unsigned int PMAC_BASE_ADDR = 0xD0000;
00078 static unsigned int PMAC_IO_ADDR = 0x210;
00079 
00080 /* suggested parameters for single 8K dual-ported RAM in PC bus */
00081 
00082 #define PMAC_NAME "pmac"
00083 #define PMAC_DPRAM_SIZE ((long) 0x4000) /* 16K bytes = 8K 16-bit DP RAM */
00084 #define PMAC_IO_SIZE    ((long) 0x8) /* 8 bytes of IO space. */
00085 #define PMAC_RESERVED 0x800     /* 2K reserved for future use */
00086 
00087 #define PMAC_IO_SPEED 9         /* speed factor for 486-66; see PMAC
00088                                    manual, v. 1.13, p. 3-189 */
00089 
00090 #define PMAC_LAST_CHAR (PMAC_SIZE - PMAC_RESERVED - PMAC_MSG_LEN - 4 - 1)
00091 #define PMAC_LAST_SHORT ((PMAC_SIZE - PMAC_RESERVED - PMAC_MSG_LEN - 4) / sizeof(short) - 1)
00092 #define PMAC_LAST_INT ((PMAC_SIZE - PMAC_RESERVED - PMAC_MSG_LEN - 4) / sizeof(int) - 1)
00093 #define PMAC_LAST_FLOAT ((PMAC_SIZE - PMAC_RESERVED - PMAC_MSG_LEN - 4) / sizeof(float) - 1)
00094 
00095 #if !defined(lynxosPC) && !defined(WIN32)
00096 #define DEBUG_PMAC                      /* all non-Lynx platforms must use
00097                                            debug version (no PMAC hardware) */
00098 #endif
00099 
00100 #ifdef DEBUG_PMAC
00101 
00102 #include <stdio.h>
00103 #include <errno.h>
00104 
00105 #endif
00106 
00107 PHYSMEM_HANDLE *pmac_dpram_handle=NULL;
00108 PHYSMEM_HANDLE *pmac_io_handle=NULL;
00109 
00110 #define TIMEOUT 100*PMAC_IO_SPEED*100 /* timeout for bus port wait-- see
00111                                        PMAC manual, v1.13, p. 3-191 */
00112 
00113 static int sendchar(char c, int timeout);
00114 static PMAC_RETURN_VAL getline(char *, int);
00115 static PMAC_RETURN_VAL sendline(const char *line, int timeout);
00116 
00117 #define ACK 6
00118 #define BELL 7
00119 #define LF 10
00120 #define CR 13
00121 #define CTRL_X 24
00122 
00123 #define PMAC_DATA_BASE_OFFSET (0x800 + 4 + PMAC_MSG_LEN)
00124 
00125 
00126 void pmac_outportb(unsigned long port, char byte)
00127 {
00128 #if defined(lynxosPC)
00129         outportb(port, byte);
00130 #else
00131 #if defined(linux)
00132        outb(byte, port);
00133 #else
00134         if(NULL != pmac_io_handle)
00135         {
00136                 pmac_io_handle->offset =  port - PMAC_IO_ADDR;
00137                 pmac_io_handle->write(&byte, 1);
00138         }
00139 #endif
00140 #endif
00141 }
00142 
00143 char pmac_inportb(unsigned long port)
00144 {
00145         char byte;
00146 #if defined(lynxosPC)
00147         byte = inportb(port);
00148 #else
00149 #if defined(linux)
00150         byte = inb(port);
00151 #else
00152         if(NULL != pmac_io_handle)
00153         {
00154                 pmac_io_handle->offset =  port - PMAC_IO_ADDR;
00155                 pmac_io_handle->read(&byte, 1);
00156         }
00157 #endif
00158 #endif
00159         return byte;
00160 }
00161 
00162 static int pmac_initialized = 0;
00163 
00164 void pmac_init()
00165 {
00166 #ifndef DEBUG_PMAC
00167  char reply[PMAC_MSG_LEN];
00168 
00169  if(pmac_initialized)
00170  {
00171    return;
00172  }
00173 
00174  if(NULL == pmac_io_handle)
00175  {
00176   pmac_io_handle = new PHYSMEM_HANDLE(PMAC_IO_ADDR, NT_ISA_IO_ADDRESS, PMAC_IO_SIZE);
00177   if(NULL == pmac_io_handle)
00178   {
00179 #ifndef rtlinux
00180     rcs_print_error( "can't get PMAC IO\n");
00181 #endif
00182     return;
00183   }
00184   if(!pmac_io_handle->valid())
00185   {
00186 #ifndef rtlinux
00187     rcs_print_error( "can't get PMAC IO\n");
00188 #endif
00189     return;
00190   }
00191  }
00192   /* clear serial registers */
00193   pmac_outportb(PMAC_IO_ADDR+5, 0);
00194   pmac_outportb(PMAC_IO_ADDR+6, 0);
00195 
00196    /* read any chars from port-- ignore any timeout status since
00197      it will probably time out */
00198 #ifndef WIN32
00199   getline(reply, TIMEOUT);
00200 #else
00201  getline(reply, TIMEOUT/10);
00202 #endif
00203 
00204   if(NULL == pmac_dpram_handle)
00205   {
00206         pmac_dpram_handle = new PHYSMEM_HANDLE(PMAC_BASE_ADDR, NT_ISA_MEM_ADDRESS, PMAC_DPRAM_SIZE);
00207         if(NULL == pmac_dpram_handle)
00208         {
00209 #ifndef rtlinux
00210                 rcs_print_error( "can't get PMAC DP RAM\n");
00211 #endif
00212                 return;
00213         }
00214         if(!pmac_dpram_handle->valid())
00215         {
00216 #ifndef rtlinux
00217                 rcs_print_error( "can't get PMAC DP RAM\n");
00218 #endif
00219                 return;
00220         }
00221   }
00222 
00223   /* put it in online mode */
00224   (void) pmac_online();
00225    pmac_initialized = 1;
00226 #endif
00227 }
00228 
00229 void pmac_exit()
00230 {
00231 #ifndef DEBUG_PMAC
00232   pmac_initialized = 0;
00233  if(NULL != pmac_dpram_handle)
00234   {
00235          delete pmac_dpram_handle;
00236          pmac_dpram_handle = NULL;
00237   }
00238   if(NULL != pmac_io_handle)
00239   {
00240           delete pmac_io_handle;
00241           pmac_io_handle = NULL;
00242   }
00243 
00244 #endif
00245 }
00246 
00247 static int pmac_dpram_error_message_sent = 0;
00248 
00249 /*
00250   Read contents of dual-ported RAM as a character,
00251   8 bits on LynxOS/386.
00252 
00253   base is a pointer, pmac_get() <= base < size;
00254   index is number of characters up from base.
00255 
00256   Returns unsigned char found at indexed location.
00257   */
00258 PMAC_UINT8 read_pmac_uint8(int index)
00259 {
00260 #ifdef DEBUG_PMAC
00261   return 0;
00262 #else
00263   PMAC_UINT8 byte;
00264   if(NULL == pmac_dpram_handle)
00265   {
00266           pmac_init();
00267   }
00268   if(NULL == pmac_dpram_handle)
00269   {
00270           if(!pmac_dpram_error_message_sent)
00271           {
00272 #ifndef rtlinux
00273                   rcs_print_error("Can't read from PMAC's dual-ported RAM.\n");
00274 #endif
00275           }
00276           pmac_dpram_error_message_sent=1;
00277           return 0;
00278   }
00279   pmac_dpram_handle->offset = PMAC_DATA_BASE_OFFSET + index;
00280   pmac_dpram_handle->read(&byte, 1);
00281   return byte;
00282 #endif
00283 }
00284 
00285 /*
00286   Write a character into dual-ported RAM,
00287   8 bits on LynxOS/386.
00288 
00289   base is a pointer, pmac_get() <= base < size;
00290   index is number of characters up from base.
00291   val is unsigned char to write at indexed location.
00292   */
00293 void write_pmac_uint8(int index, PMAC_UINT8 val)
00294 {
00295 #ifdef DEBUG_PMAC
00296   return;
00297 #else
00298  if(NULL == pmac_dpram_handle)
00299   {
00300           pmac_init();
00301   }
00302   if(NULL == pmac_dpram_handle)
00303   {
00304           if(!pmac_dpram_error_message_sent)
00305           {
00306 #ifndef rtlinux
00307                   rcs_print_error("Can't write to PMAC's dual-ported RAM.\n");
00308 #endif
00309           }
00310           pmac_dpram_error_message_sent=1;
00311           return;
00312   }
00313   pmac_dpram_handle->offset = PMAC_DATA_BASE_OFFSET + index;
00314   pmac_dpram_handle->write(&val, 1);
00315 #endif
00316 }
00317 
00318 /*
00319   Read contents of dual-ported RAM as a short integer,
00320   16 bits on LynxOS/386.
00321 
00322   base is a pointer, pmac_get() <= base < size;
00323   index is number of short integers up from base.
00324 
00325   Returns unsigned short found at indexed location.
00326   */
00327 PMAC_UINT16 read_pmac_uint16(int index)
00328 {
00329 #ifdef DEBUG_PMAC
00330   return 0;
00331 #else
00332   PMAC_UINT16 retval;
00333  if(NULL == pmac_dpram_handle)
00334   {
00335           pmac_init();
00336   }
00337   if(NULL == pmac_dpram_handle)
00338   {
00339           if(!pmac_dpram_error_message_sent)
00340           {
00341 #ifndef rtlinux
00342                   rcs_print_error("Can't read from PMAC's dual-ported RAM.\n");
00343 #endif
00344           }
00345           pmac_dpram_error_message_sent=1;
00346           return 0;
00347   }
00348   pmac_dpram_handle->offset = PMAC_DATA_BASE_OFFSET + index*2;
00349   pmac_dpram_handle->read(&retval, 2);
00350   return retval;
00351 #endif
00352 }
00353 
00354 /*
00355   Write a short integer into dual-ported RAM,
00356   16 bits on LynxOS/386.
00357 
00358   base is a pointer, pmac_get() <= base < size;
00359   index is number of short integers up from base.
00360   val is unsigned short integer to write at indexed location.
00361   */
00362 void write_pmac_uint16(int index, PMAC_UINT16 val)
00363 {
00364 #ifdef DEBUG_PMAC
00365   return;
00366 #else
00367  if(NULL == pmac_dpram_handle)
00368   {
00369           pmac_init();
00370   }
00371   if(NULL == pmac_dpram_handle)
00372   {
00373           if(!pmac_dpram_error_message_sent)
00374           {
00375 #ifndef rtlinux
00376                   rcs_print_error("Can't write to PMAC's dual-ported RAM.\n");
00377 #endif
00378           }
00379           pmac_dpram_error_message_sent=1;
00380           return;
00381   }
00382   pmac_dpram_handle->offset = PMAC_DATA_BASE_OFFSET + index*2;
00383   pmac_dpram_handle->write(&val, 2);
00384 #endif
00385 }
00386 
00387 /*
00388   Read contents of dual-ported RAM as an integer,
00389   32 bits on LynxOS/386.
00390 
00391   base is a pointer, pmac_get() <= base < size;
00392   index is number of integers up from base.
00393 
00394   Returns unsigned integer found at indexed location.
00395   */
00396 PMAC_UINT32 read_pmac_uint32(int index)
00397 {
00398 #ifdef DEBUG_PMAC
00399   return 0;
00400 #else
00401   PMAC_UINT16 lo, hi;
00402   PMAC_UINT32 retval;
00403 
00404   lo = read_pmac_uint16(index*2);
00405   hi = read_pmac_uint16(index*2+1);
00406   retval = ((PMAC_UINT32)hi << 16) + lo;
00407   return retval;
00408 #endif
00409 }
00410 
00411 /*
00412   Write an integer into dual-ported RAM,
00413   32 bits on LynxOS/386.
00414 
00415   base is a pointer, pmac_get() <= base < size;
00416   index is number of integers up from base.
00417   val is unsigned integer to write at indexed location.
00418   */
00419 void pmac_writeint(int index, unsigned int val)
00420 {
00421 #ifdef DEBUG_PMAC
00422   return;
00423 #else
00424   PMAC_UINT16 lo, hi;
00425 
00426 
00427   lo = (unsigned short) (val & 0x0000FFFF);
00428   hi = (unsigned short) ((val & 0xFFFF0000) >> 16);
00429 
00430   write_pmac_uint16( index*2,   lo);
00431   write_pmac_uint16( index*2+1, hi);
00432 #endif
00433 }
00434 
00435 void write_pmac_uint32(int index, PMAC_UINT32 val)
00436 {
00437   pmac_writeint(index, (unsigned int) val);
00438 }
00439 
00440 /*
00441   Read contents of dual-ported RAM as a float,
00442   32 bits on LynxOS/386.
00443 
00444   base is a pointer, pmac_get() <= base < size;
00445   index is number of floats up from base.
00446 
00447   Returns float found at indexed location.
00448   */
00449 float pmac_readfloat(int index)
00450 {
00451 #ifdef DEBUG_PMAC
00452   return 0;
00453 #else
00454   PMAC_UINT16 lo, hi;
00455   PMAC_UINT32 temp32;
00456 
00457 
00458   lo = read_pmac_uint16(2*index);
00459   hi = read_pmac_uint16(2*index+1);
00460 
00461   temp32 = (hi << 16) + lo;
00462   return *((float *) &temp32);
00463 #endif
00464 }
00465 
00466 /*
00467   Write a float into dual-ported RAM,
00468   32 bits on LynxOS/386.
00469 
00470   base is a pointer, pmac_get() <= base < size;
00471   index is number of floats up from base.
00472   val is float to write at indexed location.
00473   */
00474 void pmac_writefloat(int index, float val)
00475 {
00476 #ifdef DEBUG_PMAC
00477   return;
00478 #else
00479   PMAC_UINT16 lo, hi;
00480 
00481   lo = (unsigned short) (*((unsigned int *) &val) & 0x0000FFFF);
00482   hi = (unsigned short) ((*((unsigned int *) &val) & 0xFFFF0000) >> 16);
00483 
00484   write_pmac_uint16(index*2,lo);
00485   write_pmac_uint16(index*2+1,hi);
00486 #endif
00487 }
00488 
00489 
00490 
00491 
00492 static int write_ready()
00493 {
00494 #ifndef DEBUG_PMAC
00495   /* is bit 2 of addr+2 set? if so, return 1, else return 0 */
00496   return pmac_inportb(PMAC_IO_ADDR+2) & 2 ? 1 : 0;
00497 #else
00498   return 1;
00499 #endif
00500 }
00501 
00502 static int read_ready()
00503 {
00504 #ifndef DEBUG_PMAC
00505   /* is bit 1 of addr+2 set? if so, return 1, else return 0 */
00506   return pmac_inportb(PMAC_IO_ADDR+2) & 1 ? 1 : 0;
00507 #else
00508   return 1;
00509 #endif
00510 }
00511 
00512 static int sendchar(char outchar, int timeout)
00513 {
00514 #ifndef DEBUG_PMAC
00515   int i = 0;
00516 
00517   while (i++ < timeout && !write_ready())
00518     ;
00519   if (i < timeout)
00520   {
00521     pmac_outportb(PMAC_IO_ADDR+7, outchar);
00522     return 0;
00523   }
00524   return -1;
00525 #else
00526   return 0;
00527 #endif
00528 }
00529 
00530 static PMAC_RETURN_VAL sendline(const char *line, int timeout)
00531 {
00532 #ifndef PMAC_DEBUG
00533   int i = 0;
00534 
00535   while (line[i] != 0)
00536   {
00537     if (-1 == sendchar(line[i++], timeout))
00538       return PMAC_WRITE_TIMEOUT;
00539   }
00540   if (-1 == sendchar(13, timeout))
00541     return PMAC_WRITE_TIMEOUT;
00542 
00543   return PMAC_ACK;
00544 #else
00545   return PMAC_ACK;
00546 #endif
00547 }
00548 
00549 /* set I3=2 for this to work. The default, I3=1, will result in the
00550    first char of replies being LF. The reply will be blank, and the
00551    return value of pmac_writemsg will be PMAC_INVALID_COMM_PARAMS.
00552    */
00553 static PMAC_RETURN_VAL getline(char *linebuf, int timeout)
00554 {
00555 #ifdef DEBUG_PMAC
00556   return PMAC_ACK;
00557 #else
00558 
00559   char ic;
00560   int timer, nc;
00561   PMAC_RETURN_VAL retval = PMAC_ACK;
00562 
00563   ic = nc = timer = 0;
00564   for (;;)
00565   {
00566     if (read_ready())
00567     {
00568       ic = pmac_inportb(PMAC_IO_ADDR+7);
00569       timer = 0;
00570 
00571       /* check for -1-- this is an error */
00572       if (ic == -1)
00573       {
00574         retval = PMAC_INVALID_COMM_PARAMS;
00575         break;
00576       }
00577 
00578       /* check for ACK-- break if found */
00579       if (ic == ACK)
00580       {
00581         /* if message overran, then retval was set to
00582            PMAC_BUF_TOO_SMALL. If it's a normal message
00583            termination, then retval will be PMAC_ACK, as it was
00584            initialized to. Just break in either case. */
00585         break;
00586       }
00587 
00588       /* check for LF-- PMAC is in an invalid comm setup if
00589          so (I3 is probably the default, 1) */
00590       if (ic == LF)
00591       {
00592         retval = PMAC_INVALID_COMM_PARAMS;
00593         break;
00594       }
00595 
00596       /* check for BELL error-- if so, reset message and wait for
00597          CR */
00598       if (ic == BELL)
00599       {
00600         /* now need to wait 'til following CR--  reset everything*/
00601         retval = PMAC_ERR;
00602         continue;               /* keep going for the CR */
00603       }
00604 
00605       /* check for CR-- this will normally just pass through and
00606          not stop us. When there's been an error, this is the
00607          final char */
00608       if (ic == CR && retval == PMAC_ERR)
00609       {
00610         /* error message done */
00611         break;
00612       }
00613 
00614       /* wrap around any message overrun */
00615       if (nc >= PMAC_MSG_LEN-1)
00616       {
00617         retval = PMAC_BUF_TOO_SMALL;
00618         continue;               /* so we get it all out */
00619       }
00620 
00621       /* got here-- it's a data char */
00622       linebuf[nc++] = ic;
00623       continue;
00624     }
00625     else
00626     {
00627       /* not ready for read */
00628       if (timer++ >= timeout)
00629       {
00630         retval = PMAC_TIMEOUT;
00631         break;
00632       }
00633     }
00634   }
00635 
00636   /* null-terminate response */
00637   linebuf[nc++] = 0;
00638 
00639   return retval;
00640 
00641 #endif                          /* not DEBUG_PMAC */
00642 }
00643 
00644 static PMAC_RETURN_VAL pmac_writemsg_bus(const char *msg, char *reply, int len)
00645 {
00646 #ifndef DEBUG_PMAC
00647 
00648   int timeout = 10*700*PMAC_IO_SPEED;
00649   PMAC_RETURN_VAL retval;
00650 
00651   /* send this message */
00652   if ((retval = sendline(msg, timeout)) != PMAC_ACK)
00653     return retval;
00654 
00655   /* wait for reply */
00656   return getline(reply, timeout);
00657 #else
00658   return PMAC_ACK;
00659 
00660 #endif
00661 }
00662 
00663 /* select which version of comm you want:
00664    pmac_writemsg_v13
00665    pmac_writemsg_v15
00666    pmac_writemsg_bus
00667    */
00668 PMAC_RETURN_VAL pmac_writemsg(const char *msg, char *reply, int len)
00669 {
00670 #ifdef DEBUG_PMAC
00671   printf("%s\n", msg);
00672   return PMAC_ACK;
00673 #else
00674   return pmac_writemsg_bus(msg, reply, len);
00675 #endif
00676 }
00677 
00678 /* resets the PMAC to EEPROM settings */
00679 PMAC_RETURN_VAL pmac_reset()
00680 {
00681   int timeout = 10*700*PMAC_IO_SPEED;
00682 
00683 #if defined(lynxosPC) || defined(linux)
00684   if (NULL == pmac_io_handle)
00685     return PMAC_ERR;
00686 #endif
00687 
00688   /* send $$$ */
00689   return sendline("$$$", timeout);
00690 }
00691 
00692 /* pmac_sendstring assumes that PMAC has been initialized elsewhere */
00693 int pmac_sendstring(const char *string)
00694 {
00695 #ifdef DEBUG_PMAC
00696   printf("%s\n", string);
00697   return 0;
00698 #else
00699   int dperr;
00700   char reply[PMAC_MSG_LEN];
00701 
00702 #if defined(lynxosPC) || defined(linux)
00703   /* check for valid pmac address */
00704   if (NULL == pmac_io_handle)
00705   {
00706     /* PMAC not initialized-- init it */
00707     pmac_init();
00708   }
00709 #endif
00710 
00711   /* send it out */
00712   if ((dperr =  pmac_writemsg(string, reply, PMAC_MSG_LEN)) != PMAC_ACK)
00713   {
00714     /* something went wrong with the write */
00715     pmac_print_error(dperr, reply);
00716 #ifndef rtlinux
00717     rcs_print_error( "command is %s\n", string);
00718 #endif
00719     return -1;
00720   }
00721   else
00722   {
00723     /* command went okay */
00724     return 0;
00725   }
00726 #endif
00727 }
00728 
00729 #ifdef DEBUG_PMAC
00730 /* current pmac state */
00731 static int pmac_online_state;
00732 #endif
00733 
00734 /* put the PMAC in online mode */
00735 int pmac_online()
00736 {
00737   /* abort any programs */
00738   if (-1 == pmac_sendstring("A")) /* abort any prog */
00739     return -1;
00740   /* close any buffer */
00741   if (-1 == pmac_sendstring("CLOSE")) /* close any buffer */
00742     return -1;
00743   /* delete any rotary programs */
00744   if (-1 == pmac_sendstring("DELETE ROT")) /* delete any rot buffer */
00745     return -1;
00746 
00747   return 0;
00748 }
00749 
00750 /* put the PMAC in program mode */
00751 int pmac_program()
00752 {
00753   /* abort any programs */
00754   if (-1 == pmac_sendstring("A")) /* abort any prog */
00755     return -1;
00756   /* close any open buffers */
00757   if (-1 == pmac_sendstring("CLOSE"))
00758     return -1;
00759   /* delete any rotary buffers */
00760   if (-1 == pmac_sendstring("DELETE ROT"))
00761     return -1;
00762   /* define the transformation matrix */
00763   if (-1 == pmac_sendstring("DEFINE TBUF 1"))
00764     return -1;
00765   /* define a rotary buffer */
00766   if (-1 == pmac_sendstring("DEFINE ROT 8192"))
00767     return -1;
00768   /* start the rotary buffer */
00769   if (-1 == pmac_sendstring("B0")) /* position rot buff at beginning */
00770     return -1;
00771   if (-1 == pmac_sendstring("OPEN ROT")) /* open it up */
00772     return -1;
00773   if (-1 == pmac_sendstring("R")) /* start running any motions */
00774     return -1;
00775   /* select the transformation matrix */
00776   if (-1 == pmac_sendstring("TSEL 1"))
00777     return -1;
00778   /* initialize the transformation matrix */
00779   if (-1 == pmac_sendstring("TINIT"))
00780     return -1;
00781   if (-1 == pmac_sendstring("ADIS 1")) /* Q1, Q2, and Q3 */
00782     return -1;
00783 
00784   return 0;
00785 }
00786 
00787 /* Returns 1 if the axis is in position, 0 if it is not, or -1
00788    if there is an error (bad axis number) */
00789 int pmac_in_position(int axis)
00790 {
00791 #ifdef DEBUG_PMAC
00792   return 1;                     /* always in position in simulation */
00793 #else
00794   int ipos;
00795 
00796   /* set up the ipos index into DP RAM */
00797   switch (axis) {
00798   case 1:
00799     ipos = IPOS_1;
00800     break;
00801   case 2:
00802     ipos = IPOS_2;
00803     break;
00804   case 3:
00805     ipos = IPOS_3;
00806     break;
00807   case 4:
00808     ipos = IPOS_4;
00809     break;
00810   default:
00811     return 1;
00812   }
00813 
00814   if (read_pmac_uint32(ipos) == 1)
00815     return 1;
00816   return 0;
00817 #endif
00818 }
00819 
00820 /* Returns 1 if the axis is at home, 0 if it is not, or -1
00821    if there is an error (bad axis number) */
00822 int pmac_at_home(int axis)
00823 {
00824 #ifdef DEBUG_PMAC
00825   return 1;                     /* always at home in simulation */
00826 #else
00827   int homed;
00828 
00829   /* set up the homed index into DP RAM */
00830   switch (axis) {
00831   case 1:
00832     homed = HOMED_1;
00833     break;
00834   case 2:
00835     homed = HOMED_2;
00836     break;
00837   case 3:
00838     homed = HOMED_3;
00839     break;
00840   default:
00841     return -1;                  /* only 3 axes supported */
00842   }
00843 
00844   if (read_pmac_uint32(homed) == 1)
00845     return 1;
00846   return 0;
00847 #endif
00848 }
00849 
00850 /* Returns -1, 0, or 1 if the axis is at neg, not, or pos limit */
00851 int pmac_at_limit(int axis)
00852 {
00853 #ifdef DEBUG_PMAC
00854   return 0;                     /* never at limit in simulation */
00855 #else
00856   int limit;
00857 
00858   switch (axis)
00859   {
00860   case 1:
00861     limit = read_pmac_uint32(NEG_LIM_1) == 1 ? -1 :
00862       read_pmac_uint32(POS_LIM_1) == 1 ? 1 : 0;
00863     break;
00864   case 2:
00865     limit = read_pmac_uint32(NEG_LIM_2) == 1 ? -1 :
00866       read_pmac_uint32(POS_LIM_2) == 1 ? 1 : 0;
00867     break;
00868   case 3:
00869     limit = read_pmac_uint32(NEG_LIM_3) == 1 ? -1 :
00870       read_pmac_uint32(POS_LIM_3) == 1 ? 1 : 0;
00871     break;
00872   default:
00873     return -1;                  /* only 3 axes supported */
00874   }
00875 
00876   return limit;
00877 #endif
00878 }
00879 
00880 /* returns -1, 0, or 1 if the axis is at software limit */
00881 int pmac_at_sw_limit(int axis)
00882 {
00883 #ifdef DEBUG_PMAC
00884   return 0;                     /* never at limit in simulation */
00885 #else
00886   int limit;
00887 
00888   switch (axis)
00889   {
00890   case 1:
00891     limit = read_pmac_uint32(SW_NEG_LIM_1) == 1 ? -1 :
00892       read_pmac_uint32(SW_POS_LIM_1) == 1 ? 1 : 0;
00893     break;
00894   case 2:
00895     limit = read_pmac_uint32(SW_NEG_LIM_2) == 1 ? -1 :
00896       read_pmac_uint32(SW_POS_LIM_2) == 1 ? 1 : 0;
00897     break;
00898   case 3:
00899     limit = read_pmac_uint32(SW_NEG_LIM_3) == 1 ? -1 :
00900       read_pmac_uint32(SW_POS_LIM_3) == 1 ? 1 : 0;
00901     break;
00902   case 4:
00903     limit = read_pmac_uint32(SW_NEG_LIM_4) == 1 ? -1 :
00904       read_pmac_uint32(SW_POS_LIM_4) == 1 ? 1 : 0;
00905     break;
00906   default:
00907     return -1;                  /* only 3 axes supported */
00908   }
00909 
00910   return limit;
00911 #endif
00912 }
00913 
00914 /*
00915   Returns 1 if a PMAC motion program is running, 0 if not.
00916   Heuristics:  program running bit is 0.
00917   */
00918 int pmac_prog_running()
00919 {
00920 #ifdef DEBUG_PMAC
00921   return !pmac_online_state;
00922 #else
00923   return read_pmac_uint32(CS_PROG_RUNNING);
00924 #endif
00925 }
00926 
00927 #ifdef DEBUG_PMAC
00928 static double _pos[AXIS_MAX];
00929 #endif
00930 
00931 /* returns the actual position of the specified axis */
00932 double pmac_pos(int axis)
00933 {
00934 #ifdef DEBUG_PMAC
00935   return 0.0;                   /* use _pos[] array if you start
00936                                    simulating PMAC pos; for now it's
00937                                    0 for all axes */
00938 #else
00939   int index;
00940   int pos;
00941 
00942   /* set up the position index into DP RAM */
00943   switch (axis) {
00944   case 1:
00945     index = ACT_POS_1;
00946     break;
00947   case 2:
00948     index = ACT_POS_2;
00949     break;
00950   case 3:
00951     index = ACT_POS_3;
00952     break;
00953   case 4:                       /* 4 is spindle */
00954     index = ACT_POS_4;
00955     break;
00956   default:
00957     return -1;
00958   }
00959 
00960   pos = (int) read_pmac_uint32(index);
00961   return pos;                   /* in counts! */
00962 #endif
00963 }
00964 
00965 /* returns the target position of the specified axis */
00966 double pmac_target_pos(int axis)
00967 {
00968 #ifdef DEBUG_PMAC
00969   return 0.0;
00970 #else
00971   int index;
00972   int target;
00973 
00974   /* set up the position index into DP RAM */
00975   switch (axis) {
00976   case 1:
00977     index = TARGET_POS_1;
00978     break;
00979   case 2:
00980     index = TARGET_POS_2;
00981     break;
00982   case 3:
00983     index = TARGET_POS_3;
00984     break;
00985   case 4:                       /* 4 is spindle */
00986     index = TARGET_POS_4;
00987     break;
00988   default:
00989     return -1;
00990   }
00991 
00992   target = (int) read_pmac_uint32(index);
00993   return target;                        /* in counts! */
00994 #endif
00995 }
00996 
00997 /* pass the reply buffer of the PMAC when you get PMAC_ERR, and
00998    this prints a line with a more descriptive error, as documented
00999    in PMAC manual for I-var I6, pp. 5-7, 5-8*/
01000 void pmac_print_error(int dperr, const char *reply)
01001 {
01002   int error_number;
01003 
01004   switch (dperr)
01005   {
01006   case PMAC_ACK:
01007     return;
01008 
01009   case PMAC_BUF_TOO_SMALL:
01010 #ifndef rtlinux
01011     rcs_print_error( "buffer too small to hold reply\n");
01012 #endif
01013     return;
01014 
01015   case PMAC_BAD_PARAMS:
01016 #ifndef rtlinux
01017     rcs_print_error( "bad parameters to call to pmac_writemsg()\n");
01018 #endif
01019     return;
01020 
01021   case PMAC_TIMEOUT:
01022 #ifndef rtlinux
01023     rcs_print_error( "timeout on read from PMAC\n");
01024 #endif
01025     return;
01026 
01027   case PMAC_WRITE_TIMEOUT:
01028 #ifndef rtlinux
01029     rcs_print_error( "timeout on write to PMAC\n");
01030 #endif
01031     return;
01032 
01033   case PMAC_INVALID_COMM_PARAMS:
01034 #ifndef rtlinux
01035     rcs_print_error( "invalid PMAC comm params\n");
01036 #endif
01037     return;
01038 
01039   case PMAC_ERR:
01040 
01041     /* line will look like "ERR003" -- scan past the "ERR" */
01042     if (1 != sscanf(&reply[3], "%d", &error_number))
01043     {
01044 #ifndef rtlinux
01045       rcs_print_error( "invalid error string: %s\n", reply);
01046 #endif
01047       return;                   /* invalid string */
01048     }
01049 
01050     /* print the descriptive text */
01051     switch (error_number)
01052     {
01053     case 1:
01054 #ifndef rtlinux
01055       rcs_print_error( "command not allowed during program execution\n");
01056 #endif
01057       break;
01058 
01059     case 3:
01060 #ifndef rtlinux
01061       rcs_print_error( "data error or unrecognized command\n");
01062 #endif
01063       break;
01064 
01065     case 5:
01066 #ifndef rtlinux
01067       rcs_print_error( "command not allowed unless buffer is open\n");
01068 #endif
01069       break;
01070 
01071     case 6:
01072 #ifndef rtlinux
01073       rcs_print_error( "no room in buffer for command\n");
01074 #endif
01075       break;
01076 
01077     case 7:
01078 #ifndef rtlinux
01079       rcs_print_error( "buffer already in use\n");
01080 #endif
01081       break;
01082 
01083     case 9:
01084 #ifndef rtlinux
01085       rcs_print_error( "program structural error (e.g., ENDIF without IF)\n");
01086 #endif
01087       break;
01088 
01089     case 10:
01090 #ifndef rtlinux
01091       rcs_print_error( "both overtravel limits set for a motor in the C.S.\n");
01092 #endif
01093       break;
01094 
01095     case 11:
01096 #ifndef rtlinux
01097       rcs_print_error( "previous move not completed\n");
01098 #endif
01099       break;
01100 
01101     case 12:
01102 #ifndef rtlinux
01103       rcs_print_error( "a motor in the coordinate system is open-loop\n");
01104 #endif
01105       break;
01106 
01107     case 13:
01108 #ifndef rtlinux
01109       rcs_print_error( "a motor in the coordinate system is not activated\n");
01110 #endif
01111       break;
01112 
01113     case 14:
01114 #ifndef rtlinux
01115       rcs_print_error( "no motors in the coordinate system\n");
01116 #endif
01117       break;
01118 
01119     case 15:
01120 #ifndef rtlinux
01121       rcs_print_error( "not pointing to a valid program buffer\n");
01122 #endif
01123       break;
01124 
01125     case 16:
01126 #ifndef rtlinux
01127       rcs_print_error( "running improperly structured program (e.g., missing ENDWHILE)\n");
01128 #endif
01129       break;
01130 
01131     default:
01132       break;
01133     }                           /* case PMAC_ERR */
01134 
01135   default:
01136     return;
01137   }                             /* case dperr */
01138 }
01139 
01140 /* spindle stuff */
01141 
01142 #ifdef DEBUG_PMAC
01143 
01144 static int _spindle_enabled = 0;
01145 static double _spindle_speed = 0.0;
01146 
01147 #endif
01148 
01149 /* rpm calibration data from linear regression (!) */
01150 
01151 #define GEAR_1_A 39.4
01152 #define GEAR_1_B 0.0
01153 
01154 #define GEAR_2_A 12.1
01155 #define GEAR_2_B 0.0
01156 
01157 #define GEAR_3_A 3.66
01158 #define GEAR_3_B 0.0
01159 
01160 static int rpms_to_counts(double rpms, int gear)
01161 {
01162   switch (gear)
01163   {
01164   case 1:
01165   case 4:                       /* in transition = low gear */
01166     return GEAR_1_A * rpms + GEAR_1_B;
01167   case 2:
01168     return GEAR_2_A * rpms + GEAR_2_B;
01169   case 3:
01170     return GEAR_3_A * rpms + GEAR_3_B;
01171   default:
01172     return 0;
01173   }
01174 }
01175 
01176 static double clip_rpms(double speed_factor, int gear)
01177 {
01178  /* clip RPMs to limit:
01179      low gear: 0 - 335
01180      medium gear: 336 - 1086
01181      high gear: 1087 - 3000
01182      */
01183   switch (gear)
01184   {
01185   case 1:
01186   case 4:                       /* in transition = low gear */
01187     if (speed_factor > 336)
01188       speed_factor = 336;
01189     else if (speed_factor < -336)
01190       speed_factor = -336;
01191     break;
01192   case 2:
01193     if (speed_factor > 1086)
01194         speed_factor = 1086;
01195     else if (speed_factor < -1086)
01196       speed_factor = -1086;
01197     break;
01198   case 3:
01199     if (speed_factor > 3000)
01200       speed_factor = 3000;
01201     else if (speed_factor < -3000)
01202       speed_factor = -3000;
01203     break;
01204   default:
01205     /* coding error */
01206     break;
01207   }
01208 
01209   return speed_factor;
01210 }
01211 
01212 #define MAX_COUNTS 12000
01213 
01214 /* speed is in RPMs, gear is 1=low, 2=med, 3=hi */
01215 void pmac_spindle_speed(double rpms, int gear)
01216 {
01217   int val;
01218 
01219   /* clip rpms */
01220   rpms = clip_rpms(rpms, gear);
01221 
01222   /* convert rpms to counts */
01223   val = rpms_to_counts(rpms, gear);
01224 
01225   /* clip counts */
01226   if (val < -MAX_COUNTS)
01227   {
01228     val = -MAX_COUNTS;
01229   }
01230   else if (val > MAX_COUNTS)
01231   {
01232     val = MAX_COUNTS;
01233   }
01234 
01235   val = -val;                   /* FIXME--works for kt800, remove for
01236                                    minimill-- need an ini file variable */
01237 
01238   pmac_writeint(SPINDLE_SPEED, val);
01239 #ifdef DEBUG_PMAC
01240   printf("setting pmac spindle speed to %d\n", val);
01241   _spindle_speed = rpms;
01242 #endif                          /* DEBUG_PMAC */
01243 }
01244 
01245 /* enable the spindle-- this means disable any servoing, and enable
01246    the spindle amp manually */
01247 int pmac_enable_spindle()
01248 {
01249   /* if we're in on-line mode, *don't* force on-line-- we may have
01250      motions queued that can't be aborted */
01251   if (pmac_prog_running())
01252   {
01253     /* the spindle cannot be enabled when a motion program is running--
01254        it should be done */
01255     /* FIXME-- check queue and report error if any motions are queued */
01256     if (-1 == pmac_online())
01257       return -1;
01258   }
01259 
01260   /* format and send on-line kill command */
01261   if (-1 == pmac_sendstring("#4K"))
01262     return -1;
01263 
01264   /* disable motor calcs */
01265   if (-1 == pmac_sendstring("I400=0"))
01266     return -1;
01267 
01268 #ifdef DEBUG_PMAC
01269   _spindle_enabled = 1;
01270 #endif
01271 
01272   return 0;
01273 }
01274 
01275 /* disable the spindle-- this means don't output any DAC voltage,
01276    and disable the spindle amp manually */
01277 int pmac_disable_spindle()
01278 {
01279   /* command no velocity */
01280   pmac_spindle_speed(0.0, 1);
01281 
01282   /* assure on-line command mode */
01283   if (pmac_prog_running())
01284   {
01285     if (-1 == pmac_online())
01286       return -1;
01287   }
01288 
01289   /* enable motor calcs and servo here*/
01290   if (-1 == pmac_sendstring("I400=1"))
01291     return -1;
01292   if (-1 == pmac_sendstring("#4J/"))
01293     return -1;
01294 
01295 
01296 #ifdef DEBUG_PMAC
01297   _spindle_enabled = 0;
01298 #endif
01299 
01300   return 0;
01301 }
01302 
01303 int pmac_spindle_is_open_loop()
01304 {
01305   /* returns 1 if it's open loop, or 0 if it's closed loop.
01306      1 means that we're using it in cutting mode, by writing to
01307      the DAC; 0 means that we're using it for orienting */
01308 
01309   return read_pmac_uint32(OPEN_LOOP_4);
01310 }
01311 
01312 /* Probing */
01313 
01314 /* Enables the use of motor 1-3's FAULT line for latching.
01315    Sets I902, I907, and I912 to 2 for flag select only,
01316    and sets flag select to 3 for FAULT. */
01317 int pmac_probe_on()
01318 {
01319   /* make sure we're in online mode */
01320   if (pmac_prog_running())
01321   {
01322     if (-1 == pmac_online())
01323     {
01324       return -1;
01325     }
01326   }
01327 
01328   /* set the I-vars to 2 for rising edge of flag */
01329   pmac_sendstring("I902=2");
01330   pmac_sendstring("I907=2");
01331   pmac_sendstring("I912=2");
01332 
01333   /* set the flag to FAULT */
01334   pmac_sendstring("I903=3");
01335   pmac_sendstring("I908=3");
01336   pmac_sendstring("I913=3");
01337 
01338   return 0;
01339 }
01340 
01341 /* Restores the use of motor 1-3's index pulse for homing.
01342    Restores the P-variable copies of I902, I907, and I912, and sets
01343    flag select to 0 for home flag. */
01344 int pmac_probe_off()
01345 {
01346   /* make sure we're in online mode */
01347   if (pmac_prog_running())
01348   {
01349     if (-1 == pmac_online())
01350     {
01351       return -1;
01352     }
01353   }
01354 
01355   /* restore the I-vars from P-vars */
01356   pmac_sendstring("I902=P902");
01357   pmac_sendstring("I907=P907");
01358   pmac_sendstring("I912=P912");
01359 
01360   /* set the flag to HOME */
01361   pmac_sendstring("I903=0");
01362   pmac_sendstring("I908=0");
01363   pmac_sendstring("I913=0");
01364 
01365   return 0;
01366 }
01367 
01368 int pmac_probe_clear(int axis)
01369 {
01370   switch (axis)
01371   {
01372   case 1:
01373     pmac_writeint(CAPTURE_READY_1, 0);
01374     break;
01375   case 2:
01376     pmac_writeint(CAPTURE_READY_2, 0);
01377     break;
01378   case 3:
01379     pmac_writeint(CAPTURE_READY_3, 0);
01380     break;
01381   default:
01382     return -1;
01383   }
01384   return 0;
01385 }
01386 
01387 /* returns non-zero when the probe tripped and all axes positions have
01388    been latched. */
01389 int pmac_probe_tripped(int axis)
01390 {
01391   switch (axis)
01392   {
01393   case 1:
01394     return read_pmac_uint32(CAPTURE_READY_1);
01395   case 2:
01396     return read_pmac_uint32(CAPTURE_READY_2);
01397   case 3:
01398     return read_pmac_uint32(CAPTURE_READY_3);
01399   default:
01400     return 0;
01401   }
01402 }
01403 
01404 /* returns encoder counts of probe trip from 0 home */
01405 int pmac_probe_value(int axis)
01406 {
01407   int value;
01408   int offset;
01409 
01410   /* check axis */
01411   if (axis < 1 || axis > 3)
01412   {
01413     return 0;
01414   }
01415 
01416   /* read output */
01417   switch (axis)
01418   {
01419   case 1:
01420     value = read_pmac_uint32(CAPTURED_1);
01421     offset = read_pmac_uint32(HOME_OFFSET_1);
01422     break;
01423   case 2:
01424     value = read_pmac_uint32(CAPTURED_2);
01425     offset = read_pmac_uint32(HOME_OFFSET_2);
01426     break;
01427   case 3:
01428     value = read_pmac_uint32(CAPTURED_3);
01429     offset = read_pmac_uint32(HOME_OFFSET_3);
01430     break;
01431   }
01432 
01433   /* compute probe value in mm */
01434   return (value - offset);
01435 }

Generated on Sun Dec 2 15:56:51 2001 for rcslib by doxygen1.2.11.1 written by Dimitri van Heesch, © 1997-2001