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

simmot.c

Go to the documentation of this file.
00001 /*
00002   simmot.c
00003 
00004   Simulated external motion interface for a DC servomotor system
00005 
00006   The simulation is clocked by calls to simEncoderRead(). Each time
00007   this call is done, the motor advances. Calls to simDacWrite() usually
00008   precede calls to simEncoderRead(), but need not. If not, the last
00009   value is used.
00010 
00011   Modification history:
00012 
00013   28-Jun-2000 WPS eliminated some unused variables.
00014   17-Apr-2000 WPS moved SIM_MAX_AXIS to simmot_n.h.
00015   14-Apr-2000 WPS added _attribute__((unused)) to ident
00016   21-Sep-1999  WPS eliminate sscanf and printf calls not supported under CE.
00017   21-Jun-1999  FMP changed SIM_MAX_AXIS to 8
00018   17-Apr-1998  FMP compile-switched stat'ing of switch files using
00019   USE_STAT_FILES
00020   17-Mar-1998  FMP added amp, motor, encoder simulations; changed
00021   SIM_MAX_AXIS from 3 to 4
00022   25-Nov-1997 FMP changed extLimitSwitchRead to extPos,NegLimit...
00023   01-Aug-1997  FMP changed encoder counts from int to double
00024   28-Jul-1997  FMP added extLimitSwitchRead()
00025   24-Jun-1997  FMP created
00026   */
00027 
00028 /* FIXME-- encoder calibration stuff not used, stat files used instead */
00029 
00030 /* Define this if you want to test limit switches, home switches by
00031    touching files and having stat() look for them. On an NFS file system,
00032    this can generate lots of traffic.
00033    Otherwise, the functions will just return "normal" status. */
00034 /* #define USE_STAT_FILES */
00035 
00036 
00037 #ifndef UNDER_CE
00038 #include <stdio.h>              /* printf() */
00039 #endif
00040 
00041 #if !defined(rtlinux) && !defined(rtai)
00042 #include <stdlib.h>             /* sizeof(), _itoa() */
00043 #include <string.h>             /* strcpy() */
00044 #ifndef UNDER_CE
00045 #include <sys/types.h>
00046 #endif
00047 #endif
00048 #ifdef USE_STAT_FILES
00049 #include <sys/stat.h>
00050 #endif
00051 #include "sim.h"                /* these decls */
00052 #include "extintf.h"            /* EXT_ENCODER_INDEX_MODEL */
00053 
00054 #if !defined(rtlinux) && !defined(rtai)
00055 #include "rcs_prnt.hh"          /* rcs_print() */
00056 #include "inifile.h"
00057 #endif
00058 #include "amplifier.h"          /* AMPLIFIER_STRUCT */
00059 #include "dcmotor2.h"           /* DCMOTOR_STRUCT */
00060 #include "encoder.h"            /* ENCODER_STRUCT */
00061 
00062 /* ident tag */
00063 #ifndef __GNUC__
00064 #ifndef __attribute__
00065 #define __attribute__(x)
00066 #endif
00067 #endif
00068 
00069 static char __attribute__((unused)) ident[] = "$Id: simmot.c,v 1.11 2001/12/01 21:24:29 paul_c Exp $";
00070 
00071 #define NAMELEN 8               /* length of stat file names */
00072 
00073 #include "simmot_n.h"
00074 
00075 #if defined(rtlinux) || defined(rtai)
00076 #include "rtlnml.h"
00077 
00078 rtlnml_t nml_sim_command_channel = NULL;
00079 rtlnml_t nml_sim_status_channel = NULL;
00080 
00081 #endif
00082 
00083 static AMPLIFIER_STRUCT amplifier[SIM_MAX_AXIS];
00084 static double ampOutput[SIM_MAX_AXIS];
00085 static DC_MOTOR_STRUCT dcmotor[SIM_MAX_AXIS];
00086 static ENCODER_STRUCT encoder[SIM_MAX_AXIS];
00087 
00088 #if defined(rtlinux) || defined(rtai)
00089 static struct simmot_status_struct stat;
00090 #endif
00091 
00092 
00093 /*
00094   simInit takes INI file, then composes section strings as:
00095 
00096   AXIS_<0..SIM_MAX_AXIS-1>
00097   */
00098 int simMotInit(const char * filename)
00099 {
00100   int t;
00101 #if !defined(rtlinux) && !defined(rtai)
00102   char sectionString[INIFILE_MAX_LINELEN];
00103 #endif
00104   int retval = 0;
00105 #if defined(rtlinux) || defined(rtai)
00106   struct simmot_command_struct *cmd;
00107 #endif
00108 
00109 #if defined(rtlinux) || defined(rtai)
00110   if (NULL == nml_sim_command_channel) {
00111     rtlnml_init();
00112 #ifdef rtlinux
00113     nml_sim_command_channel = rtlnml_open("simmot_cmd","simmot","emc.nml",4096,1);
00114 #else
00115     nml_sim_command_channel = rtainml_open("simmot_cmd","simmot","emc.nml",4096, 1,1014);
00116 #endif
00117     if (NULL == nml_sim_command_channel) {
00118       return -1;
00119     }
00120   }
00121 
00122   if (NULL == nml_sim_status_channel) {
00123 #ifdef rtlinux
00124     nml_sim_status_channel = rtlnml_open("simmot_stat","simmot","emc.nml",4096,1);
00125 #else
00126     nml_sim_status_channel = rtainml_open("simmot_stat","simmot","emc.nml",4096, 1, 1015);
00127 #endif
00128     if (NULL == nml_sim_status_channel) {
00129       return -1;
00130     }
00131   }
00132 
00133   switch(rtlnml_read(nml_sim_command_channel)) {
00134   case 0:
00135     /* FIXME  this function needs to be polled */
00136     break;
00137 
00138   case SIMMOT_COMMAND_TYPE:
00139     cmd = (struct simmot_command_struct *) rtlnml_get_local_pointer(nml_sim_command_channel);
00140     for (t = 0; t < SIM_MAX_AXIS; t++) {
00141       stat.amplifier[t] = amplifier[t] = cmd->amplifier[t];
00142       stat.dcmotor[t] = dcmotor[t] = cmd->dcmotor[t];
00143       stat.encoder[t] = encoder[t] = cmd->encoder[t];
00144     }
00145     stat.initialized = 1;
00146     stat.cmd_count++;
00147     rtlnml_write(nml_sim_status_channel, &stat,SIMMOT_STATUS_TYPE,sizeof(stat));
00148     break;
00149 
00150   case -1:
00151     /* Error from rtlnml_read() */
00152     return -1;
00153 
00154   default:
00155     /* THIS should never happen */
00156     break;
00157   }
00158 
00159 #else
00160 
00161   for (t = 0; t < SIM_MAX_AXIS; t++) {
00162 #ifndef UNDER_CE
00163      sprintf(sectionString, "AXIS_%d", t);
00164 #else
00165     strcpy(sectionString,"AXIS_");
00166     _itoa(t,sectionString+5,10);
00167 #endif
00168 
00169     if (0 != amplifierIniLoad(&amplifier[t], filename, sectionString)) {
00170       retval = -1;
00171     }
00172     ampOutput[t] = 0.0;
00173 
00174     if (0 != dcmotorIniLoad(&dcmotor[t], filename, sectionString)) {
00175       retval = -1;
00176     }
00177 
00178     if (0 != encoderIniLoad(&encoder[t], filename, sectionString)) {
00179       retval = -1;
00180     }
00181   }
00182 #endif
00183 
00184   return retval;
00185 }
00186 
00187 int simMotQuit()
00188 {
00189 #if defined(rtlinux) || defined(rtai)
00190 
00191   if (NULL != nml_sim_command_channel) {
00192     rtlnml_close(nml_sim_command_channel,"sim_cmd");
00193   }
00194 
00195   if (NULL != nml_sim_status_channel) {
00196     rtlnml_close(nml_sim_status_channel,"sim_stat");
00197   }
00198 
00199   rtlnml_exit();
00200 #endif
00201 
00202   return 0;
00203 }
00204 
00205 int simDacNum()
00206 {
00207   return SIM_MAX_AXIS;
00208 }
00209 
00210 /*
00211   simDacWrite just runs a cycle on the amplifier simulator to get
00212   the resulting output voltage. This is saved in the ampOutput[]
00213   array for use by simEncoderRead(), which calls the motor simulation
00214   */
00215 int simDacWrite(int dac, double volts)
00216 {
00217   ampOutput[dac] = amplifierRunCycle(&amplifier[dac], volts);
00218 
00219   return 0;
00220 }
00221 
00222 int simDacWriteAll(int max, double * volts)
00223 {
00224   int t;
00225 
00226   if (max > SIM_MAX_AXIS) {
00227     return -1;
00228   }
00229 
00230   for (t = 0; t < max; t++) {
00231     if (-1 == simDacWrite(t, volts[t])) {
00232       return -1;
00233     }
00234   }
00235 
00236   return 0;
00237 }
00238 
00239 unsigned int simEncoderIndexModel(void)
00240 {
00241   return EXT_ENCODER_INDEX_MODEL_MANUAL;
00242 }
00243 
00244 int simEncoderSetIndexModel(unsigned int model)
00245 {
00246   if (model != EXT_ENCODER_INDEX_MODEL_MANUAL) {
00247     return -1;
00248   }
00249 
00250   return 0;
00251 }
00252 
00253 int simEncoderNum()
00254 {
00255   return SIM_MAX_AXIS;
00256 }
00257 
00258 /*
00259   simEncoderRead() clocks the simulation. The amp output set by the
00260   call to simDacWrite() for this axis is used as the motor input.
00261   */
00262 int simEncoderRead(int axis, double * counts)
00263 {
00264   double motorPos;
00265   int iCounts;
00266 
00267   motorPos = dcmotorRunCycle(&dcmotor[axis], ampOutput[axis]);
00268   iCounts = encoderGetCounts(&encoder[axis], motorPos);
00269 
00270   *counts = (double) iCounts;
00271 
00272   simPos[axis] = *counts;
00273 
00274   return 0;
00275 }
00276 
00277 int simEncoderReadAll(int max, double * counts)
00278 {
00279   int t;
00280 
00281   if (max > SIM_MAX_AXIS) {
00282     return -1;
00283   }
00284 
00285   for (t = 0; t < max; t++) {
00286     if (-1 == simEncoderRead(t, &counts[t])) {
00287       return -1;
00288     }
00289   }
00290 
00291 #if defined(rtlinux) || defined(rtai)
00292   if (NULL !=  nml_sim_status_channel) {
00293     for (t = 0; t < SIM_MAX_AXIS; t++) {
00294       stat.amplifier[t] = amplifier[t];
00295       stat.dcmotor[t] = dcmotor[t];
00296       stat.encoder[t] = encoder[t];
00297       stat.ampOutput[t] = ampOutput[t];
00298     }
00299     rtlnml_write(nml_sim_status_channel, &stat,SIMMOT_STATUS_TYPE,sizeof(stat));
00300   }
00301 #endif
00302   return 0;
00303 }
00304 
00305 int simEncoderResetIndex(int encoder)
00306 {
00307   return 0;
00308 }
00309 
00310 int simEncoderReadLatch(int encoder, int * flag)
00311 {
00312 #ifdef USE_STAT_FILES
00313   struct stat buf;
00314   char homeFile[NAMELEN];
00315 #endif
00316 
00317   if (encoder < 0 ||
00318       encoder >= SIM_MAX_AXIS) {
00319     return -1;
00320   }
00321 
00322 #ifdef USE_STAT_FILES
00323   /* to test home flag logic, this code tests for the existence
00324      of files "home<n>", for axis n.
00325      During controller debug, touch these files to create them
00326      and the controller should see a home flag. */
00327 
00328 #ifndef UNDER_CE
00329   sprintf(homeFile, "home%d", encoder);
00330 #else
00331   strcpy(homeFile,"home");
00332   _itoa(encoder, homeFile+4,10);
00333 #endif
00334 
00335   if (0 == stat(homeFile, &buf)) {
00336     /* positive limit file exists */
00337     *flag = 1;
00338   }
00339   else {
00340     *flag = 0;
00341   }
00342 
00343 #else
00344   *flag = 1;                    /* always show latch so homing will work */
00345 
00346 #endif
00347 
00348   return 0;
00349 }
00350 
00351 int simEncoderReadLevel(int encoder, int * flag)
00352 {
00353   *flag = 0;
00354 
00355   return 0;
00356 }
00357 
00358 int simMaxLimitSwitchRead(int axis, int * flag)
00359 {
00360 #ifdef USE_STAT_FILES
00361   struct stat buf;
00362   char maxFile[NAMELEN];
00363 #endif
00364 
00365   if (axis < 0 ||
00366       axis >= SIM_MAX_AXIS) {
00367     return -1;
00368   }
00369 
00370 #ifdef USE_STAT_FILES
00371   /* to test limit switch logic, this code tests for the existence
00372      of files "lim<n>p" for max limits on axis n.
00373      During controller debug, touch these files to create them
00374      and the controller should see a limit. */
00375 #ifndef UNDER_CE
00376   sprintf(maxFile, "lim%dp", axis);
00377 #else
00378   strcpy(maxFile,"lim");
00379   _itoa(axis, maxFile+3,10);
00380   strcat(maxFile,"p");
00381 #endif
00382 
00383   if (0 == stat(maxFile, &buf)) {
00384     /* maximum limit file exists */
00385     *flag = 1;
00386   }
00387   else {
00388     *flag = 0;
00389   }
00390 
00391 #else
00392   *flag = 0;
00393 
00394 #endif
00395 
00396   return 0;
00397 }
00398 
00399 int simMinLimitSwitchRead(int axis, int * flag)
00400 {
00401 #ifdef USE_STAT_FILES
00402   struct stat buf;
00403   char minFile[NAMELEN];
00404 #endif
00405 
00406   if (axis < 0 ||
00407       axis >= SIM_MAX_AXIS) {
00408     return -1;
00409   }
00410 
00411 #ifdef USE_STAT_FILES
00412   /* to test limit switch logic, this code tests for the existence
00413      of files "lim<n>n" for min limits on axis n.
00414      During controller debug, touch these files to create them
00415      and the controller should see a limit. */
00416 
00417 #ifndef UNDER_CE
00418   sprintf(minFile, "lim%dn", axis);
00419 #else
00420   strcpy(minFile,"lim");
00421   _itoa(axis, minFile+3,10);
00422   strcat(minFile,"n");
00423 #endif
00424 
00425   if (0 == stat(minFile, &buf)) {
00426     /* minimum limit file exists */
00427     *flag = 1;
00428   }
00429   else {
00430     *flag = 0;
00431   }
00432 
00433 #else
00434   *flag = 0;
00435 
00436 #endif
00437 
00438   return 0;
00439 }
00440 
00441 static int silly_count=0;
00442 
00443 int simHomeSwitchRead(int axis, int * flag)
00444 {
00445 #ifdef USE_STAT_FILES
00446   struct stat buf;
00447   char homeFile[NAMELEN];
00448 #endif
00449 
00450   if (axis < 0 ||
00451       axis >= SIM_MAX_AXIS) {
00452     return -1;
00453   }
00454 
00455 #ifdef USE_STAT_FILES
00456   /* to test home switch logic, this code tests for the existence
00457      of file "hs<n>" for home switch on axis n.
00458      During controller debug, touch these files to create them
00459      and the controller should see a home. */
00460 
00461 #ifndef UNDER_CE
00462   sprintf(homeFile, "hs%d", axis);
00463 #else
00464   strcpy(homeFile,"hs");
00465   _itoa(axis, homeFile+2,10);
00466 #endif
00467 
00468   if (0 == stat(homeFile, &buf)) {
00469     /* home switch file exists */
00470     *flag = 1;
00471   }
00472   else {
00473     *flag = 0;
00474   }
00475 
00476 #else
00477   *flag = ((silly_count++)%100)>50; /* always show switch on so homing will work */
00478 
00479 #endif
00480 
00481   return 0;
00482 }
00483 
00484 int simAmpEnable(int axis, int enable)
00485 {
00486   if (axis < 0 ||
00487       axis >= SIM_MAX_AXIS) {
00488     return -1;
00489   }
00490 
00491   amplifierEnable(&amplifier[axis]);
00492 
00493   return 0;
00494 }
00495 
00496 int simAmpFault(int axis, int * fault)
00497 {
00498   if (axis < 0 ||
00499       axis >= SIM_MAX_AXIS) {
00500     return -1;
00501   }
00502 
00503   *fault = amplifierIsTripped(&amplifier[axis]);
00504 
00505   return 0;
00506 }

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