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

emcstepmot.c

Go to the documentation of this file.
00001 #ifdef rtlinux
00002 #ifndef MODULE
00003 #define MODULE                  /* make it a module for RT-Linux */
00004 #endif
00005 #endif
00006 
00007 /*
00008   emcstepmot.c
00009 
00010   Real-time motion controller for queued 3-axis motion planning, independent
00011   axis motion, cubic subinterpolation, and stepper or servo control.
00012 
00013   Modification history:
00014 
00015 *FIX ME* extMotDout is throwing an "unresolved symbol" error for stepper
00016 systems. Have included a dummy call as a temp fix.
00017 
00018   16-Jul-2001  FMP upped the task stack sizes for stepper and emcmot tasks
00019   to 4096 and 8192, resp., matching the fix that Will did in emcmot.c
00020   28-Jun-2001  FMP fixed WPS's mmxavg debug structs; added STEPPING_TYPE
00021   as a module parameter, just to be compatible with runs scripts that
00022   pass this to freqmod.
00023   31-May-2001  FMP took out EMCMOT_C conditional
00024   24-Oct-2000 terrylr added define EMCMOT_C to allow for the conditional
00025   declaration of init_module & cleanup_module in emcmot.h.
00026   21-Sep-2000  FMP added check against GET_AXIS_ENABLE_FLAG() before
00027   aborting amp faults. Changed AMP_FAULT_DEBOUNCE from 10 to 100. For
00028   500 usec servos, this is 50 msecs, and fixes the race condition problem
00029   between amp enable and a reset of amp fault, in systems where amp fault
00030   equals not amp enable.
00031   15-Aug-2000  FMP added alter to comping compatibility
00032   8-Aug-2000  FMP added EMCMOT_COMP stuff for compatibility, but nothing
00033   is done with it here; added probing stuff from emcmot.c
00034   31-Jul-2000  FMP put PERIOD definition in, to keep the .run scripts
00035   from failing when insmod set this variable. It's unused here, so it
00036   has no effect other than to make the .run script happy.
00037   21-Jul-2000  FMP put gain setting back in, so that gains don't get reset
00038   12-Apr-2000 WPS eliminated redundant second include string.h
00039   30-Mar-2000 WPS added ferrorCurrent and ferrorHighMark junk
00040   21-Mar-2000 WPS eliminated #includes of <rtl_fifo.h>, we don't use FIFO's
00041   anymore and it caused an anoying warning message.
00042   13-Mar-2000 WPS changed hrgettime to gethrtime and fixed the
00043   rt_make_task_periodic that was still compiled under RTL 2.0.
00044   13-Mar-2000 WPS added unused attribute to ident to avoid 'defined but
00045   not used' compiler warning, and added (void) to many functions with no
00046   arguments to avoid 'declaration is not a prototype'  compiler warning
00047   6-Mar-2000 WPS eliminated the #include <linux/rt_sched.h> and
00048   <linux/rt_time.h>, which appeared to be only needed for pre- rtlinux_09J
00049   platforms and those are unlikely to work anyway.
00050   3-Mar-2000  FMP changed filename from emcmot.c to emcstepmot.c, along
00051   with changing emcfreqmot.c to emcmot.c. This file has thus been demoted.
00052   28-Feb-2000  FMP changed static smStepsAccum[] to non-static stepperCount[]
00053   30-Jan-2000  FMP added quantization of computed position about input
00054   scale, using rounding
00055   22-Jan-2000  FMP added triggering of POS_VOLTAGE log with dac write
00056   13-Jan-2000  WPS updated for rtlinux2 including the following:
00057   -> replace rt_task_ functions with pthread_ functions (more portable?)
00058   -> replace lilo ioremap/vremap with mbuff calls. (no need for lilo append)
00059   -> replace rt_get_time with gethrtime() (high-resolution time)
00060   20-Dec-1999  FMP restored dual-cycle version of stepper code, from
00061   1.119 version, which ran best on Bridgeport.
00062   17-Dec-1999  FMP ran sm task at half, not quarter time, so the cycle
00063   time would be the same as everybody expects. Note that this is twice
00064   as fast as it need run, since we're at one full pulse per sm task.
00065   9-Dec-1999  FMP reversed priorities on motion and stepper tasks, so that
00066   stepper task had highest priority; only cleared clock bits at start of
00067   stepper task, leaving direction bits alone.
00068   7-Dec-1999  FMP changed smController to run at full pulse rate
00069   3-Dec-1999  FMP added smCyclesPerAxis as configuration variable, that isn't
00070   recalculated using floating point in smController each cycle. This was to
00071   speed it up.
00072   23-Nov-1999  FMP restored last output bytes in smController to preserve
00073   last values of bits not changed.
00074   16-Nov-1999  FMP changed the logic in the stepper code so that pulses
00075   are spread across the whole servo cycle, instead of bunched at the front,
00076   and the duty cycle is 50-50. Added later fix on smLastUp so that a group
00077   never finished on an up pulse.
00078   12-Nov-1999  FMP took negative axis in EMCMOT_OVERRIDE_LIMITS to mean
00079   don't override limits
00080   3-Nov-1999  FMP added EMCMOT_LOG_POS_VOLTAGE
00081   29-Oct-1999  FMP changed rtlinux_b11 to rtlinux2
00082   22-Oct-1999  FMP added MODULE_PARM() calls for globals
00083   21-Oct-1999  FMP added rtlinux_b11 port to 2.2 kernels; ioremap(),
00084   iounmap() calls for 2.2.
00085   21-Oct-1999  FMP added call to SET_AXIS_HOMED_FLAG(axis, 0) for steppers,
00086   to clear the homed flag if we went into the disabled state. This is to
00087   catch the case where steppers aren't on a full pulse when power is taken
00088   away, which could make the system off by pulse requiring homing again.
00089   18-Oct-1999  FMP added missing call to tpClear() for each axis' motion
00090   planner, to fix problem with axes jumping when overriding a limit.
00091   8-Oct-1999  FMP added isHoming() to check for any axis homing, to support
00092   homing off a limit switch tied into all axes.
00093   5-Oct-1999  FMP added limitFerror, the speed-dependent following error.
00094   Now following error depends linearly on speed, so for slower moves the
00095   fatal following error is lower.
00096   30-Sep-1999  FMP didn't flag an error or abort on hardware limits when
00097   homing, and used them as a home condition along with home switch.
00098   29-Sep-1999  FMP added homeOffset[] to status, EMCMOT_SET_HOME_OFFSET to cmd
00099   21-Sep-1999  WPS eliminate sscanf and printf calls not supported under CE.
00100   14-Sep-1999  FMP added inverseOutputScale[], like inverseInputScale[], to
00101   save a division at the servo cycle.
00102   17-Aug-1999  FMP fixed typo from yesterday
00103   16-Aug-1999  FMP allowed calculation of actualPos if not homed, if we
00104   have trivial kinematics
00105   9-Aug-1999  FMP added inverseInputScale[] = 1/inputScale[], to convert
00106   a division into a multiplication to save calc time at the servo rate.
00107   Added setting of home position(s) to be jointHome[], worldHome, from
00108   EMCMOT_SET_WORLD_HOME, EMCMOT_SET_JOINT_HOME. Revised calls to kinematics
00109   to use new naming convention "kinematicsInv/For/Home".
00110   4-Aug-1999  FMP fixed watchdog so that sound port bit is zeroed when
00111   watchdog is turned off; fixed newly-introduced bug in soft limit checking
00112   that gave a soft limit when not homed, for negative directions.
00113   3-Aug-1999  FMP bracketed checks for limit, fault, home switch with
00114   check that the joint is active; set default for axis to be deactivated
00115   2-Aug-1999  FMP split out Cartesian and joint motion more explicitly;
00116   added cubicOffset in place of cubicDrain when a joint homed. Reworked
00117   the way kinematics functions were called, and coord/free mode interacted.
00118   Added coarseJointPos[] array. Called forward kins at the simulated
00119   trajectory rate when disabled, via the interpolationCounter var. Fixed
00120   handling of axes >=4 in smController().
00121   26-Jul-1999  FMP put 6 axes' worth of bits into stepper motor task
00122   23-Jul-1999  FMP fixed bug in calculating smUnitsPerStep from 1/input scale,
00123   in which negative input scales gave negative units per step, which were
00124   always assumed to be positive in the backlash calcs. Converted backlash
00125   comp from step-per-cycle application to acc/dec application.
00126   Suppressed redundant writes of stepper motor byte in smController.
00127   Added smInhibit flag that causes smController to set command steps
00128   equal to accum steps, so we won't have stepper runaway.
00129   22-Jul-1999  FMP added backlash comp for steppers, in which backlash
00130   takeup was meted out one pulse per servo cycle; fixed homing so that
00131   there was a controlled move from the post-home decel back to home.
00132   Previously after the post-home decel the home position was given directly
00133   to the servos, so it screamed back the full decel distance. This was so
00134   small that no one noticed.
00135   14-Jul-1999  FMP set emcmotStatus->qVscale,axVscale[] only when
00136   EMCMOT_SCALE was read, not every cycle; put head/tail in command handler
00137   and moved down a bit in controller
00138   1-Jul-1999  FMP reduced calls to kinematicsForward()
00139   24-Jun-1999  FMP added vremap(), vfree() calls to RT Linux shared mem;
00140   changed EMCMOT_NO_MAIN to EMCMOT_MAIN
00141   16-Jun-1999  FMP added axisPos[] to status
00142   14-Jun-1999  FMP added #ifdef STEPPER_MOTORS bracketing around some more
00143   stepper data
00144   11-Jun-1999  FMP calculated smTask cycle time using T = 1/2 * 1/(V*P),
00145   where V is max vel, P is pulses per unit. Whenever these are changed,
00146   the task rate is changed also.
00147   10-Jun-1999  FMP added magFerror to solve problem that following error
00148   was only compared in the positive direction against the max
00149   8-Jun-1999  FMP ran smTask at twice the servo rate, instead of at rate
00150   configured by now-obsolete SM_CYCLE_TIME. It's twice so the effective
00151   pulse rate is the same as the servo cycle time, e.g., 100 microsecond
00152   cycle time means a pulse every 100 microseconds at max speed. Set
00153   'bigVel' with emcmotConfig->limitVel, for upper velocity limit.
00154   Added EMCMOT_SET_VEL_LIMIT
00155   7-Jun-1999  FMP fixed logging of trajectory cycle points with the logIt
00156   flag, without which points were logged every servo cycle; #ifdef'ed out
00157   PID, output, and rawoutput sections in code if we're doing steppers
00158   2-Jun-1999  FMP bracketed debounce of inputs so that it's not done when
00159   using steppers-- the debounce caused motion to stop when jog speeds were
00160   less than 1.0.
00161   21-May-1999  FMP added EMCMOT_LOG_TYPE_TRAJ_POS for logging of Cartesian
00162   points from the trajectory planner at the traj rate
00163   8-May-1999  FMP bracketed references to emcmotLog out of RT_FIFO sections;
00164   added 1 to size of fifos in rtf_create. Note: the status structure worked
00165   fine when created with sizeof(status structure), but the command structure
00166   caused infinite wait during Linux process write() to fifo if it was exactly
00167   the size of the command. When it was made one byte larger, it worked.
00168   8-Mar-1999  FMP changed calls to tpCreate to provide a third argument
00169   for the queue space, and added queueTcSpace, freeAxisTcSpace arrays for
00170   this memory.
00171   3-Mar-1999  FMP took out static malloc stuff, since we now use rtmalloc.h
00172   in files that do malloc(), which is macroed to kmalloc().
00173   25-Feb-1999  FMP changed queue.queue.full to tcqFull(&queue.queue) to
00174   reflect the change in tc.c; added commandEcho to status
00175   24-Feb-1999  RSB added switched for rtlinux_1_0
00176   18-Feb-1999  FMP replaced hard-coded fifo numbers with symbolic names
00177   from emcmot.h
00178   12-Feb-1999  FMP reportError'ed following error, and SET_AXIS_ERROR_FLAG
00179   in addition to SET_AXIS_FERROR_FLAG; cleared error flags when enabling
00180   10-Feb-1999  RSB changed the rtlinux-0.9H switch to rtlinux-0.9J
00181   10-Feb-1999  FMP set the non-moving axes for the homing destination to
00182   0 so they wouldn't erroneously count toward total displacement for move;
00183   fixed a failure to reset lastInput[] when the input offset changed due
00184   to homing
00185   7-Feb-1999  FMP added input debounce with bigVel and lastInput[], so that
00186   inputs/cycle time > 10X max speed are set to the last input value; made
00187   emcmotStatus->ferror the mag of the max; added logging of instantaneous
00188   following error "thisFerror[]"
00189   4-Feb-1999  FMP removed reportError on limits, since servo jitter about
00190   a limit caused flooding of these reports; added fix to weird jog problem
00191   caused when you switched to another axis, and the previous value it had
00192   for another axis' goal position wasn't "here", so it added to the scalar
00193   distance and slowed the move
00194   22-Jan-1999 WPS added memset to init sharedmemory area.
00195   21-Jan-1999  FMP fixed bug in continuous jogging where values for
00196   non-jogged axes were uninitialized, instead of read out of status
00197   12-Nov-1998  FMP made fixes to axis homing and other problems discovered
00198   by Angelo: axis home destination is twice axis range; setting offset to
00199   latch position is now accompanied by corresponding correction of input
00200   position to avoid momentary jump.
00201   22-Oct-1998  FMP zeroed shared memory; removed call to extEncoderReadAll()
00202   after extEncoderSetIndexModel() in init_module()
00203   13-Oct-1998  FMP changed continuous jogging to go to soft limit
00204   7-Oct-1998 FMP added homing vel stuff
00205   25-Sep-1998  FMP set axis error flag if on hard or soft limit
00206   2-Sep-1998  FMP put inRange back in, and included soft and hard limits
00207   in check to prevent moves from being initiated; added call to tpAbort()
00208   when inRange() failed in EMCMOT_SET_LINE,CIRCLE command cases
00209   10-Aug-1998  FMP fixed cut-and-paste bug in which maxLimitSwitchCount
00210   was being used for min limit switch debounce
00211   5-Aug-1998  FMP added baseline stepper motor control, keeping all original
00212   calcs and bracketing new code with ifdef STEPPER_MOTORS
00213   8-Jul-1998  FMP replaced -shm, -base cmd line args to main() with
00214   sym=value style, as per insmod, using getArgs() function here
00215   6-Jul-1998  FMP added -base to main() simulation, not that the simulation
00216   uses physical shared memory at this point
00217   15-Jun-1998  FMP added EMCMOT_SET_TERM_COND
00218   27-May-1998  FMP incremented head and tail in emcmotController()
00219   11-May-1998  FMP took out <sys/types.h> for size_t, since it gave
00220   compiler errors. I inlined decl of size_t as unsigned int.
00221   3-Apr-1998  FMP added active axis concept, with GET_AXIS_ACTIVE_FLAG(),
00222   SET_AXIS_ACTIVE_FLAG(), etc.
00223   26-Mar-1998  FMP replaced local etime(), esleep(), and shmget()/shmat()
00224   with rcslib equivalents, for portability; changed saveLatch[] to doubles
00225   from ints since that's what they really are
00226   23-Mar-1998  FMP pulled reportError() out of plat ifdefs since it was
00227   the same for all
00228   3-Mar-1998  FMP added -shm to main() process
00229   25-Feb-1998  FMP added AXIS_ERROR_FLAG
00230   23-Feb-1998  FMP added logging all inpos, outpos
00231   17-Feb-1998  FMP added homed bit
00232   13-Feb-1998  FMP forced inRange() to return 1 always, since it was
00233   erroneously returning 0 sometimes and causing dropped moves. Will fix later.
00234   12-Feb-1998  FMP added error logging to memory queue
00235   9-Feb-1998  FMP fixed bug in which I forgot to set free planner traj
00236   times in setTrajCycleTime)
00237   6-Feb-1998  FMP added log types
00238   22-Jan-1998  FMP changed priority to 1
00239   20-Jan-1998  FMP added COMM_COPY compile flag to select between direct
00240   access of upper memory or OS shared memory (fast), or copy-in, copy-out
00241   access (slowwwww).
00242   13-Jan-1998  FMP took out stdlib.h, when switching to rtlinux-0.5a
00243   12-Jan-1998  FMP put RT_FIFO switch in, since we were having NaN
00244   problems with shared memory (race condition?)
00245   12-Jan-1998  FMP took rt_use_fp() out of emcmotCommandHandler since
00246   it's now just a function within emcmotController, which does call it
00247   8-Jan-1998  FMP wrote polarity for enabling, instead of direct 1, 0;
00248   disabled amps in cleanup_module since we took it out of extQuit code;
00249   fixed bug where max lim switch flag was set for both max and min
00250   7-Jan-1998  FMP got rid of rt_task_suspend call in emcmotCommandHandler,
00251   when changing cycle times. It hangs now that emcmotCommandHandler is
00252   part of RT task
00253   6-Jan-1998  FMP switched to shared memory instead of fifos; added
00254   PID gain and input/output offset globals for init
00255   25-Nov-1997  FMP changed calls from extLimitSwitchRead() to
00256   extPos,NegLimit...
00257   4-Nov-1997  FMP put call to rt_use_fp() in emcmotController(). It was
00258   in emcmotCommandHandler(), and everything seemed to work OK, but rtlinux
00259   fp code example had it in cyclic code.
00260   16-Oct-1997  FMP added compile-time globals
00261   15-Oct-1997  FMP fixed bug in jog message handlers where vel was being
00262   set to status, not command
00263   25-Sep-1997  FMP added EMCMOT_NO_MAIN flag for not compiling in the
00264   default main loop
00265   13-Aug-1997  FMP removed setting of pidOutput[] to 0 when axis disabled,
00266   to allow for DAC writes to go out
00267   01-Aug-1997  FMP changed jointPos from int to double; called pidReset()
00268   upon enabling
00269   15-Jul-1997  FMP changed estop to enable, for consistency with interface
00270   30-Jun-1997  FMP added axis software limits; incremental and abs jog
00271   24-Jun-1997  FMP combined with non-RT-Linux code; added estop; added
00272   external interface "ext*" calls
00273   2-May-1997  FMP added logging
00274   17-Apr-1997  FMP added computeTime calcs
00275   16-Apr-1997  FMP created
00276   */
00277 
00278 #ifdef rtlinux
00279 
00280 #if (defined(rtlinux2) || defined(RTLINUX_V2)) && !defined(CONFIG_RTL_USE_V1_API)
00281 #define USE_RTL2
00282 #endif
00283 
00284 
00285 #ifdef USE_RTL2
00286 #include <rtl.h>
00287 #ifdef RT_FIFO
00288 #include <rtl_fifo.h>
00289 #endif
00290 #include <time.h>
00291 #include <rtl_sched.h>
00292 #include <rtl_sync.h>
00293 #include <pthread.h>
00294 #include <unistd.h>
00295 #include <rtl_debug.h>
00296 #include <errno.h>
00297 #include "mbuff.h"
00298 #endif
00299 
00300 /*
00301   FIXME-- should include <stdlib.h> for sizeof(), but conflicts with
00302   a bunch of <linux> headers
00303   */
00304 #include <linux/module.h>
00305 #include <linux/kernel.h>
00306 #include <linux/version.h>
00307 #include <linux/errno.h>
00308 #include <linux/mm.h>           /* vremap(), vfree() */
00309 
00310 #ifndef USE_RTL2
00311 #include <rtl_sched.h>
00312 #include <rtl_fifo.h>
00313 #endif
00314 
00315 
00316 #include <asm/io.h>
00317 
00318 #include <math.h>
00319 #include <stdarg.h>             /* vsprintf() */
00320 
00321 #else  /* not rtlinux */
00322 
00323 #include "_timer.h"             /* rcslib etime(), esleep() */
00324 #include "_shm.h"               /* rcslib shm_t, rcs_shm_open(), ... */
00325 #if !defined(UNDER_CE) && !defined(NO_STDIO_SUPPORT)
00326 #include <stdio.h>              /* printf() */
00327 #endif
00328 #include <stdlib.h>             /* sizeof() */
00329 #include <math.h>
00330 #include <stdarg.h>             /* va_start() */
00331 #include <string.h>             /* memset() */
00332 
00333 #endif /* else not rtlinux */
00334 
00335 #include "posemath.h"           /* PmPose, pmCartMag() */
00336 #include "emcpos.h"
00337 #include "emcmotcfg.h"
00338 #include "emcmotglb.h"
00339 #include "emcmot.h"
00340 #include "pid.h"
00341 #include "cubic.h"
00342 #include "tc.h"
00343 #include "tp.h"
00344 #include "extintf.h"
00345 #include "mmxavg.h"
00346 #include "emcmotlog.h"
00347 
00348 /* ident tag */
00349 #ifndef __GNUC__
00350 #ifndef __attribute__
00351 #define __attribute__(x)
00352 #endif
00353 #endif
00354 
00355 static char __attribute__((unused))  ident[] = "$Id: emcstepmot.c,v 1.18 2001/10/18 15:29:09 wshackle Exp $";
00356 
00357 void extMotDout(unsigned char byte)     // P.C. Added this to fix a broken call
00358     {                                   // when the functioning call has been
00359     return;                             // included for steppermotors, this
00360     }                                   // can be deleted.
00361     
00362 #ifdef rtlinux
00363 
00364 /* useful conversion from secs to RTIME */
00365 /* RT_TICKS_PER_SEC is 1193180, BTW */
00366 #define SECS_TO_RTIME(secs) ((RTIME) (RT_TICKS_PER_SEC * secs))
00367 
00368 /* task struct */
00369 #ifdef USE_RTL2
00370 static pthread_t emcmotTask;
00371 #else
00372 static RT_TASK emcmotTask;
00373 #endif
00374 
00375 #define RT_TASK_PRIORITY 2      /* the highest is 1, the lowest is
00376                                    RT_LOWEST_PRIORITY */
00377 #define RT_TASK_STACK_SIZE 8192
00378 
00379 #ifdef STEPPER_MOTORS
00380 #ifdef USE_RTL2
00381 static pthread_t smTask;
00382 #else
00383 static RT_TASK smTask;
00384 #endif
00385 #define SM_TASK_PRIORITY 1
00386 #define SM_TASK_STACK_SIZE 4096
00387 #endif
00388 
00389 /* for RT-Linux, can have watchdog sound port, parallel port bit toggling */
00390 #define SOUND_PORT 0x61
00391 #define SOUND_MASK 0x02
00392 static unsigned char soundByte;
00393 
00394 #endif /* rtlinux */
00395 
00396 /*
00397   Principles of communication:
00398 
00399   Data is copied in or out from the various types of comm mechanisms:
00400   FIFOs or mapped memory for Linux/RT-Linux, or OS shared memory for Unixes.
00401 
00402   For FIFOs,
00403   emcmotCommandBuffer is used as arg to fifo get, and emcmotCommand
00404   points to this;
00405   emcmotStatusBuffer is used as arg to fifo put, and emcmotStatus
00406   points to this;
00407   there is no emcmotError, since error reporting is done at report time
00408   into the error fifo;
00409   there is no emcmotLog, since logging is done at log time
00410   into the log fifo.
00411 
00412   For shared memory or mapped memory, emcmotStruct is ptr to this memory.
00413   emcmotCommand points to emcmotStruct->command,
00414   emcmotStatus points to emcmotStruct->status,
00415   emcmotError points to emcmotStruct->error, and
00416   emcmotLog points to emcmotStruct->log.
00417   emcmotComp[] points to emcmotStruct->comp[].
00418  */
00419 
00420 #if defined (rtlinux) && defined (RT_FIFO)
00421 
00422 /* need to allocate command, status */
00423 static EMCMOT_COMMAND emcmotCommandBuffer;
00424 static EMCMOT_STATUS emcmotStatusBuffer;
00425 static EMCMOT_CONFIG emcmotConfigBuffer;
00426 static EMCMOT_DEBUG emcmotDebugBuffer;
00427 
00428 #else  /* not rtlinux or not RT_FIFO */
00429 
00430 /* need to point to command, status, error, and log */
00431 EMCMOT_STRUCT *emcmotStruct;
00432 
00433 #ifndef rtlinux
00434 /* also need to get shared memory id */
00435 static shm_t *shmem = NULL;
00436 #endif
00437 
00438 #endif /* not rtlinux or not RT_FIFO */
00439 
00440 /* ptrs to either buffered copies or direct memory for
00441    command and status */
00442 static EMCMOT_COMMAND *emcmotCommand;
00443 static EMCMOT_STATUS *emcmotStatus;
00444 static EMCMOT_CONFIG *emcmotConfig;
00445 static EMCMOT_DEBUG *emcmotDebug;
00446 
00447 #if defined (rtlinux) && defined (RT_FIFO)
00448 #else
00449 static EMCMOT_ERROR *emcmotError; /* unused for RT_FIFO */
00450 static EMCMOT_LOG *emcmotLog;   /* unused for RT_FIFO */
00451 static EMCMOT_COMP *emcmotComp[EMCMOT_MAX_AXIS]; /* unused for RT_FIFO */
00452 #endif /* not RT_FIFO */
00453 
00454 static EMCMOT_LOG_STRUCT ls;
00455 static int logSkip = 0;         /* how many to skip, for per-cycle logging */
00456 static int loggingAxis = 0;     /* record of which axis to log */
00457 static int logIt = 0;
00458 
00459 /* flag for enabling, disabling watchdog; multiple for down-stepping */
00460 static int wdEnabling = 0;
00461 static int wdEnabled = 0;
00462 static int wdWait = 0;
00463 static int wdCount = 0;
00464 static unsigned char wdToggle = 0;
00465 
00466 /* flag that all active axes are homed */
00467 static unsigned char allHomed = 0;
00468 
00469 /* values for joint home positions */
00470 static double jointHome[EMCMOT_MAX_AXIS];
00471 
00472 /* value for world home position */
00473 static EmcPose worldHome = {{0.0, 0.0, 0.0},
00474                            0.0, 0.0, 0.0};
00475 
00476 /* kinematics flags */
00477 static KINEMATICS_FORWARD_FLAGS fflags = 0;
00478 static KINEMATICS_INVERSE_FLAGS iflags = 0;
00479 
00480 /* the type of kinematics, from emcmot.h */
00481 static int kinType = 0;
00482 
00483 /* debouncing */
00484 #define LIMIT_SWITCH_DEBOUNCE 10
00485 static int maxLimitSwitchCount[EMCMOT_MAX_AXIS];
00486 static int minLimitSwitchCount[EMCMOT_MAX_AXIS];
00487 #define AMP_FAULT_DEBOUNCE 100
00488 static int ampFaultCount[EMCMOT_MAX_AXIS];
00489 
00490 /* diagnostics printing */
00491 #ifdef rtlinux
00492 #define diagnostics printk
00493 #else
00494 #ifdef UNDER_CE
00495 #include "rcs_prnt.hh"          /* rcs_print() */
00496 #define diagnostics rcs_print
00497 #else
00498 #define diagnostics printf
00499 #endif
00500 #endif
00501 
00502 static inline void MARK_EMCMOT_CONFIG_CHANGE(void)
00503 {
00504   if(emcmotConfig->head == emcmotConfig->tail) { 
00505     emcmotConfig->config_num++;
00506     emcmotStatus->config_num = emcmotConfig->config_num;
00507     emcmotConfig->head++;
00508   }
00509 }
00510 
00511 /* macros for reading, writing bit flags */
00512 
00513 /* motion flags */
00514 
00515 #define GET_MOTION_ERROR_FLAG() (emcmotStatus->motionFlag & EMCMOT_MOTION_ERROR_BIT ? 1 : 0)
00516 
00517 #define SET_MOTION_ERROR_FLAG(fl) if (fl) emcmotStatus->motionFlag |= EMCMOT_MOTION_ERROR_BIT; else emcmotStatus->motionFlag &= ~EMCMOT_MOTION_ERROR_BIT;
00518 
00519 #define GET_MOTION_COORD_FLAG() (emcmotStatus->motionFlag & EMCMOT_MOTION_COORD_BIT ? 1 : 0)
00520 
00521 #define SET_MOTION_COORD_FLAG(fl) if (fl) emcmotStatus->motionFlag |= EMCMOT_MOTION_COORD_BIT; else emcmotStatus->motionFlag &= ~EMCMOT_MOTION_COORD_BIT;
00522 
00523 #define GET_MOTION_INPOS_FLAG() (emcmotStatus->motionFlag & EMCMOT_MOTION_INPOS_BIT ? 1 : 0)
00524 
00525 #define SET_MOTION_INPOS_FLAG(fl) if (fl) emcmotStatus->motionFlag |= EMCMOT_MOTION_INPOS_BIT; else emcmotStatus->motionFlag &= ~EMCMOT_MOTION_INPOS_BIT;
00526 
00527 #define GET_MOTION_ENABLE_FLAG() (emcmotStatus->motionFlag & EMCMOT_MOTION_ENABLE_BIT ? 1 : 0)
00528 
00529 #define SET_MOTION_ENABLE_FLAG(fl) if (fl) emcmotStatus->motionFlag |= EMCMOT_MOTION_ENABLE_BIT; else emcmotStatus->motionFlag &= ~EMCMOT_MOTION_ENABLE_BIT;
00530 
00531 /* axis flags */
00532 
00533 #define GET_AXIS_ENABLE_FLAG(ax) (emcmotStatus->axisFlag[ax] & EMCMOT_AXIS_ENABLE_BIT ? 1 : 0)
00534 
00535 #define SET_AXIS_ENABLE_FLAG(ax,fl) if (fl) emcmotStatus->axisFlag[ax] |= EMCMOT_AXIS_ENABLE_BIT; else emcmotStatus->axisFlag[ax] &= ~EMCMOT_AXIS_ENABLE_BIT;
00536 
00537 #define GET_AXIS_ACTIVE_FLAG(ax) (emcmotStatus->axisFlag[ax] & EMCMOT_AXIS_ACTIVE_BIT ? 1 : 0)
00538 
00539 #define SET_AXIS_ACTIVE_FLAG(ax,fl) if (fl) emcmotStatus->axisFlag[ax] |= EMCMOT_AXIS_ACTIVE_BIT; else emcmotStatus->axisFlag[ax] &= ~EMCMOT_AXIS_ACTIVE_BIT;
00540 
00541 #define GET_AXIS_INPOS_FLAG(ax) (emcmotStatus->axisFlag[ax] & EMCMOT_AXIS_INPOS_BIT ? 1 : 0)
00542 
00543 #define SET_AXIS_INPOS_FLAG(ax,fl) if (fl) emcmotStatus->axisFlag[ax] |= EMCMOT_AXIS_INPOS_BIT; else emcmotStatus->axisFlag[ax] &= ~EMCMOT_AXIS_INPOS_BIT;
00544 
00545 #define GET_AXIS_ERROR_FLAG(ax) (emcmotStatus->axisFlag[ax] & EMCMOT_AXIS_ERROR_BIT ? 1 : 0)
00546 
00547 #define SET_AXIS_ERROR_FLAG(ax,fl) if (fl) emcmotStatus->axisFlag[ax] |= EMCMOT_AXIS_ERROR_BIT; else emcmotStatus->axisFlag[ax] &= ~EMCMOT_AXIS_ERROR_BIT;
00548 
00549 #define GET_AXIS_PSL_FLAG(ax) (emcmotStatus->axisFlag[ax] & EMCMOT_AXIS_MAX_SOFT_LIMIT_BIT ? 1 : 0)
00550 
00551 #define SET_AXIS_PSL_FLAG(ax,fl) if (fl) emcmotStatus->axisFlag[ax] |= EMCMOT_AXIS_MAX_SOFT_LIMIT_BIT; else emcmotStatus->axisFlag[ax] &= ~EMCMOT_AXIS_MAX_SOFT_LIMIT_BIT;
00552 
00553 #define GET_AXIS_NSL_FLAG(ax) (emcmotStatus->axisFlag[ax] & EMCMOT_AXIS_MIN_SOFT_LIMIT_BIT ? 1 : 0)
00554 
00555 #define SET_AXIS_NSL_FLAG(ax,fl) if (fl) emcmotStatus->axisFlag[ax] |= EMCMOT_AXIS_MIN_SOFT_LIMIT_BIT; else emcmotStatus->axisFlag[ax] &= ~EMCMOT_AXIS_MIN_SOFT_LIMIT_BIT;
00556 
00557 #define GET_AXIS_PHL_FLAG(ax) (emcmotStatus->axisFlag[ax] & EMCMOT_AXIS_MAX_HARD_LIMIT_BIT ? 1 : 0)
00558 
00559 #define SET_AXIS_PHL_FLAG(ax,fl) if (fl) emcmotStatus->axisFlag[ax] |= EMCMOT_AXIS_MAX_HARD_LIMIT_BIT; else emcmotStatus->axisFlag[ax] &= ~EMCMOT_AXIS_MAX_HARD_LIMIT_BIT;
00560 
00561 #define GET_AXIS_NHL_FLAG(ax) (emcmotStatus->axisFlag[ax] & EMCMOT_AXIS_MIN_HARD_LIMIT_BIT ? 1 : 0)
00562 
00563 #define SET_AXIS_NHL_FLAG(ax,fl) if (fl) emcmotStatus->axisFlag[ax] |= EMCMOT_AXIS_MIN_HARD_LIMIT_BIT; else emcmotStatus->axisFlag[ax] &= ~EMCMOT_AXIS_MIN_HARD_LIMIT_BIT;
00564 
00565 #define GET_AXIS_HOME_SWITCH_FLAG(ax) (emcmotStatus->axisFlag[ax] & EMCMOT_AXIS_HOME_SWITCH_BIT ? 1 : 0)
00566 
00567 #define SET_AXIS_HOME_SWITCH_FLAG(ax,fl) if (fl) emcmotStatus->axisFlag[ax] |= EMCMOT_AXIS_HOME_SWITCH_BIT; else emcmotStatus->axisFlag[ax] &= ~EMCMOT_AXIS_HOME_SWITCH_BIT;
00568 
00569 #define GET_AXIS_HOMING_FLAG(ax) (emcmotStatus->axisFlag[ax] & EMCMOT_AXIS_HOMING_BIT ? 1 : 0)
00570 
00571 #define SET_AXIS_HOMING_FLAG(ax,fl) if (fl) emcmotStatus->axisFlag[ax] |= EMCMOT_AXIS_HOMING_BIT; else emcmotStatus->axisFlag[ax] &= ~EMCMOT_AXIS_HOMING_BIT;
00572 
00573 #define GET_AXIS_HOMED_FLAG(ax) (emcmotStatus->axisFlag[ax] & EMCMOT_AXIS_HOMED_BIT ? 1 : 0)
00574 
00575 #define SET_AXIS_HOMED_FLAG(ax,fl) if (fl) emcmotStatus->axisFlag[ax] |= EMCMOT_AXIS_HOMED_BIT; else emcmotStatus->axisFlag[ax] &= ~EMCMOT_AXIS_HOMED_BIT;
00576 
00577 #define GET_AXIS_FERROR_FLAG(ax) (emcmotStatus->axisFlag[ax] & EMCMOT_AXIS_FERROR_BIT ? 1 : 0)
00578 
00579 #define SET_AXIS_FERROR_FLAG(ax,fl) if (fl) emcmotStatus->axisFlag[ax] |= EMCMOT_AXIS_FERROR_BIT; else emcmotStatus->axisFlag[ax] &= ~EMCMOT_AXIS_FERROR_BIT;
00580 
00581 #define GET_AXIS_FAULT_FLAG(ax) (emcmotStatus->axisFlag[ax] & EMCMOT_AXIS_FAULT_BIT ? 1 : 0)
00582 
00583 #define SET_AXIS_FAULT_FLAG(ax,fl) if (fl) emcmotStatus->axisFlag[ax] |= EMCMOT_AXIS_FAULT_BIT; else emcmotStatus->axisFlag[ax] &= ~EMCMOT_AXIS_FAULT_BIT;
00584 
00585 /* polarity flags */
00586 
00587 #define GET_AXIS_ENABLE_POLARITY(ax) (emcmotConfig->axisPolarity[ax] & EMCMOT_AXIS_ENABLE_BIT ? 1 : 0)
00588 
00589 #define SET_AXIS_ENABLE_POLARITY(ax,fl) if (fl) emcmotConfig->axisPolarity[ax] |= EMCMOT_AXIS_ENABLE_BIT; else emcmotConfig->axisPolarity[ax] &= ~EMCMOT_AXIS_ENABLE_BIT;
00590 
00591 #define GET_AXIS_PHL_POLARITY(ax) (emcmotConfig->axisPolarity[ax] & EMCMOT_AXIS_MAX_HARD_LIMIT_BIT ? 1 : 0)
00592 
00593 #define SET_AXIS_PHL_POLARITY(ax,fl) if (fl) emcmotConfig->axisPolarity[ax] |= EMCMOT_AXIS_MAX_HARD_LIMIT_BIT; else emcmotConfig->axisPolarity[ax] &= ~EMCMOT_AXIS_MAX_HARD_LIMIT_BIT;
00594 
00595 #define GET_AXIS_NHL_POLARITY(ax) (emcmotConfig->axisPolarity[ax] & EMCMOT_AXIS_MIN_HARD_LIMIT_BIT ? 1 : 0)
00596 
00597 #define SET_AXIS_NHL_POLARITY(ax,fl) if (fl) emcmotConfig->axisPolarity[ax] |= EMCMOT_AXIS_MIN_HARD_LIMIT_BIT; else emcmotConfig->axisPolarity[ax] &= ~EMCMOT_AXIS_MIN_HARD_LIMIT_BIT;
00598 
00599 #define GET_AXIS_HOME_SWITCH_POLARITY(ax) (emcmotConfig->axisPolarity[ax] & EMCMOT_AXIS_HOME_SWITCH_BIT ? 1 : 0)
00600 
00601 #define SET_AXIS_HOME_SWITCH_POLARITY(ax,fl) if (fl) emcmotConfig->axisPolarity[ax] |= EMCMOT_AXIS_HOME_SWITCH_BIT; else emcmotConfig->axisPolarity[ax] &= ~EMCMOT_AXIS_HOME_SWITCH_BIT;
00602 
00603 #define GET_AXIS_HOMING_POLARITY(ax) (emcmotConfig->axisPolarity[ax] & EMCMOT_AXIS_HOMING_BIT ? 1 : 0)
00604 
00605 #define SET_AXIS_HOMING_POLARITY(ax,fl) if (fl) emcmotConfig->axisPolarity[ax] |= EMCMOT_AXIS_HOMING_BIT; else emcmotConfig->axisPolarity[ax] &= ~EMCMOT_AXIS_HOMING_BIT;
00606 
00607 #define GET_AXIS_FAULT_POLARITY(ax) (emcmotConfig->axisPolarity[ax] & EMCMOT_AXIS_FAULT_BIT ? 1 : 0)
00608 
00609 #define SET_AXIS_FAULT_POLARITY(ax,fl) if (fl) emcmotConfig->axisPolarity[ax] |= EMCMOT_AXIS_FAULT_BIT; else emcmotConfig->axisPolarity[ax] &= ~EMCMOT_AXIS_FAULT_BIT;
00610 
00611 static TP_STRUCT queue;         /* coordinated mode planner */
00612 /* the freeAxis TP_STRUCTs are used to store the single joint value,
00613    in tran.x, that enables us to use the TP_STRUCT functions for axis
00614    planning. This is overkill, and we need to create a simpler TP_STRUCT
00615    for single-joint motion planning. */
00616 static TP_STRUCT freeAxis[EMCMOT_MAX_AXIS];
00617 /* freePose is a EmcPose struct that is used to hold a joint value, in
00618    tran.x, so that the TP_STRUCT functions can be called for scalar joint
00619    planning */
00620 static EmcPose freePose = {{0.0, 0.0, 0.0}, 0.0, 0.0, 0.0};
00621 static CUBIC_STRUCT cubic[EMCMOT_MAX_AXIS];
00622 
00623 /* space for trajectory planner queues, plus 10 more for safety */
00624 /* FIXME-- default is used; dynamic is not honored */
00625 static TC_STRUCT queueTcSpace[DEFAULT_TC_QUEUE_SIZE + 10];
00626 #define FREE_AXIS_QUEUE_SIZE 4  /* don't really queue free axis motion */
00627 static TC_STRUCT freeAxisTcSpace[EMCMOT_MAX_AXIS][FREE_AXIS_QUEUE_SIZE];
00628 
00629 static double rawInput[EMCMOT_MAX_AXIS];        /* raw feedback from sensors */
00630 static double rawOutput[EMCMOT_MAX_AXIS]; /* raw output to actuators */
00631 
00632 static double coarseJointPos[EMCMOT_MAX_AXIS];  /* trajectory point, in joints */
00633 static double jointPos[EMCMOT_MAX_AXIS]; /* interpolated point, in joints */
00634 static double jointVel[EMCMOT_MAX_AXIS]; /* joint velocity */
00635 static double oldJointPos[EMCMOT_MAX_AXIS]; /* ones from last cycle, for vel */
00636 static double oldInput[EMCMOT_MAX_AXIS]; /* ones for actual pos, last cycle */
00637 /* inverseInputScale[] is 1/inputScale[], and lets us use a multiplication
00638    instead of a division each servo cycle */
00639 static double inverseInputScale[EMCMOT_MAX_AXIS];
00640 static double inverseOutputScale[EMCMOT_MAX_AXIS];
00641 static EmcPose oldPos;           /* last position, used for vel differencing */
00642 static EmcPose oldVel, newVel;   /* velocities, used for acc differencing */
00643 static EmcPose newAcc;           /* differenced acc */
00644 
00645 /* value of speed past which we debounce the feedback */
00646 static double bigVel = 1.0;
00647 
00648 static int waitingForLatch[EMCMOT_MAX_AXIS]; /* flags for homing */
00649 static int latchFlag[EMCMOT_MAX_AXIS]; /* flags for axis latched */
00650 static double saveLatch[EMCMOT_MAX_AXIS]; /* saved axis latch values */
00651 
00652 static int enabling = 0;        /* starts up disabled */
00653 static int coordinating = 0;    /* starts up in free mode */
00654 
00655 static int wasOnLimit = 0;      /* non-zero means we already aborted
00656                                    everything due to a soft
00657                                    limit, and need not re-abort. It's
00658                                    cleared only when all limits are
00659                                    cleared. */
00660 static int onLimit = 0;         /* non-zero means at least one axis is
00661                                    on a soft limit */
00662 
00663 static int overriding = 0;      /* non-zero means we've initiated an axis
00664                                    move while overriding limits */
00665 
00666 static int stepping = 0;
00667 static int idForStep = 0;
00668 
00669 #ifdef STEPPER_MOTORS
00670 
00671 /* FIXME-- shouldn't hard code parallel port, use ext intf instead */
00672 #include "parport.h"
00673 
00674 static char smInhibit = 0 ;     /* non-zero means zero stepper task */
00675 static int smSteps[EMCMOT_MAX_AXIS];
00676 static double smStepsPerUnit[EMCMOT_MAX_AXIS]; /* signed, from input scale */
00677 static double smMagUnitsPerStep[EMCMOT_MAX_AXIS]; /* magnitude, always pos */
00678 static double smMaxStepsPerUnit; /* inited to INPUT_SCALE in init_module() */
00679 /* int stepperCount[EMCMOT_MAX_AXIS]; */
00680 static double smVPmax;          /* 1/smVPmax is clock rate for stepper pulse */
00681 static double smCycleTime;
00682 static int smCyclesPerAxis = 1;
00683 static int smNewCycle[EMCMOT_MAX_AXIS];
00684 
00685 #endif
00686 
00687 /* min-max-avg structs for traj and servo cycles */
00688 #if 0
00689 static MMXAVG_STRUCT tMmxavg;
00690 static MMXAVG_STRUCT sMmxavg;
00691 static MMXAVG_STRUCT nMmxavg;
00692 #endif
00693 
00694 #ifdef rtlinux
00695 
00696 static double etime(void)
00697 {
00698 #ifdef USE_RTL2
00699   hrtime_t now;
00700 
00701   now = gethrtime();            /* in HR_TICKS */
00702 
00703   return ((double) now) / ((double) HRTICKS_PER_SEC);
00704 #else
00705 
00706   RTIME now;
00707 
00708   now = rt_get_time();          /* in RT_TICKS */
00709 
00710   return ((double) now) / ((double) RT_TICKS_PER_SEC);
00711 #endif
00712 }
00713 
00714 #endif /* if rtlinux */
00715 
00716 #ifdef UNDER_CE
00717 #include "rcs_ce.h"             /* RCS_CE_VSPRINTF() */
00718 #endif
00719 
00720 static void reportError(const char *fmt, ...)
00721 {
00722   va_list args;
00723   char error[EMCMOT_ERROR_LEN];
00724 
00725   va_start(args, fmt);
00726 #ifndef UNDER_CE
00727   vsprintf(error, fmt, args);
00728 #else
00729   RCS_CE_VSPRINTF(error,fmt,args);
00730 #endif
00731   va_end(args);
00732 
00733 #if defined (rtlinux) && defined (RT_FIFO)
00734   rtf_put(EMCMOT_ERROR_RTF, error, EMCMOT_ERROR_LEN);
00735 
00736 #else
00737   emcmotErrorPut(emcmotError, error);
00738 
00739 #endif
00740 }
00741 
00742 /* isHoming() returns non-zero if any axes are homing, 0 if none are */
00743 static int isHoming(void)
00744 {
00745   int axis;
00746 
00747   for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
00748     if (GET_AXIS_HOMING_FLAG(axis)) {
00749       return 1;
00750     }
00751   }
00752 
00753   /* got here, so none are homing */
00754   return 0;
00755 }
00756 
00757 /* axis lengths */
00758 #define AXRANGE(axis) ((emcmotConfig->maxLimit[axis] - emcmotConfig->minLimit[axis]))
00759 
00760 /* inRange() returns non-zero if the position lies within the axis
00761    limits, or 0 if not */
00762 static int inRange(EmcPose pos)
00763 {
00764   double joint[EMCMOT_MAX_AXIS];
00765   int axis;
00766 
00767   /* fill in all joints with 0 */
00768   for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
00769     joint[axis] = 0.0;
00770   }
00771 
00772   /* now fill in with real values, for joints that are used */
00773   kinematicsInverse(&pos, joint, &iflags, &fflags);
00774 
00775   for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
00776     if (! GET_AXIS_ACTIVE_FLAG(axis)) {
00777       /* if axis is not active, don't even look at its limits */
00778       continue;
00779     }
00780 
00781     if (joint[axis] > emcmotConfig->maxLimit[axis] ||
00782         joint[axis] < emcmotConfig->minLimit[axis]) {
00783       return 0;         /* can't move further past limit */
00784     }
00785   }
00786 
00787   /* okay to move */
00788   return 1;
00789 }
00790 
00791 /* checkLimits() returns 1 if none of the soft or hard limits are
00792    set, 0 if any are set. Called on a linear and circular move. */
00793 static int checkLimits(void)
00794 {
00795   int axis;
00796 
00797   for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
00798     if (! GET_AXIS_ACTIVE_FLAG(axis)) {
00799       /* if axis is not active, don't even look at its limits */
00800       continue;
00801     }
00802 
00803     if (GET_AXIS_PSL_FLAG(axis) ||
00804         GET_AXIS_NSL_FLAG(axis) ||
00805         GET_AXIS_PHL_FLAG(axis) ||
00806         GET_AXIS_NHL_FLAG(axis)) {
00807       return 0;
00808     }
00809   }
00810 
00811   return 1;
00812 }
00813 
00814 /* check the value of the axis and velocity against current position,
00815    returning 1 (okay) if the request is to jog off the limit, 0 (bad)
00816    if the request is to jog further past a limit. Software limits are
00817    ignored if the axis hasn't been homed */
00818 static int checkJog(int axis, double vel)
00819 {
00820   if (emcmotStatus->overrideLimits) {
00821     return 1;                   /* okay to jog when limits overridden */
00822   }
00823 
00824   if (axis < 0 ||
00825       axis >= EMCMOT_MAX_AXIS) {
00826     return 0;                   /* can't jog out-of-range axis */
00827   }
00828 
00829   if (vel > 0.0 &&
00830       (GET_AXIS_PSL_FLAG(axis) ||
00831        GET_AXIS_PHL_FLAG(axis))) {
00832     return 0;                   /* can't jog further past max limit */
00833   }
00834 
00835   if (vel < 0.0 &&
00836       (GET_AXIS_NSL_FLAG(axis) ||
00837        GET_AXIS_NHL_FLAG(axis))) {
00838     return 0;                   /* can't jog further past min limit */
00839   }
00840 
00841   /* okay to jog */
00842   return 1;
00843 }
00844 
00845 /* counter that triggers computation of forward kinematics during
00846    disabled state, making them run at the trajectory rate instead
00847    of the servo rate. In the disabled state the interpolators are
00848    not queried so we don't know when a trajectory cycle would occur,
00849    so we use this counter. It's loaded with emcmotConfig->interpolationRate
00850    whenever it goes to zero, during the code executed in the disabled
00851    state. */
00852 static int interpolationCounter = 0;
00853 
00854 /* call this when setting the trajectory cycle time */
00855 static void setTrajCycleTime(double secs)
00856 {
00857   static int t;
00858 
00859   /* make sure it's not zero */
00860   if (secs <= 0.0) {
00861     return;
00862   }
00863   MARK_EMCMOT_CONFIG_CHANGE();
00864 
00865 
00866   /* compute the interpolation rate as nearest integer to traj/servo*/
00867   emcmotConfig->interpolationRate =
00868     (int) (secs / emcmotConfig->servoCycleTime + 0.5);
00869 
00870   /* set traj planner */
00871   tpSetCycleTime(&queue, secs);
00872 
00873   /* set the free planners, cubic interpolation rate and segment time */
00874   for (t = 0; t < EMCMOT_MAX_AXIS; t++) {
00875     tpSetCycleTime(&freeAxis[t], secs);
00876     cubicSetInterpolationRate(&cubic[t], emcmotConfig->interpolationRate);
00877   }
00878 
00879   /* copy into status out */
00880   emcmotConfig->trajCycleTime = secs;
00881 }
00882 
00883 /* call this when setting the servo cycle time */
00884 static void setServoCycleTime(double secs)
00885 {
00886   static int t;
00887 
00888   /* make sure it's not zero */
00889   if (secs <= 0.0) {
00890     return;
00891   }
00892 
00893   MARK_EMCMOT_CONFIG_CHANGE();
00894 
00895   /* compute the interpolation rate as nearest integer to traj/servo*/
00896   emcmotConfig->interpolationRate =
00897     (int) (emcmotConfig->trajCycleTime / secs + 0.5);
00898 
00899   /* set the cubic interpolation rate and PID cycle time */
00900   for (t = 0; t < EMCMOT_MAX_AXIS; t++) {
00901     cubicSetInterpolationRate(&cubic[t], emcmotConfig->interpolationRate);
00902     cubicSetSegmentTime(&cubic[t], secs);
00903 #ifndef STEPPER_MOTORS
00904     pidSetCycleTime(&emcmotConfig->pid[t], secs);
00905 #endif
00906   }
00907 
00908   /* copy into status out */
00909   emcmotConfig->servoCycleTime = secs;
00910 
00911 #ifdef STEPPER_MOTORS
00912   smCyclesPerAxis = (int) (emcmotConfig->servoCycleTime / smCycleTime);
00913 #endif
00914 }
00915 
00916 /*
00917   emcmotCommandHandler() is called each main cycle to read the
00918   shared memory buffer
00919   */
00920 static int emcmotCommandHandler(void)
00921 {
00922   int axis;                     /* loop counter */
00923 #ifdef rtlinux
00924 #ifdef RT_FIFO
00925   int err;
00926 #endif
00927 #endif
00928   int valid;
00929 #ifdef STEPPER_MOTORS
00930   double mag;                   /* temporary value for magnitudes, to
00931                                    avoid calling fabs() all the time */
00932 #endif
00933 
00934   /* copy command from outside into local buffers */
00935 
00936 #if defined (rtlinux) && defined (RT_FIFO)
00937   while ((err =
00938           rtf_get(EMCMOT_COMMAND_RTF, &emcmotCommandBuffer,
00939                   sizeof(EMCMOT_COMMAND))) == sizeof(EMCMOT_COMMAND)) {
00940 
00941 #endif /* rtlinux and RT_FIFO */
00942 
00943     /* check for split read */
00944     if (emcmotCommand->head != emcmotCommand->tail) {
00945       emcmotDebug->split++;
00946       return 0;                 /* not really an error */
00947     }
00948 
00949     if (emcmotCommand->commandNum != emcmotStatus->commandNumEcho) {
00950       /* increment head count-- we'll be modifying emcmotStatus */
00951       emcmotStatus->head++;
00952       emcmotDebug->head++;
00953 
00954       /* got a new command-- echo command and number... */
00955       emcmotStatus->commandEcho = emcmotCommand->command;
00956       emcmotStatus->commandNumEcho = emcmotCommand->commandNum;
00957 
00958       /* clear status value by default */
00959       emcmotStatus->commandStatus = EMCMOT_COMMAND_OK;
00960 
00961       /* log it, if appropriate */
00962       if (emcmotStatus->logStarted &&
00963           emcmotStatus->logType == EMCMOT_LOG_TYPE_CMD) {
00964         ls.item.cmd.time = etime();
00965         ls.item.cmd.command = emcmotCommand->command;
00966         ls.item.cmd.commandNum = emcmotCommand->commandNum;
00967 #if defined (rtlinux) && defined (RT_FIFO)
00968         rtf_put(EMCMOT_LOG_RTF, &ls, sizeof(EMCMOT_LOG_STRUCT));
00969 #else  /* not rtlinux or not RT_FIFO */
00970         emcmotLogAdd(emcmotLog, ls);
00971         emcmotStatus->logPoints = emcmotLog->howmany;
00972 #endif /* else not rtlinux nor RT_FIFO */
00973       }
00974 
00975       /* ...and process command */
00976       switch (emcmotCommand->command) {
00977       case EMCMOT_FREE:
00978         /* change the mode to free axis motion */
00979         /* can be done at any time */
00980         /* reset the coordinating flag to defer transition to
00981            controller cycle */
00982         coordinating = 0;
00983         break;
00984 
00985       case EMCMOT_COORD:
00986         /* change the mode to coordinated axis motion */
00987         /* can be done at any time */
00988         /* set the coordinating flag to defer transition to
00989            controller cycle */
00990         coordinating = 1;
00991         break;
00992 
00993       case EMCMOT_SET_NUM_AXES:
00994         MARK_EMCMOT_CONFIG_CHANGE();
00995         /* set the global NUM_AXES, which must be between 1 and
00996            EMCMOT_MAX_AXIS, inclusive */
00997         axis = emcmotCommand->axis;
00998         /* note that this comparison differs from the check on the
00999            range of 'axis' in most other places, since those checks
01000            are for a value to be used as an index and here it's a value
01001            to be used as a counting number. The indenting is different
01002            here so as not to match macro editing on that other bunch. */
01003         if
01004           (
01005            axis <= 0 ||
01006            axis > EMCMOT_MAX_AXIS
01007            ) {
01008           break;
01009         }
01010         NUM_AXES = axis;
01011         break;
01012 
01013       case EMCMOT_SET_WORLD_HOME:
01014         worldHome = emcmotCommand->pos;
01015         break;
01016 
01017       case EMCMOT_SET_JOINT_HOME:
01018         axis = emcmotCommand->axis;
01019         if (axis < 0 ||
01020             axis >= EMCMOT_MAX_AXIS) {
01021           break;
01022         }
01023         jointHome[axis] = emcmotCommand->offset; /* FIXME-- use 'home' instead */
01024         break;
01025 
01026       case EMCMOT_SET_HOME_OFFSET:
01027         axis = emcmotCommand->axis;
01028         if (axis < 0 ||
01029             axis >= EMCMOT_MAX_AXIS) {
01030           break;
01031         }
01032         emcmotConfig->homeOffset[axis] = emcmotCommand->offset;
01033         break;
01034 
01035       case EMCMOT_OVERRIDE_LIMITS:
01036         if (emcmotCommand->axis < 0) {
01037           /* don't override limits */
01038           emcmotStatus->overrideLimits = 0;
01039         }
01040         else {
01041           emcmotStatus->overrideLimits = 1;
01042         }
01043         overriding = 0;
01044         for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
01045           SET_AXIS_ERROR_FLAG(axis, 0);
01046         }
01047         break;
01048 
01049       case EMCMOT_SET_TRAJ_CYCLE_TIME:
01050         MARK_EMCMOT_CONFIG_CHANGE();
01051         /* set the cycle time for trajectory calculations */
01052         /* really should be done only at startup before
01053            controller is run, but at least it requires
01054            no active motions and the interpolators need
01055            to be cleared */
01056         setTrajCycleTime(emcmotCommand->cycleTime);
01057         break;
01058 
01059       case EMCMOT_SET_SERVO_CYCLE_TIME:
01060         MARK_EMCMOT_CONFIG_CHANGE();
01061         /* set the cycle time for servo calculations, which is the
01062            period for emcmotController execution */
01063         /* really should be done only at startup before
01064            controller is run, but at least it requires
01065            no active motions and the interpolators need
01066            to be cleared */
01067         setServoCycleTime(emcmotCommand->cycleTime);
01068 #ifdef rtlinux
01069 #ifdef USE_RTL2
01070         pthread_make_periodic_np(emcmotTask,
01071                                  gethrtime(),
01072                                  (hrtime_t)  (HRTICKS_PER_SEC *
01073                                              emcmotConfig->servoCycleTime));
01074 #else
01075         rt_task_make_periodic(&emcmotTask,
01076                               rt_get_time(),
01077                               (RTIME) (RT_TICKS_PER_SEC *
01078                                        emcmotConfig->servoCycleTime));
01079 #endif
01080 #endif /* rtlinux */
01081         break;
01082 
01083       case EMCMOT_SET_POSITION_LIMITS:
01084         MARK_EMCMOT_CONFIG_CHANGE();
01085         /* set the position limits for the axis */
01086         /* can be done at any time */
01087         axis = emcmotCommand->axis;
01088         if (axis < 0 ||
01089             axis >= EMCMOT_MAX_AXIS) {
01090           break;
01091         }
01092         emcmotConfig->minLimit[axis] = emcmotCommand->minLimit;
01093         emcmotConfig->maxLimit[axis] = emcmotCommand->maxLimit;
01094         break;
01095 
01096       case EMCMOT_SET_OUTPUT_LIMITS:
01097         MARK_EMCMOT_CONFIG_CHANGE();
01098         /* set the output limits for the axis */
01099         /* can be done at any time */
01100         axis = emcmotCommand->axis;
01101         if (axis < 0 ||
01102             axis >= EMCMOT_MAX_AXIS) {
01103           break;
01104         }
01105 
01106         emcmotConfig->minOutput[axis] = emcmotCommand->minLimit;
01107         emcmotConfig->maxOutput[axis] = emcmotCommand->maxLimit;
01108         break;
01109 
01110       case EMCMOT_SET_OUTPUT_SCALE:
01111         axis = emcmotCommand->axis;
01112         if (axis < 0 ||
01113             axis >= EMCMOT_MAX_AXIS ||
01114             emcmotCommand->scale == 0) {
01115           break;
01116         }
01117         emcmotStatus->outputScale[axis] = emcmotCommand->scale;
01118         emcmotStatus->outputOffset[axis] = emcmotCommand->offset;
01119         inverseOutputScale[axis] = 1.0 / emcmotStatus->outputScale[axis];
01120         break;
01121 
01122       case EMCMOT_SET_INPUT_SCALE:
01123         /*
01124           change the scale factor for the position input, e.g.,
01125           encoder counts per unit. Note that this is not a good idea
01126           once things have gotten underway, since the axis will
01127           jump servo to the "new" position, the gains will no longer
01128           be appropriate, etc.
01129         */
01130         axis = emcmotCommand->axis;
01131         if (axis < 0 ||
01132             axis >= EMCMOT_MAX_AXIS ||
01133             emcmotCommand->scale == 0.0) {
01134           break;
01135         }
01136 
01137         /* adjust last saved input value to match this one, so we
01138            don't get a spurious following error */
01139         oldInput[axis] = oldInput[axis] * emcmotStatus->inputScale[axis] +
01140           emcmotStatus->inputOffset[axis]; /* temp calc */
01141         oldInput[axis] = (oldInput[axis] - emcmotCommand->offset) /
01142           emcmotCommand->scale;
01143 
01144         /* now make them active */
01145         emcmotStatus->inputScale[axis] = emcmotCommand->scale;
01146         emcmotStatus->inputOffset[axis] = emcmotCommand->offset;
01147         inverseInputScale[axis] = 1.0 / emcmotStatus->inputScale[axis];
01148 
01149 #ifdef STEPPER_MOTORS
01150         /* change the units on the stepper counts; note that this
01151            is a signed value. De-sign it if you want to consider
01152            just its magnitude. */
01153         smStepsPerUnit[axis] = emcmotCommand->scale;
01154         mag = fabs(smStepsPerUnit[axis]);
01155         smMagUnitsPerStep[axis] = 1.0 / mag;
01156         /* update smVPmax so that stepper task runs at proper rate */
01157         if (mag > smMaxStepsPerUnit) {
01158           smVPmax = smVPmax * mag / smMaxStepsPerUnit;
01159           smMaxStepsPerUnit = mag;
01160         }
01161         /* set the period to twice the max pulse rate. It need only
01162            be the same as the pulse rate, but this makes it the same
01163            as before */
01164         smCycleTime = 0.5/smVPmax;
01165         smCyclesPerAxis = (int) (emcmotConfig->servoCycleTime / smCycleTime);
01166 #ifdef USE_RTL2
01167         pthread_make_periodic_np(smTask,
01168                               gethrtime(),
01169                               ((hrtime_t) (HRTICKS_PER_SEC * smCycleTime)));
01170 #else
01171         rt_task_make_periodic(&smTask,
01172                               rt_get_time(),
01173                               ((RTIME) (RT_TICKS_PER_SEC * smCycleTime)));
01174 #endif
01175 #endif
01176         break;
01177 
01178         /*
01179           Max and min ferror work like this:
01180           limiting ferror is determined by slope of ferror line,
01181           = maxFerror/limitVel
01182           -> limiting ferror = maxFerror/limitVel * vel.
01183           If ferror < minFerror then OK else
01184           if ferror < limiting ferror then OK else ERROR
01185          */
01186 
01187       case EMCMOT_SET_MAX_FERROR:
01188         MARK_EMCMOT_CONFIG_CHANGE();
01189         axis = emcmotCommand->axis;
01190         if (axis < 0 ||
01191             axis >= EMCMOT_MAX_AXIS ||
01192             emcmotCommand->maxFerror < 0.0) {
01193           break;
01194         }
01195         emcmotConfig->maxFerror[axis] = emcmotCommand->maxFerror;
01196         break;
01197 
01198       case EMCMOT_SET_MIN_FERROR:
01199         MARK_EMCMOT_CONFIG_CHANGE();
01200         axis = emcmotCommand->axis;
01201         if (axis < 0 ||
01202             axis >= EMCMOT_MAX_AXIS ||
01203             emcmotCommand->minFerror < 0.0) {
01204           break;
01205         }
01206         emcmotConfig->minFerror[axis] = emcmotCommand->minFerror;
01207         break;
01208 
01209       case EMCMOT_JOG_CONT:
01210         /* do a continuous jog, implemented as an incremental
01211            jog to the software limit, or the full range of travel
01212            if software limits don't yet apply because we're not homed */
01213 
01214         /* check axis range */
01215         axis = emcmotCommand->axis;
01216         if (axis < 0 ||
01217             axis >= EMCMOT_MAX_AXIS) {
01218           break;
01219         }
01220 
01221         /* requires no motion, in free mode, enable on */
01222         if (GET_MOTION_COORD_FLAG() ||
01223             ! GET_MOTION_INPOS_FLAG() ||
01224             ! GET_MOTION_ENABLE_FLAG()) {
01225           SET_AXIS_ERROR_FLAG(axis, 1);
01226           break;
01227         }
01228 
01229         /* don't jog further onto limits */
01230         if (! checkJog(axis, emcmotCommand->vel)) {
01231           SET_AXIS_ERROR_FLAG(axis, 1);
01232           break;
01233         }
01234 
01235         if (emcmotCommand->vel > 0.0) {
01236           if (GET_AXIS_HOMED_FLAG(axis)) {
01237             freePose.tran.x = emcmotConfig->maxLimit[axis];
01238           }
01239           else {
01240             freePose.tran.x = AXRANGE(axis);
01241           }
01242         }
01243         else {
01244           if (GET_AXIS_HOMED_FLAG(axis)) {
01245             freePose.tran.x = emcmotConfig->minLimit[axis];
01246           }
01247           else {
01248             freePose.tran.x = - AXRANGE(axis);
01249           }
01250         }
01251 
01252         tpSetVmax(&freeAxis[axis], fabs(emcmotCommand->vel));
01253         tpAddLine(&freeAxis[axis], freePose);
01254         SET_AXIS_ERROR_FLAG(axis, 0);
01255 
01256         break;
01257 
01258       case EMCMOT_JOG_INCR:
01259         /* do an incremental jog */
01260 
01261         /* check axis range */
01262         axis = emcmotCommand->axis;
01263         if (axis < 0 ||
01264             axis >= EMCMOT_MAX_AXIS) {
01265           break;
01266         }
01267 
01268         /* requires no motion, in free mode, enable on */
01269         if (GET_MOTION_COORD_FLAG() ||
01270             ! GET_MOTION_INPOS_FLAG() ||
01271             ! GET_MOTION_ENABLE_FLAG()) {
01272           SET_AXIS_ERROR_FLAG(axis, 1);
01273           break;
01274         }
01275 
01276         /* don't jog further onto limits */
01277         if (! checkJog(axis, emcmotCommand->vel)) {
01278           SET_AXIS_ERROR_FLAG(axis, 1);
01279           break;
01280         }
01281 
01282         if (emcmotCommand->vel > 0.0) {
01283           freePose.tran.x = jointPos[axis] + emcmotCommand->offset; /* FIXME-- use 'goal' instead */
01284           if (GET_AXIS_HOMED_FLAG(axis)) {
01285             if (freePose.tran.x > emcmotConfig->maxLimit[axis]) {
01286               freePose.tran.x = emcmotConfig->maxLimit[axis];
01287             }
01288           }
01289         }
01290         else {
01291           freePose.tran.x = jointPos[axis] - emcmotCommand->offset; /* FIXME-- use 'goal' instead */
01292           if (GET_AXIS_HOMED_FLAG(axis)) {
01293             if (freePose.tran.x < emcmotConfig->minLimit[axis]) {
01294               freePose.tran.x = emcmotConfig->minLimit[axis];
01295             }
01296           }
01297         }
01298 
01299         tpSetVmax(&freeAxis[axis], fabs(emcmotCommand->vel));
01300         tpAddLine(&freeAxis[axis], freePose);
01301         SET_AXIS_ERROR_FLAG(axis, 0);
01302 
01303         break;
01304 
01305       case EMCMOT_JOG_ABS:
01306         /* do an absolute jog */
01307 
01308         /* check axis range */
01309         axis = emcmotCommand->axis;
01310         if (axis < 0 ||
01311             axis >= EMCMOT_MAX_AXIS) {
01312           break;
01313         }
01314 
01315         /* requires no motion, in free mode, enable on */
01316         if (GET_MOTION_COORD_FLAG() ||
01317             ! GET_MOTION_INPOS_FLAG() ||
01318             ! GET_MOTION_ENABLE_FLAG()) {
01319           SET_AXIS_ERROR_FLAG(axis, 1);
01320           break;
01321         }
01322 
01323         /* don't jog further onto limits */
01324         if (! checkJog(axis, emcmotCommand->vel)) {
01325           SET_AXIS_ERROR_FLAG(axis, 1);
01326           break;
01327         }
01328 
01329         freePose.tran.x = emcmotCommand->offset; /* FIXME-- use 'goal' instead */
01330         if (GET_AXIS_HOMED_FLAG(axis)) {
01331           if (freePose.tran.x > emcmotConfig->maxLimit[axis]) {
01332             freePose.tran.x = emcmotConfig->maxLimit[axis];
01333           }
01334           else if (freePose.tran.x < emcmotConfig->minLimit[axis]) {
01335             freePose.tran.x = emcmotConfig->minLimit[axis];
01336           }
01337         }
01338 
01339         tpSetVmax(&freeAxis[axis], fabs(emcmotCommand->vel));
01340         tpAddLine(&freeAxis[axis], freePose);
01341         SET_AXIS_ERROR_FLAG(axis, 0);
01342 
01343         break;
01344 
01345       case EMCMOT_SET_TERM_COND:
01346         /* sets termination condition for motion queue */
01347         tpSetTermCond(&queue, emcmotCommand->termCond);
01348         break;
01349 
01350       case EMCMOT_SET_LINE:
01351         /* queue up a linear move */
01352         /* requires coordinated mode, enable off, not on limits */
01353         if (! GET_MOTION_COORD_FLAG() ||
01354             ! GET_MOTION_ENABLE_FLAG()) {
01355           reportError("Need to be enabled, in coord mode for linear move");
01356           emcmotStatus->commandStatus = EMCMOT_COMMAND_INVALID_COMMAND;
01357           SET_MOTION_ERROR_FLAG(1);
01358           break;
01359         }
01360         else if (! inRange(emcmotCommand->pos)) {
01361           reportError("Linear move %d out of range",
01362                       emcmotCommand->id);
01363           emcmotStatus->commandStatus = EMCMOT_COMMAND_INVALID_PARAMS;
01364           tpAbort(&queue);
01365           SET_MOTION_ERROR_FLAG(1);
01366           break;
01367         }
01368         else if (! checkLimits()) {
01369           reportError("Can't do linear move with limits exceeded");
01370           emcmotStatus->commandStatus = EMCMOT_COMMAND_INVALID_PARAMS;
01371           tpAbort(&queue);
01372           SET_MOTION_ERROR_FLAG(1);
01373           break;
01374         }
01375 
01376         /* append it to the queue */
01377         tpSetId(&queue, emcmotCommand->id);
01378         if (-1 == tpAddLine(&queue, emcmotCommand->pos)) {
01379           reportError("Can't add linear move");
01380           emcmotStatus->commandStatus = EMCMOT_COMMAND_BAD_EXEC;
01381           tpAbort(&queue);
01382           SET_MOTION_ERROR_FLAG(1);
01383           break;
01384         }
01385         else {
01386           SET_MOTION_ERROR_FLAG(0);
01387         }
01388         break;
01389 
01390       case EMCMOT_SET_CIRCLE:
01391         /* queue up a circular move */
01392         /* requires coordinated mode, enable on, not on limits */
01393         if (! GET_MOTION_COORD_FLAG() ||
01394             ! GET_MOTION_ENABLE_FLAG()) {
01395           reportError("Need to be enabled, in coord mode for circular move");
01396           emcmotStatus->commandStatus = EMCMOT_COMMAND_INVALID_COMMAND;
01397           SET_MOTION_ERROR_FLAG(1);
01398           break;
01399         }
01400         else if (! inRange(emcmotCommand->pos)) {
01401           reportError("Circular move %d out of range",
01402                       emcmotCommand->id);
01403           emcmotStatus->commandStatus = EMCMOT_COMMAND_INVALID_PARAMS;
01404           tpAbort(&queue);
01405           SET_MOTION_ERROR_FLAG(1);
01406           break;
01407         }
01408         else if (! checkLimits()) {
01409           reportError("Can't do circular move with limits exceeded");
01410           emcmotStatus->commandStatus = EMCMOT_COMMAND_INVALID_PARAMS;
01411           tpAbort(&queue);
01412           SET_MOTION_ERROR_FLAG(1);
01413           break;
01414         }
01415 
01416         /* append it to the queue */
01417         tpSetId(&queue, emcmotCommand->id);
01418         if (-1 ==
01419             tpAddCircle(&queue, emcmotCommand->pos,
01420                         emcmotCommand->center, emcmotCommand->normal,
01421                         emcmotCommand->turn)) {
01422           reportError("Can't add circular move");
01423           emcmotStatus->commandStatus = EMCMOT_COMMAND_BAD_EXEC;
01424           tpAbort(&queue);
01425           SET_MOTION_ERROR_FLAG(1);
01426           break;
01427         }
01428         else {
01429           SET_MOTION_ERROR_FLAG(0);
01430         }
01431         break;
01432 
01433       case EMCMOT_SET_VEL:
01434         /* set the velocity for subsequent moves */
01435         /* can do it at any time */
01436         emcmotStatus->vel = emcmotCommand->vel;
01437         for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
01438           tpSetVmax(&freeAxis[axis], emcmotStatus->vel);
01439         }
01440         tpSetVmax(&queue, emcmotStatus->vel);
01441         break;
01442 
01443 
01444       case EMCMOT_SET_AXIS_VEL_LIMIT:
01445         /* check axis range */
01446         axis = emcmotCommand->axis;
01447         if (axis < 0 ||
01448             axis >= EMCMOT_MAX_AXIS) {
01449           break;
01450         }
01451         tpSetVlimit(&freeAxis[axis], emcmotCommand->vel);
01452         emcmotConfig->axisLimitVel[axis] = emcmotCommand->vel;
01453         // bigVel[axis = 10 * emcmotCommand->vel;
01454         break;
01455         
01456       case EMCMOT_SET_VEL_LIMIT:
01457         /* set the absolute max velocity for all subsequent moves */
01458         /* can do it at any time */
01459 #ifdef STEPPER_MOTORS
01460         /* update smVPmax so that stepper task runs at proper rate,
01461            before we lose emcmotStatus->vel from overwrite by new value */
01462         smVPmax = smVPmax * emcmotCommand->vel / emcmotConfig->limitVel;
01463         /* set the period to twice the max pulse rate. It need only
01464            be the same as the pulse rate, but this makes it the same
01465            as before */
01466         smCycleTime = 0.5/smVPmax;
01467         smCyclesPerAxis = (int) (emcmotConfig->servoCycleTime / smCycleTime);
01468 #ifdef USE_RTL2
01469         pthread_make_periodic_np(smTask,
01470                               gethrtime(),
01471                               ((hrtime_t) (HRTICKS_PER_SEC * smCycleTime)));
01472 #else
01473         rt_task_make_periodic(&smTask,
01474                               rt_get_time(),
01475                               ((RTIME) (RT_TICKS_PER_SEC * smCycleTime)));
01476 #endif
01477 #endif
01478         emcmotConfig->limitVel = emcmotCommand->vel;
01479         for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
01480           tpSetVlimit(&freeAxis[axis], emcmotConfig->limitVel);
01481         }
01482         tpSetVlimit(&queue, emcmotConfig->limitVel);
01483         /* set the debounce vel */
01484         bigVel = 10.0 * emcmotConfig->limitVel;
01485         break;
01486 
01487       case EMCMOT_SET_HOMING_VEL:
01488         /* set the homing velocity */
01489         /* can do it at any time */
01490         /* sign of vel should set polarity, and mag-sign are recorded */
01491 
01492         /* check axis range */
01493         axis = emcmotCommand->axis;
01494         if (axis < 0 ||
01495             axis >= EMCMOT_MAX_AXIS) {
01496           break;
01497         }
01498 
01499         if (emcmotCommand->vel < 0.0) {
01500           emcmotConfig->homingVel[axis] = - emcmotCommand->vel;
01501           SET_AXIS_HOMING_POLARITY(axis, 0);
01502         }
01503         else {
01504           emcmotConfig->homingVel[axis] = emcmotCommand->vel;
01505           SET_AXIS_HOMING_POLARITY(axis, 1);
01506         }
01507         break;
01508 
01509       case EMCMOT_SET_ACC:
01510         /* set the max acceleration */
01511         /* can do it at any time */
01512         emcmotStatus->acc = emcmotCommand->acc;
01513         for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
01514           tpSetAmax(&freeAxis[axis], emcmotStatus->acc);
01515         }
01516         tpSetAmax(&queue, emcmotStatus->acc);
01517         break;
01518 
01519       case EMCMOT_PAUSE:
01520         /* pause the motion */
01521         /* can happen at any time */
01522         for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
01523           tpPause(&freeAxis[axis]);
01524         }
01525         tpPause(&queue);
01526         emcmotStatus->paused = 1;
01527         break;
01528 
01529       case EMCMOT_RESUME:
01530         /* resume paused motion */
01531         /* can happen at any time */
01532         stepping = 0;
01533         for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
01534           tpResume(&freeAxis[axis]);
01535         }
01536         tpResume(&queue);
01537         emcmotStatus->paused = 0;
01538         break;
01539 
01540       case EMCMOT_STEP:
01541         /* resume paused motion until id changes */
01542         /* can happen at any time */
01543         idForStep = emcmotStatus->id;
01544         stepping = 1;
01545         for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
01546           tpResume(&freeAxis[axis]);
01547         }
01548         tpResume(&queue);
01549         emcmotStatus->paused = 0;
01550         break;
01551 
01552       case EMCMOT_SCALE:
01553         /* override speed */
01554         /* can happen at any time */
01555         if (emcmotCommand->scale < 0.0) {
01556           emcmotCommand->scale = 0.0; /* clamp it */
01557         }
01558         for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
01559           tpSetVscale(&freeAxis[axis], emcmotCommand->scale);
01560           emcmotStatus->axVscale[axis] = emcmotCommand->scale;
01561         }
01562         tpSetVscale(&queue, emcmotCommand->scale);
01563         emcmotStatus->qVscale = emcmotCommand->scale;
01564         break;
01565 
01566       case EMCMOT_ABORT:
01567         /* abort motion */
01568         /* can happen at any time */
01569         /* check for coord or free space motion active */
01570         if (GET_MOTION_COORD_FLAG()) {
01571           tpAbort(&queue);
01572           SET_MOTION_ERROR_FLAG(0);
01573         }
01574         else {
01575           /* check axis range */
01576           axis = emcmotCommand->axis;
01577           if (axis < 0 ||
01578               axis >= EMCMOT_MAX_AXIS) {
01579             break;
01580           }
01581           tpAbort(&freeAxis[axis]);
01582           SET_AXIS_HOMING_FLAG(axis, 0);
01583           SET_AXIS_ERROR_FLAG(axis, 0);
01584         }
01585         break;
01586 
01587       case EMCMOT_DISABLE:
01588         /* go into disable */
01589         /* can happen at any time */
01590         /* reset the enabling flag to defer disable until
01591            controller cycle (it *will* be honored) */
01592         enabling = 0;
01593         break;
01594 
01595       case EMCMOT_ENABLE:
01596         /* come out of disable */
01597         /* can happen at any time */
01598         /* set the enabling flag to defer enable
01599            until controller cycle */
01600         enabling = 1;
01601         break;
01602 
01603       case EMCMOT_SET_PID:
01604         /* configure the PID gains */
01605         axis = emcmotCommand->axis;
01606         if (axis < 0 ||
01607             axis >= EMCMOT_MAX_AXIS) {
01608           break;
01609         }
01610         /* force it, instead of callind pidSetGains(), which would require
01611            that we link in pid.o, which we don't really need to do */
01612         emcmotConfig->pid[axis].p = emcmotCommand->pid.p;
01613         emcmotConfig->pid[axis].i = emcmotCommand->pid.i;
01614         emcmotConfig->pid[axis].d = emcmotCommand->pid.d;
01615         emcmotConfig->pid[axis].ff0 = emcmotCommand->pid.ff0;
01616         emcmotConfig->pid[axis].ff1 = emcmotCommand->pid.ff1;
01617         emcmotConfig->pid[axis].ff2 = emcmotCommand->pid.ff2;
01618         emcmotConfig->pid[axis].backlash = emcmotCommand->pid.backlash;
01619         emcmotConfig->pid[axis].bias = emcmotCommand->pid.bias;
01620         emcmotConfig->pid[axis].maxError = emcmotCommand->pid.maxError;
01621         emcmotConfig->pid[axis].deadband = emcmotCommand->pid.deadband;
01622         break;
01623 
01624       case EMCMOT_ACTIVATE_AXIS:
01625         /* make axis active, so that amps will be enabled when
01626            system is enabled or disabled */
01627         /* can be done at any time */
01628         axis = emcmotCommand->axis;
01629         if (axis < 0 ||
01630             axis >= EMCMOT_MAX_AXIS) {
01631           break;
01632         }
01633         SET_AXIS_ACTIVE_FLAG(axis, 1);
01634         break;
01635 
01636       case EMCMOT_DEACTIVATE_AXIS:
01637         /* make axis inactive, so that amps won't be affected when
01638            system is enabled or disabled */
01639         /* can be done at any time */
01640         axis = emcmotCommand->axis;
01641         if (axis < 0 ||
01642             axis >= EMCMOT_MAX_AXIS) {
01643           break;
01644         }
01645         SET_AXIS_ACTIVE_FLAG(axis, 0);
01646         break;
01647 
01648       case EMCMOT_ENABLE_AMPLIFIER:
01649         /* enable the amplifier directly, but don't enable calculations */
01650         /* can be done at any time */
01651         axis = emcmotCommand->axis;
01652         if (axis < 0 ||
01653             axis >= EMCMOT_MAX_AXIS) {
01654           break;
01655         }
01656         extAmpEnable(axis, GET_AXIS_ENABLE_POLARITY(axis));
01657         break;
01658 
01659       case EMCMOT_DISABLE_AMPLIFIER:
01660         /* disable the axis calculations and amplifier, but don't
01661            disable calculations */
01662         /* can be done at any time */
01663         axis = emcmotCommand->axis;
01664         if (axis < 0 ||
01665             axis >= EMCMOT_MAX_AXIS) {
01666           break;
01667         }
01668         extAmpEnable(axis, ! GET_AXIS_ENABLE_POLARITY(axis));
01669         break;
01670 
01671       case EMCMOT_OPEN_LOG:
01672         /* open a data log */
01673         axis = emcmotCommand->axis;
01674         valid = 0;
01675         if (emcmotCommand->logSize > 0 &&
01676             emcmotCommand->logSize <= EMCMOT_LOG_MAX) {
01677           /* handle log-specific data */
01678           switch (emcmotCommand->logType) {
01679           case EMCMOT_LOG_TYPE_AXIS_POS:
01680           case EMCMOT_LOG_TYPE_AXIS_VEL:
01681           case EMCMOT_LOG_TYPE_POS_VOLTAGE:
01682             if (axis >= 0 &&
01683                 axis < EMCMOT_MAX_AXIS) {
01684               loggingAxis = axis;
01685               valid = 1;
01686             }
01687             break;
01688 
01689           default:
01690             valid = 1;
01691             break;
01692           }
01693         }
01694 
01695         if (valid) {
01696           /* success */
01697 #if defined (rtlinux) && defined (RT_FIFO)
01698           if (-1 ==
01699               rtf_create(EMCMOT_LOG_RTF,
01700                          emcmotCommand->logSize *
01701                          sizeof(EMCMOT_LOG_STRUCT))) {
01702             /* error-- can't open log */
01703             break;
01704           }
01705 #else  /* not rtlinux or not RT_FIFO */
01706           emcmotLogInit(emcmotLog,
01707                         emcmotCommand->logType,
01708                         emcmotCommand->logSize);
01709 #endif /* else not rtlinux or not RT_FIFO */
01710           emcmotStatus->logOpen = 1;
01711           emcmotStatus->logStarted = 0;
01712           emcmotStatus->logSize = emcmotCommand->logSize;
01713           emcmotStatus->logSkip = emcmotCommand->logSkip;
01714           emcmotStatus->logType = emcmotCommand->logType;
01715         }
01716         break;
01717 
01718       case EMCMOT_START_LOG:
01719         /* start logging */
01720         /* first ignore triggered log types */
01721         if (emcmotStatus->logType == EMCMOT_LOG_TYPE_POS_VOLTAGE) {
01722           break;
01723         }
01724         if (emcmotStatus->logOpen) {
01725           emcmotStatus->logStarted = 1;
01726           logSkip = 0;
01727         }
01728         break;
01729 
01730       case EMCMOT_STOP_LOG:
01731         /* stop logging */
01732         emcmotStatus->logStarted = 0;
01733         break;
01734 
01735       case EMCMOT_CLOSE_LOG:
01736 #if defined (rtlinux) && defined (RT_FIFO)
01737         rtf_destroy(EMCMOT_LOG_RTF);
01738 #endif /* rtlinux and RT_FIFO */
01739         emcmotStatus->logOpen = 0;
01740         emcmotStatus->logStarted = 0;
01741         emcmotStatus->logSize = 0;
01742         emcmotStatus->logSkip = 0;
01743         emcmotStatus->logType = 0;
01744         break;
01745 
01746       case EMCMOT_DAC_OUT:
01747         /* write output to dacs directly */
01748         /* will only persist if amplifiers are disabled */
01749         axis = emcmotCommand->axis;
01750         if (axis < 0 ||
01751             axis >= EMCMOT_MAX_AXIS) {
01752           break;
01753         }
01754         /* trigger log, if active */
01755         if (emcmotStatus->logType == EMCMOT_LOG_TYPE_POS_VOLTAGE &&
01756             loggingAxis == axis &&
01757             emcmotStatus->logOpen != 0) {
01758           emcmotStatus->logStarted = 1;
01759           logSkip = 0;
01760         }
01761         emcmotStatus->output[axis] = emcmotCommand->dacOut;
01762         break;
01763 
01764       case EMCMOT_HOME:
01765         /* home the specified axis */
01766         /* need to be in free mode, enable on */
01767         /* homing is basically a slow incremental jog to full range */
01768         axis = emcmotCommand->axis;
01769         if (axis < 0 ||
01770             axis >= EMCMOT_MAX_AXIS) {
01771           break;
01772         }
01773         if (GET_MOTION_COORD_FLAG() ||
01774             ! GET_MOTION_ENABLE_FLAG()) {
01775           break;
01776         }
01777 
01778         if (GET_AXIS_HOMING_POLARITY(axis)) {
01779           freePose.tran.x = + 2.0 * AXRANGE(axis);
01780         }
01781         else {
01782           freePose.tran.x = - 2.0 * AXRANGE(axis);
01783         }
01784 
01785         tpSetVmax(&freeAxis[axis], emcmotConfig->homingVel[axis]);
01786         tpAddLine(&freeAxis[axis], freePose);
01787         waitingForLatch[axis] = 1;
01788         SET_AXIS_HOMING_FLAG(axis, 1);
01789         SET_AXIS_HOMED_FLAG(axis, 0);
01790         break;
01791 
01792       case EMCMOT_ENABLE_WATCHDOG:
01793         wdEnabling = 1;
01794         wdWait = emcmotCommand->wdWait;
01795         if (wdWait < 0) {
01796           wdWait = 0;
01797         }
01798         break;
01799 
01800       case EMCMOT_DISABLE_WATCHDOG:
01801         wdEnabling = 0;
01802         break;
01803 
01804       case EMCMOT_SET_POLARITY:
01805         axis = emcmotCommand->axis;
01806         if (axis < 0 ||
01807             axis >= EMCMOT_MAX_AXIS) {
01808           break;
01809         }
01810         if (emcmotCommand->level) {
01811           /* normal */
01812           emcmotConfig->axisPolarity[axis] |= emcmotCommand->axisFlag;
01813         }
01814         else {
01815           /* inverted */
01816           emcmotConfig->axisPolarity[axis] &= ~emcmotCommand->axisFlag;
01817         }
01818         break;
01819 
01820 #ifdef ENABLE_PROBING
01821       case EMCMOT_SET_PROBE_INDEX:
01822         emcmotConfig->probeIndex = emcmotCommand->probeIndex;
01823         break;
01824 
01825       case EMCMOT_SET_PROBE_POLARITY:
01826         emcmotConfig->probePolarity = emcmotCommand->level;
01827         break;
01828 
01829       case EMCMOT_CLEAR_PROBE_FLAGS:
01830         emcmotStatus->probeTripped = 0;
01831         emcmotStatus->probing = 1;
01832         break;
01833 
01834       case EMCMOT_PROBE:
01835         /* most of this is taken from EMCMOT_SET_LINE */
01836         /* queue up a linear move */
01837         /* requires coordinated mode, enable off, not on limits */
01838         if (! GET_MOTION_COORD_FLAG() ||
01839             ! GET_MOTION_ENABLE_FLAG()) {
01840           reportError("Need to be enabled, in coord mode for linear move");
01841           emcmotStatus->commandStatus = EMCMOT_COMMAND_INVALID_COMMAND;
01842           SET_MOTION_ERROR_FLAG(1);
01843           break;
01844         }
01845         else if (! inRange(emcmotCommand->pos)) {
01846           reportError("Linear move %d out of range",
01847                       emcmotCommand->id);
01848           emcmotStatus->commandStatus = EMCMOT_COMMAND_INVALID_PARAMS;
01849           tpAbort(&queue);
01850           SET_MOTION_ERROR_FLAG(1);
01851           break;
01852         }
01853         else if (! checkLimits()) {
01854           reportError("Can't do linear move with limits exceeded");
01855           emcmotStatus->commandStatus = EMCMOT_COMMAND_INVALID_PARAMS;
01856           tpAbort(&queue);
01857           SET_MOTION_ERROR_FLAG(1);
01858           break;
01859         }
01860 
01861         /* append it to the queue */
01862         tpSetId(&queue, emcmotCommand->id);
01863         if (-1 == tpAddLine(&queue, emcmotCommand->pos)) {
01864           reportError("Can't add linear move");
01865           emcmotStatus->commandStatus = EMCMOT_COMMAND_BAD_EXEC;
01866           tpAbort(&queue);
01867           SET_MOTION_ERROR_FLAG(1);
01868           break;
01869         }
01870         else {
01871           emcmotStatus->probeTripped = 0;
01872           emcmotStatus->probing = 1;
01873           SET_MOTION_ERROR_FLAG(0);
01874         }
01875         break;
01876 #endif /* ENABLE_PROBING */
01877 
01878       default:
01879         reportError("Unrecognized command %d", emcmotCommand->command);
01880         emcmotStatus->commandStatus = EMCMOT_COMMAND_UNKNOWN_COMMAND;
01881         break;
01882       } /* end of: command switch */
01883 
01884       /* synch tail count */
01885       emcmotStatus->tail = emcmotStatus->head;
01886       emcmotConfig->tail = emcmotConfig->head;
01887       emcmotDebug->tail = emcmotDebug->head;
01888 
01889     } /* end of: if-new-command */
01890 
01891 #if defined (rtlinux) && defined (RT_FIFO)
01892   } /* end of: while-msg loop for RT FIFO */
01893 
01894   if (err != 0) {
01895     return -1;
01896   }
01897 
01898 #endif /* rtlinux and RT_FIFO */
01899 
01900   return 0;
01901 }
01902 
01903 /* FIXME */
01904 int EMCMOT_NO_FORWARD_KINEMATICS = 0;
01905 
01906 /*
01907   emcmotController() runs the trajectory and interpolation calculations
01908   each control cycle
01909 
01910   Inactive axes are still calculated, but the PIDs are inhibited and
01911   the amp enable/disable are inhibited
01912   */
01913 #ifdef USE_RTL2
01914 static void *emcmotController(void *arg)
01915 #else
01916 static void emcmotController(int arg)
01917 #endif
01918 {
01919   double start, end, delta;     /* time stamping */
01920   int homeFlag;                 /* result of ext read to home switch */
01921   int axis;                     /* axis loop counter */
01922   int t;                        /* loop counter if we're in axis loop */
01923   int isLimit;                  /* result of ext read to limit sw */
01924   int whichCycle;               /* 0=none, 1=servo, 2=traj */
01925   int fault;
01926   double numres;
01927   double thisFerror[EMCMOT_MAX_AXIS];
01928   double limitFerror;           /* current scaled ferror */
01929   double magFerror;
01930 #ifdef STEPPER_MOTORS
01931   double bcomp[EMCMOT_MAX_AXIS]; /* backlash comp value */
01932   char bcompdir[EMCMOT_MAX_AXIS]; /* 0=none, 1=pos, -1=neg */
01933   double bcompincr[EMCMOT_MAX_AXIS]; /* incremental backlash comp value */
01934   double dsteps;                /* steps value (double) for stepper task */
01935   double oldbcomp;
01936   /* various parameters for acc/dec backlash comp */
01937   char bac_done[EMCMOT_MAX_AXIS];
01938   double bac_d[EMCMOT_MAX_AXIS];
01939   double bac_di[EMCMOT_MAX_AXIS];
01940   double bac_D[EMCMOT_MAX_AXIS];
01941   double bac_halfD[EMCMOT_MAX_AXIS];
01942   double bac_incrincr[EMCMOT_MAX_AXIS];
01943   double bac_incr[EMCMOT_MAX_AXIS];
01944 #endif
01945   char finalHome[EMCMOT_MAX_AXIS];
01946 
01947   for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
01948 #ifdef STEPPER_MOTORS
01949     bcomp[axis] = 0.0;
01950     bcompdir[axis] = 0;
01951     bcompincr[axis] = 0.0;
01952     bac_done[axis] = 1;
01953     bac_d[axis] = 0.0;
01954     bac_di[axis] = 0.0;
01955     bac_D[axis] = 0.0;
01956     bac_halfD[axis] = 0.0;
01957     bac_incrincr[axis] = 0.0;
01958     bac_incr[axis] = 0.0;
01959 #endif
01960     finalHome[axis] = 0;
01961   }
01962 
01963 #ifdef rtlinux
01964   for (;;) {
01965 #endif /* rtlinux */
01966 
01967 #ifdef rtlinux
01968     /* toggle sound port watchdog */
01969 
01970     if (wdEnabling && ! wdEnabled) {
01971       /* just turned WD on */
01972       wdCount = wdWait;
01973       wdToggle = 0;
01974       wdEnabled = 1;
01975     }
01976     if (! wdEnabling && wdEnabled) {
01977       /* just turned WD off */
01978       /* clear the bit */
01979       soundByte = inb(SOUND_PORT);
01980       soundByte &= ~SOUND_MASK;
01981       outb(soundByte, SOUND_PORT);
01982       wdEnabled = 0;
01983     }
01984 
01985     if (wdEnabled && wdCount-- <= 0) {
01986       soundByte = inb(SOUND_PORT);
01987       wdToggle = ! wdToggle;
01988       if (wdToggle) {
01989         soundByte |= SOUND_MASK;
01990       }
01991       else {
01992         soundByte &= ~SOUND_MASK;
01993       }
01994       outb(soundByte, SOUND_PORT);
01995       wdCount = wdWait;
01996     }
01997 #endif /* rtlinux */
01998 
01999     /* record start time */
02000     start = etime();
02001 
02002     /* READ COMMAND: */
02003 
02004 #ifndef RT_FIFO
02005     emcmotCommandHandler();
02006 
02007 #endif /* not RT_FIFO */
02008 
02009     /* increment head count */
02010     emcmotStatus->head++;
02011     emcmotDebug->head++;
02012 
02013     /* READ INPUTS: */
02014 
02015 #ifndef STEPPER_MOTORS
02016     /* latch all encoder feedback into raw input array, done outside
02017        of for-loop on joints below, since it's a single call for all
02018        joints */
02019     extEncoderReadAll(EMCMOT_MAX_AXIS, rawInput);
02020 #endif
02021 
02022     /* process input and read limit switches */
02023     for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
02024 #ifdef STEPPER_MOTORS
02025       /* READ INPUTS, deferred from above */
02026       rawInput[axis] = (double) emcmotDebug->stepperCount[axis] -
02027         bcompincr[axis] * smStepsPerUnit[axis];
02028 #endif
02029 
02030       /* save old cycle's values */
02031       oldInput[axis] = emcmotStatus->input[axis];
02032       /* set input, scaled according to input = (raw - offset) / scale */
02033       emcmotStatus->input[axis] =
02034         (rawInput[axis] - emcmotStatus->inputOffset[axis]) *
02035         inverseInputScale[axis];
02036 
02037 #ifndef STEPPER_MOTORS
02038       /* debounce bad feedback */
02039       if (fabs(emcmotStatus->input[axis] - oldInput[axis]) /
02040           emcmotConfig->servoCycleTime > bigVel) {
02041         /* bad input value-- debounce with the last value */
02042         emcmotStatus->input[axis] = oldInput[axis];
02043       }
02044 #endif
02045 
02046       /* read limit switches and amp fault from external
02047          interface, and set 'enabling' to zero if tripped
02048          to cause immediate stop */
02049 
02050       /* handle limits */
02051       if (GET_AXIS_ACTIVE_FLAG(axis)) {
02052         extMaxLimitSwitchRead(axis, &isLimit);
02053         if (isLimit == GET_AXIS_PHL_POLARITY(axis)) {
02054           if (++maxLimitSwitchCount[axis] > LIMIT_SWITCH_DEBOUNCE) {
02055             SET_AXIS_PHL_FLAG(axis, 1);
02056             maxLimitSwitchCount[axis] = LIMIT_SWITCH_DEBOUNCE;
02057             if (emcmotStatus->overrideLimits ||
02058                 isHoming()) {
02059             }
02060             else {
02061               SET_AXIS_ERROR_FLAG(axis, 1);
02062               enabling = 0;
02063             }
02064           }
02065         }
02066         else {
02067           SET_AXIS_PHL_FLAG(axis, 0);
02068           maxLimitSwitchCount[axis] = 0;
02069         }
02070       }
02071       if (GET_AXIS_ACTIVE_FLAG(axis)) {
02072         extMinLimitSwitchRead(axis, &isLimit);
02073         if (isLimit == GET_AXIS_NHL_POLARITY(axis)) {
02074           if (++minLimitSwitchCount[axis] > LIMIT_SWITCH_DEBOUNCE) {
02075             SET_AXIS_NHL_FLAG(axis, 1);
02076             minLimitSwitchCount[axis] = LIMIT_SWITCH_DEBOUNCE;
02077             if (emcmotStatus->overrideLimits ||
02078                 isHoming()) {
02079             }
02080             else {
02081               SET_AXIS_ERROR_FLAG(axis, 1);
02082               enabling = 0;
02083             }
02084           }
02085         }
02086         else {
02087           SET_AXIS_NHL_FLAG(axis, 0);
02088           minLimitSwitchCount[axis] = 0;
02089         }
02090       }
02091 
02092       if (GET_AXIS_ACTIVE_FLAG(axis) &&
02093           GET_AXIS_ENABLE_FLAG(axis)) {
02094         extAmpFault(axis, &fault);
02095         if (fault == GET_AXIS_FAULT_POLARITY(axis)) {
02096           if (++ampFaultCount[axis] > AMP_FAULT_DEBOUNCE) {
02097             SET_AXIS_ERROR_FLAG(axis, 1);
02098             SET_AXIS_FAULT_FLAG(axis, 1);
02099             ampFaultCount[axis] = AMP_FAULT_DEBOUNCE;
02100             enabling = 0;
02101           }
02102         }
02103         else {
02104           SET_AXIS_FAULT_FLAG(axis, 0);
02105           ampFaultCount[axis] = 0;
02106         }
02107       }
02108 
02109       /* read home switch and set flag if tripped. Handling of home
02110          sequence is done later. */
02111       if (GET_AXIS_ACTIVE_FLAG(axis)) {
02112         extHomeSwitchRead(axis, &homeFlag);
02113         if (homeFlag == GET_AXIS_HOME_SWITCH_POLARITY(axis)) {
02114           SET_AXIS_HOME_SWITCH_FLAG(axis, 1);
02115         }
02116         else {
02117           SET_AXIS_HOME_SWITCH_FLAG(axis, 0);
02118         }
02119       }
02120 
02121     } /* end of: loop on axes, for reading inputs, setting limit and
02122            home switch flags */
02123 
02124     /* now we're outside the axis loop, having just read input, scaled it,
02125          read the limit and home switches and amp faults. We need to abort
02126          all motion if we're on limits, handle homing sequence, and handle
02127          mode and state transitions. */
02128 
02129     /* RUN STATE LOGIC: */
02130 
02131     /* check for disabling */
02132     if (! enabling && GET_MOTION_ENABLE_FLAG()) {
02133       /* clear out the motion queue and interpolators */
02134       tpClear(&queue);
02135       for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
02136         tpClear(&freeAxis[axis]);
02137         cubicDrain(&cubic[axis]);
02138         if (GET_AXIS_ACTIVE_FLAG(axis)) {
02139           extAmpEnable(axis, ! GET_AXIS_ENABLE_POLARITY(axis));
02140           SET_AXIS_ENABLE_FLAG(axis, 0);
02141           SET_AXIS_HOMING_FLAG(axis, 0);
02142           emcmotStatus->output[axis] = 0.0;
02143         }
02144         /* don't clear the axis error flag, since that may signify why
02145            we just went into disabled state */
02146       }
02147       /* reset the trajectory interpolation counter, so that the kinematics
02148          functions called during the disabled state run at the nominal
02149          trajectory rate rather than the servo rate. It's loaded with
02150          emcmotConfig->interpolationRate when it goes to zero. */
02151       interpolationCounter = 0;
02152 #ifdef STEPPER_MOTORS
02153       smInhibit = 1;
02154 #endif
02155       SET_MOTION_ENABLE_FLAG(0);
02156       /* don't clear the motion error flag, since that may signify why
02157          we just went into disabled state */
02158     }
02159 
02160     /* check for enabling */
02161     if (enabling && ! GET_MOTION_ENABLE_FLAG()) {
02162       tpSetPos(&queue, emcmotStatus->pos);
02163       for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
02164         freePose.tran.x = jointPos[axis];
02165         tpSetPos(&freeAxis[axis], freePose);
02166 #ifndef STEPPER_MOTORS
02167         pidReset(&emcmotConfig->pid[axis]);
02168 #endif
02169         if (GET_AXIS_ACTIVE_FLAG(axis)) {
02170           extAmpEnable(axis, GET_AXIS_ENABLE_POLARITY(axis));
02171           SET_AXIS_ENABLE_FLAG(axis, 1);
02172           SET_AXIS_HOMING_FLAG(axis, 0);
02173         }
02174         /* clear any outstanding axis errors when going into enabled state */
02175         SET_AXIS_ERROR_FLAG(axis, 0);
02176       }
02177 #ifdef STEPPER_MOTORS
02178       smInhibit = 0;
02179 #endif
02180       SET_MOTION_ENABLE_FLAG(1);
02181       /* clear any outstanding motion errors when going into enabled state */
02182       SET_MOTION_ERROR_FLAG(0);
02183     }
02184 
02185     /* check for entering coordinated mode */
02186     if (coordinating && ! GET_MOTION_COORD_FLAG()) {
02187       if (GET_MOTION_INPOS_FLAG()) {
02188         /* update coordinated queue position */
02189         tpSetPos(&queue, emcmotStatus->pos);
02190         /* drain the cubics so they'll synch up */
02191         for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
02192           cubicDrain(&cubic[axis]);
02193         }
02194         /* clear the override limits flags */
02195         overriding = 0;
02196         emcmotStatus->overrideLimits = 0;
02197         SET_MOTION_COORD_FLAG(1);
02198         SET_MOTION_ERROR_FLAG(0);
02199       }
02200       else {
02201         /* not in position-- don't honor mode change */
02202         coordinating = 0;
02203       }
02204     }
02205 
02206     /* check entering free space mode */
02207     if (! coordinating && GET_MOTION_COORD_FLAG()) {
02208       if (GET_MOTION_INPOS_FLAG()) {
02209         for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
02210           /* update free planner positions */
02211           freePose.tran.x = jointPos[axis];
02212           tpSetPos(&freeAxis[axis], freePose);
02213           /* drain the cubics so they'll synch up */
02214           cubicDrain(&cubic[axis]);
02215         }
02216         SET_MOTION_COORD_FLAG(0);
02217         SET_MOTION_ERROR_FLAG(0);
02218       }
02219       else {
02220         /* not in position-- don't honor mode change */
02221         coordinating = 1;
02222       }
02223     }
02224 
02225     /* check for homing sequences */
02226     for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
02227       if (GET_AXIS_HOMING_FLAG(axis)) {
02228         if (tpIsDone(&freeAxis[axis])) {
02229           /* check for decel or final move */
02230           if (finalHome[axis]) {
02231             /* reset flag-- we're back at home */
02232             finalHome[axis] = 0;
02233 
02234             /* rework the home kinematics values-- this could be done
02235                after each message to set world or joint kinematics, but
02236                we'll defer it to here so it happens just prior to when
02237                it's needed. Note that the nominal value of these may be
02238                changed, if the kinematics need to. */
02239             kinematicsHome(&worldHome, jointHome, &fflags, &iflags);
02240 
02241             /* set input offset to value such that resulting input
02242                is the jointHome[] value, with:
02243                input = (raw - offset) / scale ->
02244                offset = raw - input * scale ->
02245                offset = raw - jointHome * scale */
02246 
02247             emcmotStatus->inputOffset[axis] = rawInput[axis] -
02248               jointHome[axis] * emcmotStatus->inputScale[axis];
02249 
02250             /* recompute inputs to match so we don't have a
02251                momentary jump */
02252             emcmotStatus->input[axis] = jointHome[axis];
02253             oldInput[axis] = emcmotStatus->input[axis];
02254 
02255             /* reset interpolator so that it doesn't jump */
02256             cubicOffset(&cubic[axis], jointHome[axis] - coarseJointPos[axis]);
02257 
02258             /* set axis position to jointHome upon homing */
02259             jointPos[axis] = jointHome[axis];
02260             freePose.tran.x = jointHome[axis];
02261             tpSetPos(&freeAxis[axis], freePose);
02262 
02263             SET_AXIS_HOMING_FLAG(axis, 0);
02264             SET_AXIS_HOMED_FLAG(axis, 1);
02265 
02266             /* set allHomed flag if all active axes are homed; this
02267                  will signify that kinematics functions can be called */
02268             allHomed = 1;
02269             for (t = 0; t < EMCMOT_MAX_AXIS; t++) {
02270               if (GET_AXIS_ACTIVE_FLAG(t) &&
02271                   ! GET_AXIS_HOMED_FLAG(t)) {
02272                 /* one active axis is not homed */
02273                 allHomed = 0;
02274                 break;
02275               }
02276             }
02277             /* FIXME-- this only works with no forward kins */
02278             if (allHomed) {
02279               emcmotStatus->pos = worldHome;
02280               emcmotStatus->actualPos = worldHome;
02281             }
02282           }
02283           else {
02284             /* just finished decel, now we'll do final home */
02285             finalHome[axis] = 1;
02286             /* add move back to latched position + backoff */
02287             freePose.tran.x =
02288               (saveLatch[axis] - emcmotStatus->inputOffset[axis]) *
02289               inverseInputScale[axis] +
02290               emcmotConfig->homeOffset[axis];
02291             tpAddLine(&freeAxis[axis], freePose);
02292           }
02293         } /* end of: if axis is done either decel or final home */
02294       } /* end of: if axis is homing */
02295     } /* end of: axis loop that checks for homing */
02296 
02297     /* RUN MOTION CALCULATIONS: */
02298 
02299     /* run axis interpolations and outputs, but only if we're
02300        enabled. This section is "suppressed" if we're not
02301        enabled, although the read/write of encoders/dacs is still
02302        done. */
02303     whichCycle = 0;
02304     if (GET_MOTION_ENABLE_FLAG()) {
02305       /* set whichCycle to be at least a servo cycle, for calc time logging */
02306       whichCycle = 1;
02307 
02308       /* check to see if the interpolators are empty */
02309       while (cubicNeedNextPoint(&cubic[0])) {
02310         /* they're empty, so pull next point(s) off Cartesian or
02311            joint planner, depending upon coord or free mode. */
02312 
02313         /* check to see whether we're in coordinated or free mode, to
02314            decide which motion planner to call */
02315         if (GET_MOTION_COORD_FLAG()) {
02316           /* we're in coordinated mode-- pull a pose off the Cartesian
02317              trajectory planner, run it through the inverse kinematics,
02318              and spline up the joint points for interpolation in
02319              servo cycles. */
02320 
02321           /* set whichCycle to be a Cartesian trajectory cycle,
02322              for calc time logging */
02323           whichCycle = 2;
02324 
02325           /* run coordinated trajectory planning cycle */
02326           tpRunCycle(&queue);
02327 
02328           /* set new commanded traj pos */
02329           emcmotStatus->pos = tpGetPos(&queue);
02330 
02331           /* convert to joints */
02332           kinematicsInverse(&emcmotStatus->pos, coarseJointPos, &iflags, &fflags);
02333 
02334           /* spline joints up-- note that we may be adding points that
02335              fail soft limits, but we'll abort at the end of this cycle
02336              so it doesn't really matter */
02337           for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
02338             cubicAddPoint(&cubic[axis], coarseJointPos[axis]);
02339           }
02340 
02341           /* call forward kinematics on input points for actual pos,
02342              at trajectory rate to save bandwidth */
02343           /* FIXME */
02344           if (EMCMOT_NO_FORWARD_KINEMATICS) {
02345             /* fake it by setting actual pos to commanded pos */
02346             emcmotStatus->actualPos = emcmotStatus->pos;
02347           }
02348           else {
02349             kinematicsForward(emcmotStatus->input, &emcmotStatus->actualPos, &fflags, &iflags);
02350           }
02351 
02352           /* now emcmotStatus->actualPos, emcmotStatus->pos, and
02353              coarseJointPos[] are set */
02354 
02355         } /* end of: coord mode */
02356         else {
02357           /* we're in free mode-- run joint planning cycles */
02358           for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
02359             /* set whichCycle to be a joint trajectory cycle,
02360                for calc time logging */
02361             /* note that this may include one or more joint trajectory
02362                cycles, so calc time may be inherently variable */
02363             whichCycle = 2;
02364 
02365             /* run joint trajectory planning cycle */
02366             tpRunCycle(&freeAxis[axis]);
02367 
02368             /* set new coarse joint position. FIXME-- this uses only
02369                the tran.x field of the TP_STRUCT, which is overkill.
02370                We need a TP_STRUCT with a single scalar element. */
02371             coarseJointPos[axis] = tpGetPos(&freeAxis[axis]).tran.x;
02372 
02373             /* spline joint up-- note that we may be adding a point that
02374                fails soft limit, but we'll abort at the end of this cycle
02375                so it doesn't really matter */
02376             cubicAddPoint(&cubic[axis], coarseJointPos[axis]);
02377 
02378           } /* end of: axis for loop for joint planning cycle */
02379 
02380           if (EMCMOT_NO_FORWARD_KINEMATICS) {
02381             /* can't do anything */
02382           }
02383           else {
02384             /* call forward kinematics on input points for actual pos,
02385                at trajectory rate to save bandwidth */
02386             kinematicsForward(emcmotStatus->input, &emcmotStatus->actualPos, &fflags, &iflags);
02387 
02388             /* push coarseJointPos[] through the forward kins to
02389              set emcmotStatus->pos, which are not computed in free
02390              mode as they are in coord mode */
02391           /* Note: in systems where the forward kins are costly to compute,
02392              emcmotStatus->pos can be set to emcmotStatus->actualPos to
02393              save one call to the forward kins */
02394             kinematicsForward(coarseJointPos, &emcmotStatus->pos, &fflags, &iflags);
02395           }
02396 
02397           /* now emcmotStatus->actualPos, emcmotStatus->pos, and
02398              coarseJointPos[] are set */
02399 
02400         } /* end of: free mode trajectory planning */
02401       } /* end of: while (cubicNeedNextPoint(0)) */
02402 
02403       /* we're still in motion enabled section. For coordinated mode,
02404          the Cartesian trajectory cycle has been computed, if necessary,
02405          run through the inverse kinematics, and the joints have been
02406          splined up for interpolation. For free mode, the joint trajectory
02407          cycles have been computed, if necessary, and the joints have
02408          been splined up for interpolation. We still need to push the
02409          actual input through the forward kinematics, for actual pos.
02410 
02411          Effects:
02412 
02413          For coord mode, emcmotStatus->pos contains the commanded
02414          Cartesian pose, coarseJointPos[] contains the results of the
02415          inverse kinematics at the coarse (trajectory) rate, and the
02416          interpolators are not empty.
02417 
02418          For free mode, emcmotStatus->pos is unchanged, and needs to
02419          be updated via the forward kinematics. FIXME-- make sure this
02420          happens, and note where in this comment. coarseJointPos[]
02421          contains the results of the joint trajectory calculations
02422          at the coarse (trajectory) rate, and the interpolators are
02423          not empty.
02424       */
02425 
02426       /* check for soft joint limits. If so, abort all motion. The
02427          interpolators will pick this up further down and begin
02428          planning abort and stop. */
02429       onLimit = 0;
02430       for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
02431         SET_AXIS_PSL_FLAG(axis, 0);
02432         SET_AXIS_NSL_FLAG(axis, 0);
02433         if (GET_AXIS_HOMED_FLAG(axis)) {
02434           if (coarseJointPos[axis] > emcmotConfig->maxLimit[axis]) {
02435             SET_AXIS_ERROR_FLAG(axis, 1);
02436             SET_AXIS_PSL_FLAG(axis, 1);
02437             onLimit = 1;
02438           }
02439           else if (coarseJointPos[axis] < emcmotConfig->minLimit[axis]) {
02440             SET_AXIS_ERROR_FLAG(axis, 1);
02441             SET_AXIS_NSL_FLAG(axis, 1);
02442           }
02443         }
02444       }
02445 
02446       /* reset wasOnLimit flag iff all joints are free of
02447        soft limits, as seen in the flag bits set last cycle.
02448        No need to do this for hard limits, since wasOnLimit
02449        only prevents flurry of aborts while on a soft limit
02450        and hard limits don't abort, they disable. */
02451       if (onLimit) {
02452         if (! wasOnLimit) {
02453           /* abort everything, regardless of coord or free mode */
02454           tpAbort(&queue);
02455           for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
02456             tpAbort(&freeAxis[axis]);
02457             wasOnLimit = 1;
02458           }
02459         }
02460         /* else we were on a limit, so inhibit firing of aborts */
02461       }
02462       else {
02463         /* not on a limit, so clear wasOnLimit so aborts fire next
02464            time we are on a limit */
02465         wasOnLimit = 0;
02466       }
02467 
02468       if (whichCycle == 2) {
02469         /* we're on a trajectory cycle, either Cartesian or joint planning, so
02470            log per-traj-cycle data if logging active */
02471         logIt = 0;
02472 
02473         if (emcmotStatus->logStarted &&
02474             emcmotStatus->logSkip >= 0) {
02475 
02476           /* calculate current vel, accel, for logging */
02477           newVel.tran.x = (emcmotStatus->pos.tran.x - oldPos.tran.x) /
02478             emcmotConfig->trajCycleTime;
02479           newVel.tran.y = (emcmotStatus->pos.tran.y - oldPos.tran.y) /
02480             emcmotConfig->trajCycleTime;
02481           newVel.tran.z = (emcmotStatus->pos.tran.z - oldPos.tran.z) /
02482             emcmotConfig->trajCycleTime;
02483           oldPos = emcmotStatus->pos;
02484           newAcc.tran.x = (newVel.tran.x - oldVel.tran.x) /
02485             emcmotConfig->trajCycleTime;
02486           newAcc.tran.y = (newVel.tran.y - oldVel.tran.y) /
02487             emcmotConfig->trajCycleTime;
02488           newAcc.tran.z = (newVel.tran.z - oldVel.tran.z) /
02489             emcmotConfig->trajCycleTime;
02490           oldVel = newVel;
02491 
02492           /* save the type with the log item */
02493           ls.type = emcmotStatus->logType;
02494 
02495           /* now log type-specific data */
02496           switch (emcmotStatus->logType) {
02497 
02498           case EMCMOT_LOG_TYPE_TRAJ_POS:
02499             if (logSkip-- <= 0) {
02500               ls.item.trajPos.time = start;
02501               ls.item.trajPos.pos = emcmotStatus->pos.tran;
02502               logSkip = emcmotStatus->logSkip;
02503               logIt = 1;
02504             }
02505             break;
02506 
02507           case EMCMOT_LOG_TYPE_TRAJ_VEL:
02508             if (logSkip-- <= 0) {
02509               ls.item.trajVel.time = start;
02510               ls.item.trajVel.vel = newVel.tran;
02511               pmCartMag(newVel.tran, &ls.item.trajVel.mag);
02512               logSkip = emcmotStatus->logSkip;
02513               logIt = 1;
02514             }
02515             break;
02516 
02517           case EMCMOT_LOG_TYPE_TRAJ_ACC:
02518             if (logSkip-- <= 0) {
02519               ls.item.trajAcc.time = start;
02520               ls.item.trajAcc.acc = newAcc.tran;
02521               pmCartMag(newAcc.tran, &ls.item.trajAcc.mag);
02522               logSkip = emcmotStatus->logSkip;
02523               logIt = 1;
02524             }
02525             break;
02526 
02527           default:
02528             break;
02529           } /* end of: switch on log type */
02530 
02531           /* now log it */
02532 #if defined (rtlinux) && defined (RT_FIFO)
02533           if (logIt) {
02534             rtf_put(EMCMOT_LOG_RTF, &ls, sizeof(EMCMOT_LOG_STRUCT));
02535             /* FIXME-- update emcmotStatus->logPoints */
02536             logIt = 0;
02537           }
02538 #else
02539           if (logIt) {
02540             emcmotLogAdd(emcmotLog, ls);
02541             emcmotStatus->logPoints = emcmotLog->howmany;
02542             logIt = 0;
02543           }
02544 #endif
02545         } /* end of: if (emcmotStatus->logStarted &&
02546                          emcmotStatus->logSkip >= 0) */
02547       } /* end of: if (whichCycle == 2), for trajectory cycle logging */
02548 
02549       /* run interpolation and compensation */
02550       for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
02551         /* interpolate */
02552         oldJointPos[axis] = jointPos[axis];
02553         jointPos[axis] = cubicInterpolate(&cubic[axis], 0, 0, 0, 0);
02554         /* round position to input resolution */
02555         numres = jointPos[axis] * emcmotStatus->inputScale[axis];
02556         if (numres < 0.0) {
02557           jointPos[axis] = inverseInputScale[axis] * ((int) (numres - 0.5));
02558         }
02559         else {
02560           jointPos[axis] = inverseInputScale[axis] * ((int) (numres + 0.5));
02561         }
02562         jointVel[axis] = (jointPos[axis] - oldJointPos[axis]) /
02563           emcmotConfig->servoCycleTime;
02564 
02565         /* run output calculations */
02566         if (GET_AXIS_ACTIVE_FLAG(axis)) {
02567 #ifdef STEPPER_MOTORS
02568           /* backlash compensation for steppers*/
02569           /* This is pretty screwed up, since backlash was originally
02570              part of the PID structure. We need to duplicate the
02571              correction method here, and use the backlash value from
02572              the PID structure since that's where it ends up.
02573              FIXME-- make backlash part of the EMC status proper, not
02574              the PID structure */
02575           if (jointPos[axis] - oldJointPos[axis] > 0.0) {
02576             oldbcomp = bcomp[axis];
02577             bcomp[axis] = + emcmotConfig->pid[axis].backlash / 2.0;
02578             if (bcompdir[axis] != + 1) {
02579               bac_done[axis] = 0;
02580               bac_di[axis] = bcompincr[axis];
02581               bac_d[axis] = 0;
02582               bac_D[axis] = bcomp[axis] - oldbcomp;
02583               bac_halfD[axis] = 0.5 * bac_D[axis];
02584               bac_incrincr[axis] = emcmotStatus->acc *
02585                 emcmotConfig->servoCycleTime * emcmotConfig->servoCycleTime;
02586               bac_incr[axis] = - 0.5 * bac_incrincr[axis];
02587               bcompdir[axis] = + 1;
02588             }
02589           }
02590           else if (jointPos[axis] - oldJointPos[axis] < 0.0) {
02591             oldbcomp = bcomp[axis];
02592             bcomp[axis] = - emcmotConfig->pid[axis].backlash / 2.0;
02593             if (bcompdir[axis] != - 1) {
02594               bac_done[axis] = 0;
02595               bac_di[axis] = bcompincr[axis];
02596               bac_d[axis] = 0;
02597               bac_D[axis] = bcomp[axis] - oldbcomp;
02598               bac_halfD[axis] = 0.5 * bac_D[axis];
02599               bac_incrincr[axis] = emcmotStatus->acc *
02600                 emcmotConfig->servoCycleTime * emcmotConfig->servoCycleTime;
02601               bac_incr[axis] = - 0.5 * bac_incrincr[axis];
02602               bcompdir[axis] = - 1;
02603             }
02604           }
02605           /* else no motion, so leave bcomp what it was */
02606 
02607           /* mete out the backlash according to an acc/dec profile */
02608           if (! bac_done[axis]) {
02609             if (bac_D[axis] > 0.0) {
02610               bcompincr[axis] = bac_di[axis] + bac_d[axis];
02611               if (bac_d[axis] < bac_halfD[axis]) {
02612                 bac_incr[axis] += bac_incrincr[axis];
02613                 bac_d[axis] += bac_incr[axis];
02614               }
02615               else if (bac_d[axis] < bac_D[axis]) {
02616                 bac_incr[axis] -= bac_incrincr[axis];
02617                 bac_d[axis] += bac_incr[axis];
02618               }
02619               if (bac_d[axis] >= bac_D[axis] || bac_incr[axis] <= 0.0) {
02620                 bac_done[axis] = 1;
02621               }
02622             }
02623             else {
02624               bcompincr[axis] = bac_di[axis] + bac_d[axis];
02625               if (bac_d[axis] > bac_halfD[axis]) {
02626                 bac_incr[axis] += bac_incrincr[axis];
02627                 bac_d[axis] -= bac_incr[axis];
02628               }
02629               else if (bac_d[axis] > bac_D[axis]) {
02630                 bac_incr[axis] -= bac_incrincr[axis];
02631                 bac_d[axis] -= bac_incr[axis];
02632               }
02633               if (bac_d[axis] <= bac_D[axis] || bac_incr[axis] <= 0.0) {
02634                 bac_done[axis] = 1;
02635               }
02636             }
02637           } /* end of: if not bac_done[axis] */
02638 
02639           /* fill in global smSteps[] for stepper task */
02640           /* first get steps, as a floating point */
02641           dsteps = (jointPos[axis] + bcompincr[axis]) *
02642             smStepsPerUnit[axis] + emcmotStatus->inputOffset[axis];
02643           /* round to nearest integer */
02644           if (dsteps < 0.0) {
02645             smSteps[axis] = (int) (dsteps - 0.5);
02646           }
02647           else {
02648             smSteps[axis] = (int) (dsteps + 0.5);
02649           }
02650 
02651           /* flag this as the start of a new chunk for the stepper task */
02652           smNewCycle[axis] = 1;
02653 #else
02654           /* COMPENSATE: */
02655 
02656           /*
02657             compensation means compute output
02658             'emcmotStatus->output[]' based on desired position
02659             'jointPos[]' and input 'emcmotStatus->input[]'.
02660 
02661             Currently the source calls for PID compensation.
02662             FIXME-- add wrapper for compensator, with ptr to
02663             emcmotStatus struct, with semantics that ->output[]
02664             needs to be filled.
02665           */
02666 
02667           /* here is PID compensation */
02668           emcmotStatus->output[axis] =
02669             pidRunCycle(&emcmotConfig->pid[axis],
02670                         emcmotStatus->input[axis],
02671                         jointPos[axis]);
02672 #endif
02673 
02674           /* COMPUTE FOLLOWING ERROR: */
02675 
02676           /* compute signed following error and magnitude */
02677           thisFerror[axis] = jointPos[axis] - emcmotStatus->input[axis];
02678           emcmotDebug->ferrorCurrent[axis] = thisFerror[axis];
02679           magFerror = fabs(thisFerror[axis]);
02680 
02681           /* record the max ferror for this axis */
02682           if (emcmotDebug->ferrorHighMark[axis] < magFerror) {
02683             emcmotDebug->ferrorHighMark[axis] = magFerror;
02684           }
02685 
02686           /* compute the scaled ferror for a move of this speed */
02687           limitFerror = emcmotConfig->maxFerror[axis] /
02688             emcmotConfig->limitVel *
02689             jointVel[axis];
02690           if (limitFerror < emcmotConfig->minFerror[axis]) {
02691             limitFerror = emcmotConfig->minFerror[axis];
02692           }
02693 
02694           /* abort if this ferror is greater than the scaled ferror */
02695           if (magFerror > limitFerror) {
02696             /* abort! abort! following error exceeded */
02697             SET_AXIS_ERROR_FLAG(axis, 1);
02698             SET_AXIS_FERROR_FLAG(axis, 1);
02699             if (enabling) {
02700               // report the following error just this once
02701               reportError("Axis %d following error", axis);
02702             }
02703             enabling = 0;
02704           }
02705           else {
02706             SET_AXIS_FERROR_FLAG(axis, 0);
02707           }
02708         } /* end of: if (GET_AXIS_ACTIVE_FLAG(axis)) */
02709         else {
02710           /* axis is not active-- leave the pid output where it is--
02711              if axis is not active one can still write to the dac */
02712         }
02713 
02714 #ifndef STEPPER_MOTORS
02715         /* CLAMP OUTPUT: */
02716 
02717         /*
02718           clamp output means take 'emcmotStatus->output[]' and
02719           limit to range
02720           'emcmotConfig->minOutput[] .. emcmotConfig->maxOutput[]'
02721         */
02722         if (emcmotStatus->output[axis] < emcmotConfig->minOutput[axis]) {
02723           emcmotStatus->output[axis] = emcmotConfig->minOutput[axis];
02724         }
02725         else if (emcmotStatus->output[axis] > emcmotConfig->maxOutput[axis]) {
02726           emcmotStatus->output[axis] = emcmotConfig->maxOutput[axis];
02727         }
02728 #endif
02729 
02730         /* CHECK FOR LATCH CONDITION: */
02731 
02732         /*
02733           check for latch condition means if we're waiting for a
02734           latched index pulse, and we see the pulse and the home
02735           switch, we read the raw input and abort. The offset is set
02736           above in the homing section by noting that if we're homing,
02737           and waitingForLatch[] is cleared, we latched.
02738 
02739           This presumes an encoder index pulse.
02740           FIXME-- remove explicit calls to encoder index pulse, to
02741           allow for open-loop control latching via switches only.
02742         */
02743         if (waitingForLatch[axis]) {
02744           if (GET_AXIS_HOME_SWITCH_FLAG(axis) ||
02745               GET_AXIS_PHL_FLAG(axis) ||
02746               GET_AXIS_NHL_FLAG(axis)) {
02747             /* read encoder index */
02748 #ifdef STEPPER_MOTORS
02749             /* force an "encoder latch" */
02750             latchFlag[axis] = 1;
02751 #else
02752             extEncoderResetIndex(axis);
02753             extEncoderReadLatch(axis, &latchFlag[axis]);
02754 #endif
02755             if (latchFlag[axis]) {
02756               /* get latched position in RAW UNITS */
02757               saveLatch[axis] = rawInput[axis];
02758               waitingForLatch[axis] = 0;
02759               /* call for an abort-- when it's finished, code
02760                  above sets inputOffset[] to saveLatch[] */
02761               finalHome[axis] = 0;
02762               tpAbort(&freeAxis[axis]);
02763             }
02764           } /* end of: if (GET_AXIS_HOME_SWITCH_FLAG(axis)) */
02765         }/* end of: if (waitingForLatch[axis]) */
02766       } /* end of: for (axis = 0; ...) */
02767     } /* end of: if (GET_MOTION_ENABLE_FLAG()) */
02768     else {
02769       /* we're not enabled, so no motion planning or interpolation has
02770          been done. jointPos[] is set to emcmotStatus->input[], and
02771          likewise with coarseJointPos[], which is normally updated at
02772          the traj rate but it's convenient to do them here at the same
02773          time at the servo rate. emcmotStatus->pos, ->actualPos need to
02774          be run through forward kinematics.
02775          Note that we are running at the servo rate, so we may need
02776          to slow down by the interpolation factor to avoid soaking
02777          the CPU. If we were enabled, ->pos was set by calcs (coord mode)
02778          or forward kins (free mode), and ->actualPos was set by forward
02779          kins on ->input[], all at the trajectory rate. */
02780       for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
02781         coarseJointPos[axis] = emcmotStatus->input[axis];
02782         jointPos[axis] = coarseJointPos[axis];
02783       }
02784       /* synthesize the trajectory interpolation, via a counter that
02785          decrements from the interpolation rate. This causes the statements
02786          to execute at the trajectory rate instead of the servo rate at which
02787          this enclosing code is called. */
02788       if (--interpolationCounter <= 0) {
02789         if (! EMCMOT_NO_FORWARD_KINEMATICS) {
02790           /* call the forward kinematics, at the effective trajectory rate */
02791           if (allHomed ||
02792               kinType == KINEMATICS_IDENTITY) {
02793             kinematicsForward(emcmotStatus->input, &emcmotStatus->actualPos, &fflags, &iflags);
02794           }
02795           emcmotStatus->pos = emcmotStatus->actualPos;
02796         }
02797         /* reload the interpolation counter that simulates the interpolation
02798            done when enabled */
02799         interpolationCounter = emcmotConfig->interpolationRate;
02800       }
02801     }
02802 
02803 #ifdef ENABLE_PROBING
02804     extDioRead(emcmotConfig->probeIndex, &emcmotStatus->probeval);
02805     if (emcmotStatus->probing && emcmotStatus->probeTripped) {
02806       tpClear(&queue);
02807       emcmotStatus->probing = 0;
02808     }
02809     else if (emcmotStatus->probing && GET_MOTION_INPOS_FLAG() &&
02810              tpQueueDepth(&queue) == 0) {
02811       emcmotStatus->probing = 0;
02812     }
02813     else if (emcmotStatus->probing) {
02814       if (emcmotStatus->probeval == emcmotConfig->probePolarity) {
02815         emcmotStatus->probeTripped = 1;
02816         emcmotStatus->probedPos = emcmotStatus->actualPos;
02817         if (GET_MOTION_COORD_FLAG()) {
02818           tpAbort(&queue);
02819           SET_MOTION_ERROR_FLAG(0);
02820         }
02821         else {
02822           /* check axis range */
02823           for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
02824             tpAbort(&freeAxis[axis]);
02825             SET_AXIS_HOMING_FLAG(axis, 0);
02826             SET_AXIS_ERROR_FLAG(axis, 0);
02827           }
02828         }
02829       }
02830     }
02831 #endif /* ENABLE_PROBING */
02832 
02833 #ifndef STEPPER_MOTORS
02834 
02835     /* SCALE OUTPUTS: */
02836 
02837     for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
02838       rawOutput[axis] =
02839         (emcmotStatus->output[axis] - emcmotStatus->outputOffset[axis]) *
02840         inverseOutputScale[axis];
02841     }
02842 
02843     /* WRITE OUTPUTS: */
02844 
02845     /* write DACs-- note that this is done even when not
02846        enabled, although in this case the pidOutputs are
02847        all zero unless manually overridden. They will not
02848        be set by any calculations if we're not enabled. */
02849     extDacWriteAll(EMCMOT_MAX_AXIS, rawOutput);
02850 #endif
02851 
02852     /* UPDATE THE REST OF THE DYNAMIC STATUS: */
02853 
02854     /* copy computed axis positions to status. Note that if motion is
02855        disabled, this is the same as ->input[]. */
02856     for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
02857       emcmotStatus->axisPos[axis] = jointPos[axis];
02858     }
02859 
02860     /* health heartbeat */
02861     emcmotStatus->heartbeat++;
02862 
02863     /* motion queue status */
02864     emcmotStatus->depth = tpQueueDepth(&queue);
02865     emcmotStatus->activeDepth = tpActiveDepth(&queue);
02866     emcmotStatus->id = tpGetExecId(&queue);
02867     emcmotStatus->queueFull = tcqFull(&queue.queue);
02868     SET_MOTION_INPOS_FLAG(0);
02869     if (tpIsDone(&queue)) {
02870       SET_MOTION_INPOS_FLAG(1);
02871     }
02872 
02873     /* axis status */
02874     for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
02875       SET_AXIS_INPOS_FLAG(axis, 0);
02876       if (tpIsDone(&freeAxis[axis])) {
02877         SET_AXIS_INPOS_FLAG(axis, 1);
02878       }
02879       else {
02880         /* this axis, at least, is moving, so set overriding flag */
02881         if (emcmotStatus->overrideLimits) {
02882           overriding = 1;
02883         }
02884       }
02885     }
02886 
02887     /* reset overrideLimits flag if we have started a move and now
02888        are in position */
02889     for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
02890       if (! GET_AXIS_INPOS_FLAG(axis)) {
02891         break;
02892       }
02893     }
02894     if (axis == EMCMOT_MAX_AXIS) {
02895       /* ran through all axes, and all are in position */
02896       if (overriding) {
02897         overriding = 0;
02898         emcmotStatus->overrideLimits = 0;
02899       }
02900     }
02901 
02902     /* check to see if we should pause in order to implement
02903        single stepping */
02904     if (stepping && idForStep != emcmotStatus->id) {
02905       for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
02906         tpPause(&freeAxis[axis]);
02907       }
02908       tpPause(&queue);
02909       stepping = 0;
02910       emcmotStatus->paused = 1;
02911     }
02912 
02913     /* calculate elapsed time and min/max/avg */
02914     end = etime();
02915     delta = end - start;
02916     emcmotStatus->computeTime = delta;
02917     if (2 == whichCycle) {
02918       /* traj calcs done this cycle-- use tMin,Max,Avg */
02919       mmxavgAdd(&emcmotDebug->tMmxavg, delta);
02920       emcmotDebug->tMin = mmxavgMin(&emcmotDebug->tMmxavg);
02921       emcmotDebug->tMax = mmxavgMax(&emcmotDebug->tMmxavg);
02922       emcmotDebug->tAvg = mmxavgAvg(&emcmotDebug->tMmxavg);
02923     }
02924     else if (1 == whichCycle) {
02925       /* servo calcs only this cycle-- use sMin,Max,Avg */
02926       mmxavgAdd(&emcmotDebug->sMmxavg, delta);
02927       emcmotDebug->sMin = mmxavgMin(&emcmotDebug->sMmxavg);
02928       emcmotDebug->sMax = mmxavgMax(&emcmotDebug->sMmxavg);
02929       emcmotDebug->sAvg = mmxavgAvg(&emcmotDebug->sMmxavg);
02930     }
02931     else {
02932       /* calcs disabled this cycle-- use nMin,Max,Avg */
02933       mmxavgAdd(&emcmotDebug->nMmxavg, delta);
02934       emcmotDebug->nMin = mmxavgMin(&emcmotDebug->nMmxavg);
02935       emcmotDebug->nMax = mmxavgMax(&emcmotDebug->nMmxavg);
02936       emcmotDebug->nAvg = mmxavgAvg(&emcmotDebug->nMmxavg);
02937     }
02938 
02939     /* log per-servo-cycle data if logging active */
02940     logIt = 0;
02941     if (emcmotStatus->logStarted &&
02942         emcmotStatus->logSkip >= 0) {
02943 
02944       /* record type here, since all will set this */
02945       ls.type = emcmotStatus->logType;
02946 
02947       /* now log type-specific data */
02948       switch (ls.type) {
02949 
02950       case EMCMOT_LOG_TYPE_AXIS_POS:
02951         if (logSkip-- <= 0) {
02952           ls.item.axisPos.time = end;
02953           ls.item.axisPos.input = emcmotStatus->input[loggingAxis];
02954           ls.item.axisPos.output = jointPos[loggingAxis];
02955           logSkip = emcmotStatus->logSkip;
02956           logIt = 1;
02957         }
02958         break;
02959 
02960       case EMCMOT_LOG_TYPE_ALL_INPOS:
02961         if (logSkip-- <= 0) {
02962           ls.item.allInpos.time = end;
02963           for (axis = 0;
02964                axis < EMCMOT_LOG_NUM_AXES &&
02965                  axis < EMCMOT_MAX_AXIS;
02966                axis++) {
02967             ls.item.allInpos.input[axis] = emcmotStatus->input[axis];
02968           }
02969           logSkip = emcmotStatus->logSkip;
02970           logIt = 1;
02971         }
02972         break;
02973 
02974       case EMCMOT_LOG_TYPE_ALL_OUTPOS:
02975         if (logSkip-- <= 0) {
02976           ls.item.allOutpos.time = end;
02977           for (axis = 0;
02978                axis < EMCMOT_LOG_NUM_AXES &&
02979                  axis < EMCMOT_MAX_AXIS;
02980                axis++) {
02981             ls.item.allOutpos.output[axis] = jointPos[axis];
02982           }
02983           logSkip = emcmotStatus->logSkip;
02984           logIt = 1;
02985         }
02986         break;
02987 
02988       case EMCMOT_LOG_TYPE_AXIS_VEL:
02989         if (logSkip-- <= 0) {
02990           ls.item.axisVel.time = end;
02991           ls.item.axisVel.cmdVel = jointPos[loggingAxis] -
02992             oldJointPos[loggingAxis];
02993           ls.item.axisVel.actVel = emcmotStatus->input[loggingAxis] -
02994             oldInput[loggingAxis];
02995           logSkip = emcmotStatus->logSkip;
02996           logIt = 1;
02997         }
02998         break;
02999 
03000       case EMCMOT_LOG_TYPE_ALL_FERROR:
03001         if (logSkip-- <= 0) {
03002           ls.item.allFerror.time = end;
03003           for (axis = 0;
03004                axis < EMCMOT_LOG_NUM_AXES &&
03005                  axis < EMCMOT_MAX_AXIS;
03006                axis++) {
03007             ls.item.allFerror.ferror[axis] = thisFerror[axis];
03008           }
03009           logSkip = emcmotStatus->logSkip;
03010           logIt = 1;
03011         }
03012         break;
03013 
03014       case EMCMOT_LOG_TYPE_POS_VOLTAGE:
03015         /* don't do a circular log-- suppress if full */
03016         if (emcmotLog->howmany >= emcmotStatus->logSize) {
03017           emcmotStatus->output[loggingAxis] = 0.0; /* drop the DAC to zero */
03018           emcmotStatus->logStarted = 0; /* stop logging */
03019           logIt = 0;            /* should still be zero, reset anyway */
03020           break;
03021         }
03022         if (logSkip-- <= 0) {
03023           ls.item.posVoltage.time = end;
03024           for (axis = 0;
03025                axis < EMCMOT_LOG_NUM_AXES &&
03026                  axis < EMCMOT_MAX_AXIS;
03027                axis++) {
03028             ls.item.posVoltage.pos = emcmotStatus->input[loggingAxis];
03029             ls.item.posVoltage.voltage = rawOutput[loggingAxis];
03030           }
03031           logSkip = emcmotStatus->logSkip;
03032           logIt = 1;
03033         }
03034         break;
03035 
03036       default:
03037         break;
03038       } /* end of: switch on log type */
03039 
03040       /* now log it */
03041 #if defined (rtlinux) && defined (RT_FIFO)
03042       if (logIt) {
03043         rtf_put(EMCMOT_LOG_RTF, &ls, sizeof(EMCMOT_LOG_STRUCT));
03044         /* FIXME-- update emcmotStatus->logPoints */
03045         logIt = 0;
03046       }
03047 #else
03048       if (logIt) {
03049         emcmotLogAdd(emcmotLog, ls);
03050         emcmotStatus->logPoints = emcmotLog->howmany;
03051         logIt = 0;
03052       }
03053 #endif
03054     } /* end of: if logging */
03055 
03056     /* set tail to head, which has already been incremented */
03057     emcmotStatus->tail = emcmotStatus->head;
03058     emcmotDebug->tail = emcmotDebug->head;
03059     emcmotConfig->tail = emcmotConfig->head;
03060 
03061     /* WRITE STATUS DATA */
03062 
03063 #if defined (rtlinux) && defined (RT_FIFO)
03064     /* write to rtlinux FIFO */
03065     rtf_put(EMCMOT_STATUS_RTF, &emcmotStatusBuffer, sizeof(EMCMOT_STATUS));
03066 
03067 #endif /* rtlinux and RT_FIFO */
03068 
03069 #ifdef rtlinux
03070     /* wait for next cycle */
03071 #ifdef USE_RTL2
03072     pthread_wait_np();
03073 #else
03074     rt_task_wait();
03075 #endif
03076   } /* end of: forever loop for RT task */
03077 #endif /* rtlinux */
03078 #ifdef USE_RTL2
03079   return(NULL);
03080 #endif
03081 } /* end of: emcmotController() function */
03082 
03083 #ifdef STEPPER_MOTORS
03084 
03085 /*
03086   smController runs the stepper motor pulse task calculations at a
03087   relatively high frequency. The time interval between calls to this
03088   task is governed by the maximum speed ([TRAJ] MAX_VELOCITY) and the
03089   max pulses-per-unit among all motors ([AXIS_#] INPUT_SCALE). The task
03090   runs at twice this time since it must issue both down pulses and up
03091   pulses, and can only do one per motor per call.
03092 
03093   For each motor, the task looks at the commanded position, in integer
03094   counts, as stored in the global smSteps[]. This is set by the
03095   emcmotController task. If the accumulated number of steps is greater
03096   (or less) than half a pulse, a pulse is sent in the proper direction and
03097   the accumulated count is incremented (or decremented).
03098 
03099   The timing of this task does not vary with the speed of each motor.
03100 
03101   The parallel port is used for outputs, using the pptDioByteWrite()
03102   function. Four axes (step and direction) are put on the low byte, and
03103   the remaining two axes are put on the high byte.
03104 */
03105 
03106 #define _TESTING
03107 #ifdef USE_RTL2
03108 static void *smController(void *arg)
03109 #else
03110 static void smController(int arg)
03111 #endif
03112 {
03113   static unsigned char oldSmLoByte = 0, oldSmHiByte = 0;
03114   static int smCount[EMCMOT_MAX_AXIS];
03115   static int up[EMCMOT_MAX_AXIS];
03116   static int down[EMCMOT_MAX_AXIS];
03117   static int direction[EMCMOT_MAX_AXIS];
03118 #ifdef TESTING
03119   static char toggle = 0;
03120 #endif
03121   int axis;
03122   unsigned char smLoByte = 0, smHiByte = 0;
03123   int delta;
03124   int period;
03125 
03126 #ifndef STANDALONE
03127   for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
03128     smCount[axis] = 0;
03129     up[axis] = 0;
03130     down[axis] = 0;
03131     direction[axis] = 1;
03132   }
03133 
03134   for (;;) {
03135 #endif
03136     smLoByte = oldSmLoByte;
03137     smHiByte = oldSmHiByte;
03138 
03139     for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
03140 
03141       if (smNewCycle[axis]) {
03142         smCount[axis] = smCyclesPerAxis;
03143         smNewCycle[axis] = 0;
03144       }
03145 
03146       if (up[axis] > 0) {
03147         up[axis]--;
03148         if (direction[axis]) {
03149           smLoByte |= (0x01 << (axis << 1)); /* dir */
03150           smLoByte |= (0x02 << (axis << 1)); /* clk */
03151         }
03152         else {
03153           smLoByte &= ~(0x01 << (axis << 1)); /* dir */
03154           smLoByte |= (0x02 << (axis << 1)); /* clk */
03155         }
03156       }
03157       else if (down[axis] > 0) {
03158         down[axis]--;
03159         smLoByte &= ~(0x02 << (axis << 1)); /* clk */
03160       }
03161       else {
03162         delta = smSteps[axis] - emcmotDebug->stepperCount[axis];
03163         if (delta > 0) {
03164           direction[axis] = 1;
03165           period = smCount[axis] / +delta;
03166           up[axis] = period / 2;
03167           if (up[axis] <= 0) up[axis] = 1;
03168           down[axis] = period - up[axis];
03169           if (down[axis] <= 0) down[axis] = 1;
03170           smLoByte |= (0x01 << (axis << 1)); /* dir */
03171           smLoByte |= (0x02 << (axis << 1)); /* clk */
03172           emcmotDebug->stepperCount[axis]++;
03173           up[axis]--;
03174         }
03175         else if (delta < 0) {
03176           direction[axis] = 0;
03177           period = smCount[axis] / -delta;
03178           up[axis] = period / 2;
03179           if (up[axis] <= 0) up[axis] = 1;
03180           down[axis] = period - up[axis];
03181           if (down[axis] <= 0) down[axis] = 1;
03182           smLoByte &= ~(0x01 << (axis << 1)); /* dir */
03183           smLoByte |= (0x02 << (axis << 1)); /* clk */
03184           emcmotDebug->stepperCount[axis]--;
03185           up[axis]--;
03186         }
03187         else {
03188           /* no delta, so output a down */
03189           smLoByte &= ~(0x02 << (axis << 1)); /* clk */
03190         }
03191       }
03192 
03193       smCount[axis]--;
03194     }
03195 
03196 #ifndef STANDALONE
03197 #ifdef TESTING
03198     /* channel 2 is sm task trigger */
03199     if (toggle) {
03200       smLoByte |= 0x0C;
03201     }
03202     else {
03203       smLoByte &= ~0x0C;
03204     }
03205     toggle = ! toggle;
03206 #endif
03207     /* suppress redundant writes */
03208     if (smLoByte != oldSmLoByte) {
03209       pptDioByteWrite(0, smLoByte);
03210       oldSmLoByte = smLoByte;
03211     }
03212     if (smHiByte != oldSmHiByte) {
03213       pptDioByteWrite(1, smHiByte);
03214       oldSmHiByte = smHiByte;
03215     }
03216 #else
03217     pptDioByteWrite(0, smLoByte);
03218 #endif
03219 
03220 #ifndef STANDALONE
03221 #ifdef USE_RTL2
03222     pthread_wait_np();
03223 #else
03224     rt_task_wait();
03225 #endif
03226   }
03227 #endif
03228 #ifdef USE_RTL2
03229   return(NULL);
03230 #endif
03231 
03232 }
03233 
03234 #endif /* ifdef STEPPER_MOTORS */
03235 
03236 /* fix for scripts that pass PERIOD to insmod; we don't use it here but it
03237    will keep insmod from complaining */
03238 #ifndef __GNUC__
03239 #ifndef __attribute__
03240 #define __attribute__(x)
03241 #endif
03242 #endif
03243 
03244 static int __attribute__((unused)) PERIOD = 1;
03245 
03246 /* STEPPING_TYPE is unused here, but provided for compatibility with
03247    scripts that run this code and pass this as a parameter */
03248 static int __attribute__((unused)) STEPPING_TYPE = 0;
03249 
03250 #if defined(rtlinux2)
03251 /* register symbols to be modified by insmod */
03252 MODULE_PARM(PERIOD, "i");
03253 MODULE_PARM(SHMEM_BASE_ADDRESS, "l");
03254 MODULE_PARM(STG_BASE_ADDRESS, "h");
03255 MODULE_PARM(PARPORT_IO_ADDRESS, "l");
03256 MODULE_PARM(EMCMOT_NO_FORWARD_KINEMATICS, "i");
03257 MODULE_PARM(STEPPING_TYPE, "i");
03258 #endif
03259 
03260 int init_module(void)
03261 {
03262   int axis;
03263   int t;
03264 #ifdef rtlinux
03265 #ifdef USE_RTL2
03266   hrtime_t now;
03267   pthread_attr_t attr;
03268   struct sched_param sched_param;
03269   clockid_t local_clock;
03270 #else
03271   RTIME now;
03272 #endif
03273 #endif
03274   PID_STRUCT pid;
03275 
03276 #ifdef rtlinux
03277 
03278 #ifdef RT_FIFO
03279   rtf_create(EMCMOT_COMMAND_RTF, sizeof(EMCMOT_COMMAND) + 1);
03280   rtf_create(EMCMOT_STATUS_RTF, sizeof(EMCMOT_STATUS) + 1);
03281   rtf_create(EMCMOT_ERROR_RTF, EMCMOT_ERROR_NUM * EMCMOT_ERROR_LEN + 1);
03282   /* log is created, deleted dynamically */
03283 
03284   /* fifo puts and gets work on buffer structs, so point to these */
03285   emcmotCommand = &emcmotCommandBuffer;
03286   emcmotStatus = &emcmotStatusBuffer;
03287   emcmotConfig = &emcmotConfigBuffer;
03288   emcmotDebug = &emcmotDebugBuffer;
03289 
03290 #else  /* not RT_FIFO */
03291 
03292 
03293 #ifdef USE_RTL2
03294   /* set shared memory pointer using mbuff which does not require that memory be resevered in lilo.conf */
03295   printk(KERN_INFO "calling mbuff_alloc(%s,%d)\n",
03296          "emcmotStruct",
03297          (int) sizeof(EMCMOT_STRUCT));
03298   emcmotStruct = (EMCMOT_STRUCT *) mbuff_alloc("emcmotStruct",sizeof(EMCMOT_STRUCT));
03299   printk(KERN_INFO "mbuff_alloc returned %d\n",((int) emcmotStruct));
03300 
03301 #else
03302 #ifdef rtlinux2
03303   /* set shared memory pointer using ioremap for 2.1+ kernels */
03304   emcmotStruct = (EMCMOT_STRUCT *) ioremap(SHMEM_BASE_ADDRESS, sizeof(EMCMOT_STRUCT));
03305 
03306 #else
03307   /* set shared memory pointer */
03308   emcmotStruct = (EMCMOT_STRUCT *) vremap(SHMEM_BASE_ADDRESS, sizeof(EMCMOT_STRUCT));
03309 #endif
03310 #endif
03311 
03312 #endif /* else not RT_FIFO */
03313 
03314 #else  /* not rtlinux */
03315   /* get command shmem */
03316   shmem = rcs_shm_open(SHMEM_KEY, sizeof(EMCMOT_STRUCT), 1, 0666);
03317   if (NULL == shmem ||
03318       NULL == shmem->addr)
03319     {
03320       diagnostics("can't get shared memory\n");
03321       return -1;
03322     }
03323 
03324   memset(shmem->addr, 0, sizeof(EMCMOT_STRUCT));
03325   /* map shmem area into local address space */
03326   emcmotStruct = (EMCMOT_STRUCT *) shmem->addr;
03327 
03328 #endif /* else not rtlinux */
03329 
03330 #ifndef RT_FIFO
03331   /* we'll reference emcmotStruct directly */
03332   emcmotCommand = (EMCMOT_COMMAND *) &emcmotStruct->command;
03333   emcmotStatus = (EMCMOT_STATUS *) &emcmotStruct->status;
03334   emcmotConfig = (EMCMOT_CONFIG *) &emcmotStruct->config;
03335   emcmotDebug = (EMCMOT_DEBUG *) &emcmotStruct->debug;
03336   emcmotError = (EMCMOT_ERROR *) &emcmotStruct->error;
03337   emcmotLog = (EMCMOT_LOG *) &emcmotStruct->log;
03338   for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
03339     emcmotComp[axis] = (EMCMOT_COMP *) &emcmotStruct->comp[axis];
03340   }
03341 
03342   /* zero shared memory */
03343   for (t = 0; t < sizeof(EMCMOT_STRUCT); t++) {
03344     ((char *) emcmotStruct)[t] = 0;
03345   }
03346 #endif /* not RT_FIFO */
03347 
03348   /* init locals */
03349   for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
03350     maxLimitSwitchCount[axis] = 0;
03351     minLimitSwitchCount[axis] = 0;
03352     ampFaultCount[axis] = 0;
03353 #ifdef STEPPER_MOTORS
03354     smStepsPerUnit[axis] = INPUT_SCALE;
03355     smMagUnitsPerStep[axis] = fabs(1.0 / INPUT_SCALE);
03356     emcmotDebug->stepperCount[axis] = 0;
03357     smNewCycle[axis] = 1;
03358 #endif
03359   }
03360 
03361 #ifndef RT_FIFO
03362   /* init compensation struct */
03363   for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
03364     emcmotComp[axis]->total = 0;
03365     emcmotComp[axis]->alter = 0.0;
03366     /* leave out the avgint, nominal, forward, and reverse, since
03367        these can't be zero and the total flag prevents their use anyway */
03368   }
03369 
03370   /* init error struct */
03371   emcmotErrorInit(emcmotError);
03372 #endif /* not RT_FIFO */
03373 
03374   /* init command struct */
03375   emcmotCommand->head = 0;
03376   emcmotCommand->command = 0;
03377   emcmotCommand->commandNum = 0;
03378   emcmotCommand->tail = 0;
03379 
03380   /* init status struct */
03381 
03382   emcmotStatus->head = 0;
03383   emcmotConfig->head = 0;
03384   emcmotDebug->head = 0;
03385 
03386   emcmotStatus->motionFlag = 0;
03387   SET_MOTION_ERROR_FLAG(0);
03388   SET_MOTION_COORD_FLAG(0);
03389   emcmotDebug->split = 0;
03390   emcmotStatus->commandEcho = 0;
03391   emcmotStatus->commandNumEcho = 0;
03392   emcmotStatus->commandStatus = 0;
03393   emcmotStatus->heartbeat = 0;
03394   emcmotStatus->computeTime = 0.0;
03395   emcmotConfig->numAxes = EMCMOT_MAX_AXIS;
03396   emcmotConfig->trajCycleTime = TRAJ_CYCLE_TIME;
03397   emcmotConfig->servoCycleTime = SERVO_CYCLE_TIME;
03398   emcmotStatus->pos.tran.x = 0.0;
03399   emcmotStatus->pos.tran.y = 0.0;
03400   emcmotStatus->pos.tran.z = 0.0;
03401   emcmotStatus->actualPos.tran.x = 0.0;
03402   emcmotStatus->actualPos.tran.y = 0.0;
03403   emcmotStatus->actualPos.tran.z = 0.0;
03404   emcmotStatus->vel = VELOCITY;
03405   emcmotConfig->limitVel = VELOCITY;
03406   emcmotStatus->acc = ACCELERATION;
03407   emcmotStatus->qVscale = 1.0;
03408   emcmotStatus->id = 0;
03409   emcmotStatus->depth = 0;
03410   emcmotStatus->activeDepth = 0;
03411   emcmotStatus->paused = 0;
03412   emcmotStatus->overrideLimits = 0;
03413   SET_MOTION_INPOS_FLAG(1);
03414   emcmotStatus->logOpen = 0;
03415   emcmotStatus->logStarted = 0;
03416   emcmotStatus->logSize = 0;
03417   emcmotStatus->logSkip = 0;
03418   emcmotStatus->logPoints = 0;
03419   SET_MOTION_ENABLE_FLAG(0);
03420 
03421   oldPos = emcmotStatus->pos;
03422   oldVel.tran.x = 0.0;
03423   oldVel.tran.y = 0.0;
03424   oldVel.tran.z = 0.0;
03425 
03426   for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
03427     emcmotConfig->homingVel[axis] = VELOCITY;
03428     emcmotConfig->homeOffset[axis] = 0.0;
03429     emcmotStatus->axisFlag[axis] = 0;
03430     emcmotConfig->maxLimit[axis] = MAX_LIMIT;
03431     emcmotConfig->minLimit[axis] = MIN_LIMIT;
03432     emcmotConfig->maxOutput[axis] = MAX_OUTPUT;
03433     emcmotConfig->minOutput[axis] = MIN_OUTPUT;
03434     emcmotConfig->minFerror[axis] = 0.0; /* gives a true linear ferror */
03435     emcmotConfig->maxFerror[axis] = MAX_FERROR;
03436     emcmotDebug->ferrorCurrent[axis] = 0.0;
03437     emcmotDebug->ferrorHighMark[axis] = 0.0;
03438     emcmotStatus->outputScale[axis] = OUTPUT_SCALE;
03439     emcmotStatus->outputOffset[axis] = OUTPUT_OFFSET;
03440     emcmotStatus->inputScale[axis] = INPUT_SCALE;
03441     inverseInputScale[axis] = 1.0 / INPUT_SCALE;
03442     emcmotStatus->inputOffset[axis] = INPUT_OFFSET;
03443     inverseOutputScale[axis] = 1.0 / OUTPUT_SCALE;
03444     emcmotStatus->axVscale[axis] = 1.0;
03445     SET_AXIS_ENABLE_FLAG(axis, 0);
03446     SET_AXIS_ACTIVE_FLAG(axis, 0); /* default is not to use it; need an
03447                                       explicit activate */
03448     SET_AXIS_NSL_FLAG(axis, 0);
03449     SET_AXIS_PSL_FLAG(axis, 0);
03450     SET_AXIS_NHL_FLAG(axis, 0);
03451     SET_AXIS_PHL_FLAG(axis, 0);
03452     SET_AXIS_INPOS_FLAG(axis, 1);
03453     SET_AXIS_HOMING_FLAG(axis, 0);
03454     SET_AXIS_HOMED_FLAG(axis, 0);
03455     SET_AXIS_FERROR_FLAG(axis, 0);
03456     SET_AXIS_FAULT_FLAG(axis, 0);
03457     SET_AXIS_ERROR_FLAG(axis, 0);
03458     emcmotConfig->axisPolarity[axis] = (EMCMOT_AXIS_FLAG) 0xFFFFFFFF;
03459     /* will read encoders directly, so don't set them here */
03460   }
03461 
03462   /* FIXME-- add emcmotError */
03463 
03464   /* init min-max-avg stats */
03465   mmxavgInit(&emcmotDebug->tMmxavg, emcmotDebug->tMmxavgSpace, MMXAVG_SIZE);
03466   mmxavgInit(&emcmotDebug->sMmxavg, emcmotDebug->sMmxavgSpace, MMXAVG_SIZE);
03467   mmxavgInit(&emcmotDebug->nMmxavg, emcmotDebug->nMmxavgSpace, MMXAVG_SIZE);
03468   emcmotDebug->tMin = 0.0;
03469   emcmotDebug->tMax = 0.0;
03470   emcmotDebug->tAvg = 0.0;
03471   emcmotDebug->sMin = 0.0;
03472   emcmotDebug->sMax = 0.0;
03473   emcmotDebug->sAvg = 0.0;
03474   emcmotDebug->nMin = 0.0;
03475   emcmotDebug->nMax = 0.0;
03476   emcmotDebug->nAvg = 0.0;
03477 
03478   /* init motion queue */
03479   if (-1 == tpCreate(&queue, DEFAULT_TC_QUEUE_SIZE, queueTcSpace)) {
03480     diagnostics("can't create motion queue\n");
03481     return -1;
03482   }
03483   tpInit(&queue);
03484   tpSetCycleTime(&queue, emcmotConfig->trajCycleTime);
03485   tpSetPos(&queue, emcmotStatus->pos);
03486   tpSetVmax(&queue, emcmotStatus->vel);
03487   tpSetAmax(&queue, emcmotStatus->acc);
03488 
03489   /* init the axis components */
03490   pid.p = P_GAIN;
03491   pid.i = I_GAIN;
03492   pid.d = D_GAIN;
03493   pid.ff0 = FF0_GAIN;
03494   pid.ff1 = FF1_GAIN;
03495   pid.ff2 = FF2_GAIN;
03496   pid.backlash = BACKLASH;
03497   pid.bias = BIAS;
03498   pid.maxError = MAX_ERROR;
03499 
03500   for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
03501     if (-1 == tpCreate(&freeAxis[axis], FREE_AXIS_QUEUE_SIZE, freeAxisTcSpace[axis])) {
03502       diagnostics("can't create axis queue %d\n", axis);
03503       return -1;
03504     }
03505     tpInit(&freeAxis[axis]);
03506     tpSetCycleTime(&freeAxis[axis], emcmotConfig->trajCycleTime);
03507     /* freePose is inited to 0's in decl */
03508     tpSetPos(&freeAxis[axis], freePose);
03509     tpSetVmax(&freeAxis[axis], emcmotStatus->vel);
03510     tpSetAmax(&freeAxis[axis], emcmotStatus->acc);
03511 #ifndef STEPPER_MOTORS
03512     pidInit(&emcmotConfig->pid[axis]);
03513     pidSetGains(&emcmotConfig->pid[axis], pid);
03514 #endif
03515     cubicInit(&cubic[axis]);
03516   }
03517 
03518   /* init the time and rate using functions to affect traj, the
03519      pids, and the cubics properly, since they're coupled */
03520   setTrajCycleTime(TRAJ_CYCLE_TIME);
03521   setServoCycleTime(SERVO_CYCLE_TIME);
03522 
03523   /* init board */
03524   if (-1 == extMotInit((const char *) 0)) {
03525     diagnostics("can't initialize motion hardware\n");
03526     return -1;
03527   }
03528   if (-1 == extDioInit((const char *) 0)) {
03529     diagnostics("can't initialize DIO hardware\n");
03530     return -1;
03531   }
03532   if (-1 == extAioInit((const char *) 0)) {
03533     diagnostics("can't initialize AIO hardware\n");
03534     return -1;
03535   }
03536 
03537   /* record the kinematics type of the machine */
03538   kinType = kinematicsType();
03539 
03540   extEncoderSetIndexModel(EXT_ENCODER_INDEX_MODEL_MANUAL);
03541   for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
03542     rawInput[axis] = 0.0;
03543     rawOutput[axis] = 0.0;
03544     coarseJointPos[axis] = 0.0;
03545     jointPos[axis] = 0.0;
03546     jointVel[axis] = 0.0;
03547     emcmotStatus->axisPos[axis] = 0.0;
03548     oldJointPos[axis] = 0.0;
03549 
03550     waitingForLatch[axis] = 0;
03551     latchFlag[axis] = 0;
03552     saveLatch[axis] = 0.0;
03553 
03554     emcmotStatus->input[axis] = 0.0;
03555     oldInput[axis] = 0.0;
03556     emcmotStatus->output[axis] = 0.0;
03557 
03558     jointHome[axis] = 0.0;
03559 
03560     extAmpEnable(axis,
03561                  ! GET_AXIS_ENABLE_POLARITY(axis));
03562   }
03563 
03564   emcmotStatus->tail = 0;
03565 
03566 #ifdef rtlinux
03567 
03568 
03569 #ifdef USE_RTL2
03570   local_clock = rtl_getschedclock();
03571 
03572 #if 0
03573   if(!rtl_setclockmode(local_clock, RTL_CLOCK_MODE_PERIODIC, 20000))
03574     {
03575     diagnostics("can't set periodic mode\n");
03576   }
03577 #else
03578   rtl_setclockmode(local_clock, RTL_CLOCK_MODE_ONESHOT,0);
03579 #endif
03580 
03581 #else // RTL before version 2
03582 #if 0
03583   if (RT_TIME_END == rtl_set_periodic_mode(20)) {
03584     diagnostics("can't set periodic mode\n");
03585   }
03586 #else
03587   rtl_set_oneshot_mode();
03588 #endif
03589 
03590 #endif
03591 
03592 #ifdef USE_RTL2
03593   pthread_attr_init (&attr);
03594   sched_param.sched_priority = RT_TASK_PRIORITY;
03595   pthread_attr_setschedparam (&attr, &sched_param);
03596   attr.use_fp = 1;
03597   attr.stack_size = RT_TASK_STACK_SIZE;
03598   pthread_create( &emcmotTask, &attr, emcmotController, (void *) 1);
03599 
03600   /* get current time as base for starting tasks */
03601   now =gethrtime();
03602 
03603   pthread_setfp_np(emcmotTask,1);
03604   pthread_make_periodic_np(emcmotTask,
03605                            now + 0.010*HRTICKS_PER_SEC,
03606                            (hrtime_t) (HRTICKS_PER_SEC *
03607                                        emcmotConfig->servoCycleTime));
03608 #else
03609 
03610   /* init control task */
03611   rt_task_init(&emcmotTask,     /* RT_TASK * */
03612                emcmotController, /* task code */
03613                0,               /* startup arg to task code */
03614                RT_TASK_STACK_SIZE, /* task stack size */
03615                RT_TASK_PRIORITY); /* priority */
03616 
03617   /* make sure we save FP context */
03618   rt_task_use_fp(&emcmotTask, 1);
03619 
03620   /* get current time as base for starting tasks */
03621   now = rt_get_time();
03622 
03623   /* schedule control task to run */
03624   rt_task_make_periodic(&emcmotTask,
03625                         now + SECS_TO_RTIME(0.010),
03626                         (RTIME) (RT_TICKS_PER_SEC *
03627                                  emcmotConfig->servoCycleTime));
03628 
03629 
03630 #endif
03631 
03632 
03633 
03634 #ifdef STEPPER_MOTORS
03635 
03636 
03637   /* schedule stepper task to run at 1/(V*P), where V is max velocity
03638      and P is the max stepper pulses per unit among all axes, i.e.,
03639      inputScale. Note that this is also done whenever limit vel or input
03640      scales are changed */
03641   smVPmax = VELOCITY * INPUT_SCALE; /* use defaults at first */
03642   smMaxStepsPerUnit = INPUT_SCALE;
03643   /* set the period to twice the max pulse rate. It need only
03644      be the same as the pulse rate, but this makes it the same
03645      as before */
03646   smCycleTime = 0.5/smVPmax;
03647   smCyclesPerAxis = (int) (emcmotConfig->servoCycleTime / smCycleTime);
03648 
03649 
03650 #ifdef USE_RTL2
03651   pthread_attr_init (&attr);
03652   sched_param.sched_priority = SM_TASK_PRIORITY;
03653   pthread_attr_setschedparam (&attr, &sched_param);
03654   attr.use_fp = 1;
03655   attr.stack_size = SM_TASK_STACK_SIZE;
03656   pthread_create( &smTask, &attr, smController, NULL);
03657 
03658   /* get current time as base for starting tasks */
03659   now =gethrtime();
03660 
03661   pthread_setfp_np(emcmotTask,1);
03662   pthread_make_periodic_np(emcmotTask,
03663                            now + 0.010*HRTICKS_PER_SEC,
03664                            (hrtime_t) (HRTICKS_PER_SEC *
03665                                        smCycleTime));
03666 
03667 #else
03668 
03669   /* init stepper motor task */
03670   rt_task_init(&smTask, /* RT_TASK * */
03671                smController, /* task code */
03672                0,               /* startup arg to task code */
03673                SM_TASK_STACK_SIZE, /* task stack size */
03674                SM_TASK_PRIORITY); /* priority */
03675 
03676   /* make sure we save FP context */
03677   rt_task_use_fp(&smTask, 1);
03678 
03679   rt_task_make_periodic(&smTask,
03680                         now + SECS_TO_RTIME(0.010),
03681                         ((RTIME) (RT_TICKS_PER_SEC * smCycleTime)));
03682 
03683 #endif
03684 #endif
03685 
03686   /* FIXME */
03687   diagnostics("inited emcmot\n");
03688 
03689 #endif /* rtlinux */
03690 
03691 #if defined (rtlinux) && defined (RT_FIFO)
03692   /* create user process handler on control channel */
03693   rtf_create_handler(EMCMOT_COMMAND_RTF, /* fifo number */
03694                      emcmotCommandHandler /* control message handler */
03695                      );
03696 
03697 #endif /* rtlinux and RT_FIFO */
03698 
03699   return 0;
03700 }
03701 
03702 void cleanup_module(void)
03703 {
03704   int axis;
03705 
03706   /* release traj planner space */
03707   tpDelete(&queue);
03708 
03709   /* disable amps */
03710   for (axis = 0; axis < EMCMOT_MAX_AXIS; axis++) {
03711     extAmpEnable(axis,
03712                  ! GET_AXIS_ENABLE_POLARITY(axis));
03713   }
03714 
03715   /* quit board */
03716   extAioQuit();
03717   extDioQuit();
03718   extMotQuit();
03719 
03720 #ifdef rtlinux
03721 
03722 #ifdef RT_FIFO
03723   rtf_destroy(EMCMOT_COMMAND_RTF);
03724   rtf_destroy(EMCMOT_STATUS_RTF);
03725   rtf_destroy(EMCMOT_ERROR_RTF);
03726 #endif
03727 
03728   /* delete control task */
03729 #ifdef USE_RTL2
03730   pthread_delete_np(emcmotTask);
03731 #else
03732   rt_task_delete(&emcmotTask);
03733 #endif
03734 
03735 #ifdef STEPPER_MOTORS
03736 
03737   /* delete stepper motor task */
03738 #ifdef USE_RTL2
03739   pthread_delete_np(smTask);
03740 #else
03741   rt_task_delete(&smTask);
03742 #endif
03743 
03744 #endif
03745 
03746   /* free shared memory */
03747 #ifdef USE_RTL2
03748   mbuff_free("emcmotStruct",emcmotStruct);
03749 #else
03750 #ifdef rtlinux2
03751   iounmap(emcmotStruct);
03752 #else
03753   vfree(emcmotStruct);
03754 #endif
03755 #endif
03756 
03757 
03758   /* FIXME */
03759   diagnostics("exited emcmot\n");
03760 #ifdef STEPPER_MOTORS
03761   diagnostics("sm cycle time %d\n", (int) (smCycleTime * 1000000.0));
03762   diagnostics("sm cycles per axis %d\n", smCyclesPerAxis);
03763 #endif
03764 
03765 #else
03766 
03767   /* detach from shmem */
03768   if (NULL != shmem) {
03769     rcs_shm_close(shmem);
03770     shmem = NULL;
03771   }
03772 
03773 #endif
03774 }
03775 
03776 /* Build a standalone executable with main() if not rtlinux */
03777 
03778 #ifndef rtlinux
03779 int emcmot_done = 0;
03780 static void emcmot_quit(int sig)
03781 {
03782   emcmot_done = 1;
03783 }
03784 
03785 #ifndef UNDER_CE
03786 #include <signal.h>             /* signal(), SIGINT */
03787 #endif
03788 
03789 #ifndef UNDER_CE
03790 static int getArgs(int argc, char *argv[])
03791 {
03792   int t;
03793   int len;
03794 
03795   for (t = 1; t < argc; t++) {
03796     /* try -ini */
03797     /* NOTE: motion controller cannot normally read an INI file.
03798        This is provided for main() simulation, which can read
03799        an INI file and needs it for the plant simulation parameters */
03800     if (!strcmp(argv[t], "-ini")) {
03801       if (t == argc - 1) {
03802         diagnostics("missing -ini parameter\n");
03803         return -1;
03804       }
03805       else {
03806         strcpy(EMCMOT_INIFILE, argv[t+1]);
03807         t++;            /* step over following arg */
03808         continue;
03809       }
03810     }
03811 
03812     /* try SHMEM_BASE_ADDRESS */
03813     len = strlen("SHMEM_BASE_ADDRESS");
03814     if (! strncmp(argv[t], "SHMEM_BASE_ADDRESS", len)) {
03815       if (argv[t][len] != '=' ||
03816           1 != sscanf(&argv[t][len + 1], "%i", &SHMEM_BASE_ADDRESS)) {
03817         diagnostics("syntax: %s SHMEM_BASE_ADDRESS=integer\n", argv[0]);
03818         return -1;
03819       }
03820       else {
03821         continue;
03822       }
03823     }
03824 
03825     /* try SHMEM_KEY */
03826     len = strlen("SHMEM_KEY");
03827     if (! strncmp(argv[t], "SHMEM_KEY", len)) {
03828       if (argv[t][len] != '=' ||
03829           1 != sscanf(&argv[t][len + 1], "%i", &SHMEM_KEY)) {
03830         diagnostics("syntax: %s SHMEM_KEY=integer\n", argv[0]);
03831         return -1;
03832       }
03833       else {
03834         continue;
03835       }
03836     }
03837 
03838     /* FIXME */
03839     /* try -noforward */
03840     if (!strcmp(argv[t], "-noforward")) {
03841       EMCMOT_NO_FORWARD_KINEMATICS = 1;
03842       continue;
03843     }
03844 
03845     /* no match-- bad arg */
03846     diagnostics("bad argument to %s: %s\n", argv[0], argv[t]);
03847     return -1;
03848   }
03849 
03850   return 0;
03851 }
03852 #endif
03853 
03854 
03855 /*
03856   syntax: a.out SHMEM_BASE_ADDRESS=int SHMEM_KEY=int STG_BASE_ADDRESS=int
03857 
03858   Syntax matches that used with insmod sym=value, for consistency
03859   */
03860 #ifndef UNDER_CE
03861 int main(int argc, char *argv[])
03862 #else
03863 int emcmotsim()
03864 #endif
03865 {
03866   double delta;                 /* elapsed time */
03867 
03868 #ifndef UNDER_CE
03869   /* trap ^C */
03870   signal(SIGINT, emcmot_quit);
03871 
03872   /* process command line args */
03873   if (0 != getArgs(argc, argv)) {
03874     diagnostics("can't init module-- bad arguments\n");
03875     exit(1);
03876   }
03877 #endif
03878 
03879   /* set up data structs */
03880   if (-1 == init_module()) {
03881     diagnostics("can't init module-- execution permission problems?\n");
03882 #ifndef UNDER_CE
03883     exit(1);
03884 #else
03885     return 1;
03886 #endif
03887   }
03888 
03889   while (! emcmot_done) {
03890     delta = etime();
03891     emcmotController(0);
03892     delta = etime() - delta;
03893     delta = emcmotConfig->servoCycleTime - delta;
03894 
03895     if (delta > 0.0) {
03896       esleep(delta);
03897     }
03898   }
03899 
03900   cleanup_module();
03901 #ifndef UNDER_CE
03902   exit(0);
03903 #else
03904   return 0;
03905 #endif
03906 }
03907 
03908 #endif /* not rtlinux */

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