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

xemc.cc

Go to the documentation of this file.
00001 /*
00002   xemc.cc - X GUI for the EMC
00003 
00004   Modification history:
00005 
00006   30-May-2001 WPS added readig EMC_NMLFILE to iniLoad().
00007   30-May-2001 WPS added readig EMC_DEBUG to iniLoad().
00008   30-Mar-2000 WPS added ferrorCurrent and ferrorHighMark junk.
00009   20-Mar-2000 WPS made the EMC_DEBUG_NML flag enable NML error messages.
00010   8-Oct-1999  FMP added "L" key for overriding pos limits; added
00011   stepIncrement for incremental jogs of the smallest step size.
00012   1-Oct-1999  FMP added lookup of EMC_NMLFILE in ini file; added limit
00013   override button
00014   3-Sep-1999  FMP looked in both [TASK] and [DISPLAY] for PROGRAM_PREFIX
00015   17-Aug-1999  FMP added pre-send of program open when stepping
00016   16-Jul-1999  FMP added silent retry for NML buffers
00017   15-Jun-1999  FMP added "v" key for program verify
00018   10-Jun-1999  FMP updated program window with lines that the interpreter
00019   is reading through, if they're being skipped via a run mark.
00020   7-Jun-1999  FMP added printing of mag for traj vel and acc log plotting
00021   2-Jun-1999  FMP added setting of initial jog speed and max jog speed to
00022   honor ini file values rather than hard-coded 60, 120.
00023   21-May-1999  FMP added EMC_LOG_TYPE_TRAJ_POS, changing TRAJ_INPOS,OUTPOS
00024   to AXES_INPOS,OUTPOS
00025   3-May-1999  FMP added kill click catching for top level and all other
00026   popup windows.
00027   23-Apr-1999  FMP added catching of kill click for help window, with more
00028   windows to come.
00029   25-Mar-1999  FMP added automatic mode change to auto when running program
00030   23-Mar-1999  FMP added file marking to set program start line; added
00031   highlighting of active line with two previous lines above
00032   22-Mar-1999  FMP added line field to EMC_TASK_PLAN_RUN
00033   25-Feb-1999  FMP changed app name to XEmc from xemc, per X app convention;
00034   added more info to diagnostics popup
00035   24-Feb-1999  FMP changed direction for 'i' key to decrease jogIncrement,
00036   since you usually jog big, then small, then smaller. Jog increment is
00037   also saved when you go into continuous mode and restored when you go
00038   back into incremental mode.
00039   22-Feb-1999  FMP added EMC_TOOL_SET_OFFSET handling
00040   21-Feb-1999  FMP added posOffset dialog for setting axis offsets, with
00041   alt-X, etc.
00042   17-Feb-1999  FMP changed sendMdi(char *) to sendMdiCmd(char *) so as not
00043   to overload with sendMdi() for setting the mode.
00044   11-Feb-1999  FMP added setting of following error in calibration dialog;
00045   added diagnostics popup in view menu
00046   9-Feb-1999  FMP added more logging and plotting features, namely buttons
00047   that work; fixed problem in which changing a program contents and then
00048   re-opening it didn't change the contents in the bottom program window
00049   8-Feb-1999  FMP added logging and plotting
00050   4-Feb-1999  FMP added flag to prevent multiple errors from popping up
00051   dialog boxes (multiples are printed to stderr, for now); checked jog
00052   increment before stopping jogs so we don't prematurely abort an incremental
00053   jog; allowed coolant and spindle commands through in auto-idle/paused
00054   and mdi; made some widgets topLevelShellWidgetClass types so they have
00055   title bars and can be moved around
00056   30-Jan-1999  FMP improved editor so you can create new files; changed
00057   terminology from absolute coordinates to machine coordinates
00058   29-Jan-1999  FMP added program status string (running, idle, paused);
00059   edit dialog box and mini-editor;
00060   27-Jan-1999  FMP added popups for setting jog speed and feed override;
00061   menu for abs/rel, cmd/act
00062   26-Jan-1999  FMP added I and C key for setting jog increment; < and >
00063   keys for changing jog speed; maxFeedOverride from MAX_FEED_OVERRIDE ini
00064   file parameter; honored ini file JOGGING_POLARITY; added End button and
00065   dialog for quit confirm; added offset/variable file edit window
00066   25-Jan-1999  FMP added Xemc help file display; b/B brake off/on; made
00067   tool table window dynamic so that the changes could be canceled and
00068   external edits would show up
00069   24-Jan-1999  FMP added editable/loadable tool table window
00070   22-Jan-1999  FMP added other keys; cmd/act and rel/abs display;
00071   tool number and length offset; dynamic program text display;
00072   resizable dialog box for text entry; tab highlights buttons when
00073   there are more than one in a dialog; tool table window
00074   21-Jan-1999  FMP added function keys
00075   13-Jan-1999  FMP took out rereading of emcCommandSerialNumber from
00076   EMC status, since it caused duplicate numbers in rapid-fire commands.
00077   Now, the serial number is maintained internally, and if 2 GUIs are running
00078   and they use the same serial number one will not go through. This is not
00079   a normal situation.
00080   Added colors for axis homed, on limit; pulled resources out into xemc;
00081   11-Jan-1999  FMP fixed menu dimming bug where the manual menus came
00082   up enabled regardless of initial state; added pause/resume/step;
00083   7-Jan-1999  FMP added create,destroyErrorShell(); incremental jogs
00084   05-Jan-1998  FMP added many more controls; took out calls to
00085   emcCommandWait(emcCommandSerialNumber) after all
00086   emcCommandBuffer->write() calls
00087   31-Dec-1998  FMP created
00088  */
00089 
00090 #include <stdio.h>
00091 #include <string.h>
00092 #include <stdlib.h>
00093 #include <ctype.h>
00094 #include <values.h>             // DBL_MAX, maybe
00095 #include <limits.h>             // DBL_MAX, maybe
00096 #include <stdarg.h>
00097 #include <sys/stat.h>           // struct stat, stat()
00098 #include <unistd.h>
00099 #include <fcntl.h>              // O_CREAT
00100 
00101 #include "rcs.hh"               // etime()
00102 #include "emc.hh"               // EMC NML
00103 #include "emcglb.h"             // EMC_NMLFILE, TRAJ_MAX_VELOCITY, TOOL_TABLE_FILE
00104 #include "emccfg.h"             // DEFAULT_TRAJ_MAX_VELOCITY
00105 #include "inifile.h"            // INIFILE
00106 
00107 /*
00108  * Include files required for all Toolkit programs
00109  */
00110 #include <X11/Intrinsic.h>      /* Intrinsics Definitions */
00111 #include <X11/StringDefs.h>     /* Standard Name-String definitions */
00112 
00113 /*
00114  * Public include file for widgets we actually use in this file.
00115  */
00116 #include <X11/Xaw/Form.h>
00117 #include <X11/Xaw/Box.h>
00118 #include <X11/Xaw/Command.h>
00119 #include <X11/Xaw/Label.h>
00120 #include <X11/Xaw/AsciiText.h>
00121 #include <X11/Xaw/MenuButton.h>
00122 #include <X11/Xaw/SimpleMenu.h>
00123 #include <X11/Xaw/SmeBSB.h>
00124 #include <X11/Xaw/SmeLine.h>
00125 #include <X11/Xaw/Dialog.h>
00126 
00127 #define UPDATE_MSECS 100
00128 
00129 // the NML channels to the EMC task
00130 static RCS_CMD_CHANNEL *emcCommandBuffer = 0;
00131 static RCS_STAT_CHANNEL *emcStatusBuffer = 0;
00132 EMC_STAT *emcStatus = 0;
00133 
00134 // the NML channel for errors
00135 static NML *emcErrorBuffer = 0;
00136 static char error_string[EMC_OPERATOR_ERROR_LEN] = "";
00137 
00138 // the current command numbers, set up updateStatus(), used in main()
00139 static int emcCommandSerialNumber = 0;
00140 
00141 // forward decls
00142 
00143 // forward decls for error popup
00144 static void errorReturnAction(Widget w, XEvent *event, String *params, Cardinal *num_params);
00145 static void errorDoneCB(Widget w, XtPointer client_data, XtPointer call_data);
00146 static int createErrorShell();
00147 static int destroyErrorShell();
00148 static void popupError(const char *fmt, ...);
00149 
00150 // forward decl for quit() function
00151 static void quit();
00152 
00153 static int emcTaskNmlGet()
00154 {
00155   int retval = 0;
00156 
00157   // try to connect to EMC cmd
00158   if (emcCommandBuffer == 0)
00159     {
00160       emcCommandBuffer = new RCS_CMD_CHANNEL(emcFormat, "emcCommand", "xemc", EMC_NMLFILE);
00161       if (! emcCommandBuffer->valid())
00162         {
00163           delete emcCommandBuffer;
00164           emcCommandBuffer = 0;
00165           retval = -1;
00166         }
00167     }
00168 
00169   // try to connect to EMC status
00170   if (emcStatusBuffer == 0)
00171     {
00172       emcStatusBuffer = new RCS_STAT_CHANNEL(emcFormat, "emcStatus", "xemc", EMC_NMLFILE);
00173       if (! emcStatusBuffer->valid() ||
00174           EMC_STAT_TYPE != emcStatusBuffer->peek())
00175         {
00176           delete emcStatusBuffer;
00177           emcStatusBuffer = 0;
00178           emcStatus = 0;
00179           retval = -1;
00180         }
00181       else
00182         {
00183           emcStatus = (EMC_STAT *) emcStatusBuffer->get_address();
00184         }
00185     }
00186 
00187   return retval;
00188 }
00189 
00190 static int emcErrorNmlGet()
00191 {
00192   int retval = 0;
00193 
00194   if (emcErrorBuffer == 0)
00195     {
00196       emcErrorBuffer = new NML(nmlErrorFormat, "emcError", "xemc", EMC_NMLFILE);
00197       if (! emcErrorBuffer->valid())
00198         {
00199           delete emcErrorBuffer;
00200           emcErrorBuffer = 0;
00201           retval = -1;
00202         }
00203     }
00204 
00205   return retval;
00206 }
00207 
00208 static void printError(char *error)
00209 {
00210   printf("%s\n", error);
00211 }
00212 
00213 static int updateStatus()
00214 {
00215   NMLTYPE type;
00216 
00217   if (0 == emcStatus ||
00218       0 == emcStatusBuffer ||
00219       ! emcStatusBuffer->valid())
00220     {
00221       return -1;
00222     }
00223 
00224   switch (type = emcStatusBuffer->peek())
00225     {
00226     case -1:
00227       // error on CMS channel
00228       return -1;
00229       break;
00230 
00231     case 0:                     // no new data
00232     case EMC_STAT_TYPE: // new data
00233       // new data
00234       break;
00235 
00236     default:
00237       return -1;
00238       break;
00239     }
00240 
00241   return 0;
00242 }
00243 
00244 static int updateError()
00245 {
00246   NMLTYPE type;
00247 
00248   if (0 == emcErrorBuffer ||
00249       ! emcErrorBuffer->valid())
00250     {
00251       return -1;
00252     }
00253 
00254   switch (type = emcErrorBuffer->read())
00255     {
00256     case -1:
00257       // error reading channel
00258       return -1;
00259       break;
00260 
00261     case 0:
00262       // nothing new
00263       error_string[0] = 0;
00264       break;
00265 
00266     case EMC_OPERATOR_ERROR_TYPE:
00267       strncpy(error_string,
00268              ((EMC_OPERATOR_ERROR *) (emcErrorBuffer->get_address()))->error,
00269               EMC_OPERATOR_ERROR_LEN - 1);
00270       error_string[EMC_OPERATOR_ERROR_LEN - 1] = 0;
00271       break;
00272 
00273     case EMC_OPERATOR_TEXT_TYPE:
00274       strncpy(error_string,
00275              ((EMC_OPERATOR_TEXT *) (emcErrorBuffer->get_address()))->text,
00276               EMC_OPERATOR_ERROR_LEN - 1);
00277       error_string[EMC_OPERATOR_ERROR_LEN - 1] = 0;
00278       break;
00279 
00280     case EMC_OPERATOR_DISPLAY_TYPE:
00281       strncpy(error_string,
00282              ((EMC_OPERATOR_DISPLAY *) (emcErrorBuffer->get_address()))->display,
00283               EMC_OPERATOR_ERROR_LEN - 1);
00284       error_string[EMC_OPERATOR_ERROR_LEN - 1] = 0;
00285       break;
00286 
00287     case NML_ERROR_TYPE:
00288       strncpy(error_string,
00289              ((NML_ERROR *) (emcErrorBuffer->get_address()))->error,
00290               NML_ERROR_LEN - 1);
00291       error_string[NML_ERROR_LEN - 1] = 0;
00292       break;
00293 
00294     case NML_TEXT_TYPE:
00295       strncpy(error_string,
00296              ((NML_TEXT *) (emcErrorBuffer->get_address()))->text,
00297               NML_ERROR_LEN - 1);
00298       error_string[NML_ERROR_LEN - 1] = 0;
00299       break;
00300 
00301     case NML_DISPLAY_TYPE:
00302       strncpy(error_string,
00303              ((NML_DISPLAY *) (emcErrorBuffer->get_address()))->display,
00304               NML_ERROR_LEN - 1);
00305       error_string[NML_ERROR_LEN - 1] = 0;
00306       break;
00307 
00308     default:
00309       sprintf(error_string, "unrecognized error %ld",type);
00310       return -1;
00311       break;
00312     }
00313 
00314   return 0;
00315 }
00316 
00317 #define EMC_COMMAND_TIMEOUT 1.0 // how long to wait until timeout
00318 #define EMC_COMMAND_DELAY   0.1 // how long to sleep between checks
00319 
00320 /*
00321   emcCommandWaitReceived() waits until the EMC reports that it got
00322   the command with the indicated serial_number.
00323   emcCommandWaitDone() waits until the EMC reports that it got the
00324   command with the indicated serial_number, and it's done, or error.
00325 */
00326 
00327 static int emcCommandWaitReceived(int serial_number)
00328 {
00329   double start = etime();
00330 
00331   while (etime() - start < EMC_COMMAND_TIMEOUT) {
00332     updateStatus();
00333 
00334     if (emcStatus->echo_serial_number == serial_number) {
00335       return 0;
00336     }
00337 
00338     esleep(EMC_COMMAND_DELAY);
00339   }
00340 
00341   return -1;
00342 }
00343 
00344 static int emcCommandWaitDone(int serial_number)
00345 {
00346   double start = etime();
00347 
00348   while (etime() - start < EMC_COMMAND_TIMEOUT) {
00349     updateStatus();
00350 
00351     if (emcStatus->echo_serial_number == serial_number) {
00352       if (emcStatus->status == RCS_DONE) {
00353         return 0;
00354       }
00355       else if (emcStatus->status == RCS_ERROR) {
00356         return -1;
00357       }
00358     }
00359 
00360     esleep(EMC_COMMAND_DELAY);
00361   }
00362 
00363   return -1;
00364 }
00365 
00366 /*
00367   functions for handling the windowing of a file, where you
00368   give the line you wish to window and it produces an array
00369   of string, or single string, of the file's contents
00370   at that point and some lines beyond
00371   */
00372 
00373 #define LF 10
00374 #define CR 13
00375 
00376 typedef struct {
00377   /* the array holding the window of lines in the file */
00378   char *fileWindow;
00379 
00380   /* the number of lines in the window */
00381   int maxWindowLines;
00382 
00383   /* the max length of each line */
00384   int maxLineLen;
00385 
00386   /* which array index holds the first filled slot */
00387   int windowStart;
00388 
00389   /* which array index holds the next open slot */
00390   int windowEnd;
00391 
00392   /* number in ring, also used to differentiate start = end as full/empty */
00393   int windowCount;
00394 
00395   /* the file to window */
00396   FILE * fileFp;
00397 
00398   /* the line currently at the top of the window */
00399   int fileFpLine;
00400 
00401   /* flag that the line should be kept */
00402   int keepNextLine;
00403 
00404 } FILE_WINDOW;
00405 
00406 static int fwClear(FILE_WINDOW *fw)
00407 {
00408   int t;
00409 
00410   if (NULL == fw) {
00411     return -1;
00412   }
00413 
00414   for (t = 0; t < fw->maxWindowLines; t++) {
00415     fw->fileWindow[t * fw->maxLineLen] = 0;
00416   }
00417 
00418   fw->windowStart = 0;
00419   fw->windowEnd = 0;
00420   fw->windowCount = 0;
00421 
00422   fw->fileFpLine = 0;
00423 
00424   fw->keepNextLine = 1;
00425 
00426   return 0;
00427 }
00428 
00429 static int fwInit(FILE_WINDOW *fw, int _maxWindowLines, int _maxLineLen)
00430 {
00431   if (NULL == fw) {
00432     return -1;
00433   }
00434 
00435   fw->fileWindow = (char *) malloc(_maxLineLen * _maxWindowLines);
00436 
00437   fw->maxWindowLines = _maxWindowLines;
00438   fw->maxLineLen = _maxLineLen;
00439 
00440   /* clear out the remaining vars */
00441   if (0 != fwClear(fw)) {
00442     return -1;
00443   }
00444 
00445   /* mark the file closed */
00446   fw->fileFp = NULL;
00447 
00448   return 0;
00449 }
00450 
00451 static int fwOpen(FILE_WINDOW *fw, const char *file)
00452 {
00453   if (NULL == fw) {
00454     return -1;
00455   }
00456 
00457   /* close any open file */
00458   if (NULL != fw->fileFp) {
00459     fclose(fw->fileFp);
00460     fw->fileFp = NULL;
00461   }
00462 
00463   if (NULL == (fw->fileFp = fopen(file, "r"))) {
00464     return -1;
00465   }
00466 
00467   fw->keepNextLine = 1;
00468 
00469   return 0;
00470 }
00471 
00472 static int fwClose(FILE_WINDOW *fw)
00473 {
00474   int retval = 0;
00475 
00476   if (NULL == fw) {
00477     return -1;
00478   }
00479 
00480   /* first clear out the window */
00481   if (0 != fwClear(fw)) {
00482     retval = -1;
00483   }
00484 
00485   if (NULL != fw->fileFp) {
00486     fclose(fw->fileFp);
00487   }
00488   fw->fileFp = NULL;
00489 
00490   return retval;
00491 }
00492 
00493 #if 0
00494 static int fwDelete(FILE_WINDOW *fw)
00495 {
00496   if (NULL == fw) {
00497     return -1;
00498   }
00499 
00500   /* should have been closed by call to fwClose(), but make sure */
00501   if (NULL != fw->fileFp) {
00502     fclose(fw->fileFp);
00503     fw->fileFp = NULL;
00504   }
00505 
00506   free(fw->fileWindow);
00507 
00508   return 0;
00509 }
00510 
00511 static int fwPrintWindow(FILE_WINDOW *fw)
00512 {
00513   int start;
00514 
00515   if (NULL == fw) {
00516     return -1;
00517   }
00518 
00519   start = fw->windowStart;
00520 
00521   if (0 == fw->windowCount) {
00522     return 0;
00523   }
00524 
00525   do {
00526     printf("%s\n", &(fw->fileWindow[start * fw->maxLineLen]));
00527     if (++start >= fw->maxWindowLines) {
00528       start = 0;
00529     }
00530   } while (start != fw->windowEnd);
00531 
00532   return 0;
00533 }
00534 #endif
00535 
00536 static int fwAddLine(FILE_WINDOW *fw, const char *line)
00537 {
00538   if (NULL == fw) {
00539     return -1;
00540   }
00541 
00542   strncpy(&fw->fileWindow[fw->windowEnd * fw->maxLineLen], line, fw->maxLineLen - 1);
00543   fw->fileWindow[fw->windowEnd * fw->maxLineLen + fw->maxLineLen - 1] = 0;
00544 
00545   if (fw->windowEnd == fw->windowStart &&
00546       0 != fw->windowCount) {
00547     /* we're full, so move fw->windowStart up */
00548     /* and don't increment fw->windowCount */
00549     if (++fw->windowStart >= fw->maxWindowLines) {
00550       fw->windowStart = 0;
00551     }
00552   }
00553   else {
00554     /* we're not full, so no need to move fw->windowStart up */
00555     /* but do increment fw->windowCount */
00556     ++fw->windowCount;
00557   }
00558 
00559   /* now increment fw->windowEnd to point to next slot */
00560   if (++fw->windowEnd >= fw->maxWindowLines) {
00561     fw->windowEnd = 0;
00562   }
00563 
00564   return 0;
00565 }
00566 
00567 #if 0
00568 static int fwDeleteLine(FILE_WINDOW *fw)
00569 {
00570   if (NULL == fw) {
00571     return -1;
00572   }
00573 
00574   if (0 == fw->windowCount) {
00575     return 0;
00576   }
00577 
00578   fw->fileWindow[fw->windowStart * fw->maxLineLen] = 0;
00579   if (++fw->windowStart >= fw->maxWindowLines) {
00580     fw->windowStart = 0;
00581   }
00582 
00583   --fw->windowCount;
00584 
00585   return 0;
00586 }
00587 #endif
00588 
00589 static int fwSyncLine(FILE_WINDOW *fw, int syncLine)
00590 {
00591   char line[256];               // FIXME-- hardcoded
00592   int pad;
00593   int len;
00594   int sawEol;
00595 
00596   if (NULL == fw) {
00597     return -1;
00598   }
00599 
00600   if (NULL == fw->fileFp) {
00601     return -1;
00602   }
00603 
00604   /* if syncLine is <= 0, make it 1 */
00605   if (syncLine <= 0) {
00606     syncLine = 1;
00607   }
00608 
00609   /* reset syncLine so that it means the first line is synched */
00610   syncLine += fw->maxWindowLines - 1;
00611 
00612   /* check if our window is ahead of file, and rewind if so */
00613   if (syncLine < fw->fileFpLine) {
00614     /* we're ahead of program, so rewind */
00615     rewind(fw->fileFp);
00616     /* and clear out fw->fileWindow */
00617     fwClear(fw);
00618   }
00619 
00620   /* now the window is at or behind the file */
00621   /* so fill it up */
00622   while (fw->fileFpLine < syncLine) {
00623     if (NULL == fgets(line, fw->maxLineLen, fw->fileFp)) {
00624       /* end file */
00625       /* pad remainder if any */
00626       pad = syncLine - fw->fileFpLine;
00627       while (pad-- > 0) {
00628         fwAddLine(fw, "");
00629       }
00630       fw->fileFpLine = syncLine;
00631       break;
00632     }
00633 
00634     sawEol = 0;
00635     len = strlen(line);
00636     while (--len >= 0) {
00637       if (CR == line[len] ||
00638           LF == line[len]) {
00639         line[len] = 0;
00640         sawEol = 1;
00641       }
00642       else {
00643         break;
00644       }
00645     }
00646 
00647     if (fw->keepNextLine) {
00648       fwAddLine(fw, line);
00649       ++fw->fileFpLine;
00650     }
00651 
00652     fw->keepNextLine = sawEol;
00653   }
00654 
00655   return 0;
00656 }
00657 
00658 static int fwString(FILE_WINDOW *fw, char *string)
00659 {
00660   int start;
00661 
00662   if (NULL == fw) {
00663     return -1;
00664   }
00665 
00666   start = fw->windowStart;
00667   string[0] = 0;
00668 
00669   if (0 == fw->windowCount) {
00670     return 0;
00671   }
00672 
00673   do {
00674     strncat(string, &(fw->fileWindow[start * fw->maxLineLen]),
00675             fw->maxLineLen - 2);
00676     strcat(string, "\n");
00677     if (++start >= fw->maxWindowLines) {
00678       start = 0;
00679     }
00680   } while (start != fw->windowEnd);
00681 
00682   return 0;
00683 }
00684 
00685 // the file window structure for the program window and related stuff
00686 
00687 #define PROGRAM_FW_NUM_LINES 10
00688 #define PROGRAM_FW_LEN_LINES 80
00689 
00690 static char *programFwString = NULL;
00691 static FILE_WINDOW programFw;
00692 
00693 // number of axes supported
00694 #define XEMC_NUM_AXES 3
00695 
00696 // string for ini file version num
00697 static char version_string[INIFILE_MAX_LINELEN] = "";
00698 
00699 // interpreter parameter file name, from ini file
00700 static char PARAMETER_FILE[EMC_TASK_FILENAME_LEN] = "";
00701 
00702 // the program path prefix
00703 static char programPrefix[EMC_TASK_FILENAME_LEN] = "";
00704 // the program name currently displayed
00705 static char programFile[EMC_TASK_FILENAME_LEN] = "*";
00706 // the program last loaded by the controller
00707 static char lastProgramFile[EMC_TASK_FILENAME_LEN] = "*";
00708 
00709 // integer version of ini file max scale factor
00710 static int maxFeedOverride = 100;
00711 
00712 #define MDI_LINELEN 80
00713 static char active_g_codes_string[MDI_LINELEN] = "";
00714 static char active_m_codes_string[MDI_LINELEN] = "";
00715 
00716 // how position is to be displayed-- relative or machine
00717 typedef enum {
00718   COORD_RELATIVE = 1,
00719   COORD_MACHINE
00720 } COORD_TYPE;
00721 
00722 static COORD_TYPE coords = COORD_RELATIVE;
00723 
00724 // how position is to be displayed-- actual or commanded
00725 typedef enum {
00726   POS_DISPLAY_ACT = 1,
00727   POS_DISPLAY_CMD
00728 } POS_DISPLAY_TYPE;
00729 
00730 static POS_DISPLAY_TYPE posDisplay = POS_DISPLAY_ACT;
00731 
00732 // marker for the active axis
00733 static int activeAxis = 0;      // default is 0, X
00734 static int oldActiveAxis = -1;  // force an update at startup
00735 
00736 /*
00737   Note: the X key press/release events with multiple keys behave such that
00738   if key a is pressed, then b, then a released, its key-release event
00739   won't go through. So, multi-axis jogging has been disallowed in xemc,
00740   although it's supported in the motion system.
00741 */
00742 // flag that an axis is jogging, so other jogs won't go out
00743 static int axisJogging = -1;
00744 
00745 // current jog speed setting
00746 static int jogSpeed = 1;        // overridden in iniLoad()
00747 static int maxJogSpeed = 1;     // overridden in iniLoad()
00748 static int jogSpeedChange = 0;  // 0 means no change, +/- means inc/dec
00749 
00750 // current jog increment setting, non-positive means continuous
00751 static double jogIncrement = 0.0;
00752 
00753 // the size of the smallest increment to jog, = 1/INPUT_SCALE
00754 static double stepIncrement = 0.0001;
00755 
00756 // polarities for axis jogging, from ini file
00757 static int jogPol[XEMC_NUM_AXES];
00758 
00759 static int oldFeedOverride = -1; // forces an update at startup
00760 static int feedOverride;        // 100% integer copy of EMC status
00761 static int feedOverrideChange = 0; // same as jogSpeedChange
00762 #define FEED_OVERRIDE_DELAY_COUNT 1
00763 // timer delays until dec/inc appears
00764 static int feedOverrideDelayCount = FEED_OVERRIDE_DELAY_COUNT;
00765 
00766 // command sending functions
00767 
00768 static int sendEstop()
00769 {
00770   EMC_TASK_SET_STATE state_msg;
00771 
00772   state_msg.state = EMC_TASK_STATE_ESTOP;
00773   state_msg.serial_number = ++emcCommandSerialNumber;
00774   emcCommandBuffer->write(state_msg);
00775 
00776   return 0;
00777 }
00778 
00779 static int sendEstopReset()
00780 {
00781   EMC_TASK_SET_STATE state_msg;
00782 
00783   state_msg.state = EMC_TASK_STATE_ESTOP_RESET;
00784   state_msg.serial_number = ++emcCommandSerialNumber;
00785   emcCommandBuffer->write(state_msg);
00786 
00787   return 0;
00788 }
00789 
00790 static int sendMachineOn()
00791 {
00792   EMC_TASK_SET_STATE state_msg;
00793 
00794   state_msg.state = EMC_TASK_STATE_ON;
00795   state_msg.serial_number = ++emcCommandSerialNumber;
00796   emcCommandBuffer->write(state_msg);
00797 
00798   return 0;
00799 }
00800 
00801 static int sendMachineOff()
00802 {
00803   EMC_TASK_SET_STATE state_msg;
00804 
00805   state_msg.state = EMC_TASK_STATE_OFF;
00806   state_msg.serial_number = ++emcCommandSerialNumber;
00807   emcCommandBuffer->write(state_msg);
00808 
00809   return 0;
00810 }
00811 
00812 static int sendManual()
00813 {
00814   EMC_TASK_SET_MODE mode_msg;
00815 
00816   mode_msg.mode = EMC_TASK_MODE_MANUAL;
00817   mode_msg.serial_number = ++emcCommandSerialNumber;
00818   emcCommandBuffer->write(mode_msg);
00819 
00820   return 0;
00821 }
00822 
00823 static int sendAuto()
00824 {
00825   EMC_TASK_SET_MODE mode_msg;
00826 
00827   mode_msg.mode = EMC_TASK_MODE_AUTO;
00828   mode_msg.serial_number = ++emcCommandSerialNumber;
00829   emcCommandBuffer->write(mode_msg);
00830 
00831   return 0;
00832 }
00833 
00834 static int sendMdi()
00835 {
00836   EMC_TASK_SET_MODE mode_msg;
00837 
00838   mode_msg.mode = EMC_TASK_MODE_MDI;
00839   mode_msg.serial_number = ++emcCommandSerialNumber;
00840   emcCommandBuffer->write(mode_msg);
00841 
00842   return 0;
00843 }
00844 
00845 static int sendToolSetOffset(int tool, double length, double diameter)
00846 {
00847   EMC_TOOL_SET_OFFSET emc_tool_set_offset_msg;
00848 
00849   emc_tool_set_offset_msg.tool = tool;
00850   emc_tool_set_offset_msg.length = length;
00851   emc_tool_set_offset_msg.diameter = diameter;
00852   emc_tool_set_offset_msg.serial_number = ++emcCommandSerialNumber;
00853   emcCommandBuffer->write(emc_tool_set_offset_msg);
00854 
00855   return 0;
00856 }
00857 
00858 static int sendMistOn()
00859 {
00860   EMC_COOLANT_MIST_ON emc_coolant_mist_on_msg;
00861 
00862   emc_coolant_mist_on_msg.serial_number = ++emcCommandSerialNumber;
00863   emcCommandBuffer->write(emc_coolant_mist_on_msg);
00864 
00865   return 0;
00866 }
00867 
00868 static int sendMistOff()
00869 {
00870   EMC_COOLANT_MIST_OFF emc_coolant_mist_off_msg;
00871 
00872   emc_coolant_mist_off_msg.serial_number = ++emcCommandSerialNumber;
00873   emcCommandBuffer->write(emc_coolant_mist_off_msg);
00874 
00875   return 0;
00876 }
00877 
00878 static int sendFloodOn()
00879 {
00880   EMC_COOLANT_FLOOD_ON emc_coolant_flood_on_msg;
00881 
00882   emc_coolant_flood_on_msg.serial_number = ++emcCommandSerialNumber;
00883   emcCommandBuffer->write(emc_coolant_flood_on_msg);
00884 
00885   return 0;
00886 }
00887 
00888 static int sendFloodOff()
00889 {
00890   EMC_COOLANT_FLOOD_OFF emc_coolant_flood_off_msg;
00891 
00892   emc_coolant_flood_off_msg.serial_number = ++emcCommandSerialNumber;
00893   emcCommandBuffer->write(emc_coolant_flood_off_msg);
00894 
00895   return 0;
00896 }
00897 
00898 static int sendSpindleForward()
00899 {
00900   EMC_SPINDLE_ON emc_spindle_on_msg;
00901 
00902   emc_spindle_on_msg.speed = +1;
00903   emc_spindle_on_msg.serial_number = ++emcCommandSerialNumber;
00904   emcCommandBuffer->write(emc_spindle_on_msg);
00905 
00906   return 0;
00907 }
00908 
00909 static int sendSpindleReverse()
00910 {
00911   EMC_SPINDLE_ON emc_spindle_on_msg;
00912 
00913   emc_spindle_on_msg.speed = -1;
00914   emc_spindle_on_msg.serial_number = ++emcCommandSerialNumber;
00915   emcCommandBuffer->write(emc_spindle_on_msg);
00916 
00917   return 0;
00918 }
00919 
00920 static int sendSpindleOff()
00921 {
00922   EMC_SPINDLE_OFF emc_spindle_off_msg;
00923 
00924   emc_spindle_off_msg.serial_number = ++emcCommandSerialNumber;
00925   emcCommandBuffer->write(emc_spindle_off_msg);
00926 
00927   return 0;
00928 }
00929 
00930 static int sendSpindleIncrease()
00931 {
00932   EMC_SPINDLE_INCREASE emc_spindle_increase_msg;
00933 
00934   emc_spindle_increase_msg.serial_number = ++emcCommandSerialNumber;
00935   emcCommandBuffer->write(emc_spindle_increase_msg);
00936 
00937   return 0;
00938 }
00939 
00940 static int sendSpindleDecrease()
00941 {
00942   EMC_SPINDLE_DECREASE emc_spindle_decrease_msg;
00943 
00944   emc_spindle_decrease_msg.serial_number = ++emcCommandSerialNumber;
00945   emcCommandBuffer->write(emc_spindle_decrease_msg);
00946 
00947   return 0;
00948 }
00949 
00950 static int sendSpindleConstant()
00951 {
00952   EMC_SPINDLE_CONSTANT emc_spindle_constant_msg;
00953 
00954   emc_spindle_constant_msg.serial_number = ++emcCommandSerialNumber;
00955   emcCommandBuffer->write(emc_spindle_constant_msg);
00956 
00957   return 0;
00958 }
00959 
00960 static int sendBrakeEngage()
00961 {
00962   EMC_SPINDLE_BRAKE_ENGAGE emc_spindle_brake_engage_msg;
00963 
00964   emc_spindle_brake_engage_msg.serial_number = ++emcCommandSerialNumber;
00965   emcCommandBuffer->write(emc_spindle_brake_engage_msg);
00966 
00967   return 0;
00968 }
00969 
00970 static int sendBrakeRelease()
00971 {
00972   EMC_SPINDLE_BRAKE_RELEASE emc_spindle_brake_release_msg;
00973 
00974   emc_spindle_brake_release_msg.serial_number = ++emcCommandSerialNumber;
00975   emcCommandBuffer->write(emc_spindle_brake_release_msg);
00976 
00977   return 0;
00978 }
00979 
00980 static int sendAbort()
00981 {
00982   EMC_TASK_ABORT task_abort_msg;
00983 
00984   task_abort_msg.serial_number = ++emcCommandSerialNumber;
00985   emcCommandBuffer->write(task_abort_msg);
00986 
00987   return 0;
00988 }
00989 
00990 static int sendOverrideLimits()
00991 {
00992   EMC_AXIS_OVERRIDE_LIMITS lim_msg;
00993 
00994   lim_msg.axis = 0;             // same number for all
00995   lim_msg.serial_number = ++emcCommandSerialNumber;
00996   emcCommandBuffer->write(lim_msg);
00997 
00998   return 0;
00999 }
01000 
01001 static int sendJogStop(int axis)
01002 {
01003   EMC_AXIS_ABORT emc_axis_abort_msg;
01004 
01005   if (axis < 0 || axis >= XEMC_NUM_AXES) {
01006     return -1;
01007   }
01008 
01009   // don't send request to jog if none are jogging
01010   if (axisJogging == -1) {
01011     return 0;
01012   }
01013 
01014   emc_axis_abort_msg.serial_number = ++emcCommandSerialNumber;
01015   emc_axis_abort_msg.axis = axisJogging;
01016   emcCommandBuffer->write(emc_axis_abort_msg);
01017 
01018   axisJogging = -1;
01019 
01020   return 0;
01021 }
01022 
01023 static int sendJogCont(int axis, double speed)
01024 {
01025   EMC_AXIS_JOG emc_axis_jog_msg;
01026 
01027   if (axis < 0 || axis >= XEMC_NUM_AXES) {
01028     return -1;
01029   }
01030 
01031   if (axisJogging != -1) {
01032     // ignore request to jog, if an axis is already jogging
01033     return 0;
01034   }
01035 
01036   if (0 == jogPol[axis]) {
01037     speed = -speed;
01038   }
01039 
01040   emc_axis_jog_msg.serial_number = ++emcCommandSerialNumber;
01041   emc_axis_jog_msg.axis = axis;
01042   emc_axis_jog_msg.vel = speed / 60.0;
01043   emcCommandBuffer->write(emc_axis_jog_msg);
01044 
01045   axisJogging = axis;
01046 
01047   return 0;
01048 }
01049 
01050 static int sendJogIncr(int axis, double speed, double incr)
01051 {
01052   EMC_AXIS_INCR_JOG emc_axis_incr_jog_msg;
01053 
01054   if (axis < 0 || axis >= XEMC_NUM_AXES) {
01055     return -1;
01056   }
01057 
01058   if (axisJogging != -1) {
01059     // ignore request to jog, if an axis is already jogging
01060     return 0;
01061   }
01062 
01063   if (0 == jogPol[axis]) {
01064     speed = -speed;
01065   }
01066 
01067   emc_axis_incr_jog_msg.serial_number = ++emcCommandSerialNumber;
01068   emc_axis_incr_jog_msg.axis = axis;
01069   emc_axis_incr_jog_msg.vel = speed / 60.0;
01070   emc_axis_incr_jog_msg.incr = jogIncrement;
01071   emcCommandBuffer->write(emc_axis_incr_jog_msg);
01072 
01073   // don't flag incremental jogs as jogging an axis-- we can
01074   // allow multiple incremental jogs since we don't need a key release
01075 
01076   return 0;
01077 }
01078 
01079 static int sendHome(int axis)
01080 {
01081   EMC_AXIS_HOME emc_axis_home_msg;
01082 
01083   emc_axis_home_msg.serial_number = ++emcCommandSerialNumber;
01084   emc_axis_home_msg.axis = axis;
01085   emcCommandBuffer->write(emc_axis_home_msg);
01086 
01087   return 0;
01088 }
01089 
01090 static int sendFeedOverride(double override)
01091 {
01092   EMC_TRAJ_SET_SCALE emc_traj_set_scale_msg;
01093 
01094   if (override < 0.0) {
01095     override = 0.0;
01096   }
01097   else if (override > (double) maxFeedOverride / 100.0) {
01098     override = (double) maxFeedOverride / 100.0;
01099   }
01100   emc_traj_set_scale_msg.serial_number = ++emcCommandSerialNumber;
01101   emc_traj_set_scale_msg.scale = override;
01102   emcCommandBuffer->write(emc_traj_set_scale_msg);
01103 
01104   return 0;
01105 }
01106 
01107 static int sendTaskPlanInit()
01108 {
01109   EMC_TASK_PLAN_INIT task_plan_init_msg;
01110 
01111   task_plan_init_msg.serial_number = ++emcCommandSerialNumber;
01112   emcCommandBuffer->write(task_plan_init_msg);
01113 
01114   return 0;
01115 }
01116 
01117 static int sendProgramOpen(char *program)
01118 {
01119   EMC_TASK_PLAN_OPEN emc_task_plan_open_msg;
01120 
01121   // first put in auto mode if it's not
01122   if (0 == emcStatus->task.mode != EMC_TASK_MODE_AUTO) {
01123     // send a request to go to auto mode
01124     sendAuto();
01125   }
01126 
01127   // wait for any previous one to go out
01128   if (0 != emcCommandWaitDone(emcCommandSerialNumber)) {
01129     printError("error executing command\n");
01130     return -1;
01131   }
01132 
01133   emc_task_plan_open_msg.serial_number = ++emcCommandSerialNumber;
01134   strcpy(emc_task_plan_open_msg.file, program);
01135   emcCommandBuffer->write(emc_task_plan_open_msg);
01136 
01137   // now clear out our stored version of the program, in case
01138   // the file contents have changed but the name is the same
01139   programFile[0] = 0;
01140 
01141   return 0;
01142 }
01143 
01144 // line in program to run from; set it in GUI when user clicks on a line,
01145 // and pass it in calls to sendProgramRun(). sendProgramRun() won't use
01146 // this directly.
01147 static int programStartLine = 0;
01148 static int programStartLineLast = 0;
01149 
01150 static int sendProgramRun(int line)
01151 {
01152   EMC_TASK_PLAN_RUN emc_task_plan_run_msg;
01153 
01154   // first reopen program if it's not open
01155   if (0 == emcStatus->task.file[0]) {
01156     // send a request to open last one
01157     sendProgramOpen(lastProgramFile);
01158 
01159     // wait for command to go out
01160     if (0 != emcCommandWaitDone(emcCommandSerialNumber)) {
01161       printError("error executing command\n");
01162       return -1;
01163     }
01164   }
01165 
01166   emc_task_plan_run_msg.serial_number = ++emcCommandSerialNumber;
01167   emc_task_plan_run_msg.line = line;
01168   emcCommandBuffer->write(emc_task_plan_run_msg);
01169 
01170   programStartLineLast = programStartLine;
01171   programStartLine = 0;
01172 
01173   return 0;
01174 }
01175 
01176 static int sendProgramPause()
01177 {
01178   EMC_TASK_PLAN_PAUSE emc_task_plan_pause_msg;
01179 
01180   emc_task_plan_pause_msg.serial_number = ++emcCommandSerialNumber;
01181   emcCommandBuffer->write(emc_task_plan_pause_msg);
01182 
01183   return 0;
01184 }
01185 
01186 static int sendProgramResume()
01187 {
01188   EMC_TASK_PLAN_RESUME emc_task_plan_resume_msg;
01189 
01190   emc_task_plan_resume_msg.serial_number = ++emcCommandSerialNumber;
01191   emcCommandBuffer->write(emc_task_plan_resume_msg);
01192 
01193   return 0;
01194 }
01195 
01196 static int sendProgramStep()
01197 {
01198   EMC_TASK_PLAN_STEP emc_task_plan_step_msg;
01199 
01200   // first reopen program if it's not open
01201   if (0 == emcStatus->task.file[0]) {
01202     // send a request to open last one
01203     sendProgramOpen(lastProgramFile);
01204 
01205     // wait for command to go out
01206     if (0 != emcCommandWaitDone(emcCommandSerialNumber)) {
01207       printError("error executing command\n");
01208       return -1;
01209     }
01210   }
01211 
01212   emc_task_plan_step_msg.serial_number = ++emcCommandSerialNumber;
01213   emcCommandBuffer->write(emc_task_plan_step_msg);
01214 
01215   programStartLineLast = programStartLine;
01216   programStartLine = 0;
01217 
01218   return 0;
01219 }
01220 
01221 static int sendMdiCmd(char *mdi)
01222 {
01223   EMC_TASK_PLAN_EXECUTE emc_task_plan_execute_msg;
01224 
01225   strcpy(emc_task_plan_execute_msg.command, mdi);
01226   emc_task_plan_execute_msg.serial_number = ++emcCommandSerialNumber;
01227   emcCommandBuffer->write(emc_task_plan_execute_msg);
01228 
01229   return 0;
01230 }
01231 
01232 static int sendLoadToolTable(const char *file)
01233 {
01234   EMC_TOOL_LOAD_TOOL_TABLE emc_tool_load_tool_table_msg;
01235 
01236   strcpy(emc_tool_load_tool_table_msg.file, file);
01237   emc_tool_load_tool_table_msg.serial_number = ++emcCommandSerialNumber;
01238   emcCommandBuffer->write(emc_tool_load_tool_table_msg);
01239 
01240   return 0;
01241 }
01242 
01243 static int sendAxisCycleTime(int axis, double cycleTime)
01244 {
01245   EMC_AXIS_SET_CYCLE_TIME emc_axis_set_cycle_time_msg;
01246 
01247   emc_axis_set_cycle_time_msg.axis = axis;
01248   emc_axis_set_cycle_time_msg.cycleTime = cycleTime;
01249   emc_axis_set_cycle_time_msg.serial_number = ++emcCommandSerialNumber;
01250   emcCommandBuffer->write(emc_axis_set_cycle_time_msg);
01251 
01252   return 0;
01253 }
01254 
01255 static int sendAxisSetGains(int axis, double p, double i, double d, double ff0, double ff1, double ff2, double backlash, double bias, double maxError)
01256 {
01257   EMC_AXIS_SET_GAINS emc_axis_set_gains_msg;
01258 
01259   emc_axis_set_gains_msg.axis = axis;
01260   emc_axis_set_gains_msg.p = p;
01261   emc_axis_set_gains_msg.i = i;
01262   emc_axis_set_gains_msg.d = d;
01263   emc_axis_set_gains_msg.ff0 = ff0;
01264   emc_axis_set_gains_msg.ff1 = ff1;
01265   emc_axis_set_gains_msg.ff2 = ff2;
01266   emc_axis_set_gains_msg.backlash = backlash;
01267   emc_axis_set_gains_msg.bias = bias;
01268   emc_axis_set_gains_msg.maxError = maxError;
01269   emc_axis_set_gains_msg.serial_number = ++emcCommandSerialNumber;
01270   emcCommandBuffer->write(emc_axis_set_gains_msg);
01271 
01272   return 0;
01273 }
01274 
01275 static int sendAxisSetOutputScale(int axis, double scale, double offset)
01276 {
01277   EMC_AXIS_SET_OUTPUT_SCALE emc_axis_set_output_scale_msg;
01278 
01279   emc_axis_set_output_scale_msg.axis = axis;
01280   emc_axis_set_output_scale_msg.scale = scale;
01281   emc_axis_set_output_scale_msg.offset = offset;
01282   emc_axis_set_output_scale_msg.serial_number = ++emcCommandSerialNumber;
01283   emcCommandBuffer->write(emc_axis_set_output_scale_msg);
01284 
01285   return 0;
01286 }
01287 
01288 static int sendAxisSetFerror(int axis, double ferror)
01289 {
01290   EMC_AXIS_SET_FERROR emc_axis_set_ferror_msg;
01291 
01292   emc_axis_set_ferror_msg.axis = axis;
01293   emc_axis_set_ferror_msg.ferror = ferror;
01294   emc_axis_set_ferror_msg.serial_number = ++emcCommandSerialNumber;
01295   emcCommandBuffer->write(emc_axis_set_ferror_msg);
01296 
01297   return 0;
01298 }
01299 
01300 // saved log file params
01301 static char saveLogFile[EMC_LOG_FILENAME_LEN] = "/tmp/emc.plot.sh";
01302 static int saveLogType = EMC_LOG_TYPE_AXES_FERROR;
01303 static int saveLogSize = 1000;
01304 static int saveLogSkip = 0;
01305 
01306 // paths to awk and xgraph, using to plot logs
01307 // fill these in for your system, if these are not in user's path
01308 #define AWK_PATH "awk"
01309 #define XGRAPH_PATH "xgraph"
01310 #define SYSTEM_STRING_LEN 1024
01311 
01312 static int plotLog(const char * logfile, int logtype)
01313 {
01314   char string[SYSTEM_STRING_LEN];
01315   int retval;
01316 
01317   if (logfile == 0)
01318     {
01319       return -1;
01320     }
01321 
01322   switch (logtype)
01323     {
01324     case EMC_LOG_TYPE_AXIS_POS:
01325     case EMC_LOG_TYPE_AXIS_VEL:
01326       sprintf(string, "( %s '{print $1 \" \" $2}' < %s ; echo \"\" ; %s '{print $1 \" \" $3}' < %s ) 2> /dev/null | %s -m 1> /dev/null 2> /dev/null", AWK_PATH, logfile, AWK_PATH, logfile, XGRAPH_PATH);
01327       break;
01328 
01329     case EMC_LOG_TYPE_AXES_INPOS:
01330     case EMC_LOG_TYPE_AXES_OUTPOS:
01331       sprintf(string, "%s '{print $2 \" \" $3}' < %s 2> /dev/null | %s -m 1> /dev/null 2> /dev/null", AWK_PATH, logfile, XGRAPH_PATH);
01332       break;
01333 
01334     case EMC_LOG_TYPE_AXES_FERROR:
01335     case EMC_LOG_TYPE_TRAJ_POS:
01336       /* we want to compose:
01337          ( awk '{print $1 " " $2}' < emc.log ; echo "" ; awk '{print $1 " " $3}' < emc.log ; echo "" ; awk '{print $1 " " $4}' < emc.log ) 2> /dev/null | xgraph -m 1> /dev/null 2> /dev/null"
01338        */
01339       sprintf(string, "( %s '{print $1 \" \" $2}' < %s ; echo \"\" ; %s '{print $1 \" \" $3}' < %s ; echo \"\" ; %s '{print $1 \" \" $4}' < %s ) 2> /dev/null | %s -m 1> /dev/null 2> /dev/null", AWK_PATH, logfile, AWK_PATH, logfile, AWK_PATH, logfile, XGRAPH_PATH);
01340       break;
01341 
01342     case EMC_LOG_TYPE_TRAJ_VEL:
01343     case EMC_LOG_TYPE_TRAJ_ACC:
01344       /* we want to compose:
01345          ( awk '{print $1 " " $2}' < emc.log ; echo "" ; awk '{print $1 " " $3}' < emc.log ; echo "" ; awk '{print $1 " " $4}' < emc.log ; echo "" ; awk '{print $1 " " $5}' < emc.log) 2> /dev/null | xgraph -m 1> /dev/null 2> /dev/null"
01346        */
01347       sprintf(string, "( %s '{print $1 \" \" $2}' < %s ; echo \"\" ; %s '{print $1 \" \" $3}' < %s ; echo \"\" ; %s '{print $1 \" \" $4}' < %s ; echo \"\" ; %s '{print $1 \" \" $5}' < %s) 2> /dev/null | %s -m 1> /dev/null 2> /dev/null", AWK_PATH, logfile, AWK_PATH, logfile, AWK_PATH, logfile, AWK_PATH, logfile, XGRAPH_PATH);
01348       break;
01349 
01350     default:
01351       return -1;
01352       break;
01353     }
01354 
01355   retval = system(string);
01356 
01357   return retval;
01358 }
01359 
01360 static int sendLogStart()
01361 {
01362   EMC_LOG_OPEN emc_log_open_msg;
01363   EMC_LOG_START emc_log_start_msg;
01364 
01365   // check for open log file first; if not, and old one saved, open it
01366   if (! emcStatus->logOpen) {
01367     if (saveLogFile[0] != 0) {
01368       strcpy(emc_log_open_msg.file, saveLogFile);
01369       emc_log_open_msg.type = saveLogType;
01370       emc_log_open_msg.size = saveLogSize;
01371       emc_log_open_msg.skip = saveLogSkip;
01372       emc_log_open_msg.which = activeAxis;
01373       emc_log_open_msg.serial_number = ++emcCommandSerialNumber;
01374       emcCommandBuffer->write(emc_log_open_msg);
01375     }
01376     else {
01377       // log is not opened, and no name saved, so ignore
01378       popupError("No log file selected");
01379       return -1;
01380     }
01381   }
01382 
01383   // wait for previous one to go out
01384   emcCommandWaitReceived(emcCommandSerialNumber);
01385 
01386   // now send log start message
01387   emc_log_start_msg.serial_number = ++emcCommandSerialNumber;
01388   emcCommandBuffer->write(emc_log_start_msg);
01389 
01390   return 0;
01391 }
01392 
01393 static int sendLogStop()
01394 {
01395   EMC_LOG_STOP emc_log_stop_msg;
01396 
01397   emc_log_stop_msg.serial_number = ++emcCommandSerialNumber;
01398   emcCommandBuffer->write(emc_log_stop_msg);
01399 
01400   return 0;
01401 };
01402 
01403 static int sendLogClose()
01404 {
01405   EMC_LOG_CLOSE emc_log_close_msg;
01406 
01407   emc_log_close_msg.serial_number = ++emcCommandSerialNumber;
01408   emcCommandBuffer->write(emc_log_close_msg);
01409 
01410   return 0;
01411 }
01412 
01413 // X stuff starts here
01414 
01415 // flag signifying that window needs to be redrawn
01416 static int redraw = 1;
01417 
01418 // global context and widgets, accessed during periodic timer
01419 static XtAppContext app_context;
01420 static Atom killAtom;
01421 static Widget topLevel;
01422 static Widget topForm;
01423 static Widget barMenuForm;
01424 static Widget abortCommand;
01425 static Widget fileMenu;
01426 static Widget viewMenu;
01427 static Widget settingsMenu;
01428 static Widget helpMenu;
01429 static Widget limCommand;
01430 static Widget commandMenuForm;
01431 static Widget stateMenu;
01432 static Widget modeMenu;
01433 static Widget mistMenu;
01434 static Widget floodMenu;
01435 static Widget spindleMenu;
01436 static Widget spindleIncLabel, spindleDecLabel;
01437 static Widget brakeMenu;
01438 static Widget toolTableShell = NULL, toolTableForm, toolTableLabel, toolTableText, toolTableDone, toolTableCancel;
01439 static Widget varFileShell = NULL, varFileForm, varFileLabel, varFileText, varFileDone, varFileCancel;
01440 static Widget toolNumberForm, toolNumberFormTitle, toolNumberFormName;
01441 static Widget toolOffsetForm, toolOffsetFormTitle, toolOffsetFormName;
01442 static Widget toolSetOffsetShell, toolSetOffsetForm, toolSetOffsetToolLabel, toolSetOffsetTool, toolSetOffsetLengthLabel, toolSetOffsetLength, toolSetOffsetDiameterLabel, toolSetOffsetDiameter, toolSetOffsetDone, toolSetOffsetCancel;
01443 static Widget positionTypeForm, positionTypeFormTitle, positionTypeFormName;
01444 static Widget workOffsetForm, workOffsetFormTitle, workOffsetFormName;
01445 static Widget posLabel[XEMC_NUM_AXES];
01446 static Widget posOffsetShell, posOffsetDialog;
01447 static Widget jogSpeedForm, jogSpeedTitleLabel,
01448   jogSpeedLabel, jogSpeedIncLabel, jogSpeedDecLabel;
01449 static Widget jogSpeedShell, jogSpeedDialog;
01450 static Widget jogIncrementForm, jogIncrementTitleLabel, jogIncrementMenu;
01451 static Widget jogForm, jogTitleLabel,
01452   jogMinusLabel, homeCommand, jogPlusLabel;
01453 static Widget feedOverrideForm, feedOverrideTitleLabel,
01454   feedOverrideLabel, feedOverrideIncLabel, feedOverrideDecLabel;
01455 static Widget feedOverrideShell, feedOverrideDialog;
01456 static Widget loggingStatusForm, loggingStatusTitleLabel,
01457   loggingStatusOpenLabel, loggingStatusStartedLabel, loggingStatusPointsLabel;
01458 static Widget mdiForm, mdiFormTitle, mdiFormText;
01459 static Widget mdiCodesLabel;
01460 static Widget programForm, programFormTitle, programFormName, programFormStateTitle, programFormState;
01461 static Widget programOpenCommand, programRunCommand, programPauseCommand, programResumeCommand, programStepCommand, programVerifyCommand;
01462 static Widget programText;
01463 static Widget fileOpenShell, fileOpenDialog, fileOpenDone, fileOpenCancel;
01464 static char EDITOR_FILE[256] = ""; // FIXME-- hardcoded
01465 static Widget fileEditShell, fileEditDialog, fileEditDone, fileEditCancel;
01466 static Widget fileEditorShell = NULL, fileEditorForm, fileEditorLabel, fileEditorText, fileEditorDone, fileEditorCancel, fileEditorMark;
01467 static Widget fileQuitShell, fileQuitDialog, fileQuitDone, fileQuitCancel;
01468 static Widget helpXemcShell = NULL, helpXemcForm, helpXemcLabel, helpXemcText, helpXemcDone;
01469 static Widget helpAboutShell, helpAboutDialog, helpAboutDone;
01470 static Widget errorShell = 0, errorDialog = 0, errorDone = 0;
01471 
01472 // Pixel values inited from strings, for hard-coded colors
01473 static Pixel pixelWhite;
01474 static Pixel pixelBlack;
01475 static Pixel pixelRed;
01476 static Pixel pixelYellow;
01477 static Pixel pixelGreen;
01478 
01479 // saved background and border colors for position labels,
01480 // cleared and restored when highlighting
01481 static Pixel posLabelBackground[XEMC_NUM_AXES];
01482 static Pixel posLabelBorderColor[XEMC_NUM_AXES];
01483 
01484 static int getColor(Widget w, Pixel *pixel, int foreground)
01485 {
01486   Arg args;
01487 
01488   if (foreground)
01489     XtSetArg(args, XtNforeground, pixel);
01490   else
01491     XtSetArg(args, XtNbackground, pixel);
01492   XtGetValues(w, &args, 1);
01493 
01494   return 0;
01495 }
01496 
01497 static int setColor(Widget w, Pixel pixel, int foreground)
01498 {
01499   if (foreground)
01500     XtVaSetValues(w, XtNforeground, pixel, NULL);
01501   else
01502     XtVaSetValues(w, XtNbackground, pixel, NULL);
01503 
01504   return 0;
01505 }
01506 
01507 static int stringToPixel(Widget w, String string, Pixel *pixel)
01508 {
01509   XrmValue from, to;
01510 
01511   from.addr = string;
01512   from.size = strlen(string) + 1;
01513   to.addr = (char *) pixel;
01514   to.size = sizeof(Pixel);
01515 
01516   if (False == XtConvertAndStore(w, XtRString, &from, XtRPixel, &to))
01517     return -1;
01518   return 0;
01519 }
01520 
01521 static int getBorderColor(Widget w, Pixel *pixel)
01522 {
01523   Arg args;
01524 
01525   XtSetArg(args, XtNborderColor, pixel);
01526   XtGetValues(w, &args, 1);
01527 
01528   return 0;
01529 }
01530 
01531 static int setBorderColor(Widget w, Pixel pixel)
01532 {
01533   XtVaSetValues(w, XtNborderColor, pixel, NULL);
01534 
01535   return 0;
01536 }
01537 
01538 static int setLabel(Widget w, char *label)
01539 {
01540   Arg args;
01541   int width;
01542 
01543   XtSetArg(args, XtNwidth, &width);
01544   XtGetValues(w, &args, 1);
01545   XtVaSetValues(w, XtNlabel, label, NULL);
01546   XtVaSetValues(w, XtNwidth, width, NULL);
01547   return(0);
01548 }
01549 
01550 static int setProgramText(char *text)
01551 {
01552   XtVaSetValues(programText, XtNstring, text, NULL);
01553   return(0);
01554 }
01555 
01556 // index is diff between top and line to highlight, 0..max
01557 static int highlightProgramText(char *text, int index)
01558 {
01559   int start, end;
01560 
01561   // position 'start' to first char on index line
01562   for (start = 0; ; start++) {
01563     if (index <= 0) {
01564       break;
01565     }
01566     if (text[start] == 0 || text[start] == '\n') {
01567       index--;
01568     }
01569   }
01570 
01571   // position 'end' to last char on index line
01572   for (end = start; ; end++) {
01573     if (text[end] == 0 || text[end] == '\n') {
01574       break;
01575     }
01576   }
01577 
01578   XawTextSetSelection(programText, start, end);
01579   return(0);
01580 }
01581 
01582 // dialogPopup() is an XtNcallback that expects a
01583 // transientShellWidget class as the client_data.
01584 // Widget w is not used, but is required if this is to be used
01585 // as a callback function. If you call it directly you can put NULL
01586 // in for w and call_data.
01587 static void dialogPopup(Widget w, XtPointer client_data, XtPointer call_data)
01588 {
01589   Position x, y;
01590   Dimension width, height;
01591 
01592   // get the coordinates of the middle of topLevel widget
01593   XtVaGetValues(topForm,
01594                 XtNwidth, &width,
01595                 XtNheight, &height,
01596                 NULL);
01597 
01598   // translate coordinates in application top-level window
01599   // into coordinates from root window origin
01600   XtTranslateCoords(topForm,
01601                     (Position) 100,
01602                     (Position) 100,
01603                     &x, &y);
01604 
01605   // move popup shell to this position (it's not visible yet)
01606   XtVaSetValues((Widget) client_data,
01607                 XtNx, x,
01608                 XtNy, y,
01609                 NULL);
01610 
01611   XtPopup((Widget) client_data, XtGrabNone);
01612 }
01613 
01614 // command callbacks
01615 
01616 static void limCB(Widget w, XtPointer client_data, XtPointer call_data)
01617 {
01618   sendOverrideLimits();
01619 }
01620 
01621 static void abortCB(Widget w, XtPointer client_data, XtPointer call_data)
01622 {
01623   sendAbort();
01624 }
01625 
01626 static void homeCB(Widget w, XtPointer client_data, XtPointer call_data)
01627 {
01628   sendHome(activeAxis);
01629 }
01630 
01631 // flag to prevent errors from popping up multiple times
01632 static int errorIsPopped = 0;
01633 
01634 static void errorReturnAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
01635 {
01636   XtPopdown(errorShell);
01637   errorIsPopped = 0;
01638   destroyErrorShell();
01639 }
01640 
01641 static void errorDoneCB(Widget w, XtPointer client_data, XtPointer call_data)
01642 {
01643   XtPopdown(errorShell);
01644   errorIsPopped = 0;
01645   destroyErrorShell();
01646 }
01647 
01648 // createErrorShell() creates the error dialog widget afresh,
01649 // so that it gets sized correctly for each different error message.
01650 // Otherwise, the widget is sized for the first message, and then
01651 // that size is used for all subsequent messages.
01652 
01653 static int createErrorShell()
01654 {
01655   if (NULL != errorShell) {
01656     return 0;
01657   }
01658 
01659   errorShell =
01660     XtVaCreatePopupShell("errorShell",
01661                          transientShellWidgetClass,
01662                          topLevel,
01663                          NULL);
01664 
01665   errorDialog =
01666     XtVaCreateManagedWidget("errorDialog",
01667                             dialogWidgetClass,
01668                             errorShell,
01669                             NULL);
01670 
01671   errorDone =
01672     XtVaCreateManagedWidget("errorDone",
01673                             commandWidgetClass,
01674                             errorDialog,
01675                             NULL);
01676 
01677   XtAddCallback(errorDone, XtNcallback, errorDoneCB, errorShell);
01678 
01679   return 0;
01680 }
01681 
01682 static int destroyErrorShell()
01683 {
01684   if (0 != errorDone)
01685     {
01686       XtDestroyWidget(errorDone);
01687       errorDone = 0;
01688     }
01689 
01690   if (0 != errorDialog)
01691     {
01692       XtDestroyWidget(errorDialog);
01693       errorDialog = 0;
01694     }
01695 
01696   if (0 != errorShell)
01697     {
01698       XtDestroyWidget(errorShell);
01699       errorShell = 0;
01700     }
01701 
01702   return 0;
01703 }
01704 
01705 static void popupError(const char *fmt, ...)
01706 {
01707   va_list ap;
01708   char string[256];             // FIXME-- hardcoded value
01709 
01710   va_start(ap, fmt);
01711   vsprintf(string, fmt, ap);
01712   va_end(ap);
01713 
01714   if (errorIsPopped) {
01715     // we're popped up already, so just print the error to stdout
01716     fprintf(stderr, "error: %s\n", string);
01717     return;
01718   }
01719 
01720   destroyErrorShell();
01721   createErrorShell();
01722 
01723   XtVaSetValues(errorDialog, XtNlabel, string, NULL);
01724   errorIsPopped = 1;
01725   dialogPopup(NULL, errorShell, NULL);
01726   // trap window kill
01727   XSetWMProtocols(XtDisplay(topLevel), XtWindow(errorShell), &killAtom, 1);
01728 }
01729 
01730 // file edit forward decls
01731 static void fileEditorDoneCB(Widget w, XtPointer client_data, XtPointer call_data);
01732 static void fileEditorCancelCB(Widget w, XtPointer client_data, XtPointer call_data);
01733 static void fileEditorMarkCB(Widget w, XtPointer client_data, XtPointer call_data);
01734 static int createFileEditorShell(int writeable);
01735 static int destroyFileEditorShell();
01736 static void doFileEditorDone(int get);
01737 
01738 static void fileEditorDoneCB(Widget w, XtPointer client_data, XtPointer call_data)
01739 {
01740   doFileEditorDone(1);
01741 }
01742 
01743 static void fileEditorCancelCB(Widget w, XtPointer client_data, XtPointer call_data)
01744 {
01745   doFileEditorDone(0);
01746 }
01747 
01748 static void fileEditorMarkCB(Widget w, XtPointer client_data, XtPointer call_data)
01749 {
01750   FILE *fp;
01751   XawTextPosition pos;
01752   int charcount = 0;
01753   int line = 1;
01754   char buffer[256];             // FIXME-- hardcoded
01755 
01756   if (NULL == (fp = fopen(EDITOR_FILE, "r"))) {
01757     return;
01758   }
01759 
01760   programStartLine = 0;
01761   pos = XawTextGetInsertionPoint(fileEditorText);
01762 
01763   while (! feof(fp)) {
01764     if (NULL == fgets(buffer, 256, fp)) {
01765       // hmmm... never found line
01766       popupError("Can't mark line-- character position\n%d outside range of file", pos);
01767       break;
01768     }
01769 
01770     charcount += strlen(buffer);
01771     if (charcount > pos) {
01772       // found it
01773       sendProgramOpen(EDITOR_FILE);
01774       popupError("Marking program to start here:\n%s", buffer);
01775       programStartLine = line;
01776       break;
01777     }
01778 
01779     line++;
01780   }
01781 
01782   fclose(fp);
01783 }
01784 
01785 static int createFileEditorShell(int writeable)
01786 {
01787   char label[256];              // FIXME-- hardcoded
01788 
01789   if (NULL != fileEditorShell) {
01790     return 0;
01791   }
01792 
01793   strcpy(label, EDITOR_FILE);
01794   if (! writeable) {
01795     strcat(label, " (read only)");
01796   }
01797 
01798   fileEditorShell =
01799     XtVaCreatePopupShell("fileEditorShell",
01800                          topLevelShellWidgetClass,
01801                          topLevel,
01802                          XtNallowShellResize, True,
01803                          NULL);
01804 
01805   fileEditorForm =
01806     XtVaCreateManagedWidget("fileEditorForm",
01807                             formWidgetClass,
01808                             fileEditorShell,
01809                             NULL);
01810 
01811   fileEditorLabel =
01812     XtVaCreateManagedWidget("fileEditorLabel",
01813                             labelWidgetClass,
01814                             fileEditorForm,
01815                             XtNlabel, label,
01816                             NULL);
01817 
01818   fileEditorText =
01819     XtVaCreateManagedWidget("fileEditorText",
01820                             asciiTextWidgetClass,
01821                             fileEditorForm,
01822                             XtNfromVert, fileEditorLabel,
01823                             XtNeditType, (writeable ? XawtextEdit :
01824                                           XawtextRead),
01825                             XtNtype, XawAsciiFile,
01826                             XtNstring, EDITOR_FILE,
01827                             XtNscrollVertical, XawtextScrollWhenNeeded,
01828                             NULL);
01829 
01830   fileEditorDone =
01831     XtVaCreateManagedWidget("fileEditorDone",
01832                             commandWidgetClass,
01833                             fileEditorForm,
01834                             XtNfromVert, fileEditorText,
01835                             NULL);
01836 
01837   XtAddCallback(fileEditorDone, XtNcallback, fileEditorDoneCB, fileEditorShell);
01838 
01839   if (writeable) {
01840     XtSetSensitive(fileEditorDone, True);
01841   }
01842   else {
01843     XtSetSensitive(fileEditorDone, False);
01844   }
01845 
01846   fileEditorCancel =
01847     XtVaCreateManagedWidget("fileEditorCancel",
01848                             commandWidgetClass,
01849                             fileEditorForm,
01850                             XtNfromVert, fileEditorText,
01851                             XtNfromHoriz, fileEditorDone,
01852                             NULL);
01853 
01854   XtAddCallback(fileEditorCancel, XtNcallback, fileEditorCancelCB, fileEditorShell);
01855 
01856   fileEditorMark =
01857     XtVaCreateManagedWidget("fileEditorMark",
01858                             commandWidgetClass,
01859                             fileEditorForm,
01860                             XtNfromVert, fileEditorText,
01861                             XtNfromHoriz, fileEditorCancel,
01862                             NULL);
01863 
01864   XtAddCallback(fileEditorMark, XtNcallback, fileEditorMarkCB, fileEditorShell);
01865 
01866   return 0;
01867 }
01868 
01869 static int destroyFileEditorShell()
01870 {
01871   if (fileEditorMark != NULL) {
01872     XtDestroyWidget(fileEditorMark);
01873     fileEditorMark = NULL;
01874   }
01875 
01876   if (fileEditorCancel != NULL) {
01877     XtDestroyWidget(fileEditorCancel);
01878     fileEditorCancel = NULL;
01879   }
01880 
01881   if (fileEditorDone != NULL) {
01882     XtDestroyWidget(fileEditorDone);
01883     fileEditorDone = NULL;
01884   }
01885 
01886   if (fileEditorText != NULL) {
01887     XtDestroyWidget(fileEditorText);
01888     fileEditorText = NULL;
01889   }
01890 
01891   if (fileEditorLabel != NULL) {
01892     XtDestroyWidget(fileEditorLabel);
01893     fileEditorLabel = NULL;
01894   }
01895 
01896   if (fileEditorForm != NULL) {
01897     XtDestroyWidget(fileEditorForm);
01898     fileEditorForm = NULL;
01899   }
01900 
01901   if (fileEditorShell != NULL) {
01902     XtDestroyWidget(fileEditorShell);
01903     fileEditorShell = NULL;
01904   }
01905 
01906   return 0;
01907 }
01908 
01909 static void doFileEditorDone(int get)
01910 {
01911   Widget source;
01912   String string;
01913 
01914   if (get) {
01915     XtVaGetValues(fileEditorText,
01916                   XtNtextSource, &source,
01917                   XtNstring, &string,
01918                   NULL);
01919 
01920     XawAsciiSave(source);
01921   }
01922 
01923   XtPopdown(fileEditorShell);
01924 
01925   destroyFileEditorShell();
01926 }
01927 
01928 // tool table forward decls
01929 static void toolTableDoneCB(Widget w, XtPointer client_data, XtPointer call_data);
01930 static void toolTableCancelCB(Widget w, XtPointer client_data, XtPointer call_data);
01931 static int createToolTableShell();
01932 static int destroyToolTableShell();
01933 static void doToolTableDone(int get);
01934 
01935 static void toolTableDoneCB(Widget w, XtPointer client_data, XtPointer call_data)
01936 {
01937   doToolTableDone(1);
01938 }
01939 
01940 static void toolTableCancelCB(Widget w, XtPointer client_data, XtPointer call_data)
01941 {
01942   doToolTableDone(0);
01943 }
01944 
01945 static int createToolTableShell()
01946 {
01947   if (NULL != toolTableShell) {
01948     return 0;
01949   }
01950 
01951   toolTableShell =
01952     XtVaCreatePopupShell("toolTableShell",
01953                          topLevelShellWidgetClass,
01954                          topLevel,
01955                          XtNallowShellResize, True,
01956                          NULL);
01957 
01958   toolTableForm =
01959     XtVaCreateManagedWidget("toolTableForm",
01960                             formWidgetClass,
01961                             toolTableShell,
01962                             NULL);
01963 
01964   toolTableLabel =
01965     XtVaCreateManagedWidget("toolTableLabel",
01966                             labelWidgetClass,
01967                             toolTableForm,
01968                             XtNlabel, TOOL_TABLE_FILE,
01969                             NULL);
01970 
01971   toolTableText =
01972     XtVaCreateManagedWidget("toolTableText",
01973                             asciiTextWidgetClass,
01974                             toolTableForm,
01975                             XtNfromVert, toolTableLabel,
01976                             XtNeditType, XawtextEdit,
01977                             XtNtype, XawAsciiFile,
01978                             XtNstring, TOOL_TABLE_FILE,
01979                             XtNscrollVertical, XawtextScrollWhenNeeded,
01980                             NULL);
01981 
01982   toolTableDone =
01983     XtVaCreateManagedWidget("toolTableDone",
01984                             commandWidgetClass,
01985                             toolTableForm,
01986                             XtNfromVert, toolTableText,
01987                             NULL);
01988 
01989   XtAddCallback(toolTableDone, XtNcallback, toolTableDoneCB, toolTableShell);
01990 
01991   toolTableCancel =
01992     XtVaCreateManagedWidget("toolTableCancel",
01993                             commandWidgetClass,
01994                             toolTableForm,
01995                             XtNfromVert, toolTableText,
01996                             XtNfromHoriz, toolTableDone,
01997                             NULL);
01998 
01999   XtAddCallback(toolTableCancel, XtNcallback, toolTableCancelCB, toolTableShell);
02000 
02001   return 0;
02002 }
02003 
02004 static int destroyToolTableShell()
02005 {
02006   if (toolTableCancel != NULL) {
02007     XtDestroyWidget(toolTableCancel);
02008     toolTableCancel = NULL;
02009   }
02010 
02011   if (toolTableDone != NULL) {
02012     XtDestroyWidget(toolTableDone);
02013     toolTableDone = NULL;
02014   }
02015 
02016   if (toolTableText != NULL) {
02017     XtDestroyWidget(toolTableText);
02018     toolTableText = NULL;
02019   }
02020 
02021   if (toolTableLabel != NULL) {
02022     XtDestroyWidget(toolTableLabel);
02023     toolTableLabel = NULL;
02024   }
02025 
02026   if (toolTableForm != NULL) {
02027     XtDestroyWidget(toolTableForm);
02028     toolTableForm = NULL;
02029   }
02030 
02031   if (toolTableShell != NULL) {
02032     XtDestroyWidget(toolTableShell);
02033     toolTableShell = NULL;
02034   }
02035 
02036   return 0;
02037 }
02038 
02039 static void doToolTableDone(int get)
02040 {
02041   Widget source;
02042   String string;
02043 
02044   if (get) {
02045     XtVaGetValues(toolTableText,
02046                   XtNtextSource, &source,
02047                   XtNstring, &string,
02048                   NULL);
02049 
02050     XawAsciiSave(source);
02051     sendLoadToolTable(string);
02052   }
02053 
02054   XtPopdown(toolTableShell);
02055 
02056   destroyToolTableShell();
02057 }
02058 
02059 // forward decls
02060 
02061 static void varFileDoneCB(Widget w, XtPointer client_data, XtPointer call_data);
02062 static void varFileCancelCB(Widget w, XtPointer client_data, XtPointer call_data);
02063 static int createVarFileShell();
02064 static int destroyVarFileShell();
02065 static void doVarFileDone(int get);
02066 
02067 static void varFileDoneCB(Widget w, XtPointer client_data, XtPointer call_data)
02068 {
02069   doVarFileDone(1);
02070 }
02071 
02072 static void varFileCancelCB(Widget w, XtPointer client_data, XtPointer call_data)
02073 {
02074   doVarFileDone(0);
02075 }
02076 
02077 static int createVarFileShell()
02078 {
02079   if (NULL != varFileShell) {
02080     return 0;
02081   }
02082 
02083   varFileShell =
02084     XtVaCreatePopupShell("varFileShell",
02085                          topLevelShellWidgetClass,
02086                          topLevel,
02087                          XtNallowShellResize, True,
02088                          NULL);
02089 
02090   varFileForm =
02091     XtVaCreateManagedWidget("varFileForm",
02092                             formWidgetClass,
02093                             varFileShell,
02094                             NULL);
02095 
02096   varFileLabel =
02097     XtVaCreateManagedWidget("varFileLabel",
02098                             labelWidgetClass,
02099                             varFileForm,
02100                             XtNlabel, PARAMETER_FILE,
02101                             NULL);
02102 
02103   varFileText =
02104     XtVaCreateManagedWidget("varFileText",
02105                             asciiTextWidgetClass,
02106                             varFileForm,
02107                             XtNfromVert, varFileLabel,
02108                             XtNeditType, XawtextEdit,
02109                             XtNtype, XawAsciiFile,
02110                             XtNstring, PARAMETER_FILE,
02111                             XtNscrollVertical, XawtextScrollWhenNeeded,
02112                             NULL);
02113 
02114   varFileDone =
02115     XtVaCreateManagedWidget("varFileDone",
02116                             commandWidgetClass,
02117                             varFileForm,
02118                             XtNfromVert, varFileText,
02119                             NULL);
02120 
02121   XtAddCallback(varFileDone, XtNcallback, varFileDoneCB, varFileShell);
02122 
02123   varFileCancel =
02124     XtVaCreateManagedWidget("varFileCancel",
02125                             commandWidgetClass,
02126                             varFileForm,
02127                             XtNfromVert, varFileText,
02128                             XtNfromHoriz, varFileDone,
02129                             NULL);
02130 
02131   XtAddCallback(varFileCancel, XtNcallback, varFileCancelCB, varFileShell);
02132 
02133   return 0;
02134 }
02135 
02136 static int destroyVarFileShell()
02137 {
02138   if (varFileCancel != NULL) {
02139     XtDestroyWidget(varFileCancel);
02140     varFileCancel = NULL;
02141   }
02142 
02143   if (varFileDone != NULL) {
02144     XtDestroyWidget(varFileDone);
02145     varFileDone = NULL;
02146   }
02147 
02148   if (varFileText != NULL) {
02149     XtDestroyWidget(varFileText);
02150     varFileText = NULL;
02151   }
02152 
02153   if (varFileLabel != NULL) {
02154     XtDestroyWidget(varFileLabel);
02155     varFileLabel = NULL;
02156   }
02157 
02158   if (varFileForm != NULL) {
02159     XtDestroyWidget(varFileForm);
02160     varFileForm = NULL;
02161   }
02162 
02163   if (varFileShell != NULL) {
02164     XtDestroyWidget(varFileShell);
02165     varFileShell = NULL;
02166   }
02167 
02168   return 0;
02169 }
02170 
02171 static void doVarFileDone(int get)
02172 {
02173   Widget source;
02174   String string;
02175 
02176   if (get) {
02177   XtVaGetValues(varFileText,
02178                 XtNtextSource, &source,
02179                 XtNstring, &string,
02180                 NULL);
02181 
02182   XawAsciiSave(source);
02183   sendTaskPlanInit();
02184   }
02185 
02186   XtPopdown(varFileShell);
02187 
02188   destroyVarFileShell();
02189 }
02190 
02191 // diagnostics dialog
02192 
02193 static Widget diagnosticsShell = NULL;
02194 static Widget diagnosticsForm = NULL;
02195 static Widget diagnosticsLabel = NULL;
02196 static Widget diagnosticsTaskHBLabel = NULL;
02197 static Widget diagnosticsTaskHB = NULL;
02198 static Widget diagnosticsIoHBLabel = NULL;
02199 static Widget diagnosticsIoHB = NULL;
02200 static Widget diagnosticsMotionHBLabel = NULL;
02201 static Widget diagnosticsMotionHB= NULL;
02202 static Widget diagnosticsFerrorLabel = NULL;
02203 static Widget diagnosticsFerror = NULL;
02204 static Widget diagnosticsDone = NULL;
02205 
02206 // flag that window is up, so we don't waste time updating labels
02207 static int diagnosticsIsPopped = 0;
02208 
02209 static void diagnosticsDoDone()
02210 {
02211   diagnosticsIsPopped = 0;
02212   XtPopdown(diagnosticsShell);
02213 }
02214 
02215 static void diagnosticsDoneCB(Widget w, XtPointer client_data, XtPointer call_data)
02216 {
02217   diagnosticsDoDone();
02218 }
02219 
02220 static void diagnosticsReturnAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
02221 {
02222   diagnosticsDoDone();
02223 }
02224 
02225 static Pixel fileOpenBorderColor;
02226 static int fileOpenDoDone = 1;
02227 
02228 static void doFileOpenDone()
02229 {
02230   String string;
02231 
02232   if (fileOpenDoDone) {
02233     // note: "*value: " must be set in resources for input box
02234     // to appear, and for this to be valid (and not dump core)
02235     string = XawDialogGetValueString(fileOpenDialog);
02236     // set value to be the same in file edit dialog
02237     strcpy(EDITOR_FILE, string);
02238     XtVaSetValues(fileEditDialog, XtNvalue, EDITOR_FILE, NULL);
02239     sendProgramOpen(string);
02240   }
02241 
02242   setBorderColor(fileOpenDone, pixelRed);
02243   setBorderColor(fileOpenCancel, fileOpenBorderColor);
02244   fileOpenDoDone = 1;
02245 
02246   XtPopdown(fileOpenShell);
02247 }
02248 
02249 static void fileOpenDoneCB(Widget w, XtPointer client_data, XtPointer call_data)
02250 {
02251   doFileOpenDone();
02252 }
02253 
02254 static void fileOpenReturnAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
02255 {
02256   doFileOpenDone();
02257 }
02258 
02259 static void fileOpenTabAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
02260 {
02261   if (fileOpenDoDone) {
02262     setBorderColor(fileOpenDone, fileOpenBorderColor);
02263     setBorderColor(fileOpenCancel, pixelRed);
02264     fileOpenDoDone = 0;
02265   }
02266   else {
02267     setBorderColor(fileOpenDone, pixelRed);
02268     setBorderColor(fileOpenCancel, fileOpenBorderColor);
02269     fileOpenDoDone = 1;
02270   }
02271 }
02272 
02273 static Pixel fileQuitBorderColor;
02274 static int fileQuitDoDone = 1;
02275 
02276 static void doFileQuitDone()
02277 {
02278   XtPopdown(fileQuitShell);
02279 
02280   if (fileQuitDoDone) {
02281     quit();
02282   }
02283   else {
02284     setBorderColor(fileQuitDone, pixelRed);
02285     setBorderColor(fileQuitCancel, fileQuitBorderColor);
02286     fileQuitDoDone = 1;
02287   }
02288 }
02289 
02290 static void fileQuitDoneCB(Widget w, XtPointer client_data, XtPointer call_data)
02291 {
02292   doFileQuitDone();
02293 }
02294 
02295 static void fileQuitReturnAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
02296 {
02297   doFileQuitDone();
02298 }
02299 
02300 static void fileQuitTabAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
02301 {
02302   if (fileQuitDoDone) {
02303     setBorderColor(fileQuitDone, fileQuitBorderColor);
02304     setBorderColor(fileQuitCancel, pixelRed);
02305     fileQuitDoDone = 0;
02306   }
02307   else {
02308     setBorderColor(fileQuitDone, pixelRed);
02309     setBorderColor(fileQuitCancel, fileQuitBorderColor);
02310     fileQuitDoDone = 1;
02311   }
02312 }
02313 
02314 static Pixel fileEditBorderColor;
02315 static int fileEditDoDone = 1;
02316 
02317 static void doFileEditDone()
02318 {
02319   String string;
02320   struct stat buf;
02321   int fd;
02322 
02323   if (fileEditDoDone) {
02324     string = XawDialogGetValueString(fileEditDialog);
02325     // set value to be the same in file open dialog
02326     strcpy(EDITOR_FILE, string);
02327     XtVaSetValues(fileOpenDialog, XtNvalue, EDITOR_FILE, NULL);
02328   }
02329 
02330   XtPopdown(fileEditShell);
02331 
02332   if (fileEditDoDone) {
02333     if (-1 == stat(EDITOR_FILE, &buf)) {
02334       // file not found-- it's a new one. Touch it so that it
02335       // exists and the text widget won't barf
02336       fd = open(EDITOR_FILE, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
02337       close(fd);
02338       createFileEditorShell(1);
02339       dialogPopup(NULL, fileEditorShell, NULL);
02340       // trap window kill
02341       XSetWMProtocols(XtDisplay(topLevel), XtWindow(fileEditorShell), &killAtom, 1);
02342     }
02343     else {
02344       // file is there-- check type and permissions
02345       if (! S_ISREG(buf.st_mode)) {
02346         // file is not a regular file
02347         popupError("Can't edit %S: not a text file", EDITOR_FILE);
02348       }
02349       else if ((S_IWUSR & buf.st_mode)) {
02350         // file is writeable
02351         createFileEditorShell(1);
02352         dialogPopup(NULL, fileEditorShell, NULL);
02353         // trap window kill
02354         XSetWMProtocols(XtDisplay(topLevel), XtWindow(fileEditorShell), &killAtom, 1);
02355       }
02356       else {
02357         // file is read-only
02358         createFileEditorShell(0);
02359         dialogPopup(NULL, fileEditorShell, NULL);
02360         // trap window kill
02361         XSetWMProtocols(XtDisplay(topLevel), XtWindow(fileEditorShell), &killAtom, 1);
02362       }
02363     }
02364   }
02365 
02366   setBorderColor(fileEditDone, pixelRed);
02367   setBorderColor(fileEditCancel, fileEditBorderColor);
02368   fileEditDoDone = 1;
02369 }
02370 
02371 static void fileEditDoneCB(Widget w, XtPointer client_data, XtPointer call_data)
02372 {
02373   doFileEditDone();
02374 }
02375 
02376 static void fileEditReturnAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
02377 {
02378   doFileEditDone();
02379 }
02380 
02381 static void fileEditTabAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
02382 {
02383   if (fileEditDoDone) {
02384     setBorderColor(fileEditDone, fileEditBorderColor);
02385     setBorderColor(fileEditCancel, pixelRed);
02386     fileEditDoDone = 0;
02387   }
02388   else {
02389     setBorderColor(fileEditDone, pixelRed);
02390     setBorderColor(fileEditCancel, fileEditBorderColor);
02391     fileEditDoDone = 1;
02392   }
02393 }
02394 
02395 static void toolSetOffsetDoDone(int done)
02396 {
02397   String str1, str2, str3;
02398   int tool;
02399   double length;
02400   double diameter;
02401 
02402   if (done) {
02403     XtVaGetValues(toolSetOffsetTool, XtNstring, &str1, NULL);
02404     XtVaGetValues(toolSetOffsetLength, XtNstring, &str2, NULL);
02405     XtVaGetValues(toolSetOffsetDiameter, XtNstring, &str3, NULL);
02406 
02407     if (1 == sscanf(str1, "%d", &tool) &&
02408         1 == sscanf(str2, "%lf", &length) &&
02409         1 == sscanf(str3, "%lf", &diameter)) {
02410       sendToolSetOffset(tool, length, diameter);
02411     }
02412   }
02413 
02414   XtPopdown(toolSetOffsetShell);
02415 }
02416 
02417 static void toolSetOffsetUpAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
02418 {
02419   char string[256];
02420 
02421   sprintf(string, "%d", emcStatus->io.tool.toolInSpindle);
02422   XtVaSetValues(toolSetOffsetTool, XtNstring, string, NULL);
02423   sprintf(string, "%f",
02424           emcStatus->motion.traj.actualPosition.tran.z -
02425           emcStatus->task.origin.tran.z);
02426   XtVaSetValues(toolSetOffsetLength, XtNstring, string, NULL);
02427   XtVaSetValues(toolSetOffsetDiameter, XtNstring, "0.0", NULL);
02428 
02429   dialogPopup(NULL, toolSetOffsetShell, NULL);
02430   // trap window kill
02431   XSetWMProtocols(XtDisplay(topLevel), XtWindow(toolSetOffsetShell), &killAtom, 1);
02432 }
02433 
02434 static Pixel toolSetOffsetFormBorderColor;
02435 static int toolSetOffsetReturnIsDone = 1;
02436 
02437 static void toolSetOffsetReturnAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
02438 {
02439   if (toolSetOffsetReturnIsDone) {
02440     toolSetOffsetDoDone(1);
02441   }
02442   else {
02443     toolSetOffsetDoDone(0);
02444   }
02445 }
02446 
02447 static void toolSetOffsetDoneCB(Widget w, XtPointer client_data, XtPointer call_data)
02448 {
02449   toolSetOffsetDoDone(1);
02450 }
02451 
02452 static void toolSetOffsetCancelCB(Widget w, XtPointer client_data, XtPointer call_data)
02453 {
02454   toolSetOffsetDoDone(0);
02455 }
02456 
02457 static void toolSetOffsetTabAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
02458 {
02459   if (toolSetOffsetReturnIsDone) {
02460     setBorderColor(toolSetOffsetDone, toolSetOffsetFormBorderColor);
02461     setBorderColor(toolSetOffsetCancel, pixelRed);
02462     toolSetOffsetReturnIsDone = 0;
02463   }
02464   else {
02465     setBorderColor(toolSetOffsetDone, pixelRed);
02466     setBorderColor(toolSetOffsetCancel, toolSetOffsetFormBorderColor);
02467     toolSetOffsetReturnIsDone = 1;
02468   }
02469 }
02470 
02471 static void doPosOffsetDone()
02472 {
02473   String string;
02474   char cmd[256];
02475   double val;
02476 
02477   string = XawDialogGetValueString(posOffsetDialog);
02478 
02479   if (1 == sscanf(string, "%lf", &val)) {
02480     // send MDI command
02481     // FIXME-- this RS-274-NGC specific; need to add NML way to do this
02482     sprintf(cmd, "G92%s%f\n",
02483             activeAxis == 0 ? "X" :
02484             activeAxis == 1 ? "Y" :
02485             activeAxis == 2 ? "Z" : "X",
02486             val);
02487     sendMdiCmd(cmd);
02488   }
02489 
02490   XtPopdown(posOffsetShell);
02491 }
02492 
02493 static void posOffsetUpAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
02494 {
02495   if (w == posLabel[0]) {
02496     activeAxis = 0;
02497   }
02498   else if (w == posLabel[1]) {
02499     activeAxis = 1;
02500   }
02501   else if (w == posLabel[2]) {
02502     activeAxis = 2;
02503   }
02504 
02505   XtVaSetValues(posOffsetDialog, XtNvalue, "0.0", NULL);
02506   dialogPopup(NULL, posOffsetShell, NULL);
02507   // trap window kill
02508   XSetWMProtocols(XtDisplay(topLevel), XtWindow(posOffsetShell), &killAtom, 1);
02509 }
02510 
02511 static void posOffsetReturnAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
02512 {
02513   doPosOffsetDone();
02514 }
02515 
02516 static void doJogSpeedDone()
02517 {
02518   String string;
02519   int val;
02520   char labelString[80];
02521 
02522   string = XawDialogGetValueString(jogSpeedDialog);
02523 
02524   if (1 == sscanf(string, "%d", &val)) {
02525     jogSpeed = val;
02526     if (jogSpeed > maxJogSpeed) {
02527       jogSpeed = maxJogSpeed;
02528     }
02529     sprintf(labelString, "%d", jogSpeed);
02530     setLabel(jogSpeedLabel, labelString);
02531     redraw = 1;
02532   }
02533 
02534   XtPopdown(jogSpeedShell);
02535 }
02536 
02537 static void jogSpeedReturnAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
02538 {
02539   doJogSpeedDone();
02540 }
02541 
02542 static void doFeedOverrideDone()
02543 {
02544   String string;
02545   double val;
02546 
02547   string = XawDialogGetValueString(feedOverrideDialog);
02548 
02549   if (1 == sscanf(string, "%lf", &val)) {
02550     sendFeedOverride(val / 100.0);
02551   }
02552 
02553   XtPopdown(feedOverrideShell);
02554 }
02555 
02556 static void feedOverrideReturnAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
02557 {
02558   doFeedOverrideDone();
02559 }
02560 
02561 static void programRunCB(Widget w, XtPointer client_data, XtPointer call_data)
02562 {
02563   sendProgramRun(programStartLine);
02564 }
02565 
02566 static void programPauseCB(Widget w, XtPointer client_data, XtPointer call_data)
02567 {
02568   sendProgramPause();
02569 }
02570 
02571 static void programResumeCB(Widget w, XtPointer client_data, XtPointer call_data)
02572 {
02573   sendProgramResume();
02574 }
02575 
02576 static void programStepCB(Widget w, XtPointer client_data, XtPointer call_data)
02577 {
02578   sendProgramStep();
02579 }
02580 
02581 static void programVerifyCB(Widget w, XtPointer client_data, XtPointer call_data)
02582 {
02583   programStartLine = -1;
02584   sendProgramRun(programStartLine);
02585 }
02586 
02587 static void helpXemcReturnAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
02588 {
02589   XtPopdown(helpXemcShell);
02590 }
02591 
02592 static void helpAboutReturnAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
02593 {
02594   XtPopdown(helpAboutShell);
02595 }
02596 
02597 static void genericDoneCB(Widget w, XtPointer client_data, XtPointer call_data)
02598 {
02599   XtPopdown((Widget) client_data);
02600 }
02601 
02602 // button handling code
02603 
02604 static void downAction(Widget w,
02605                        XEvent *ev,
02606                        String *params,
02607                        Cardinal *numParams)
02608 {
02609   char string[80];
02610 
02611   if (w == spindleIncLabel) {
02612     sendSpindleIncrease();
02613   }
02614   else if (w == spindleDecLabel) {
02615     sendSpindleDecrease();
02616   }
02617   else if (w == jogMinusLabel) {
02618     if (jogIncrement > 0.0) {
02619       sendJogIncr(activeAxis, -jogSpeed, jogIncrement);
02620     }
02621     else {
02622       sendJogCont(activeAxis, -jogSpeed);
02623     }
02624   }
02625   else if (w == jogPlusLabel) {
02626     if (jogIncrement > 0.0) {
02627       sendJogIncr(activeAxis, jogSpeed, jogIncrement);
02628     }
02629     else {
02630       sendJogCont(activeAxis, jogSpeed);
02631     }
02632   }
02633   else if (w == posLabel[0]) {
02634     activeAxis = 0;
02635   }
02636   else if (w == posLabel[1]) {
02637     activeAxis = 1;
02638   }
02639   else if (w == posLabel[2]) {
02640     activeAxis = 2;
02641   }
02642   else if (w == jogSpeedLabel) {
02643     // pop up menu to change jog speed
02644     XtVaSetValues(jogSpeedDialog,
02645                   XtNvalue, "",
02646                   NULL);
02647     dialogPopup(NULL, jogSpeedShell, NULL);
02648     // trap window kill
02649     XSetWMProtocols(XtDisplay(topLevel), XtWindow(jogSpeedShell), &killAtom, 1);
02650   }
02651   else if (w == jogSpeedDecLabel) {
02652     // change it once here and redraw
02653     if (--jogSpeed <= 0) {
02654       jogSpeed = 1;
02655     }
02656     sprintf(string, "%d", jogSpeed);
02657     setLabel(jogSpeedLabel, string);
02658     redraw = 1;
02659 
02660     // set jogSpeedChange so that timer callback will continue to change
02661     // until button up clears it
02662     jogSpeedChange = -1;
02663   }
02664   else if (w == jogSpeedIncLabel) {
02665     // change it once here and redraw
02666     if (++jogSpeed > maxJogSpeed) {
02667       jogSpeed = maxJogSpeed;
02668     }
02669     sprintf(string, "%d", jogSpeed);
02670     setLabel(jogSpeedLabel, string);
02671     redraw = 1;
02672 
02673     // set jogSpeedChange so that timer callback will continue to change
02674     // until button up clears it
02675     jogSpeedChange = +1;
02676   }
02677   else if (w == feedOverrideLabel) {
02678     // pop up menu to change feed override
02679     XtVaSetValues(feedOverrideDialog,
02680                   XtNvalue, "",
02681                   NULL);
02682     dialogPopup(NULL, feedOverrideShell, NULL);
02683     // trap window kill
02684     XSetWMProtocols(XtDisplay(topLevel), XtWindow(feedOverrideShell), &killAtom, 1);
02685   }
02686   else if (w == feedOverrideDecLabel) {
02687     // change it once here and redraw
02688     if ((feedOverride -= 10) <= 0) {
02689       feedOverride = 0;
02690     }
02691     sprintf(string, "%3d", feedOverride);
02692     setLabel(feedOverrideLabel, string);
02693     redraw = 1;
02694 
02695     // set feedOverrideChange so that timer callback will continue to change
02696     // until button up clears it
02697     feedOverrideChange = -1;
02698   }
02699   else if (w == feedOverrideIncLabel) {
02700     // change it once here and redraw
02701     if ((feedOverride += 10) > maxFeedOverride) {
02702       feedOverride = maxFeedOverride;
02703     }
02704     sprintf(string, "%3d", feedOverride);
02705     setLabel(feedOverrideLabel, string);
02706     redraw = 1;
02707 
02708     // set feedOverrideChange so that timer callback will continue to change
02709     // until button up clears it
02710     feedOverrideChange = +1;
02711   }
02712   else {
02713     printf("down\n");
02714   }
02715 }
02716 
02717 static void upAction(Widget w,
02718                      XEvent *ev,
02719                      String *params,
02720                      Cardinal *numParams)
02721 {
02722   if (w == spindleIncLabel) {
02723     sendSpindleConstant();
02724   }
02725   else if (w == spindleDecLabel) {
02726     sendSpindleConstant();
02727   }
02728   else if (w == jogMinusLabel) {
02729     // only stop it if it's continuous jogging
02730     if (jogIncrement <= 0.0) {
02731       sendJogStop(axisJogging);
02732     }
02733   }
02734   else if (w == jogPlusLabel) {
02735     // only stop it if it's continuous jogging
02736     if (jogIncrement <= 0.0) {
02737       sendJogStop(axisJogging);
02738     }
02739   }
02740   else if (w == posLabel[0]) {
02741   }
02742   else if (w == posLabel[1]) {
02743   }
02744   else if (w == posLabel[2]) {
02745   }
02746   else if (w == jogSpeedDecLabel) {
02747     jogSpeedChange = 0;
02748   }
02749   else if (w == jogSpeedIncLabel) {
02750     jogSpeedChange = 0;
02751   }
02752   else if (w == feedOverrideDecLabel) {
02753     feedOverrideChange = 0;
02754     sendFeedOverride((double) feedOverride / 100.0);
02755   }
02756   else if (w == feedOverrideIncLabel) {
02757     feedOverrideChange = 0;
02758     sendFeedOverride((double) feedOverride / 100.0);
02759   }
02760   else {
02761     printf("up\n");
02762   }
02763 }
02764 
02765 static void mdiReturnAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
02766 {
02767   String string;
02768 
02769   XtVaGetValues(mdiFormText, XtNstring, &string, NULL);
02770 
02771   sendMdiCmd(string);
02772 }
02773 
02774 // key handling code
02775 
02776 // FIXME-- better way to get these?
02777 #define XEVENT_TYPE_XKEY_KEY_PRESS_EVENT 2
02778 #define XEVENT_TYPE_XKEY_KEY_RELEASE_EVENT 3
02779 #define XKEY_EVENT_STATE_NONE    0x00
02780 #define XKEY_EVENT_STATE_SHIFT   0x01
02781 #define XKEY_EVENT_STATE_CONTROL 0x04
02782 #define XKEY_EVENT_STATE_ALT     0x08
02783 
02784 #define KEY_ESC     9
02785 #define KEY_F1     67
02786 #define KEY_F2     68
02787 #define KEY_F3     69
02788 #define KEY_F4     70
02789 #define KEY_F5     71
02790 #define KEY_F6     72
02791 #define KEY_F7     73
02792 #define KEY_F8     74
02793 #define KEY_F9     75
02794 #define KEY_F10    76
02795 #define KEY_F11    95
02796 #define KEY_F12    96
02797 #define KEY_PGUP   99
02798 #define KEY_PGDN  105
02799 #define KEY_LEFT  100
02800 #define KEY_RIGHT 102
02801 #define KEY_UP     98
02802 #define KEY_DOWN  104
02803 #define KEY_X      53
02804 #define KEY_Y      29
02805 #define KEY_Z      52
02806 #define KEY_HOME   97
02807 #define KEY_END   103
02808 #define KEY_1      10
02809 #define KEY_2      11
02810 #define KEY_3      12
02811 #define KEY_4      13
02812 #define KEY_5      14
02813 #define KEY_6      15
02814 #define KEY_7      16
02815 #define KEY_8      17
02816 #define KEY_9      18
02817 #define KEY_0      19
02818 #define KEY_O      32
02819 #define KEY_E      26
02820 #define KEY_R      27
02821 #define KEY_T      28
02822 #define KEY_P      33
02823 #define KEY_V      55
02824 #define KEY_A      38
02825 #define KEY_S      39
02826 #define KEY_L      46
02827 #define KEY_B      56
02828 #define KEY_F      41
02829 #define KEY_COMMA  59
02830 #define KEY_PERIOD 60
02831 #define KEY_I      31
02832 #define KEY_C      54
02833 
02834 static int keyReleaseOut = 0;   // set if we saw a release, cleared right away
02835                                 // if the key repeat kicks back on, else it
02836                                 // goes through as a true key release
02837 static double keyReleaseTime = 0.0;
02838 static unsigned int keyPressState;
02839 static unsigned int keyPressKeycode;
02840 static unsigned int keyReleaseState;
02841 static unsigned int keyReleaseKeycode;
02842 
02843 static void keyPressAction(unsigned int state, unsigned int keycode)
02844 {
02845   char string[256];
02846   static double saveJogIncrement = 0.1000;
02847 
02848   switch (keycode) {
02849 
02850   case KEY_ESC:
02851     sendAbort();
02852     break;
02853 
02854   case KEY_F1:
02855     // estop toggle
02856     if (emcStatus->task.state == EMC_TASK_STATE_ESTOP) {
02857       sendEstopReset();
02858     }
02859     else {
02860       sendEstop();
02861     }
02862     break;
02863 
02864   case KEY_F2:
02865     // estop toggle
02866     if (emcStatus->task.state == EMC_TASK_STATE_ESTOP_RESET) {
02867       sendMachineOn();
02868     }
02869     else {
02870       sendMachineOff();
02871     }
02872     break;
02873 
02874   case KEY_F3:
02875     // manual mode
02876     sendManual();
02877     break;
02878 
02879   case KEY_F4:
02880     // auto mode
02881     sendAuto();
02882     break;
02883 
02884   case KEY_F5:
02885     // mdi mode
02886     sendMdi();
02887     break;
02888 
02889   case KEY_F6:
02890     sendTaskPlanInit();
02891     break;
02892 
02893   case KEY_F7:
02894     // mist toggle
02895     if (emcStatus->io.coolant.mist) {
02896       sendMistOff();
02897     }
02898     else {
02899       sendMistOn();
02900     }
02901     break;
02902 
02903   case KEY_F8:
02904     // flood toggle
02905     if (emcStatus->io.coolant.flood) {
02906       sendFloodOff();
02907     }
02908     else {
02909       sendFloodOn();
02910     }
02911     break;
02912 
02913   case KEY_F9:
02914     // spindle fwd/off
02915     if (emcStatus->io.spindle.direction == 0) {
02916       // it's off, so turn forward
02917       sendSpindleForward();
02918     }
02919     else
02920       {
02921         // it's not off, so turn off
02922         sendSpindleOff();
02923       }
02924     break;
02925 
02926   case KEY_F10:
02927     // spindle rev/off
02928     if (emcStatus->io.spindle.direction == 0) {
02929       // it's off, so turn reverse
02930       sendSpindleReverse();
02931     }
02932     else
02933       {
02934         // it's not off, so turn off
02935         sendSpindleOff();
02936       }
02937     break;
02938 
02939   case KEY_F11:
02940     // spindle decrease
02941     if (emcStatus->io.spindle.direction != 0) {
02942       sendSpindleDecrease();
02943     }
02944     break;
02945 
02946   case KEY_F12:
02947     // spindle increase
02948     if (emcStatus->io.spindle.direction != 0) {
02949       sendSpindleIncrease();
02950     }
02951     break;
02952 
02953   case KEY_PGUP:
02954     activeAxis = 2;
02955     if (jogIncrement > 0.0) {
02956       sendJogIncr(activeAxis, jogSpeed, jogIncrement);
02957     }
02958     else {
02959       sendJogCont(activeAxis, jogSpeed);
02960     }
02961     break;
02962 
02963   case KEY_PGDN:
02964     activeAxis = 2;
02965     if (jogIncrement > 0.0) {
02966       sendJogIncr(activeAxis, -jogSpeed, jogIncrement);
02967     }
02968     else {
02969       sendJogCont(activeAxis, -jogSpeed);
02970     }
02971     break;
02972 
02973   case KEY_RIGHT:
02974     activeAxis = 0;
02975     if (jogIncrement > 0.0) {
02976       sendJogIncr(activeAxis, jogSpeed, jogIncrement);
02977     }
02978     else {
02979       sendJogCont(activeAxis, jogSpeed);
02980     }
02981     break;
02982 
02983   case KEY_LEFT:
02984     activeAxis = 0;
02985     if (jogIncrement > 0.0) {
02986       sendJogIncr(activeAxis, -jogSpeed, jogIncrement);
02987     }
02988     else {
02989       sendJogCont(activeAxis, -jogSpeed);
02990     }
02991     break;
02992 
02993   case KEY_UP:
02994     activeAxis = 1;
02995     if (jogIncrement > 0.0) {
02996       sendJogIncr(activeAxis, jogSpeed, jogIncrement);
02997     }
02998     else {
02999       sendJogCont(activeAxis, jogSpeed);
03000     }
03001     break;
03002 
03003   case KEY_DOWN:
03004     activeAxis = 1;
03005     if (jogIncrement > 0.0) {
03006       sendJogIncr(activeAxis, -jogSpeed, jogIncrement);
03007     }
03008     else {
03009       sendJogCont(activeAxis, -jogSpeed);
03010     }
03011     break;
03012 
03013   case KEY_T:
03014     switch (state) {
03015     case XKEY_EVENT_STATE_ALT:
03016       sprintf(string, "%d", emcStatus->io.tool.toolInSpindle);
03017       XtVaSetValues(toolSetOffsetTool, XtNstring, string, NULL);
03018       sprintf(string, "%f",
03019               emcStatus->motion.traj.actualPosition.tran.z -
03020               emcStatus->task.origin.tran.z);
03021       XtVaSetValues(toolSetOffsetLength, XtNstring, string, NULL);
03022       XtVaSetValues(toolSetOffsetDiameter, XtNstring, "0.0", NULL);
03023       dialogPopup(NULL, toolSetOffsetShell, NULL);
03024       // trap window kill
03025       XSetWMProtocols(XtDisplay(topLevel), XtWindow(toolSetOffsetShell), &killAtom, 1);
03026       break;
03027     }
03028     break;
03029 
03030   case KEY_X:
03031     activeAxis = 0;
03032     switch (state) {
03033     case XKEY_EVENT_STATE_ALT:
03034       XtVaSetValues(posOffsetDialog, XtNvalue, "0.0", NULL);
03035       dialogPopup(NULL, posOffsetShell, NULL);
03036       // trap window kill
03037       XSetWMProtocols(XtDisplay(topLevel), XtWindow(posOffsetShell), &killAtom, 1);
03038       break;
03039     }
03040     break;
03041 
03042   case KEY_Y:
03043     activeAxis = 1;
03044     switch (state) {
03045     case XKEY_EVENT_STATE_ALT:
03046       XtVaSetValues(posOffsetDialog, XtNvalue, "0.0", NULL);
03047       dialogPopup(NULL, posOffsetShell, NULL);
03048       // trap window kill
03049       XSetWMProtocols(XtDisplay(topLevel), XtWindow(posOffsetShell), &killAtom, 1);
03050       break;
03051     }
03052     break;
03053 
03054   case KEY_Z:
03055     activeAxis = 2;
03056     switch (state) {
03057     case XKEY_EVENT_STATE_ALT:
03058       XtVaSetValues(posOffsetDialog, XtNvalue, "0.0", NULL);
03059       dialogPopup(NULL, posOffsetShell, NULL);
03060       // trap window kill
03061       XSetWMProtocols(XtDisplay(topLevel), XtWindow(posOffsetShell), &killAtom, 1);
03062       break;
03063     }
03064     break;
03065 
03066   case KEY_HOME:
03067     sendHome(activeAxis);
03068     break;
03069 
03070   case KEY_END:
03071     dialogPopup(NULL, fileQuitShell, NULL);
03072     // trap window kill
03073     XSetWMProtocols(XtDisplay(topLevel), XtWindow(fileQuitShell), &killAtom, 1);
03074     break;
03075 
03076   case KEY_1:
03077       sendFeedOverride(0.1);
03078     break;
03079 
03080   case KEY_2:
03081     switch (state) {
03082     case XKEY_EVENT_STATE_NONE:
03083       sendFeedOverride(0.2);
03084       break;
03085 
03086     case XKEY_EVENT_STATE_SHIFT:
03087       // @
03088       if (posDisplay == POS_DISPLAY_CMD) {
03089         posDisplay = POS_DISPLAY_ACT;
03090       }
03091       else {
03092         posDisplay = POS_DISPLAY_CMD;
03093       }
03094       break;
03095 
03096     }
03097     break;
03098 
03099   case KEY_3:
03100     switch (state) {
03101     case XKEY_EVENT_STATE_NONE:
03102       sendFeedOverride(0.3);
03103       break;
03104 
03105     case XKEY_EVENT_STATE_SHIFT:
03106       if (coords == COORD_RELATIVE) {
03107         coords = COORD_MACHINE;
03108       }
03109       else {
03110         coords = COORD_RELATIVE;
03111       }
03112       break;
03113 
03114     }
03115     break;
03116 
03117   case KEY_4:
03118     sendFeedOverride(0.4);
03119     break;
03120 
03121   case KEY_5:
03122     sendFeedOverride(0.5);
03123     break;
03124 
03125   case KEY_6:
03126     sendFeedOverride(0.6);
03127     break;
03128 
03129   case KEY_7:
03130     sendFeedOverride(0.7);
03131     break;
03132 
03133   case KEY_8:
03134     sendFeedOverride(0.8);
03135     break;
03136 
03137   case KEY_9:
03138     sendFeedOverride(0.9);
03139     break;
03140 
03141   case KEY_0:
03142     sendFeedOverride(1.0);
03143     break;
03144 
03145   case KEY_O:
03146     dialogPopup(NULL, fileOpenShell, NULL);
03147     // trap window kill
03148     XSetWMProtocols(XtDisplay(topLevel), XtWindow(fileOpenShell), &killAtom, 1);
03149     break;
03150 
03151   case KEY_E:
03152     dialogPopup(NULL, fileEditShell, NULL);
03153     // trap window kill
03154     XSetWMProtocols(XtDisplay(topLevel), XtWindow(fileEditShell), &killAtom, 1);
03155     break;
03156 
03157   case KEY_R:
03158     sendProgramRun(programStartLine);
03159     break;
03160 
03161   case KEY_P:
03162     switch (state) {
03163     case XKEY_EVENT_STATE_NONE:
03164     case XKEY_EVENT_STATE_SHIFT:
03165       sendProgramPause();
03166       break;
03167 
03168     case XKEY_EVENT_STATE_ALT:
03169       sendLogStop();
03170       break;
03171 
03172     case XKEY_EVENT_STATE_CONTROL:
03173       plotLog(saveLogFile, saveLogType);
03174       break;
03175     }
03176     break;
03177 
03178   case KEY_S:
03179     switch (state) {
03180     case XKEY_EVENT_STATE_NONE:
03181     case XKEY_EVENT_STATE_SHIFT:
03182       sendProgramResume();
03183       break;
03184 
03185     case XKEY_EVENT_STATE_ALT:
03186       sendLogStart();
03187       break;
03188     }
03189     break;
03190 
03191   case KEY_V:
03192     programStartLine = -1;
03193     sendProgramRun(programStartLine);
03194     break;
03195 
03196   case KEY_F:
03197     sendLogClose();
03198     break;
03199 
03200   case KEY_A:
03201     sendProgramStep();
03202     break;
03203 
03204   case KEY_L:
03205     sendOverrideLimits();
03206     break;
03207 
03208   case KEY_B:
03209     switch (state) {
03210     case XKEY_EVENT_STATE_NONE:
03211       sendBrakeRelease();
03212       break;
03213 
03214     case XKEY_EVENT_STATE_SHIFT:
03215       sendBrakeEngage();
03216       break;
03217 
03218     }
03219     break;
03220 
03221   case KEY_I:
03222     // check for entering from continuous jog, and restore saved increment
03223     if (jogIncrement <= 0.0) {
03224       jogIncrement = saveJogIncrement;
03225     }
03226     // go from 0.1000 to 0.0100
03227     else if (jogIncrement > 0.0500) {
03228       jogIncrement = 0.0100;
03229     }
03230     // go from 0.0100 to 0.0010
03231     else if (jogIncrement > 0.0050) {
03232       jogIncrement = 0.0010;
03233     }
03234     // go from 0.0010 to stepIncrement
03235     else if (jogIncrement > stepIncrement) {
03236       jogIncrement = stepIncrement;
03237     }
03238     // go from 0.0001 to 0.1000
03239     else {
03240       jogIncrement = 0.1000;
03241     }
03242     saveJogIncrement = jogIncrement;
03243     break;
03244 
03245   case KEY_C:
03246     // change to continuous jog, but save increment for restoring
03247     jogIncrement = 0.0;
03248     break;
03249 
03250   case KEY_COMMA:
03251     // change it once here and redraw
03252     if (--jogSpeed <= 0) {
03253       jogSpeed = 1;
03254     }
03255     sprintf(string, "%d", jogSpeed);
03256     setLabel(jogSpeedLabel, string);
03257     redraw = 1;
03258 
03259     // set jogSpeedChange so that timer callback will continue to change
03260     // until button up clears it
03261     jogSpeedChange = -1;
03262     break;
03263 
03264   case KEY_PERIOD:
03265     // change it once here and redraw
03266     if (++jogSpeed > maxJogSpeed) {
03267       jogSpeed = maxJogSpeed;
03268     }
03269     sprintf(string, "%d", jogSpeed);
03270     setLabel(jogSpeedLabel, string);
03271     redraw = 1;
03272 
03273     // set jogSpeedChange so that timer callback will continue to change
03274     // until button up clears it
03275     jogSpeedChange = +1;
03276     break;
03277 
03278   default:
03279     printf("key press %d %d\n", state, keycode);
03280   }
03281 }
03282 
03283 static void keyReleaseAction(unsigned int state, unsigned int keycode)
03284 {
03285   switch (keycode) {
03286 
03287   case KEY_LEFT:
03288   case KEY_RIGHT:
03289     if (jogIncrement <= 0.0) {
03290       // only stop it if it's continuous jogging
03291       sendJogStop(axisJogging);
03292     }
03293     break;
03294 
03295   case KEY_UP:
03296   case KEY_DOWN:
03297     if (jogIncrement <= 0.0) {
03298       // only stop it if it's continuous jogging
03299       sendJogStop(axisJogging);
03300     }
03301     break;
03302 
03303   case KEY_PGUP:
03304   case KEY_PGDN:
03305     if (jogIncrement <= 0.0) {
03306       // only stop it if it's continuous jogging
03307       sendJogStop(axisJogging);
03308     }
03309     break;
03310 
03311   case KEY_F11:
03312   case KEY_F12:
03313     sendSpindleConstant();
03314     break;
03315 
03316   case KEY_COMMA:
03317   case KEY_PERIOD:
03318     jogSpeedChange = 0;
03319     break;
03320 
03321   default:
03322     printf("key release %d %d\n", state, keycode);
03323     break;
03324   }
03325 }
03326 
03327 static void keyAction(Widget w,
03328                       XEvent *ev,
03329                       String *params,
03330                       Cardinal *numParams)
03331 {
03332   if (ev->type == XEVENT_TYPE_XKEY_KEY_PRESS_EVENT) {
03333     keyPressKeycode = ev->xkey.keycode;
03334     keyPressState = ev->xkey.state;
03335 
03336     if (keyReleaseOut) {
03337       if (keyPressKeycode == keyReleaseKeycode &&
03338           keyPressState == keyReleaseState) {
03339         // the press matched the release before the timeout, so it's
03340         // a key repeat on this key and we won't signal a key release
03341         keyReleaseOut = 0;
03342       }
03343       else {
03344         // it's a key press on a different key than the previous release,
03345         // so allow the release to go through by leaving keyReleaseOut set
03346       }
03347     }
03348     else {
03349       keyPressAction(ev->xkey.state, ev->xkey.keycode);
03350     }
03351   }
03352   else if (ev->type == XEVENT_TYPE_XKEY_KEY_RELEASE_EVENT) {
03353     keyReleaseKeycode = ev->xkey.keycode;
03354     keyReleaseState = ev->xkey.state;
03355     keyReleaseTime = etime();
03356     keyReleaseOut = 1;
03357   }
03358 
03359   return;
03360 }
03361 
03362 static String fileMenuEntryNames[] = {
03363   "[O]    Open...",
03364   "[E]     Edit...",
03365   "[F6]   Reset",
03366   "-",
03367   "[End] Quit",
03368   NULL
03369 };
03370 
03371 static String viewMenuEntryNames[] = {
03372   "Tools...",
03373   "Offsets and Variables...",
03374   "Diagnostics...",
03375   NULL
03376 };
03377 
03378 static String settingsMenuEntryNames[] = {
03379   "[#] Relative Coordinates",
03380   "[#] Machine Coordinates",
03381   "-",
03382   "[@] Actual Position",
03383   "[@] Commanded Position",
03384   "-",
03385   "Calibration...",
03386   "Logging...",
03387   NULL
03388 };
03389 
03390 static String helpMenuEntryNames[] = {
03391   "Help...",
03392   "-",
03393   "About...",
03394   NULL
03395 };
03396 
03397 static String stateMenuEntryNames[] = {
03398   "[F1] Estop on",
03399   "[F1] Estop off",
03400   "-",
03401   "[F2] Machine on",
03402   "[F2] Machine off",
03403   NULL
03404 };
03405 
03406 static String modeMenuEntryNames[] = {
03407   "[F3] Manual",
03408   "[F4] Auto",
03409   "[F5] MDI",
03410   NULL
03411 };
03412 
03413 static String mistMenuEntryNames[] = {
03414   "[F7] Mist on",
03415   "[F7] Mist off",
03416   NULL
03417 };
03418 
03419 static String floodMenuEntryNames[] = {
03420   "[F8] Flood on",
03421   "[F8] Flood off",
03422   NULL
03423 };
03424 
03425 static String spindleMenuEntryNames[] = {
03426   "[F9]        Spindle forward",
03427   "[F10]      Spindle reverse",
03428   "[F9/F10] Spindle off",
03429   NULL
03430 };
03431 
03432 static String brakeMenuEntryNames[] = {
03433   "[B] Brake on",
03434   "[b] Brake off",
03435   NULL
03436 };
03437 
03438 static char stepIncrementLabel[32] = "0.123456";
03439 static String jogIncrementMenuEntryNames[] = {
03440   "0.1000",
03441   "0.0100",
03442   "0.0010",
03443   stepIncrementLabel,           // this will be overridden by step size
03444   "-",
03445   "continuous",
03446   NULL
03447 };
03448 
03449 static String loggingTypeMenuEntryNames[] = {
03450   "Axis Position",
03451   "All Input Positions",
03452   "All Output Positions",
03453   "Axis Velocity",
03454   "All Following Errors",
03455   "All Trajectory Points",
03456   "All Trajectory Vels",
03457   "All Trajectory Accels",
03458   NULL
03459 };
03460 
03461 static void fileMenuSelect(Widget w, XtPointer client_data, XtPointer call_data)
03462 {
03463   switch ((int) client_data) {
03464   case 0:                       // Open...
03465     dialogPopup(NULL, fileOpenShell, NULL);
03466     // trap window kill
03467     XSetWMProtocols(XtDisplay(topLevel), XtWindow(fileOpenShell), &killAtom, 1);
03468     break;
03469 
03470   case 1:                       // Edit...
03471     dialogPopup(NULL, fileEditShell, NULL);
03472     // trap window kill
03473     XSetWMProtocols(XtDisplay(topLevel), XtWindow(fileEditShell), &killAtom, 1);
03474     break;
03475 
03476   case 2:                       // Reset
03477     sendTaskPlanInit();
03478     break;
03479 
03480     // case 3 is separator
03481 
03482   case 4:                       // Quit
03483     dialogPopup(NULL, fileQuitShell, NULL);
03484     // trap window kill
03485     XSetWMProtocols(XtDisplay(topLevel), XtWindow(fileQuitShell), &killAtom, 1);
03486     break;
03487 
03488   default:
03489     break;
03490   }
03491 }
03492 
03493 static void viewMenuSelect(Widget w, XtPointer client_data, XtPointer call_data)
03494 {
03495   char string[256];
03496 
03497   switch ((int) client_data) {
03498   case 0:                       // Tools
03499     createToolTableShell();
03500     dialogPopup(NULL, toolTableShell, NULL);
03501     // trap window kill
03502     XSetWMProtocols(XtDisplay(topLevel), XtWindow(toolTableShell), &killAtom, 1);
03503     break;
03504 
03505   case 1:                       // Variables
03506     createVarFileShell();
03507     dialogPopup(NULL, varFileShell, NULL);
03508     // trap window kill
03509     XSetWMProtocols(XtDisplay(topLevel), XtWindow(varFileShell), &killAtom, 1);
03510     break;
03511 
03512   case 2:                       // Diagnostics
03513     sprintf(string, "Axis %d Diagnostics", activeAxis);
03514     setLabel(diagnosticsLabel, string);
03515     dialogPopup(NULL, diagnosticsShell, NULL);
03516     diagnosticsIsPopped = 1;
03517     // trap window kill
03518     XSetWMProtocols(XtDisplay(topLevel), XtWindow(diagnosticsShell), &killAtom, 1);
03519     break;
03520 
03521   default:
03522     break;
03523   }
03524 }
03525 
03526 // calibration dialog
03527 
03528 static Widget calibShell = NULL;
03529 static Widget calibForm = NULL;
03530 static Widget calibLabel = NULL;
03531 static Widget calibCycleTimeLabel = NULL;
03532 static Widget calibCycleTime = NULL;
03533 static Widget calibPGainLabel = NULL;
03534 static Widget calibPGain = NULL;
03535 static Widget calibIGainLabel = NULL;
03536 static Widget calibIGain = NULL;
03537 static Widget calibDGainLabel = NULL;
03538 static Widget calibDGain = NULL;
03539 static Widget calibFF0GainLabel = NULL;
03540 static Widget calibFF0Gain = NULL;
03541 static Widget calibFF1GainLabel = NULL;
03542 static Widget calibFF1Gain = NULL;
03543 static Widget calibFF2GainLabel = NULL;
03544 static Widget calibFF2Gain = NULL;
03545 static Widget calibBacklashLabel = NULL;
03546 static Widget calibBacklash = NULL;
03547 static Widget calibBiasLabel = NULL;
03548 static Widget calibBias = NULL;
03549 static Widget calibMaxErrorLabel = NULL;
03550 static Widget calibMaxError = NULL;
03551 static Widget calibOutputScaleLabel = NULL;
03552 static Widget calibOutputScale = NULL;
03553 static Widget calibOutputOffsetLabel = NULL;
03554 static Widget calibOutputOffset = NULL;
03555 static Widget calibFerrorLabel = NULL;
03556 static Widget calibFerror = NULL;
03557 static Widget calibDone = NULL;
03558 static Widget calibCancel = NULL;
03559 
03560 static int calibReturnIsDone = 1;
03561 static Pixel calibFormBorderColor;
03562 static void calibDoDone(int done);
03563 static void calibDoneCB(Widget w, XtPointer client_data, XtPointer call_data);
03564 static void calibCancelCB(Widget w, XtPointer client_data, XtPointer call_data);
03565 static void calibReturnAction(Widget w, XEvent *event, String *params, Cardinal *num_params);
03566 static void calibTabAction(Widget w, XEvent *event, String *params, Cardinal *num_params);
03567 
03568 static void calibDoDone(int done)
03569 {
03570   int iserror = 0;
03571   String str1, str2, str3, str4, str5, str6, str7, str8, str9, str10, str11, str12, str13;
03572   double cycleTime;
03573   double p;
03574   double i;
03575   double d;
03576   double ff0;
03577   double ff1;
03578   double ff2;
03579   double bias;
03580   double backlash;
03581   double maxError;
03582   double outputScale;
03583   double outputOffset;
03584   double ferror;
03585 
03586   if (done) {
03587     // get current values for rest of gains
03588     cycleTime = emcStatus->motion.axis[activeAxis].cycleTime;
03589     p = emcStatus->motion.axis[activeAxis].p;
03590     i = emcStatus->motion.axis[activeAxis].i;
03591     d = emcStatus->motion.axis[activeAxis].d;
03592     ff0 = emcStatus->motion.axis[activeAxis].ff0;
03593     ff1 = emcStatus->motion.axis[activeAxis].ff1;
03594     ff2 = emcStatus->motion.axis[activeAxis].ff2;
03595     backlash = emcStatus->motion.axis[activeAxis].backlash;
03596     bias = emcStatus->motion.axis[activeAxis].bias;
03597     maxError = emcStatus->motion.axis[activeAxis].maxError;
03598     outputScale = emcStatus->motion.axis[activeAxis].outputScale;
03599     outputOffset = emcStatus->motion.axis[activeAxis].outputOffset;
03600 
03601     XtVaGetValues(calibCycleTime, XtNstring, &str1, NULL);
03602     XtVaGetValues(calibPGain, XtNstring, &str2, NULL);
03603     XtVaGetValues(calibIGain, XtNstring, &str3, NULL);
03604     XtVaGetValues(calibDGain, XtNstring, &str4, NULL);
03605     XtVaGetValues(calibFF0Gain, XtNstring, &str5, NULL);
03606     XtVaGetValues(calibFF1Gain, XtNstring, &str6, NULL);
03607     XtVaGetValues(calibFF2Gain, XtNstring, &str7, NULL);
03608     XtVaGetValues(calibBacklash, XtNstring, &str8, NULL);
03609     XtVaGetValues(calibBias, XtNstring, &str9, NULL);
03610     XtVaGetValues(calibMaxError, XtNstring, &str10, NULL);
03611     XtVaGetValues(calibOutputScale, XtNstring, &str11, NULL);
03612     XtVaGetValues(calibOutputOffset, XtNstring, &str12, NULL);
03613     XtVaGetValues(calibFerror, XtNstring, &str13, NULL);
03614 
03615     if (1 == sscanf(str1, "%lf", &cycleTime) &&
03616         1 == sscanf(str2, "%lf", &p) &&
03617         1 == sscanf(str3, "%lf", &i) &&
03618         1 == sscanf(str4, "%lf", &d) &&
03619         1 == sscanf(str5, "%lf", &ff0) &&
03620         1 == sscanf(str6, "%lf", &ff1) &&
03621         1 == sscanf(str7, "%lf", &ff2) &&
03622         1 == sscanf(str8, "%lf", &backlash) &&
03623         1 == sscanf(str9, "%lf", &bias) &&
03624         1 == sscanf(str10, "%lf", &maxError) &&
03625         1 == sscanf(str11, "%lf", &outputScale) &&
03626         1 == sscanf(str12, "%lf", &outputOffset) &&
03627         1 == sscanf(str13, "%lf", &ferror)) {
03628       sendAxisCycleTime(activeAxis, cycleTime);
03629       emcCommandWaitDone(emcCommandSerialNumber);
03630       sendAxisSetGains(activeAxis, p, i, d, ff0, ff1, ff2, backlash, bias, maxError);
03631       emcCommandWaitDone(emcCommandSerialNumber);
03632       sendAxisSetOutputScale(activeAxis, outputScale, outputOffset);
03633       emcCommandWaitDone(emcCommandSerialNumber);
03634       sendAxisSetFerror(activeAxis, ferror);
03635     }
03636     else {
03637       iserror = 1;
03638     }
03639   }
03640 
03641   calibReturnIsDone = 1;
03642   XtPopdown(calibShell);
03643 
03644   if (iserror) {
03645     popupError("Bad gain values");
03646   }
03647 }
03648 
03649 static void calibDoneCB(Widget w, XtPointer client_data, XtPointer call_data)
03650 {
03651   calibDoDone(1);
03652 }
03653 
03654 static void calibCancelCB(Widget w, XtPointer client_data, XtPointer call_data)
03655 {
03656   calibDoDone(0);
03657 }
03658 
03659 static void calibReturnAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
03660 {
03661   if (calibReturnIsDone) {
03662     calibDoDone(1);
03663   }
03664   else {
03665     calibDoDone(0);
03666   }
03667 }
03668 
03669 static void calibTabAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
03670 {
03671   if (calibReturnIsDone) {
03672     setBorderColor(calibDone, calibFormBorderColor);
03673     setBorderColor(calibCancel, pixelRed);
03674     calibReturnIsDone = 0;
03675   }
03676   else {
03677     setBorderColor(calibDone, pixelRed);
03678     setBorderColor(calibCancel, calibFormBorderColor);
03679     calibReturnIsDone = 1;
03680   }
03681 }
03682 
03683 // logging dialog
03684 
03685 static Widget loggingShell = NULL;
03686 static Widget loggingForm = NULL;
03687 static Widget loggingLabel = NULL;
03688 static Widget loggingFileLabel = NULL;
03689 static Widget loggingFile = NULL;
03690 static Widget loggingTypeLabel = NULL;
03691 static Widget loggingTypeMenu = NULL;
03692 static Widget loggingSizeLabel = NULL;
03693 static Widget loggingSize = NULL;
03694 static Widget loggingSkipLabel = NULL;
03695 static Widget loggingSkip = NULL;
03696 static Widget loggingStart = NULL;
03697 static Widget loggingStop = NULL;
03698 static Widget loggingSave = NULL;
03699 static Widget loggingPlot = NULL;
03700 
03701 static Widget loggingDone = NULL;
03702 static Widget loggingCancel = NULL;
03703 
03704 static int loggingReturnIsDone = 1;
03705 static Pixel loggingFormBorderColor;
03706 static int loggingGetStrings();
03707 static void loggingDoDone(int done);
03708 static void loggingStartCB(Widget w, XtPointer client_data, XtPointer call_data);
03709 static void loggingStopCB(Widget w, XtPointer client_data, XtPointer call_data);
03710 static void loggingSaveCB(Widget w, XtPointer client_data, XtPointer call_data);
03711 static void loggingPlotCB(Widget w, XtPointer client_data, XtPointer call_data);
03712 static void loggingDoneCB(Widget w, XtPointer client_data, XtPointer call_data);
03713 static void loggingCancelCB(Widget w, XtPointer client_data, XtPointer call_data);
03714 static void loggingReturnAction(Widget w, XEvent *event, String *params, Cardinal *num_params);
03715 static void loggingTabAction(Widget w, XEvent *event, String *params, Cardinal *num_params);
03716 
03717 static int loggingGetStrings()
03718 {
03719   int iserror = 0;
03720   String str1, str2, str3;
03721 
03722   XtVaGetValues(loggingFile, XtNstring, &str1, NULL);
03723   XtVaGetValues(loggingSize, XtNstring, &str2, NULL);
03724   XtVaGetValues(loggingSkip, XtNstring, &str3, NULL);
03725 
03726   strcpy(saveLogFile, str1);
03727   if (1 == sscanf(str2, "%d", &saveLogSize) &&
03728       1 == sscanf(str3, "%d", &saveLogSkip)) {
03729     iserror = 0;
03730   }
03731   else {
03732     iserror = 1;
03733   }
03734 
03735   return iserror;
03736 }
03737 
03738 static void loggingDoDone(int done)
03739 {
03740   int retval;
03741 
03742   if (done) {
03743   retval = loggingGetStrings();
03744   }
03745 
03746   loggingReturnIsDone = 1;
03747   XtPopdown(loggingShell);
03748 
03749   if (done &&
03750       0 != retval) {
03751     popupError("Bad log values");
03752   }
03753 }
03754 
03755 static void loggingStartCB(Widget w, XtPointer client_data, XtPointer call_data)
03756 {
03757   int retval;
03758 
03759   retval = loggingGetStrings();
03760 
03761   if (0 != retval) {
03762     popupError("Bad log values");
03763   }
03764   else {
03765     sendLogStart();
03766   }
03767 }
03768 
03769 static void loggingStopCB(Widget w, XtPointer client_data, XtPointer call_data)
03770 {
03771   sendLogStop();
03772 }
03773 
03774 static void loggingSaveCB(Widget w, XtPointer client_data, XtPointer call_data)
03775 {
03776   sendLogClose();
03777 }
03778 
03779 static void loggingPlotCB(Widget w, XtPointer client_data, XtPointer call_data)
03780 {
03781   plotLog(saveLogFile, saveLogType);
03782 }
03783 
03784 static void loggingDoneCB(Widget w, XtPointer client_data, XtPointer call_data)
03785 {
03786   loggingDoDone(1);
03787 }
03788 
03789 static void loggingCancelCB(Widget w, XtPointer client_data, XtPointer call_data)
03790 {
03791   loggingDoDone(0);
03792 }
03793 
03794 static void loggingReturnAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
03795 {
03796   if (loggingReturnIsDone) {
03797     loggingDoDone(1);
03798   }
03799   else {
03800     loggingDoDone(0);
03801   }
03802 }
03803 
03804 static void loggingTabAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
03805 {
03806   if (loggingReturnIsDone) {
03807     setBorderColor(loggingDone, loggingFormBorderColor);
03808     setBorderColor(loggingCancel, pixelRed);
03809     loggingReturnIsDone = 0;
03810   }
03811   else {
03812     setBorderColor(loggingDone, pixelRed);
03813     setBorderColor(loggingCancel, loggingFormBorderColor);
03814     loggingReturnIsDone = 1;
03815   }
03816 }
03817 
03818 // menu select functions
03819 
03820 static void settingsMenuSelect(Widget w, XtPointer client_data, XtPointer call_data)
03821 {
03822   char string[256];             // FIXME-- hardcoded value
03823 
03824   switch ((int) client_data) {
03825   case 0:                       // Relative
03826     coords = COORD_RELATIVE;
03827     break;
03828 
03829   case 1:                       // Machine
03830     coords = COORD_MACHINE;
03831     break;
03832 
03833     // case 2 is separator
03834 
03835   case 3:                       // Actual
03836     posDisplay = POS_DISPLAY_ACT;
03837     break;
03838 
03839   case 4:                       // Commanded
03840     posDisplay = POS_DISPLAY_CMD;
03841     break;
03842 
03843     // case 5 is separator
03844 
03845   case 6:                       // Calibration...
03846 
03847     sprintf(string, "Axis %d Calibration", activeAxis);
03848     XtVaSetValues(calibLabel, XtNlabel, string, NULL);
03849 
03850     sprintf(string, "%f", emcStatus->motion.axis[activeAxis].cycleTime);
03851     XtVaSetValues(calibCycleTime, XtNstring, string, NULL);
03852 
03853     sprintf(string, "%f", emcStatus->motion.axis[activeAxis].p);
03854     XtVaSetValues(calibPGain, XtNstring, string, NULL);
03855     sprintf(string, "%f", emcStatus->motion.axis[activeAxis].i);
03856     XtVaSetValues(calibIGain, XtNstring, string, NULL);
03857     sprintf(string, "%f", emcStatus->motion.axis[activeAxis].d);
03858     XtVaSetValues(calibDGain, XtNstring, string, NULL);
03859 
03860     sprintf(string, "%f", emcStatus->motion.axis[activeAxis].ff0);
03861     XtVaSetValues(calibFF0Gain, XtNstring, string, NULL);
03862     sprintf(string, "%f", emcStatus->motion.axis[activeAxis].ff1);
03863     XtVaSetValues(calibFF1Gain, XtNstring, string, NULL);
03864     sprintf(string, "%f", emcStatus->motion.axis[activeAxis].ff2);
03865     XtVaSetValues(calibFF2Gain, XtNstring, string, NULL);
03866 
03867     sprintf(string, "%f", emcStatus->motion.axis[activeAxis].backlash);
03868     XtVaSetValues(calibBacklash, XtNstring, string, NULL);
03869     sprintf(string, "%f", emcStatus->motion.axis[activeAxis].bias);
03870     XtVaSetValues(calibBias, XtNstring, string, NULL);
03871     sprintf(string, "%f", emcStatus->motion.axis[activeAxis].maxError);
03872     XtVaSetValues(calibMaxError, XtNstring, string, NULL);
03873 
03874     sprintf(string, "%f", emcStatus->motion.axis[activeAxis].outputScale);
03875     XtVaSetValues(calibOutputScale, XtNstring, string, NULL);
03876     sprintf(string, "%f", emcStatus->motion.axis[activeAxis].outputOffset);
03877     XtVaSetValues(calibOutputOffset, XtNstring, string, NULL);
03878 
03879     sprintf(string, "%f", emcStatus->motion.axis[activeAxis].maxFerror);
03880     XtVaSetValues(calibFerror, XtNstring, string, NULL);
03881 
03882     dialogPopup(NULL, calibShell, NULL);
03883     // trap window kill
03884     XSetWMProtocols(XtDisplay(topLevel), XtWindow(calibShell), &killAtom, 1);
03885     break;
03886 
03887   case 7:                       // Logging...
03888     XtVaSetValues(loggingFile, XtNstring, saveLogFile, NULL);
03889     sprintf(string,
03890             saveLogType == EMC_LOG_TYPE_AXIS_POS ?    "Axis Position" :
03891             saveLogType == EMC_LOG_TYPE_AXES_INPOS ?  "All Input Positions" :
03892             saveLogType == EMC_LOG_TYPE_AXES_OUTPOS ? "All Output Positions" :
03893             saveLogType == EMC_LOG_TYPE_AXIS_VEL ?    "Axis Velocity" :
03894             saveLogType == EMC_LOG_TYPE_AXES_FERROR ? "All Following Errors" :
03895             saveLogType == EMC_LOG_TYPE_TRAJ_POS ? "All Trajectory Points" :
03896             saveLogType == EMC_LOG_TYPE_TRAJ_VEL ? "All Trajectory Vels" :
03897             saveLogType == EMC_LOG_TYPE_TRAJ_ACC ? "All Trajectory Accels" :
03898             "(unknown)");
03899     XtVaSetValues(loggingTypeMenu, XtNlabel, string, NULL);
03900     sprintf(string, "%d", saveLogSize);
03901     XtVaSetValues(loggingSize, XtNstring, string, NULL);
03902     sprintf(string, "%d", saveLogSkip);
03903     XtVaSetValues(loggingSkip, XtNstring, string, NULL);
03904 
03905     dialogPopup(NULL, loggingShell, NULL);
03906     // trap window kill
03907     XSetWMProtocols(XtDisplay(topLevel), XtWindow(loggingShell), &killAtom, 1);
03908     break;
03909 
03910   default:
03911     break;
03912   }
03913 }
03914 
03915 static void helpMenuSelect(Widget w, XtPointer client_data, XtPointer call_data)
03916 {
03917   switch ((int) client_data) {
03918   case 0:                       // Help...
03919     dialogPopup(w, helpXemcShell, NULL);
03920     // trap window kill
03921     XSetWMProtocols(XtDisplay(topLevel), XtWindow(helpXemcShell), &killAtom, 1);
03922     break;
03923 
03924     // case 1 is separator
03925 
03926   case 2:                       // About...
03927     dialogPopup(NULL, helpAboutShell, NULL);
03928     XSetWMProtocols(XtDisplay(topLevel), XtWindow(helpAboutShell), &killAtom, 1);
03929     break;
03930 
03931   default:
03932     break;
03933   }
03934 }
03935 
03936 static void stateMenuSelect(Widget w, XtPointer client_data, XtPointer call_data)
03937 {
03938   switch ((int) client_data) {
03939   case 0:
03940     sendEstop();
03941     break;
03942 
03943   case 1:
03944     sendEstopReset();
03945     break;
03946 
03947     // case 2 is separator
03948 
03949   case 3:
03950     sendMachineOn();
03951     break;
03952 
03953   case 4:
03954     sendMachineOff();
03955     break;
03956 
03957   default:
03958     break;
03959   }
03960 }
03961 
03962 static void modeMenuSelect(Widget w, XtPointer client_data, XtPointer call_data)
03963 {
03964   switch ((int) client_data) {
03965   case 0:
03966     sendManual();
03967     break;
03968 
03969   case 1:
03970     sendAuto();
03971     break;
03972 
03973   case 2:
03974     sendMdi();
03975     break;
03976 
03977   default:
03978     break;
03979   }
03980 }
03981 
03982 static void mistMenuSelect(Widget w, XtPointer client_data, XtPointer call_data)
03983 {
03984   switch ((int) client_data) {
03985   case 0:
03986     sendMistOn();
03987     break;
03988 
03989   case 1:
03990     sendMistOff();
03991     break;
03992 
03993   default:
03994     break;
03995   }
03996 }
03997 
03998 static void floodMenuSelect(Widget w, XtPointer client_data, XtPointer call_data)
03999 {
04000   switch ((int) client_data) {
04001   case 0:
04002     sendFloodOn();
04003     break;
04004 
04005   case 1:
04006     sendFloodOff();
04007     break;
04008 
04009   default:
04010     break;
04011   }
04012 }
04013 
04014 static void spindleMenuSelect(Widget w, XtPointer client_data, XtPointer call_data)
04015 {
04016   switch ((int) client_data) {
04017   case 0:
04018     sendSpindleForward();
04019     break;
04020 
04021   case 1:
04022     sendSpindleReverse();
04023     break;
04024 
04025   case 2:
04026     sendSpindleOff();
04027     break;
04028 
04029   default:
04030     break;
04031   }
04032 }
04033 
04034 static void brakeMenuSelect(Widget w, XtPointer client_data, XtPointer call_data)
04035 {
04036   switch ((int) client_data) {
04037   case 0:
04038     sendBrakeEngage();
04039     break;
04040 
04041   case 1:
04042     sendBrakeRelease();
04043     break;
04044 
04045   default:
04046     break;
04047   }
04048 }
04049 
04050 static void jogIncrementMenuSelect(Widget w, XtPointer client_data, XtPointer call_data)
04051 {
04052   switch ((int) client_data) {
04053   case 0:
04054     jogIncrement = 0.1000;
04055     break;
04056 
04057   case 1:
04058     jogIncrement = 0.0100;
04059     break;
04060 
04061   case 2:
04062     jogIncrement = 0.0010;
04063     break;
04064 
04065   case 3:
04066     jogIncrement = stepIncrement;
04067     break;
04068 
04069     // case 4 is separator
04070 
04071   case 5:
04072     jogIncrement = -1.0;
04073     break;
04074 
04075   default:
04076     break;
04077   }
04078 }
04079 
04080 static void loggingTypeMenuSelect(Widget w, XtPointer client_data, XtPointer call_data)
04081 {
04082   char string[256];
04083 
04084   switch ((int) client_data) {
04085   case 0:
04086     saveLogType = EMC_LOG_TYPE_AXIS_POS;
04087     break;
04088 
04089   case 1:
04090     saveLogType = EMC_LOG_TYPE_AXES_INPOS;
04091     break;
04092 
04093   case 2:
04094     saveLogType = EMC_LOG_TYPE_AXES_OUTPOS;
04095     break;
04096 
04097   case 3:
04098     saveLogType = EMC_LOG_TYPE_AXIS_VEL;
04099     break;
04100 
04101   case 4:
04102     saveLogType = EMC_LOG_TYPE_AXES_FERROR;
04103     break;
04104 
04105   case 5:
04106     saveLogType = EMC_LOG_TYPE_TRAJ_POS;
04107     break;
04108 
04109   case 6:
04110     saveLogType = EMC_LOG_TYPE_TRAJ_VEL;
04111     break;
04112 
04113   case 7:
04114     saveLogType = EMC_LOG_TYPE_TRAJ_ACC;
04115     break;
04116 
04117   default:
04118     break;
04119   }
04120 
04121   sprintf(string,
04122           saveLogType == EMC_LOG_TYPE_AXIS_POS ?    "Axis Position" :
04123           saveLogType == EMC_LOG_TYPE_AXES_INPOS ?  "All Input Positions" :
04124           saveLogType == EMC_LOG_TYPE_AXES_OUTPOS ? "All Output Positions" :
04125           saveLogType == EMC_LOG_TYPE_AXIS_VEL ?    "Axis Velocity" :
04126           saveLogType == EMC_LOG_TYPE_AXES_FERROR ? "All Following Errors" :
04127           saveLogType == EMC_LOG_TYPE_TRAJ_POS ? "All Trajectory Points" :
04128           saveLogType == EMC_LOG_TYPE_TRAJ_VEL ? "All Trajectory Vels" :
04129           saveLogType == EMC_LOG_TYPE_TRAJ_ACC ? "All Trajectory Accels" :
04130           "(unknown)");
04131   XtVaSetValues(loggingTypeMenu, XtNlabel, string, NULL);
04132 }
04133 
04134 // menu dimming
04135 
04136 static void enableAuxMenus(Boolean torf)
04137 {
04138   static Boolean auxMenusEnabled = True;
04139 
04140   if (auxMenusEnabled != torf) {
04141     XtSetSensitive(mistMenu, torf);
04142     XtSetSensitive(floodMenu, torf);
04143     XtSetSensitive(spindleMenu, torf);
04144     XtSetSensitive(brakeMenu, torf);
04145     auxMenusEnabled = torf;
04146   }
04147 }
04148 
04149 static void enableManualMenus(Boolean torf)
04150 {
04151   static Boolean manualMenusEnabled = True;
04152 
04153   if (manualMenusEnabled != torf) {
04154     XtSetSensitive(jogMinusLabel, torf);
04155     XtSetSensitive(homeCommand, torf);
04156     XtSetSensitive(jogPlusLabel, torf);
04157     XtSetSensitive(programPauseCommand, torf);
04158     XtSetSensitive(programResumeCommand, torf);
04159     manualMenusEnabled = torf;
04160   }
04161 }
04162 
04163 static void enableAutoMenus(Boolean torf)
04164 {
04165   static Boolean autoMenusEnabled = True;
04166 
04167   if (autoMenusEnabled != torf) {
04168     XtSetSensitive(programOpenCommand, torf);
04169     XtSetSensitive(programRunCommand, torf);
04170     XtSetSensitive(programPauseCommand, torf);
04171     XtSetSensitive(programResumeCommand, torf);
04172     XtSetSensitive(programStepCommand, torf);
04173     XtSetSensitive(programVerifyCommand, torf);
04174     autoMenusEnabled = torf;
04175   }
04176 }
04177 
04178 static void enableMdiMenus(Boolean torf)
04179 {
04180   static Boolean mdiMenusEnabled = True;
04181 
04182   if (mdiMenusEnabled != torf) {
04183     //FIXME    XtSetSensitive(mdiFormText, torf);
04184     XtSetSensitive(programPauseCommand, torf);
04185     XtSetSensitive(programResumeCommand, torf);
04186     mdiMenusEnabled = torf;
04187   }
04188 
04189   if (torf) {
04190     /* set focus to mdi window */
04191     XtSetKeyboardFocus(topForm, mdiFormText);
04192   }
04193   else {
04194     XtSetKeyboardFocus(topForm, None);
04195   }
04196 }
04197 
04198 // saved old values, used to determine if redraw is necessary.
04199 // Make them invalid so that everything is updated at startup, or
04200 // at least make them the same as the initial labels.
04201 static unsigned long int oldTaskHeartbeat = 0;
04202 static unsigned long int oldIoHeartbeat = 0;
04203 static unsigned long int oldMotionHeartbeat = 0;
04204 static double oldAxisFerror[XEMC_NUM_AXES]; // inited to invalid in main()
04205 static int oldOverrideLimits = -1;
04206 static int oldState = -1;
04207 static int oldMode = -1;
04208 static int oldMist = -1;
04209 static int oldFlood = -1;
04210 static int oldSpindleIncreasing = -1;
04211 static int oldSpindleDirection = -2;
04212 static int oldBrake = -1;
04213 static int oldTool = -1;
04214 static double oldToolOffset = DBL_MAX; // invalid val forces first print
04215 static double oldXOffset = DBL_MAX; // ditto
04216 static double oldYOffset = DBL_MAX;
04217 static double oldZOffset = DBL_MAX;
04218 static double oldX = DBL_MAX;
04219 static double oldY = DBL_MAX;
04220 static double oldZ = DBL_MAX;
04221 static int oldCoords = 0; // invalid val forces first print
04222 static int oldPosDisplay = 0; // ditto
04223 static double oldJogIncrement = -1.0; // invalid val forces first print
04224 static Pixel posColor[XEMC_NUM_AXES]; // inited to invalid in main()
04225 static int oldLogOpen = -1;
04226 static int oldLogStarted = -1;
04227 static int oldLogPoints = -1;
04228 static char oldMdiCodes[256] = ""; // FIXME-- harcoded
04229 static int oldProgramActiveLine = -1;
04230 static char oldProgramString[256] = "";
04231 
04232 void timeoutCB(XtPointer clientdata, XtIntervalId *id)
04233 {
04234   double now;
04235   char string[256];             // FIXME-- hardcoded
04236   int t;
04237   int changedPositionType;
04238   double newX, newY, newZ;
04239   int code;
04240   int programActiveLine;
04241   int programTopLine;
04242   char mdiCodes[256];           // FIXME-- hardcoded
04243 
04244   // set the time
04245   now = etime();
04246 
04247   // read the EMC status
04248   if (0 != updateStatus()) {
04249     sprintf(error_string, "bad status");
04250   }
04251 
04252   // read the EMC errors
04253   if (0 != updateError()) {
04254     sprintf(error_string, "bad status");
04255   }
04256 
04257   // print any result stored by updateError() in error_string
04258   if (error_string[0] != 0) {
04259     popupError(error_string);
04260     error_string[0] = 0;
04261   }
04262 
04263   // handle key up events
04264   if (keyReleaseOut &&
04265       now - keyReleaseTime > 0.100) {
04266     // key up event has occurred
04267     keyReleaseOut = 0;
04268     keyReleaseAction(keyReleaseState, keyReleaseKeycode);
04269   }
04270 
04271   // handle button press repeats
04272 
04273   if (jogSpeedChange < 0) {
04274     if (--jogSpeed <= 0) {
04275       jogSpeed = 1;
04276     }
04277     sprintf(string, "%d", jogSpeed);
04278     setLabel(jogSpeedLabel, string);
04279     redraw = 1;
04280   }
04281   else if (jogSpeedChange > 0) {
04282     if (++jogSpeed > maxJogSpeed) {
04283       jogSpeed = maxJogSpeed;
04284     }
04285     sprintf(string, "%d", jogSpeed);
04286     setLabel(jogSpeedLabel, string);
04287     redraw = 1;
04288   }
04289 
04290   if (feedOverrideChange < 0) {
04291     if (--feedOverrideDelayCount < 0) {
04292       if ((feedOverride -= 10) < 0) {
04293         feedOverride = 0;
04294       }
04295       sprintf(string, "%3d", feedOverride);
04296       setLabel(feedOverrideLabel, string);
04297       feedOverrideDelayCount = FEED_OVERRIDE_DELAY_COUNT;
04298 
04299       redraw = 1;
04300     }
04301   }
04302   else if (feedOverrideChange > 0) {
04303     if (--feedOverrideDelayCount < 0) {
04304       if ((feedOverride += 10) > maxFeedOverride) {
04305         feedOverride = maxFeedOverride;
04306       }
04307       sprintf(string, "%3d", feedOverride);
04308       setLabel(feedOverrideLabel, string);
04309       feedOverrideDelayCount = FEED_OVERRIDE_DELAY_COUNT;
04310       redraw = 1;
04311     }
04312   }
04313   else {
04314     // we're not changing it, so update it from EMC value
04315     feedOverride = (int) (emcStatus->motion.traj.scale * 100.0 + 0.5);
04316     if (feedOverride != oldFeedOverride) {
04317       oldFeedOverride = feedOverride;
04318       sprintf(string, "%3d", feedOverride);
04319       setLabel(feedOverrideLabel, string);
04320       redraw = 1;
04321     }
04322   }
04323 
04324   // handle internal status changes
04325 
04326   if (activeAxis != oldActiveAxis) {
04327     if (activeAxis == 0) {
04328       setBorderColor(posLabel[0], posLabelBorderColor[0]);
04329       setBorderColor(posLabel[1], posLabelBackground[1]);
04330       setBorderColor(posLabel[2], posLabelBackground[2]);
04331     }
04332     else if (activeAxis == 1) {
04333       setBorderColor(posLabel[0], posLabelBackground[0]);
04334       setBorderColor(posLabel[1], posLabelBorderColor[1]);
04335       setBorderColor(posLabel[2], posLabelBackground[2]);
04336     }
04337     else if (activeAxis == 2) {
04338       setBorderColor(posLabel[0], posLabelBackground[0]);
04339       setBorderColor(posLabel[1], posLabelBackground[1]);
04340       setBorderColor(posLabel[2], posLabelBorderColor[2]);
04341     }
04342     redraw = 1;
04343 
04344     oldActiveAxis = activeAxis;
04345   }
04346 
04347   if (jogIncrement != oldJogIncrement) {
04348     if (jogIncrement > stepIncrement) {
04349       sprintf(string, "%1.4f", jogIncrement);
04350     }
04351     else if (jogIncrement > 0.0) {
04352       sprintf(string, "%1.6f", jogIncrement);
04353     }
04354     else {
04355       sprintf(string, "continuous");
04356     }
04357     setLabel(jogIncrementMenu, string);
04358     redraw = 1;
04359 
04360     oldJogIncrement = jogIncrement;
04361   }
04362 
04363   // handle EMC status changes
04364   /*
04365     Note that changing the label changes the size of the label,
04366     but not the size of the enclosing box. So, the initial label
04367     width will set the size of the enclosing box, but won't have
04368     any other effect during the life of the label. For this reason
04369     label widths for dynamically labeled labels are not specified,
04370     and they are set manually before the labels are realized to a
04371     blank string the same width of the labels. If you use proportional
04372     fonts for the labels, they will change in size.
04373   */
04374 
04375   if (diagnosticsIsPopped) {
04376     if (emcStatus->task.heartbeat != oldTaskHeartbeat) {
04377       sprintf(string, "%ld %ld %d %d %d",
04378               emcStatus->task.heartbeat,
04379               emcStatus->task.command_type,
04380               emcStatus->task.echo_serial_number,
04381               emcStatus->task.status,
04382               emcStatus->task.execState);
04383       setLabel(diagnosticsTaskHB, string);
04384       redraw = 1;
04385 
04386       oldTaskHeartbeat = emcStatus->task.heartbeat;
04387     }
04388 
04389     if (emcStatus->io.heartbeat != oldIoHeartbeat) {
04390       sprintf(string, "%ld %ld %d %d",
04391               emcStatus->io.heartbeat,
04392               emcStatus->io.command_type,
04393               emcStatus->io.echo_serial_number,
04394               emcStatus->io.status);
04395       setLabel(diagnosticsIoHB, string);
04396       redraw = 1;
04397 
04398       oldIoHeartbeat = emcStatus->io.heartbeat;
04399     }
04400 
04401     if (emcStatus->motion.heartbeat != oldMotionHeartbeat) {
04402       sprintf(string, "%ld %ld %d %d",
04403               emcStatus->motion.heartbeat,
04404               emcStatus->motion.command_type,
04405               emcStatus->motion.echo_serial_number,
04406               emcStatus->motion.status);
04407       setLabel(diagnosticsMotionHB, string);
04408       redraw = 1;
04409 
04410       oldMotionHeartbeat = emcStatus->motion.heartbeat;
04411     }
04412 
04413     // FIXME: We are only displaying the HighMark, it would be nice to
04414     // see the current ferror also.
04415     if (emcStatus->motion.axis[activeAxis].ferrorHighMark !=
04416         oldAxisFerror[activeAxis]) {
04417       sprintf(string, "%.3f", emcStatus->motion.axis[activeAxis].ferrorHighMark);
04418       setLabel(diagnosticsFerror, string);
04419       redraw = 1;
04420 
04421       oldAxisFerror[activeAxis] = emcStatus->motion.axis[activeAxis].ferrorHighMark;
04422     }
04423   }
04424 
04425   if (emcStatus->motion.axis[0].overrideLimits &&
04426       1 != oldOverrideLimits) {
04427     setColor(limCommand, pixelRed, 0);
04428     oldOverrideLimits = 1;
04429   }
04430   else if (! emcStatus->motion.axis[0].overrideLimits &&
04431            0 != oldOverrideLimits) {
04432     setColor(limCommand, pixelWhite, 0);
04433     oldOverrideLimits = 0;
04434   }
04435 
04436   if (emcStatus->task.state != oldState) {
04437     switch(emcStatus->task.state) {
04438     case EMC_TASK_STATE_OFF:
04439       sprintf(string, "OFF");
04440       break;
04441     case EMC_TASK_STATE_ON:
04442       sprintf(string, "ON");
04443       break;
04444     case EMC_TASK_STATE_ESTOP:
04445       sprintf(string, "ESTOP");
04446       break;
04447     case EMC_TASK_STATE_ESTOP_RESET:
04448       sprintf(string, "ESTOP RESET");
04449       break;
04450     default:
04451       sprintf(string, "?");
04452       break;
04453     }
04454 
04455     setLabel(stateMenu, string);
04456     redraw = 1;
04457 
04458     oldState = emcStatus->task.state;
04459   }
04460 
04461   if (emcStatus->task.mode != oldMode) {
04462     switch(emcStatus->task.mode) {
04463     case EMC_TASK_MODE_MANUAL:
04464       sprintf(string, "MANUAL");
04465       break;
04466     case EMC_TASK_MODE_AUTO:
04467       sprintf(string, "AUTO");
04468       break;
04469     case EMC_TASK_MODE_MDI:
04470       sprintf(string, "MDI");
04471       break;
04472     default:
04473       sprintf(string, "?");
04474       break;
04475     }
04476 
04477     setLabel(modeMenu, string);
04478     redraw = 1;
04479 
04480     oldMode = emcStatus->task.mode;
04481   }
04482 
04483   if (emcStatus->io.coolant.mist != oldMist) {
04484     if (emcStatus->io.coolant.mist) {
04485       sprintf(string, "MIST ON");
04486     }
04487     else {
04488       sprintf(string, "MIST OFF");
04489     }
04490 
04491     setLabel(mistMenu, string);
04492     redraw = 1;
04493 
04494     oldMist = emcStatus->io.coolant.mist;
04495   }
04496 
04497   if (emcStatus->io.coolant.flood != oldFlood) {
04498     if (emcStatus->io.coolant.flood) {
04499       sprintf(string, "FLOOD ON");
04500     }
04501     else {
04502       sprintf(string, "FLOOD OFF");
04503     }
04504 
04505     setLabel(floodMenu, string);
04506     redraw = 1;
04507 
04508     oldFlood = emcStatus->io.coolant.flood;
04509   }
04510 
04511   if (emcStatus->io.spindle.increasing != oldSpindleIncreasing) {
04512     if (emcStatus->io.spindle.increasing > 0) {
04513       sprintf(string, "SPINDLE INC");
04514     }
04515     else if (emcStatus->io.spindle.increasing < 0) {
04516       sprintf(string, "SPINDLE DEC");
04517     }
04518     else {
04519       // spindle constant-- flag invalid oldSpindleDirection
04520       // so code below will pick up a redraw
04521       oldSpindleDirection = -2;
04522     }
04523 
04524     setLabel(spindleMenu, string);
04525     redraw = 1;
04526 
04527     oldSpindleIncreasing = emcStatus->io.spindle.increasing;
04528   }
04529 
04530   if (emcStatus->io.spindle.direction != oldSpindleDirection) {
04531     if (emcStatus->io.spindle.direction > 0) {
04532       sprintf(string, "SPINDLE FWD");
04533       XtSetSensitive(spindleDecLabel, True);
04534       XtSetSensitive(spindleIncLabel, True);
04535     }
04536     else if (emcStatus->io.spindle.direction < 0) {
04537       sprintf(string, "SPINDLE REV");
04538       XtSetSensitive(spindleDecLabel, True);
04539       XtSetSensitive(spindleIncLabel, True);
04540     }
04541     else {
04542       sprintf(string, "SPINDLE OFF");
04543       XtSetSensitive(spindleDecLabel, False);
04544       XtSetSensitive(spindleIncLabel, False);
04545     }
04546 
04547     setLabel(spindleMenu, string);
04548     redraw = 1;
04549 
04550     oldSpindleDirection = emcStatus->io.spindle.direction;
04551   }
04552 
04553   if (emcStatus->io.spindle.brake != oldBrake) {
04554     if (emcStatus->io.spindle.brake) {
04555       sprintf(string, "BRAKE ON");
04556     }
04557     else {
04558       sprintf(string, "BRAKE OFF");
04559     }
04560 
04561     setLabel(brakeMenu, string);
04562     redraw = 1;
04563 
04564     oldBrake = emcStatus->io.spindle.brake;
04565   }
04566 
04567   if (emcStatus->io.tool.toolInSpindle != oldTool) {
04568     sprintf(string, "%d", emcStatus->io.tool.toolInSpindle);
04569     setLabel(toolNumberFormName, string);
04570 
04571     redraw = 1;
04572 
04573     oldTool = emcStatus->io.tool.toolInSpindle;
04574   }
04575 
04576   if (emcStatus->task.toolOffset.tran.z != oldToolOffset) {
04577     sprintf(string, "%.4f", emcStatus->task.toolOffset.tran.z);
04578     setLabel(toolOffsetFormName, string);
04579 
04580     redraw = 1;
04581 
04582     oldToolOffset = emcStatus->task.toolOffset.tran.z;
04583   }
04584 
04585   changedPositionType = 0;
04586 
04587   if (posDisplay != oldPosDisplay) {
04588     changedPositionType = 1;
04589     oldPosDisplay = posDisplay;
04590   }
04591 
04592   if (coords != oldCoords) {
04593     changedPositionType = 1;
04594     oldCoords = coords;
04595   }
04596 
04597   // check for
04598   if (changedPositionType) {
04599     sprintf(string, "%s %s",
04600             (posDisplay == POS_DISPLAY_CMD) ? "Commanded" : "Actual",
04601             (coords == COORD_MACHINE) ? "Machine" : "Relative");
04602     setLabel(positionTypeFormName, string);
04603     redraw = 1;
04604   }
04605 
04606   if (changedPositionType) {
04607     if (coords == COORD_MACHINE) {
04608     // switched to machine display, so blank out offsets
04609       string[0] = 0;
04610       setLabel(workOffsetFormName, string);
04611       redraw = 1;
04612     }
04613     else {
04614       // switched to relative display, so redisplay offsets
04615       sprintf(string, "X%.4f  Y%.4f  Z%.4f",
04616               emcStatus->task.origin.tran.x,
04617               emcStatus->task.origin.tran.y,
04618               emcStatus->task.origin.tran.z);
04619       setLabel(workOffsetFormName, string);
04620       redraw = 1;
04621     }
04622   }
04623   else if (emcStatus->task.origin.tran.x != oldXOffset ||
04624            emcStatus->task.origin.tran.y != oldYOffset ||
04625            emcStatus->task.origin.tran.z != oldZOffset) {
04626     if (coords == COORD_MACHINE) {
04627       // display offsets changed, but we're not displaying them
04628     }
04629     else {
04630       // display offsets changed and we are displaying them
04631       sprintf(string, "X%.4f  Y%.4f  Z%.4f",
04632               emcStatus->task.origin.tran.x,
04633               emcStatus->task.origin.tran.y,
04634               emcStatus->task.origin.tran.z);
04635       setLabel(workOffsetFormName, string);
04636       redraw = 1;
04637 
04638       oldXOffset = emcStatus->task.origin.tran.x;
04639       oldYOffset = emcStatus->task.origin.tran.y;
04640       oldZOffset = emcStatus->task.origin.tran.z;
04641     }
04642   }
04643 
04644   // compute new XYZ numbers
04645   if (coords == COORD_MACHINE) {
04646     if (posDisplay == POS_DISPLAY_ACT) {
04647       newX = emcStatus->motion.traj.actualPosition.tran.x;
04648       newY = emcStatus->motion.traj.actualPosition.tran.y;
04649       newZ = emcStatus->motion.traj.actualPosition.tran.z;
04650     }
04651     else {
04652       // POS_DISPLAY_CMD
04653       newX = emcStatus->motion.traj.position.tran.x;
04654       newY = emcStatus->motion.traj.position.tran.y;
04655       newZ = emcStatus->motion.traj.position.tran.z;
04656     }
04657   }
04658   else {
04659     // COORD_RELATIVE
04660     if (posDisplay == POS_DISPLAY_ACT) {
04661       newX = emcStatus->motion.traj.actualPosition.tran.x -
04662         emcStatus->task.origin.tran.x;
04663       newY = emcStatus->motion.traj.actualPosition.tran.y -
04664         emcStatus->task.origin.tran.y;
04665       newZ = emcStatus->motion.traj.actualPosition.tran.z -
04666         emcStatus->task.origin.tran.z -
04667         emcStatus->task.toolOffset.tran.z;
04668     }
04669     else {
04670       // POS_DISPLAY_CMD
04671       newX = emcStatus->motion.traj.position.tran.x -
04672         emcStatus->task.origin.tran.x;
04673       newY = emcStatus->motion.traj.position.tran.y -
04674         emcStatus->task.origin.tran.y;
04675       newZ = emcStatus->motion.traj.position.tran.z -
04676         emcStatus->task.origin.tran.z -
04677         emcStatus->task.toolOffset.tran.z;
04678     }
04679   }
04680 
04681   if (newX != oldX) {
04682     sprintf(string, "X %9.4f", newX);
04683     setLabel(posLabel[0], string);
04684     redraw = 1;
04685 
04686     oldX = newX;
04687   }
04688 
04689   if (newY != oldY) {
04690     sprintf(string, "Y %9.4f", newY);
04691     setLabel(posLabel[1], string);
04692     redraw = 1;
04693 
04694     oldY = newY;
04695   }
04696 
04697   if (newZ != oldZ) {
04698     sprintf(string, "Z %9.4f", newZ);
04699     setLabel(posLabel[2], string);
04700     redraw = 1;
04701 
04702     oldZ = newZ;
04703   }
04704 
04705   // fill in the logging status
04706   if (oldLogOpen != emcStatus->logOpen) {
04707     strcpy(string, emcStatus->logOpen ? "Open" : "Closed");
04708     setLabel(loggingStatusOpenLabel, string);
04709     redraw = 1;
04710 
04711     oldLogOpen = emcStatus->logOpen;
04712   }
04713 
04714   if (oldLogStarted != emcStatus->logStarted) {
04715     strcpy(string, emcStatus->logStarted ? "Logging" : "Not Logging");
04716     setLabel(loggingStatusStartedLabel, string);
04717     redraw = 1;
04718 
04719     oldLogStarted = emcStatus->logStarted;
04720   }
04721 
04722   if (oldLogPoints != emcStatus->logPoints) {
04723     sprintf(string, "%d", emcStatus->logPoints);
04724     setLabel(loggingStatusPointsLabel, string);
04725     redraw = 1;
04726 
04727     oldLogPoints = emcStatus->logPoints;
04728   }
04729 
04730   // fill in the active G codes
04731   active_g_codes_string[0] = 0;
04732   for (t = 1; t < EMC_TASK_ACTIVE_G_CODES; t++) {
04733     code = emcStatus->task.activeGCodes[t];
04734     if (code == -1) {
04735       continue;
04736     }
04737     if (code % 10) {
04738       sprintf(string, "G%.1f ", (double) code / 10.0);
04739     }
04740     else {
04741       sprintf(string, "G%d ", code / 10);
04742     }
04743     strcat(active_g_codes_string, string);
04744   }
04745 
04746   // fill in the active M codes, settings too
04747   active_m_codes_string[0] = 0;
04748   for (t = 1; t < EMC_TASK_ACTIVE_M_CODES; t++) {
04749     code = emcStatus->task.activeMCodes[t];
04750     if (code == -1) {
04751       continue;
04752     }
04753     sprintf(string, "M%d ", code);
04754     strcat(active_m_codes_string, string);
04755   }
04756 
04757   sprintf(mdiCodes, "%s %s", active_g_codes_string, active_m_codes_string);
04758 
04759   // fill in F and S codes also
04760   sprintf(string, " F%.0f", emcStatus->task.activeSettings[1]);
04761   strcat(mdiCodes, string);
04762   sprintf(string, " S%.0f", emcStatus->task.activeSettings[2]);
04763   strcat(mdiCodes, string);
04764 
04765   if (0 != strcmp(oldMdiCodes, mdiCodes)) {
04766     XtVaSetValues(mdiCodesLabel, XtNlabel, mdiCodes, NULL);
04767     strcpy(oldMdiCodes, mdiCodes);
04768   }
04769 
04770   // program text updating
04771 
04772   if (0 != emcStatus->task.file[0] &&
04773       0 != strcmp(programFile, emcStatus->task.file)) {
04774     // new program has been opened-- open it here
04775 
04776     fwClose(&programFw);
04777     oldProgramActiveLine = -1;
04778 
04779     if (0 == fwOpen(&programFw, emcStatus->task.file)) {
04780       // opened successfully locally
04781       // save it to run again
04782       strcpy(lastProgramFile, emcStatus->task.file);
04783       // set string for label
04784       strcpy(string, emcStatus->task.file);
04785     }
04786     else {
04787       // couldn't open it locally
04788       // save it to run again, even though we can't see it
04789       strcpy(lastProgramFile, emcStatus->task.file);
04790       // set string for label
04791       sprintf(string, "(%s not found)", emcStatus->task.file);
04792     }
04793 
04794     // set the program label
04795     setLabel(programFormName, string);
04796     redraw = 1;
04797 
04798     strcpy(programFile, emcStatus->task.file);
04799   }
04800 
04801   // compose program state string
04802   switch (emcStatus->task.interpState) {
04803   case EMC_TASK_INTERP_IDLE:
04804     strcpy(string, "Idle");
04805     break;
04806 
04807   case EMC_TASK_INTERP_READING:
04808   case EMC_TASK_INTERP_WAITING:
04809     strcpy(string, "Running");
04810     break;
04811 
04812   case EMC_TASK_INTERP_PAUSED:
04813     strcpy(string, "PAUSED");
04814     break;
04815 
04816   default:
04817     strcpy(string, "(Idle)");   // shouldn't get here; parens for debug
04818     break;
04819   }
04820   // and print it, if new
04821   if (strcmp(string, oldProgramString)) {
04822     setLabel(programFormState, string);
04823     redraw = 1;
04824 
04825     strcpy(oldProgramString, string);
04826   }
04827 
04828   // print active line and next few in window
04829 
04830   if (programStartLineLast < 0 ||
04831       emcStatus->task.readLine < programStartLineLast) {
04832     // controller is skipping lines
04833     programActiveLine = emcStatus->task.readLine;
04834   }
04835   else {                        // controller is not skipping lines
04836     if (emcStatus->task.currentLine > 0) {
04837       if (emcStatus->task.motionLine > 0 &&
04838           emcStatus->task.motionLine < emcStatus->task.currentLine) {
04839         // active line is the motion line, which lags
04840         programActiveLine = emcStatus->task.motionLine;
04841       }
04842       else {
04843         // active line is the current line-- no motion lag
04844         programActiveLine = emcStatus->task.currentLine;
04845       }
04846     }
04847     else {
04848       // no active line at all
04849       programActiveLine = 0;
04850     }
04851   } // end of else controller is not skipping lines
04852 
04853   if (programActiveLine != oldProgramActiveLine) {
04854     programTopLine = programActiveLine - 2;
04855     if (programTopLine < 1) {
04856       programTopLine = 1;
04857     }
04858     fwSyncLine(&programFw, programTopLine);
04859     fwString(&programFw, programFwString);
04860     setProgramText(programFwString);
04861     highlightProgramText(programFwString, programActiveLine - programTopLine);
04862     redraw = 1;
04863 
04864     oldProgramActiveLine = programActiveLine;
04865   }
04866 
04867   // set label colors: do red for limit first
04868   for (t = 0; t < XEMC_NUM_AXES; t++) {
04869     if (emcStatus->motion.axis[t].minHardLimit ||
04870         emcStatus->motion.axis[t].minSoftLimit ||
04871         emcStatus->motion.axis[t].maxSoftLimit ||
04872         emcStatus->motion.axis[t].maxHardLimit) {
04873       if (posColor[t] != pixelRed) {
04874         setColor(posLabel[t], pixelRed, 1);
04875         posColor[t] = pixelRed;
04876       }
04877     }
04878     else if (emcStatus->motion.axis[t].homed &&
04879              posColor[t] != pixelGreen) {
04880       setColor(posLabel[t], pixelGreen, 1);
04881       posColor[t] = pixelGreen;
04882     }
04883     else if (! emcStatus->motion.axis[t].homed &&
04884              posColor[t] != pixelYellow) {
04885       setColor(posLabel[t], pixelYellow, 1);
04886       posColor[t] = pixelYellow;
04887     }
04888   }
04889 
04890   // do menu dimming
04891 
04892   if (emcStatus->task.state != EMC_TASK_STATE_ON) {
04893     // if not on, dim all menus
04894     enableAuxMenus(False);
04895     enableManualMenus(False);
04896     enableAutoMenus(False);
04897     enableMdiMenus(False);
04898   }
04899   else {
04900     // it's on, so only enable according to mode
04901     if (emcStatus->task.mode == EMC_TASK_MODE_MANUAL) {
04902       enableAuxMenus(True);
04903       enableAutoMenus(False);
04904       enableMdiMenus(False);
04905       enableManualMenus(True);
04906     }
04907     else if (emcStatus->task.mode == EMC_TASK_MODE_AUTO) {
04908       if (emcStatus->task.interpState == EMC_TASK_INTERP_IDLE ||
04909           emcStatus->task.interpState == EMC_TASK_INTERP_PAUSED) {
04910         enableAuxMenus(True);
04911       }
04912       else {
04913         enableAuxMenus(False);
04914       }
04915       enableMdiMenus(False);
04916       enableManualMenus(False);
04917       enableAutoMenus(True);
04918     }
04919     else if (emcStatus->task.mode == EMC_TASK_MODE_MDI) {
04920       enableAuxMenus(True);
04921       enableManualMenus(False);
04922       enableAutoMenus(False);
04923       enableMdiMenus(True);
04924     }
04925   }
04926 
04927   // flush changes now if necessary, don't wait for event
04928   if (redraw) {
04929     XFlush(XtDisplay(topForm));
04930     redraw = 0;
04931   }
04932 
04933   // re-register this proc for the timeout
04934   XtAppAddTimeOut(app_context, UPDATE_MSECS, timeoutCB, NULL);
04935 
04936   return;
04937 }
04938 
04939 static void topLevelProtocols(Widget w, XEvent *event, String *string, Cardinal *c)
04940 {
04941   quit();
04942 }
04943 
04944 static void fileOpenShellProtocols(Widget w, XEvent *event, String *string, Cardinal *c)
04945 {
04946   XtPopdown(fileOpenShell);
04947 }
04948 
04949 static void fileQuitShellProtocols(Widget w, XEvent *event, String *string, Cardinal *c)
04950 {
04951   XtPopdown(fileQuitShell);
04952 }
04953 
04954 static void fileEditShellProtocols(Widget w, XEvent *event, String *string, Cardinal *c)
04955 {
04956   XtPopdown(fileEditShell);
04957 }
04958 
04959 static void fileEditorShellProtocols(Widget w, XEvent *event, String *string, Cardinal *c)
04960 {
04961   XtPopdown(fileEditorShell);
04962   destroyFileEditorShell();
04963 }
04964 
04965 static void toolTableShellProtocols(Widget w, XEvent *event, String *string, Cardinal *c)
04966 {
04967   XtPopdown(toolTableShell);
04968   destroyToolTableShell();
04969 }
04970 
04971 static void toolSetOffsetShellProtocols(Widget w, XEvent *event, String *string, Cardinal *c)
04972 {
04973   XtPopdown(toolSetOffsetShell);
04974 }
04975 
04976 static void posOffsetShellProtocols(Widget w, XEvent *event, String *string, Cardinal *c)
04977 {
04978   XtPopdown(posOffsetShell);
04979 }
04980 
04981 static void jogSpeedShellProtocols(Widget w, XEvent *event, String *string, Cardinal *c)
04982 {
04983   XtPopdown(jogSpeedShell);
04984 }
04985 
04986 static void feedOverrideShellProtocols(Widget w, XEvent *event, String *string, Cardinal *c)
04987 {
04988   XtPopdown(feedOverrideShell);
04989 }
04990 
04991 static void varFileShellProtocols(Widget w, XEvent *event, String *string, Cardinal *c)
04992 {
04993   XtPopdown(varFileShell);
04994   destroyVarFileShell();
04995 }
04996 
04997 static void diagnosticsShellProtocols(Widget w, XEvent *event, String *string, Cardinal *c)
04998 {
04999   diagnosticsIsPopped = 0;
05000   XtPopdown(diagnosticsShell);
05001 }
05002 
05003 static void calibShellProtocols(Widget w, XEvent *event, String *string, Cardinal *c)
05004 {
05005   XtPopdown(calibShell);
05006 }
05007 
05008 static void loggingShellProtocols(Widget w, XEvent *event, String *string, Cardinal *c)
05009 {
05010   XtPopdown(loggingShell);
05011 }
05012 
05013 static void helpXemcProtocols(Widget w, XEvent *event, String *string, Cardinal *c)
05014 {
05015   XtPopdown(helpXemcShell);
05016 }
05017 
05018 static void helpAboutProtocols(Widget w, XEvent *event, String *string, Cardinal *c)
05019 {
05020   XtPopdown(helpAboutShell);
05021 }
05022 
05023 static void errorShellProtocols(Widget w, XEvent *event, String *string, Cardinal *c)
05024 {
05025   XtPopdown(errorShell);
05026   errorIsPopped = 0;
05027   destroyErrorShell();
05028 }
05029 
05030 static XtActionsRec actionsTable[] =
05031 {
05032   {"downAction", downAction},
05033   {"upAction", upAction},
05034   {"keyAction", keyAction},
05035   {"fileOpenReturnAction", fileOpenReturnAction},
05036   {"fileOpenTabAction", fileOpenTabAction},
05037   {"fileEditReturnAction", fileEditReturnAction},
05038   {"fileEditTabAction", fileEditTabAction},
05039   {"fileQuitReturnAction", fileQuitReturnAction},
05040   {"fileQuitTabAction", fileQuitTabAction},
05041   {"diagnosticsReturnAction", diagnosticsReturnAction},
05042   {"calibReturnAction", calibReturnAction},
05043   {"calibTabAction", calibTabAction},
05044   {"loggingReturnAction", loggingReturnAction},
05045   {"loggingTabAction", loggingTabAction},
05046   {"toolSetOffsetUpAction", toolSetOffsetUpAction},
05047   {"toolSetOffsetReturnAction", toolSetOffsetReturnAction},
05048   {"toolSetOffsetTabAction", toolSetOffsetTabAction},
05049   {"posOffsetUpAction", posOffsetUpAction},
05050   {"posOffsetReturnAction", posOffsetReturnAction},
05051   {"jogSpeedReturnAction", jogSpeedReturnAction},
05052   {"feedOverrideReturnAction", feedOverrideReturnAction},
05053   {"mdiReturnAction", mdiReturnAction},
05054   {"helpXemcReturnAction", helpXemcReturnAction},
05055   {"helpAboutReturnAction", helpAboutReturnAction},
05056   {"errorReturnAction", errorReturnAction},
05057   {"topLevelProtocols", topLevelProtocols},
05058   {"fileOpenShellProtocols", fileOpenShellProtocols},
05059   {"fileQuitShellProtocols", fileQuitShellProtocols},
05060   {"fileEditShellProtocols", fileEditShellProtocols},
05061   {"fileEditorShellProtocols", fileEditorShellProtocols},
05062   {"toolTableShellProtocols", toolTableShellProtocols},
05063   {"toolSetOffsetShellProtocols", toolSetOffsetShellProtocols},
05064   {"posOffsetShellProtocols", posOffsetShellProtocols},
05065   {"jogSpeedShellProtocols", jogSpeedShellProtocols},
05066   {"feedOverrideShellProtocols", feedOverrideShellProtocols},
05067   {"varFileShellProtocols", varFileShellProtocols},
05068   {"diagnosticsShellProtocols", diagnosticsShellProtocols},
05069   {"calibShellProtocols", calibShellProtocols},
05070   {"loggingShellProtocols", loggingShellProtocols},
05071   {"helpXemcProtocols", helpXemcProtocols},
05072   {"helpAboutProtocols", helpAboutProtocols},
05073   {"errorShellProtocols", errorShellProtocols}
05074 };
05075 
05076 typedef void (MenuSelectFunc)(Widget w, XtPointer client_data, XtPointer call_data);
05077 
05078 static int setupMenu(Widget *menu, char *label,
05079                      char **labels,
05080                      Widget which,
05081                      Widget horiz, Widget vert,
05082                      MenuSelectFunc *func)
05083 {
05084   Widget *popup = new Widget;   // this will be freed automatically at exit
05085   int t;
05086 
05087   if (NULL != horiz)
05088     {
05089       if (NULL != vert)
05090         {
05091           *menu =
05092             XtVaCreateManagedWidget(label,
05093                                     menuButtonWidgetClass,
05094                                     which,
05095                                     XtNfromHoriz, horiz,
05096                                     XtNfromVert, vert,
05097                                     NULL);
05098         }
05099       else
05100         {
05101           *menu =
05102             XtVaCreateManagedWidget(label,
05103                                     menuButtonWidgetClass,
05104                                     which,
05105                                     XtNfromHoriz, horiz,
05106                                     NULL);
05107         }
05108     }
05109   else
05110     {
05111       if (NULL != vert)
05112         {
05113           *menu =
05114             XtVaCreateManagedWidget(label,
05115                                     menuButtonWidgetClass,
05116                                     which,
05117                                     XtNfromVert, vert,
05118                                     NULL);
05119         }
05120       else
05121         {
05122           *menu =
05123             XtVaCreateManagedWidget(label,
05124                                     menuButtonWidgetClass,
05125                                     which,
05126                                     NULL);
05127         }
05128     }
05129 
05130   *popup =
05131     XtVaCreatePopupShell("menu", // need to hard-code "menu" here
05132                          simpleMenuWidgetClass,
05133                          *menu,
05134                          NULL);
05135 
05136   // set the menu item names
05137   for (t = 0; labels[t] != NULL; t++)
05138     {
05139       if (labels[t][0] == '-' &&
05140           labels[t][1] == 0)
05141         {
05142           // it's a dash
05143           XtAddCallback(XtVaCreateManagedWidget(labels[t],
05144                                                 smeLineObjectClass,
05145                                                 *popup,
05146                                                 NULL),
05147                         XtNcallback, func, (XtPointer) t);
05148 
05149         }
05150       else
05151         {
05152           XtAddCallback(XtVaCreateManagedWidget(labels[t],
05153                                                 smeBSBObjectClass,
05154                                                 *popup,
05155                                                 NULL),
05156                         XtNcallback, func, (XtPointer) t);
05157         }
05158     }
05159   return(0);
05160 }
05161 
05162 static String fallbackResources[] =
05163 {
05164   NULL
05165 };
05166 
05167 static void quit()
05168 {
05169   // clean up NML buffers
05170 
05171   if (emcErrorBuffer != 0)
05172     {
05173       delete emcErrorBuffer;
05174       emcErrorBuffer = 0;
05175     }
05176 
05177   if (emcStatusBuffer != 0)
05178     {
05179       delete emcStatusBuffer;
05180       emcStatusBuffer = 0;
05181       emcStatus = 0;
05182     }
05183 
05184   if (emcCommandBuffer != 0)
05185     {
05186       delete emcCommandBuffer;
05187       emcCommandBuffer = 0;
05188     }
05189 
05190   // get rid of program file window string
05191   if (NULL != programFwString) {
05192     free(programFwString);
05193     programFwString = 0;
05194   }
05195 
05196   exit(0);
05197 }
05198 
05199 // destructively converts string to its uppercase counterpart
05200 static char *upcase(char *string)
05201 {
05202   char *ptr = string;
05203 
05204   while (*ptr != 0)
05205     {
05206       *ptr = toupper(*ptr);
05207       ptr++;
05208     }
05209 
05210   return string;
05211 }
05212 
05213 static int iniLoad(const char *filename)
05214 {
05215   INIFILE inifile;
05216   const char *inistring;
05217   char machine[INIFILE_MAX_LINELEN] = "";
05218   char version[INIFILE_MAX_LINELEN] = "";
05219   char displayString[INIFILE_MAX_LINELEN] = "";
05220   int t;
05221   int i;
05222   double d;
05223 
05224   // open it
05225   if (-1 == inifile.open(filename)) {
05226     return -1;
05227   }
05228 
05229   if (NULL != (inistring = inifile.find("MACHINE", "EMC"))) {
05230     strcpy(machine, inistring);
05231 
05232     if (NULL != (inistring = inifile.find("VERSION", "EMC"))) {
05233       sscanf(inistring, "$Revision: %s", version);
05234 
05235       sprintf(version_string, "%s EMC Version %s", machine, version);
05236     }
05237   }
05238 
05239   if (NULL != (inistring = inifile.find("DEBUG", "EMC"))) {
05240     // copy to global
05241     if (1 != sscanf(inistring, "%i", &EMC_DEBUG)) {
05242       EMC_DEBUG = 0;
05243     }
05244   }
05245   else {
05246     // not found, use default
05247     EMC_DEBUG = 0;
05248   }
05249 
05250   if (NULL != (inistring = inifile.find("NML_FILE", "EMC"))) {
05251     // copy to global
05252     strcpy(EMC_NMLFILE, inistring);
05253   }
05254   else {
05255     // not found, use default
05256   }
05257 
05258   if (NULL != (inistring = inifile.find("TOOL_TABLE", "EMCIO"))) {
05259     strcpy(TOOL_TABLE_FILE, inistring);
05260   }
05261   else {
05262     strcpy(TOOL_TABLE_FILE, "tool.tbl"); // FIXME-- hardcoded
05263   }
05264 
05265   if (NULL != (inistring = inifile.find("PARAMETER_FILE", "RS274NGC"))) {
05266     strcpy(PARAMETER_FILE, inistring);
05267   }
05268   else {
05269     strcpy(PARAMETER_FILE, "rs274ngc.var"); // FIXME-- hardcoded
05270   }
05271 
05272   if (NULL != (inistring = inifile.find("DEFAULT_VELOCITY", "TRAJ"))) {
05273     if (1 != sscanf(inistring, "%lf", &TRAJ_DEFAULT_VELOCITY)) {
05274       TRAJ_DEFAULT_VELOCITY = DEFAULT_TRAJ_DEFAULT_VELOCITY;
05275     }
05276   }
05277   else {
05278     TRAJ_DEFAULT_VELOCITY = DEFAULT_TRAJ_DEFAULT_VELOCITY;
05279   }
05280   // round jogSpeed in display to integer, per-minute
05281   jogSpeed = (int) (TRAJ_DEFAULT_VELOCITY * 60.0 + 0.5);
05282 
05283   if (NULL != (inistring = inifile.find("MAX_VELOCITY", "TRAJ"))) {
05284     if (1 != sscanf(inistring, "%lf", &TRAJ_MAX_VELOCITY)) {
05285       TRAJ_MAX_VELOCITY = DEFAULT_TRAJ_MAX_VELOCITY;
05286     }
05287   }
05288   else {
05289     TRAJ_MAX_VELOCITY = DEFAULT_TRAJ_MAX_VELOCITY;
05290   }
05291   // round maxJogSpeed in display to integer, per-minute
05292   maxJogSpeed = (int) (TRAJ_MAX_VELOCITY * 60.0 + 0.5);
05293 
05294   if (NULL != (inistring = inifile.find("PROGRAM_PREFIX", "DISPLAY"))) {
05295     if (1 != sscanf(inistring, "%s", programPrefix)) {
05296       programPrefix[0] = 0;
05297     }
05298   }
05299   else if (NULL != (inistring = inifile.find("PROGRAM_PREFIX", "TASK"))) {
05300     if (1 != sscanf(inistring, "%s", programPrefix)) {
05301       programPrefix[0] = 0;
05302     }
05303   }
05304   else {
05305     programPrefix[0] = 0;
05306   }
05307 
05308   if (NULL != (inistring = inifile.find("POSITION_OFFSET", "DISPLAY"))) {
05309     if (1 == sscanf(inistring, "%s", displayString)) {
05310       if (! strcmp(upcase(displayString), "MACHINE")) {
05311         coords = COORD_MACHINE;
05312       }
05313       else if (1 == sscanf(inistring, "%s", displayString)) {
05314         if (! strcmp(upcase(displayString), "RELATIVE")) {
05315           coords = COORD_RELATIVE;
05316         }
05317       }
05318       else {
05319         // error-- invalid value
05320         // ignore
05321       }
05322     }
05323     else {
05324       // error-- no value provided
05325       // ignore
05326     }
05327   }
05328   else {
05329     // no line at all
05330     // ignore
05331   }
05332 
05333   if (NULL != (inistring = inifile.find("POSITION_FEEDBACK", "DISPLAY"))) {
05334     if (1 == sscanf(inistring, "%s", displayString)) {
05335       if (! strcmp(upcase(displayString), "ACTUAL")) {
05336         posDisplay = POS_DISPLAY_ACT;
05337       }
05338       else if (1 == sscanf(inistring, "%s", displayString)) {
05339         if (! strcmp(upcase(displayString), "COMMANDED")) {
05340           posDisplay = POS_DISPLAY_CMD;
05341         }
05342       }
05343       else {
05344         // error-- invalid value
05345         // ignore
05346       }
05347     }
05348     else {
05349       // error-- no value provided
05350       // ignore
05351     }
05352   }
05353   else {
05354     // no line at all
05355     // ignore
05356   }
05357 
05358   for (t = 0; t < XEMC_NUM_AXES; t++) {
05359     jogPol[t] = 1;              // set to default
05360     sprintf(displayString, "AXIS_%d", t);
05361     if (NULL != (inistring = inifile.find("JOGGING_POLARITY", displayString)) &&
05362         1 == sscanf(inistring, "%d", &i) &&
05363         i == 0) {
05364       // it read as 0, so override default
05365       jogPol[t] = 0;
05366     }
05367   }
05368 
05369   if (NULL != (inistring = inifile.find("MAX_FEED_OVERRIDE", "DISPLAY"))) {
05370     if (1 == sscanf(inistring, "%lf", &d) &&
05371         d > 0.0) {
05372       maxFeedOverride = (int) (d * 100.0 + 0.5);
05373     }
05374     else {
05375       // error-- no value provided
05376       // ignore
05377     }
05378   }
05379   else {
05380     // no line at all
05381     // ignore
05382   }
05383 
05384   // FIXME-- we're using the first axis scale to set the jog increment.
05385   // Note that stepIncrement is inited to a reasonable value above, and
05386   // will only be reset on a good ini file match
05387   if (NULL != (inistring = inifile.find("INPUT_SCALE", "AXIS_0"))) {
05388     if (1 == sscanf(inistring, "%lf", &d)) {
05389       if (d < 0.0) {
05390         stepIncrement = -1.0/d; // posify it
05391       }
05392       else if (d > 0.0) {
05393         stepIncrement = 1.0/d;
05394       }
05395       // else it's 0, so ignore (this will kill the EMC, by the way)
05396     }
05397   }
05398   // set step increment to be less than 0.0010, the last fixed increment,
05399   // if it's larger. Set to 0.0001 if so, which will be too small but it
05400   // can't hurt.
05401   if (stepIncrement >= 0.0010) {
05402     stepIncrement = 0.0001;
05403   }
05404   sprintf(jogIncrementMenuEntryNames[3], "%.6f", stepIncrement);
05405 
05406   // close it
05407   inifile.close();
05408 
05409   return 0;
05410 }
05411 
05412 int main(int argc, char **argv)
05413 {
05414   int t;
05415   double start;
05416   int good;
05417   char string[80];
05418   Dimension cmfbw, sdw, sw, siw, sh, bh, bw;
05419   Dimension stw, mw;
05420   Dimension posw;
05421   Font posfont;
05422 
05423   // process command line args
05424   if (0 != emcGetArgs(argc, argv)) {
05425     rcs_print_error("error in argument list\n");
05426     exit(1);
05427   }
05428 
05429   // read INI file
05430   iniLoad(EMC_INIFILE);
05431 
05432   // blank out the annoying RCS version message
05433   rcs_version_printed = 1;
05434 
05435   // init NML
05436 
05437 #define RETRY_TIME 10.0         // seconds to wait for subsystems to come up
05438 #define RETRY_INTERVAL 1.0      // seconds between wait tries for a subsystem
05439 
05440     if (! (EMC_DEBUG & EMC_DEBUG_NML)) {
05441       set_rcs_print_destination(RCS_PRINT_TO_NULL);     // inhibit diag messages
05442     }
05443   start = etime();
05444   good = 0;
05445   do {
05446     if (0 == emcTaskNmlGet()) {
05447       good = 1;
05448       break;
05449     }
05450     esleep(RETRY_INTERVAL);
05451   } while (etime() - start < RETRY_TIME);
05452   if (! (EMC_DEBUG & EMC_DEBUG_NML)) {
05453     set_rcs_print_destination(RCS_PRINT_TO_STDOUT); // restore diag messages
05454   }
05455   if (! good) {
05456     rcs_print_error("can't establish communication with emc\n");
05457     exit(1);
05458   }
05459 
05460     if (! (EMC_DEBUG & EMC_DEBUG_NML)) {
05461       set_rcs_print_destination(RCS_PRINT_TO_NULL);     // inhibit diag messages
05462     }
05463   start = etime();
05464   good = 0;
05465   do {
05466     if (0 == emcErrorNmlGet()) {
05467       good = 1;
05468       break;
05469     }
05470     esleep(RETRY_INTERVAL);
05471   } while (etime() - start < RETRY_TIME);
05472     if (! (EMC_DEBUG & EMC_DEBUG_NML)) {
05473       set_rcs_print_destination(RCS_PRINT_TO_STDOUT); // restore diag messages
05474     }
05475     if (! good) {
05476     rcs_print_error("can't establish communication with emc\n");
05477     exit(1);
05478   }
05479 
05480   // create file window for program text
05481 
05482   programFwString =
05483     (char *) malloc(PROGRAM_FW_NUM_LINES * PROGRAM_FW_LEN_LINES);
05484 
05485   if (0 != fwInit(&programFw, PROGRAM_FW_NUM_LINES, PROGRAM_FW_LEN_LINES)) {
05486     fprintf(stderr, "can't init file window\n");
05487     exit(1);
05488   }
05489 
05490   // get widgets
05491 
05492   topLevel =
05493     XtVaAppInitialize(&app_context, /* Application context */
05494                       "XEmc",   /* Application class */
05495                       NULL, 0,  /* command line option list */
05496                       &argc, argv, /* command line args */
05497                       fallbackResources, /* app defaults string, or NULL */
05498                       NULL);    /* terminate varargs list */
05499 
05500   topForm =
05501     XtVaCreateManagedWidget("topForm", /* arbitrary widget name */
05502                             formWidgetClass, /* widget class from Label.h */
05503                             topLevel, /* parent widget */
05504                             NULL); /* terminate varargs list */
05505 
05506   barMenuForm =
05507     XtVaCreateManagedWidget("barMenuForm",
05508                             formWidgetClass,
05509                             topForm,
05510                             NULL);
05511 
05512   setupMenu(&fileMenu, "fileMenu",
05513             fileMenuEntryNames,
05514             barMenuForm,
05515             NULL, NULL,
05516             fileMenuSelect);
05517 
05518   setupMenu(&viewMenu, "viewMenu",
05519             viewMenuEntryNames,
05520             barMenuForm,
05521             fileMenu, NULL,
05522             viewMenuSelect);
05523 
05524   setupMenu(&settingsMenu, "settingsMenu",
05525             settingsMenuEntryNames,
05526             barMenuForm,
05527             viewMenu, NULL,
05528             settingsMenuSelect);
05529 
05530   setupMenu(&helpMenu, "helpMenu",
05531             helpMenuEntryNames,
05532             barMenuForm,
05533             settingsMenu, NULL,
05534             helpMenuSelect);
05535 
05536   limCommand =
05537     XtVaCreateManagedWidget("limCommand",
05538                             commandWidgetClass,
05539                             barMenuForm,
05540                             XtNfromHoriz, helpMenu,
05541                             NULL);
05542 
05543   XtAddCallback(limCommand, XtNcallback, limCB, NULL);
05544 
05545   commandMenuForm =
05546     XtVaCreateManagedWidget("commandMenuForm",
05547                             formWidgetClass,
05548                             topForm,
05549                             XtNfromVert, barMenuForm,
05550                             NULL);
05551 
05552   setupMenu(&stateMenu, "stateMenu",
05553             stateMenuEntryNames,
05554             commandMenuForm,
05555             NULL, NULL,
05556             stateMenuSelect);
05557 
05558   XtVaGetValues(stateMenu,
05559                 XtNwidth, &stw,
05560                 NULL);
05561 
05562   setupMenu(&modeMenu, "modeMenu",
05563             modeMenuEntryNames,
05564             commandMenuForm,
05565             NULL, stateMenu,
05566             modeMenuSelect);
05567 
05568   XtVaSetValues(modeMenu,
05569                 XtNwidth, stw,
05570                 NULL);
05571 
05572   setupMenu(&mistMenu, "mistMenu",
05573             mistMenuEntryNames,
05574             commandMenuForm,
05575             stateMenu, NULL,
05576             mistMenuSelect);
05577 
05578   XtVaGetValues(mistMenu,
05579                 XtNwidth, &mw,
05580                 NULL);
05581 
05582   setupMenu(&floodMenu, "floodMenu",
05583             floodMenuEntryNames,
05584             commandMenuForm,
05585             stateMenu, mistMenu,
05586             floodMenuSelect);
05587 
05588   XtVaSetValues(floodMenu,
05589                 XtNwidth, mw,
05590                 NULL);
05591 
05592   spindleDecLabel =
05593     XtVaCreateManagedWidget("spindleDecLabel",
05594                             labelWidgetClass,
05595                             commandMenuForm,
05596                             XtNfromHoriz, mistMenu,
05597                             NULL);
05598 
05599   setupMenu(&spindleMenu, "spindleMenu",
05600             spindleMenuEntryNames,
05601             commandMenuForm,
05602             spindleDecLabel, NULL,
05603             spindleMenuSelect);
05604 
05605   spindleIncLabel =
05606     XtVaCreateManagedWidget("spindleIncLabel",
05607                             labelWidgetClass,
05608                             commandMenuForm,
05609                             XtNfromHoriz, spindleMenu,
05610                             NULL);
05611 
05612   XtVaGetValues(spindleMenu,
05613                 XtNwidth, &sw,
05614                 XtNheight, &sh,
05615                 XtNborderWidth, &cmfbw,
05616                 NULL);
05617 
05618   XtVaGetValues(spindleDecLabel,
05619                 XtNwidth, &sdw,
05620                 NULL);
05621 
05622   XtVaGetValues(spindleIncLabel,
05623                 XtNwidth, &siw,
05624                 NULL);
05625 
05626   setupMenu(&brakeMenu, "brakeMenu",
05627             brakeMenuEntryNames,
05628             commandMenuForm,
05629             mistMenu, spindleDecLabel,
05630             brakeMenuSelect);
05631 
05632   bw = sdw + cmfbw + cmfbw + sw + cmfbw + cmfbw + siw;
05633   XtVaSetValues(brakeMenu,
05634                 XtNwidth, bw,
05635                 NULL);
05636 
05637   XtVaGetValues(brakeMenu,
05638                 XtNheight, &bh,
05639                 NULL);
05640 
05641   fileOpenShell =
05642     XtVaCreatePopupShell("fileOpenShell",
05643                          transientShellWidgetClass,
05644                          topLevel,
05645                          XtNallowShellResize, True,
05646                          NULL);
05647 
05648   fileOpenDialog =
05649     XtVaCreateManagedWidget("fileOpenDialog",
05650                             dialogWidgetClass,
05651                             fileOpenShell,
05652                             XtNvalue, programPrefix,
05653                             NULL);
05654 
05655   fileOpenDone =
05656     XtVaCreateManagedWidget("fileOpenDone",
05657                             commandWidgetClass,
05658                             fileOpenDialog,
05659                             NULL);
05660 
05661   XtAddCallback(fileOpenDone, XtNcallback, fileOpenDoneCB, fileOpenShell);
05662 
05663   fileOpenCancel =
05664     XtVaCreateManagedWidget("fileOpenCancel",
05665                             commandWidgetClass,
05666                             fileOpenDialog,
05667                             NULL);
05668 
05669   XtAddCallback(fileOpenCancel, XtNcallback, genericDoneCB, fileOpenShell);
05670 
05671   fileEditShell =
05672     XtVaCreatePopupShell("fileEditShell",
05673                          transientShellWidgetClass,
05674                          topLevel,
05675                          XtNallowShellResize, True,
05676                          NULL);
05677 
05678   fileEditDialog =
05679     XtVaCreateManagedWidget("fileEditDialog",
05680                             dialogWidgetClass,
05681                             fileEditShell,
05682                             XtNvalue, programPrefix,
05683                             NULL);
05684 
05685   fileEditDone =
05686     XtVaCreateManagedWidget("fileEditDone",
05687                             commandWidgetClass,
05688                             fileEditDialog,
05689                             NULL);
05690 
05691   XtAddCallback(fileEditDone, XtNcallback, fileEditDoneCB, fileEditShell);
05692 
05693   fileEditCancel =
05694     XtVaCreateManagedWidget("fileEditCancel",
05695                             commandWidgetClass,
05696                             fileEditDialog,
05697                             NULL);
05698 
05699   XtAddCallback(fileEditCancel, XtNcallback, genericDoneCB, fileEditShell);
05700 
05701   fileQuitShell =
05702     XtVaCreatePopupShell("fileQuitShell",
05703                          transientShellWidgetClass,
05704                          topLevel,
05705                          XtNallowShellResize, True,
05706                          NULL);
05707 
05708   fileQuitDialog =
05709     XtVaCreateManagedWidget("fileQuitDialog",
05710                             dialogWidgetClass,
05711                             fileQuitShell,
05712                             NULL);
05713 
05714   fileQuitDone =
05715     XtVaCreateManagedWidget("fileQuitDone",
05716                             commandWidgetClass,
05717                             fileQuitDialog,
05718                             NULL);
05719 
05720   XtAddCallback(fileQuitDone, XtNcallback, fileQuitDoneCB, fileQuitShell);
05721 
05722   fileQuitCancel =
05723     XtVaCreateManagedWidget("fileQuitCancel",
05724                             commandWidgetClass,
05725                             fileQuitDialog,
05726                             NULL);
05727 
05728   XtAddCallback(fileQuitCancel, XtNcallback, genericDoneCB, fileQuitShell);
05729 
05730   // diagnostics shell
05731 
05732   diagnosticsShell =
05733     XtVaCreatePopupShell("diagnosticsShell",
05734                          topLevelShellWidgetClass,
05735                          topLevel,
05736                          XtNallowShellResize, True,
05737                          NULL);
05738 
05739   diagnosticsForm =
05740     XtVaCreateManagedWidget("diagnosticsForm",
05741                             formWidgetClass,
05742                             diagnosticsShell,
05743                             NULL);
05744 
05745   diagnosticsLabel =
05746     XtVaCreateManagedWidget("diagnosticsLabel",
05747                             labelWidgetClass,
05748                             diagnosticsForm,
05749                             XtNborderWidth, 0,
05750                             NULL);
05751 
05752   diagnosticsTaskHBLabel =
05753     XtVaCreateManagedWidget("diagnosticsTaskHBLabel",
05754                             labelWidgetClass,
05755                             diagnosticsForm,
05756                             XtNfromVert, diagnosticsLabel,
05757                             XtNborderWidth, 0,
05758                             NULL);
05759 
05760   diagnosticsTaskHB =
05761     XtVaCreateManagedWidget("diagnosticsTaskHB",
05762                             labelWidgetClass,
05763                             diagnosticsForm,
05764                             XtNfromVert, diagnosticsLabel,
05765                             XtNfromHoriz, diagnosticsTaskHBLabel,
05766                             NULL);
05767 
05768   diagnosticsIoHBLabel =
05769     XtVaCreateManagedWidget("diagnosticsIoHBLabel",
05770                             labelWidgetClass,
05771                             diagnosticsForm,
05772                             XtNfromVert, diagnosticsTaskHBLabel,
05773                             XtNborderWidth, 0,
05774                             NULL);
05775 
05776   diagnosticsIoHB =
05777     XtVaCreateManagedWidget("diagnosticsIoHB",
05778                             labelWidgetClass,
05779                             diagnosticsForm,
05780                             XtNfromVert, diagnosticsTaskHBLabel,
05781                             XtNfromHoriz, diagnosticsIoHBLabel,
05782                             NULL);
05783 
05784   diagnosticsMotionHBLabel =
05785     XtVaCreateManagedWidget("diagnosticsMotionHBLabel",
05786                             labelWidgetClass,
05787                             diagnosticsForm,
05788                             XtNfromVert, diagnosticsIoHBLabel,
05789                             XtNborderWidth, 0,
05790                             NULL);
05791 
05792   diagnosticsMotionHB =
05793     XtVaCreateManagedWidget("diagnosticsMotionHB",
05794                             labelWidgetClass,
05795                             diagnosticsForm,
05796                             XtNfromVert, diagnosticsIoHBLabel,
05797                             XtNfromHoriz, diagnosticsMotionHBLabel,
05798                             NULL);
05799 
05800   diagnosticsFerrorLabel =
05801     XtVaCreateManagedWidget("diagnosticsFerrorLabel",
05802                             labelWidgetClass,
05803                             diagnosticsForm,
05804                             XtNfromVert, diagnosticsMotionHBLabel,
05805                             XtNborderWidth, 0,
05806                             NULL);
05807 
05808   diagnosticsFerror =
05809     XtVaCreateManagedWidget("diagnosticsFerror",
05810                             labelWidgetClass,
05811                             diagnosticsForm,
05812                             XtNfromVert, diagnosticsMotionHBLabel,
05813                             XtNfromHoriz, diagnosticsFerrorLabel,
05814                             NULL);
05815 
05816   diagnosticsDone =
05817     XtVaCreateManagedWidget("diagnosticsDone",
05818                             commandWidgetClass,
05819                             diagnosticsForm,
05820                             XtNfromVert, diagnosticsFerrorLabel,
05821                             NULL);
05822 
05823   XtAddCallback(diagnosticsDone, XtNcallback, diagnosticsDoneCB, NULL);
05824 
05825   // calibration shell
05826 
05827   calibShell =
05828     XtVaCreatePopupShell("calibShell",
05829                          topLevelShellWidgetClass,
05830                          topLevel,
05831                          XtNallowShellResize, True,
05832                          NULL);
05833 
05834   calibForm =
05835     XtVaCreateManagedWidget("calibForm",
05836                             formWidgetClass,
05837                             calibShell,
05838                             NULL);
05839 
05840   calibLabel =
05841     XtVaCreateManagedWidget("calibLabel",
05842                             labelWidgetClass,
05843                             calibForm,
05844                             XtNborderWidth, 0,
05845                             NULL);
05846 
05847   calibCycleTimeLabel =
05848     XtVaCreateManagedWidget("calibCycleTimeLabel",
05849                             labelWidgetClass,
05850                             calibForm,
05851                             XtNfromVert, calibLabel,
05852                             XtNborderWidth, 0,
05853                             NULL);
05854 
05855   calibCycleTime =
05856     XtVaCreateManagedWidget("calibCycleTime",
05857                             asciiTextWidgetClass,
05858                             calibForm,
05859                             XtNeditType, XawtextEdit,
05860                             XtNfromVert, calibLabel,
05861                             XtNfromHoriz, calibCycleTimeLabel,
05862                             NULL);
05863 
05864   calibPGainLabel =
05865     XtVaCreateManagedWidget("calibPGainLabel",
05866                             labelWidgetClass,
05867                             calibForm,
05868                             XtNfromVert, calibCycleTimeLabel,
05869                             XtNborderWidth, 0,
05870                             NULL);
05871 
05872   calibPGain =
05873     XtVaCreateManagedWidget("calibPGain",
05874                             asciiTextWidgetClass,
05875                             calibForm,
05876                             XtNeditType, XawtextEdit,
05877                             XtNfromVert, calibCycleTimeLabel,
05878                             XtNfromHoriz, calibPGainLabel,
05879                             NULL);
05880 
05881   calibIGainLabel =
05882     XtVaCreateManagedWidget("calibIGainLabel",
05883                             labelWidgetClass,
05884                             calibForm,
05885                             XtNfromVert, calibPGainLabel,
05886                             XtNborderWidth, 0,
05887                             NULL);
05888 
05889   calibIGain =
05890     XtVaCreateManagedWidget("calibIGain",
05891                             asciiTextWidgetClass,
05892                             calibForm,
05893                             XtNeditType, XawtextEdit,
05894                             XtNfromVert, calibPGainLabel,
05895                             XtNfromHoriz, calibIGainLabel,
05896                             NULL);
05897 
05898   calibDGainLabel =
05899     XtVaCreateManagedWidget("calibDGainLabel",
05900                             labelWidgetClass,
05901                             calibForm,
05902                             XtNfromVert, calibIGainLabel,
05903                             XtNborderWidth, 0,
05904                             NULL);
05905 
05906   calibDGain =
05907     XtVaCreateManagedWidget("calibDGain",
05908                             asciiTextWidgetClass,
05909                             calibForm,
05910                             XtNeditType, XawtextEdit,
05911                             XtNfromVert, calibIGainLabel,
05912                             XtNfromHoriz, calibDGainLabel,
05913                             NULL);
05914 
05915   calibFF0GainLabel =
05916     XtVaCreateManagedWidget("calibFF0GainLabel",
05917                             labelWidgetClass,
05918                             calibForm,
05919                             XtNfromVert, calibDGainLabel,
05920                             XtNborderWidth, 0,
05921                             NULL);
05922 
05923   calibFF0Gain =
05924     XtVaCreateManagedWidget("calibFF0Gain",
05925                             asciiTextWidgetClass,
05926                             calibForm,
05927                             XtNeditType, XawtextEdit,
05928                             XtNfromVert, calibDGainLabel,
05929                             XtNfromHoriz, calibFF0GainLabel,
05930                             NULL);
05931 
05932   calibFF1GainLabel =
05933     XtVaCreateManagedWidget("calibFF1GainLabel",
05934                             labelWidgetClass,
05935                             calibForm,
05936                             XtNfromVert, calibFF0GainLabel,
05937                             XtNborderWidth, 0,
05938                             NULL);
05939 
05940   calibFF1Gain =
05941     XtVaCreateManagedWidget("calibFF1Gain",
05942                             asciiTextWidgetClass,
05943                             calibForm,
05944                             XtNeditType, XawtextEdit,
05945                             XtNfromVert, calibFF0GainLabel,
05946                             XtNfromHoriz, calibFF1GainLabel,
05947                             NULL);
05948 
05949   calibFF2GainLabel =
05950     XtVaCreateManagedWidget("calibFF2GainLabel",
05951                             labelWidgetClass,
05952                             calibForm,
05953                             XtNfromVert, calibFF1GainLabel,
05954                             XtNborderWidth, 0,
05955                             NULL);
05956 
05957   calibFF2Gain =
05958     XtVaCreateManagedWidget("calibFF2Gain",
05959                             asciiTextWidgetClass,
05960                             calibForm,
05961                             XtNeditType, XawtextEdit,
05962                             XtNfromVert, calibFF1GainLabel,
05963                             XtNfromHoriz, calibFF2GainLabel,
05964                             NULL);
05965 
05966   calibBacklashLabel =
05967     XtVaCreateManagedWidget("calibBacklashLabel",
05968                             labelWidgetClass,
05969                             calibForm,
05970                             XtNfromVert, calibFF2GainLabel,
05971                             XtNborderWidth, 0,
05972                             NULL);
05973 
05974 
05975   calibBacklash =
05976     XtVaCreateManagedWidget("calibBacklash",
05977                             asciiTextWidgetClass,
05978                             calibForm,
05979                             XtNeditType, XawtextEdit,
05980                             XtNstring, string,
05981                             XtNfromVert, calibFF2GainLabel,
05982                             XtNfromHoriz, calibBacklashLabel,
05983                             NULL);
05984 
05985   calibBiasLabel =
05986     XtVaCreateManagedWidget("calibBiasLabel",
05987                             labelWidgetClass,
05988                             calibForm,
05989                             XtNfromVert, calibBacklashLabel,
05990                             XtNborderWidth, 0,
05991                             NULL);
05992 
05993 
05994   calibBias =
05995     XtVaCreateManagedWidget("calibBias",
05996                             asciiTextWidgetClass,
05997                             calibForm,
05998                             XtNeditType, XawtextEdit,
05999                             XtNstring, string,
06000                             XtNfromVert, calibBacklashLabel,
06001                             XtNfromHoriz, calibBiasLabel,
06002                             NULL);
06003 
06004   calibMaxErrorLabel =
06005     XtVaCreateManagedWidget("calibMaxErrorLabel",
06006                             labelWidgetClass,
06007                             calibForm,
06008                             XtNfromVert, calibBiasLabel,
06009                             XtNborderWidth, 0,
06010                             NULL);
06011 
06012 
06013   calibMaxError =
06014     XtVaCreateManagedWidget("calibMaxError",
06015                             asciiTextWidgetClass,
06016                             calibForm,
06017                             XtNeditType, XawtextEdit,
06018                             XtNstring, string,
06019                             XtNfromVert, calibBiasLabel,
06020                             XtNfromHoriz, calibMaxErrorLabel,
06021                             NULL);
06022 
06023   calibOutputScaleLabel =
06024     XtVaCreateManagedWidget("calibOutputScaleLabel",
06025                             labelWidgetClass,
06026                             calibForm,
06027                             XtNfromVert, calibMaxErrorLabel,
06028                             XtNborderWidth, 0,
06029                             NULL);
06030 
06031 
06032   calibOutputScale =
06033     XtVaCreateManagedWidget("calibOutputScale",
06034                             asciiTextWidgetClass,
06035                             calibForm,
06036                             XtNeditType, XawtextEdit,
06037                             XtNstring, string,
06038                             XtNfromVert, calibMaxErrorLabel,
06039                             XtNfromHoriz, calibOutputScaleLabel,
06040                             NULL);
06041 
06042   calibOutputOffsetLabel =
06043     XtVaCreateManagedWidget("calibOutputOffsetLabel",
06044                             labelWidgetClass,
06045                             calibForm,
06046                             XtNfromVert, calibOutputScaleLabel,
06047                             XtNborderWidth, 0,
06048                             NULL);
06049 
06050 
06051   calibOutputOffset =
06052     XtVaCreateManagedWidget("calibOutputOffset",
06053                             asciiTextWidgetClass,
06054                             calibForm,
06055                             XtNeditType, XawtextEdit,
06056                             XtNstring, string,
06057                             XtNfromVert, calibOutputScaleLabel,
06058                             XtNfromHoriz, calibOutputOffsetLabel,
06059                             NULL);
06060 
06061   calibFerrorLabel =
06062     XtVaCreateManagedWidget("calibFerrorLabel",
06063                             labelWidgetClass,
06064                             calibForm,
06065                             XtNfromVert, calibOutputOffsetLabel,
06066                             XtNborderWidth, 0,
06067                             NULL);
06068 
06069 
06070   calibFerror =
06071     XtVaCreateManagedWidget("calibFerror",
06072                             asciiTextWidgetClass,
06073                             calibForm,
06074                             XtNeditType, XawtextEdit,
06075                             XtNstring, string,
06076                             XtNfromVert, calibOutputOffsetLabel,
06077                             XtNfromHoriz, calibFerrorLabel,
06078                             NULL);
06079 
06080   calibDone =
06081     XtVaCreateManagedWidget("calibDone",
06082                             commandWidgetClass,
06083                             calibForm,
06084                             XtNfromVert, calibFerrorLabel,
06085                             NULL);
06086 
06087   calibCancel =
06088     XtVaCreateManagedWidget("calibCancel",
06089                             commandWidgetClass,
06090                             calibForm,
06091                             XtNfromVert, calibFerrorLabel,
06092                             XtNfromHoriz, calibDone,
06093                             NULL);
06094 
06095   XtAddCallback(calibDone, XtNcallback, calibDoneCB, NULL);
06096   XtAddCallback(calibCancel, XtNcallback, calibCancelCB, NULL);
06097 
06098   loggingShell =
06099     XtVaCreatePopupShell("loggingShell",
06100                          topLevelShellWidgetClass,
06101                          topLevel,
06102                          XtNallowShellResize, True,
06103                          NULL);
06104 
06105   loggingForm =
06106     XtVaCreateManagedWidget("loggingForm",
06107                             formWidgetClass,
06108                             loggingShell,
06109                             NULL);
06110 
06111   loggingLabel =
06112     XtVaCreateManagedWidget("loggingLabel",
06113                             labelWidgetClass,
06114                             loggingForm,
06115                             XtNborderWidth, 0,
06116                             NULL);
06117 
06118   loggingFileLabel =
06119     XtVaCreateManagedWidget("loggingFileLabel",
06120                             labelWidgetClass,
06121                             loggingForm,
06122                             XtNfromVert, loggingLabel,
06123                             XtNborderWidth, 0,
06124                             NULL);
06125 
06126   loggingFile =
06127     XtVaCreateManagedWidget("loggingFile",
06128                             asciiTextWidgetClass,
06129                             loggingForm,
06130                             XtNeditType, XawtextEdit,
06131                             XtNfromVert, loggingLabel,
06132                             XtNfromHoriz, loggingFileLabel,
06133                             NULL);
06134 
06135   loggingTypeLabel =
06136     XtVaCreateManagedWidget("loggingTypeLabel",
06137                             labelWidgetClass,
06138                             loggingForm,
06139                             XtNfromVert, loggingFileLabel,
06140                             XtNborderWidth, 0,
06141                             NULL);
06142 
06143   setupMenu(&loggingTypeMenu, "loggingTypeMenu",
06144             loggingTypeMenuEntryNames,
06145             loggingForm,
06146             loggingTypeLabel, loggingFileLabel,
06147             loggingTypeMenuSelect);
06148 
06149   loggingSizeLabel =
06150     XtVaCreateManagedWidget("loggingSizeLabel",
06151                             labelWidgetClass,
06152                             loggingForm,
06153                             XtNfromVert, loggingTypeLabel,
06154                             XtNborderWidth, 0,
06155                             NULL);
06156 
06157   loggingSize =
06158     XtVaCreateManagedWidget("loggingSize",
06159                             asciiTextWidgetClass,
06160                             loggingForm,
06161                             XtNeditType, XawtextEdit,
06162                             XtNfromVert, loggingTypeLabel,
06163                             XtNfromHoriz, loggingSizeLabel,
06164                             NULL);
06165 
06166   loggingSkipLabel =
06167     XtVaCreateManagedWidget("loggingSkipLabel",
06168                             labelWidgetClass,
06169                             loggingForm,
06170                             XtNfromVert, loggingSizeLabel,
06171                             XtNborderWidth, 0,
06172                             NULL);
06173 
06174   loggingSkip =
06175     XtVaCreateManagedWidget("loggingSkip",
06176                             asciiTextWidgetClass,
06177                             loggingForm,
06178                             XtNeditType, XawtextEdit,
06179                             XtNfromVert, loggingSizeLabel,
06180                             XtNfromHoriz, loggingSkipLabel,
06181                             NULL);
06182 
06183   loggingStart =
06184     XtVaCreateManagedWidget("loggingStart",
06185                             commandWidgetClass,
06186                             loggingForm,
06187                             XtNfromVert, loggingSkipLabel,
06188                             NULL);
06189 
06190   loggingStop =
06191     XtVaCreateManagedWidget("loggingStop",
06192                             commandWidgetClass,
06193                             loggingForm,
06194                             XtNfromVert, loggingSkipLabel,
06195                             XtNfromHoriz, loggingStart,
06196                             NULL);
06197 
06198   loggingSave =
06199     XtVaCreateManagedWidget("loggingSave",
06200                             commandWidgetClass,
06201                             loggingForm,
06202                             XtNfromVert, loggingSkipLabel,
06203                             XtNfromHoriz, loggingStop,
06204                             NULL);
06205 
06206   loggingPlot =
06207     XtVaCreateManagedWidget("loggingPlot",
06208                             commandWidgetClass,
06209                             loggingForm,
06210                             XtNfromVert, loggingSkipLabel,
06211                             XtNfromHoriz, loggingSave,
06212                             NULL);
06213 
06214   loggingDone =
06215     XtVaCreateManagedWidget("loggingDone",
06216                             commandWidgetClass,
06217                             loggingForm,
06218                             XtNfromVert, loggingStart,
06219                             NULL);
06220 
06221   loggingCancel =
06222     XtVaCreateManagedWidget("loggingCancel",
06223                             commandWidgetClass,
06224                             loggingForm,
06225                             XtNfromVert, loggingStart,
06226                             XtNfromHoriz, loggingDone,
06227                             NULL);
06228 
06229   XtAddCallback(loggingStart, XtNcallback, loggingStartCB, NULL);
06230   XtAddCallback(loggingStop, XtNcallback, loggingStopCB, NULL);
06231   XtAddCallback(loggingSave, XtNcallback, loggingSaveCB, NULL);
06232   XtAddCallback(loggingPlot, XtNcallback, loggingPlotCB, NULL);
06233   XtAddCallback(loggingDone, XtNcallback, loggingDoneCB, NULL);
06234   XtAddCallback(loggingCancel, XtNcallback, loggingCancelCB, NULL);
06235 
06236   helpXemcShell =
06237     XtVaCreatePopupShell("helpXemcShell",
06238                          topLevelShellWidgetClass,
06239                          topLevel,
06240                          XtNallowShellResize, True,
06241                          NULL);
06242 
06243   helpXemcForm =
06244     XtVaCreateManagedWidget("helpXemcForm",
06245                             formWidgetClass,
06246                             helpXemcShell,
06247                             NULL);
06248 
06249   helpXemcLabel =
06250     XtVaCreateManagedWidget("helpXemcLabel",
06251                             labelWidgetClass,
06252                             helpXemcForm,
06253                             NULL);
06254 
06255   helpXemcText =
06256     XtVaCreateManagedWidget("helpXemcText",
06257                             asciiTextWidgetClass,
06258                             helpXemcForm,
06259                             XtNfromVert, helpXemcLabel,
06260                             XtNeditType, XawtextRead,
06261                             XtNtype, XawAsciiFile,
06262                             XtNstring, "doc/xemc.txt",
06263                             XtNscrollVertical, XawtextScrollWhenNeeded,
06264                             XtNscrollHorizontal, XawtextScrollWhenNeeded,
06265                             NULL);
06266 
06267   helpXemcDone =
06268     XtVaCreateManagedWidget("helpXemcDone",
06269                             commandWidgetClass,
06270                             helpXemcForm,
06271                             XtNfromVert, helpXemcText,
06272                             NULL);
06273 
06274   XtAddCallback(helpXemcDone, XtNcallback, genericDoneCB, helpXemcShell);
06275 
06276   helpAboutShell =
06277     XtVaCreatePopupShell("helpAboutShell",
06278                          transientShellWidgetClass,
06279                          topLevel,
06280                          NULL);
06281 
06282   helpAboutDialog =
06283     XtVaCreateManagedWidget("helpAboutDialog",
06284                             dialogWidgetClass,
06285                             helpAboutShell,
06286                             NULL);
06287 
06288   helpAboutDone =
06289     XtVaCreateManagedWidget("helpAboutDone",
06290                             commandWidgetClass,
06291                             helpAboutDialog,
06292                             NULL);
06293 
06294   XtAddCallback(helpAboutDone, XtNcallback, genericDoneCB, helpAboutShell);
06295 
06296   toolNumberForm =
06297     XtVaCreateManagedWidget("toolNumberForm",
06298                             formWidgetClass,
06299                             topForm,
06300                             XtNfromVert, commandMenuForm,
06301                             NULL);
06302 
06303   toolNumberFormTitle =
06304     XtVaCreateManagedWidget("toolNumberFormTitle",
06305                             labelWidgetClass,
06306                             toolNumberForm,
06307                             NULL);
06308 
06309   toolNumberFormName =
06310     XtVaCreateManagedWidget("toolNumberFormName",
06311                             labelWidgetClass,
06312                             toolNumberForm,
06313                             XtNfromHoriz, toolNumberFormTitle,
06314                             NULL);
06315 
06316   toolOffsetForm =
06317     XtVaCreateManagedWidget("toolOffsetForm",
06318                             formWidgetClass,
06319                             topForm,
06320                             XtNfromVert, toolNumberForm,
06321                             NULL);
06322 
06323   toolOffsetFormTitle =
06324     XtVaCreateManagedWidget("toolOffsetFormTitle",
06325                             labelWidgetClass,
06326                             toolOffsetForm,
06327                             NULL);
06328 
06329   toolOffsetFormName =
06330     XtVaCreateManagedWidget("toolOffsetFormName",
06331                             labelWidgetClass,
06332                             toolOffsetForm,
06333                             XtNfromHoriz, toolOffsetFormTitle,
06334                             NULL);
06335 
06336   toolSetOffsetShell =
06337     XtVaCreatePopupShell("toolSetOffsetShell",
06338                          transientShellWidgetClass,
06339                          topLevel,
06340                          NULL);
06341 
06342   toolSetOffsetForm =
06343     XtVaCreateManagedWidget("toolSetOffsetForm",
06344                             formWidgetClass,
06345                             toolSetOffsetShell,
06346                             NULL);
06347 
06348   toolSetOffsetToolLabel =
06349     XtVaCreateManagedWidget("toolSetOffsetToolLabel",
06350                             labelWidgetClass,
06351                             toolSetOffsetForm,
06352                             XtNborderWidth, 0,
06353                             NULL);
06354 
06355   toolSetOffsetTool =
06356     XtVaCreateManagedWidget("toolSetOffsetTool",
06357                             asciiTextWidgetClass,
06358                             toolSetOffsetForm,
06359                             XtNfromHoriz, toolSetOffsetToolLabel,
06360                             XtNeditType, XawtextEdit,
06361                             NULL);
06362 
06363   toolSetOffsetLengthLabel =
06364     XtVaCreateManagedWidget("toolSetOffsetLengthLabel",
06365                             labelWidgetClass,
06366                             toolSetOffsetForm,
06367                             XtNfromVert, toolSetOffsetToolLabel,
06368                             XtNborderWidth, 0,
06369                             NULL);
06370 
06371   toolSetOffsetLength =
06372     XtVaCreateManagedWidget("toolSetOffsetLength",
06373                             asciiTextWidgetClass,
06374                             toolSetOffsetForm,
06375                             XtNfromHoriz, toolSetOffsetLengthLabel,
06376                             XtNfromVert, toolSetOffsetToolLabel,
06377                             XtNeditType, XawtextEdit,
06378                             NULL);
06379 
06380    toolSetOffsetDiameterLabel =
06381     XtVaCreateManagedWidget("toolSetOffsetDiameterLabel",
06382                             labelWidgetClass,
06383                             toolSetOffsetForm,
06384                             XtNfromVert, toolSetOffsetLengthLabel,
06385                             XtNborderWidth, 0,
06386                             NULL);
06387 
06388    toolSetOffsetDiameter =
06389     XtVaCreateManagedWidget("toolSetOffsetDiameter",
06390                             asciiTextWidgetClass,
06391                             toolSetOffsetForm,
06392                             XtNfromHoriz, toolSetOffsetDiameterLabel,
06393                             XtNfromVert, toolSetOffsetLengthLabel,
06394                             XtNeditType, XawtextEdit,
06395                             NULL);
06396 
06397   toolSetOffsetDone =
06398     XtVaCreateManagedWidget("toolSetOffsetDone",
06399                             commandWidgetClass,
06400                             toolSetOffsetForm,
06401                             XtNfromVert, toolSetOffsetDiameterLabel,
06402                             NULL);
06403 
06404   toolSetOffsetCancel =
06405     XtVaCreateManagedWidget("toolSetOffsetCancel",
06406                             commandWidgetClass,
06407                             toolSetOffsetForm,
06408                             XtNfromVert, toolSetOffsetDiameterLabel,
06409                             XtNfromHoriz, toolSetOffsetDone,
06410                             NULL);
06411 
06412   XtAddCallback(toolSetOffsetDone, XtNcallback, toolSetOffsetDoneCB, NULL);
06413   XtAddCallback(toolSetOffsetCancel, XtNcallback, toolSetOffsetCancelCB, NULL);
06414 
06415  positionTypeForm =
06416     XtVaCreateManagedWidget("positionTypeForm",
06417                             formWidgetClass,
06418                             topForm,
06419                             XtNfromVert, commandMenuForm,
06420                             XtNfromHoriz, toolNumberForm,
06421                             NULL);
06422 
06423   positionTypeFormTitle =
06424     XtVaCreateManagedWidget("positionTypeFormTitle",
06425                             labelWidgetClass,
06426                             positionTypeForm,
06427                             NULL);
06428 
06429   positionTypeFormName =
06430     XtVaCreateManagedWidget("positionTypeFormName",
06431                             labelWidgetClass,
06432                             positionTypeForm,
06433                             XtNfromHoriz, positionTypeFormTitle,
06434                             NULL);
06435 
06436   workOffsetForm =
06437     XtVaCreateManagedWidget("workOffsetForm",
06438                             formWidgetClass,
06439                             topForm,
06440                             XtNfromVert, positionTypeForm,
06441                             XtNfromHoriz, toolNumberForm,
06442                             NULL);
06443 
06444   workOffsetFormTitle =
06445     XtVaCreateManagedWidget("workOffsetFormTitle",
06446                             labelWidgetClass,
06447                             workOffsetForm,
06448                             NULL);
06449 
06450   workOffsetFormName =
06451     XtVaCreateManagedWidget("workOffsetFormName",
06452                             labelWidgetClass,
06453                             workOffsetForm,
06454                             XtNfromHoriz, workOffsetFormTitle,
06455                             NULL);
06456 
06457   // set up position labels
06458 
06459   for (t = 0; t < XEMC_NUM_AXES; t++) {
06460     // make the resource name "posLabel0,1,2,..."
06461     sprintf(string, "posLabel%d", t);
06462     if (t == 0) {
06463       // for first label, create and get resources out
06464       posLabel[0] =
06465         XtVaCreateManagedWidget(string,
06466                                 labelWidgetClass,
06467                                 topForm,
06468                                 XtNfromVert, toolOffsetForm,
06469                                 NULL);
06470 
06471       XtVaGetValues(posLabel[0],
06472                     XtNwidth, &posw,
06473                     XtNfont, &posfont,
06474                     NULL);
06475     }
06476     else {
06477       // for other labels, use first label resources
06478       posLabel[t] =
06479         XtVaCreateManagedWidget(string,
06480                                 labelWidgetClass,
06481                                 topForm,
06482                                 XtNfromVert, posLabel[t-1],
06483                                 XtNwidth, posw,
06484                                 XtNfont, posfont,
06485                                 NULL);
06486     }
06487   }
06488 
06489   abortCommand =
06490     XtVaCreateManagedWidget("abortCommand",
06491                             commandWidgetClass,
06492                             commandMenuForm,
06493                             XtNheight, sh + cmfbw + cmfbw + bh,
06494                             XtNwidth, posw - (bw + mw + stw + 8 * cmfbw),
06495                             XtNfromHoriz, spindleIncLabel,
06496                             NULL);
06497 
06498   XtAddCallback(abortCommand, XtNcallback, abortCB, NULL);
06499 
06500   posOffsetShell =
06501     XtVaCreatePopupShell("posOffsetShell",
06502                          transientShellWidgetClass,
06503                          topLevel,
06504                          NULL);
06505 
06506   posOffsetDialog =
06507     XtVaCreateManagedWidget("posOffsetDialog",
06508                             dialogWidgetClass,
06509                             posOffsetShell,
06510                             NULL);
06511 
06512   jogSpeedForm =
06513     XtVaCreateManagedWidget("jogSpeedForm",
06514                             formWidgetClass,
06515                             topForm,
06516                             XtNfromVert, posLabel[XEMC_NUM_AXES - 1],
06517                             NULL);
06518 
06519   jogSpeedTitleLabel =
06520     XtVaCreateManagedWidget("jogSpeedTitleLabel",
06521                             labelWidgetClass,
06522                             jogSpeedForm,
06523                             NULL);
06524 
06525   jogSpeedDecLabel =
06526     XtVaCreateManagedWidget("jogSpeedDecLabel",
06527                             labelWidgetClass,
06528                             jogSpeedForm,
06529                             XtNfromVert, jogSpeedTitleLabel,
06530                             NULL);
06531 
06532   jogSpeedLabel =
06533     XtVaCreateManagedWidget("jogSpeedLabel",
06534                             labelWidgetClass,
06535                             jogSpeedForm,
06536                             XtNfromHoriz, jogSpeedDecLabel,
06537                             XtNfromVert, jogSpeedTitleLabel,
06538                             NULL);
06539 
06540   jogSpeedIncLabel =
06541     XtVaCreateManagedWidget("jogSpeedIncLabel",
06542                             labelWidgetClass,
06543                             jogSpeedForm,
06544                             XtNfromHoriz, jogSpeedLabel,
06545                             XtNfromVert, jogSpeedTitleLabel,
06546                             NULL);
06547 
06548   jogSpeedShell =
06549     XtVaCreatePopupShell("jogSpeedShell",
06550                          transientShellWidgetClass,
06551                          topLevel,
06552                          NULL);
06553 
06554   jogSpeedDialog =
06555     XtVaCreateManagedWidget("jogSpeedDialog",
06556                             dialogWidgetClass,
06557                             jogSpeedShell,
06558                             NULL);
06559 
06560   jogIncrementForm =
06561     XtVaCreateManagedWidget("jogIncrementForm",
06562                             formWidgetClass,
06563                             topForm,
06564                             XtNfromHoriz, jogSpeedForm,
06565                             XtNfromVert, posLabel[XEMC_NUM_AXES - 1],
06566                             NULL);
06567 
06568   jogIncrementTitleLabel =
06569     XtVaCreateManagedWidget("jogIncrementTitleLabel",
06570                             labelWidgetClass,
06571                             jogIncrementForm,
06572                             NULL);
06573 
06574   setupMenu(&jogIncrementMenu, "jogIncrementMenu",
06575             jogIncrementMenuEntryNames,
06576             jogIncrementForm,
06577             NULL, jogIncrementTitleLabel,
06578             jogIncrementMenuSelect);
06579 
06580   jogForm =
06581     XtVaCreateManagedWidget("jogForm",
06582                             formWidgetClass,
06583                             topForm,
06584                             XtNfromHoriz, jogIncrementForm,
06585                             XtNfromVert, posLabel[XEMC_NUM_AXES - 1],
06586                             NULL);
06587 
06588   jogTitleLabel =
06589     XtVaCreateManagedWidget("jogTitleLabel",
06590                             labelWidgetClass,
06591                             jogForm,
06592                             NULL);
06593 
06594   jogMinusLabel =
06595     XtVaCreateManagedWidget("jogMinusLabel",
06596                             labelWidgetClass,
06597                             jogForm,
06598                             XtNfromVert, jogTitleLabel,
06599                             NULL);
06600 
06601   homeCommand =
06602     XtVaCreateManagedWidget("homeCommand",
06603                             commandWidgetClass,
06604                             jogForm,
06605                             XtNfromHoriz, jogMinusLabel,
06606                             XtNfromVert, jogTitleLabel,
06607                             NULL);
06608 
06609   XtAddCallback(homeCommand, XtNcallback, homeCB, 0);
06610 
06611   jogPlusLabel =
06612     XtVaCreateManagedWidget("jogPlusLabel",
06613                             labelWidgetClass,
06614                             jogForm,
06615                             XtNfromHoriz, homeCommand,
06616                             XtNfromVert, jogTitleLabel,
06617                             NULL);
06618 
06619   feedOverrideForm =
06620     XtVaCreateManagedWidget("feedOverrideForm",
06621                             formWidgetClass,
06622                             topForm,
06623                             XtNfromHoriz, jogForm,
06624                             XtNfromVert, posLabel[XEMC_NUM_AXES - 1],
06625                             NULL);
06626 
06627   feedOverrideTitleLabel =
06628     XtVaCreateManagedWidget("feedOverrideTitleLabel",
06629                             labelWidgetClass,
06630                             feedOverrideForm,
06631                             NULL);
06632 
06633   feedOverrideDecLabel =
06634     XtVaCreateManagedWidget("feedOverrideDecLabel",
06635                             labelWidgetClass,
06636                             feedOverrideForm,
06637                             XtNfromVert, feedOverrideTitleLabel,
06638                             NULL);
06639 
06640   feedOverrideLabel =
06641     XtVaCreateManagedWidget("feedOverrideLabel",
06642                             labelWidgetClass,
06643                             feedOverrideForm,
06644                             XtNfromHoriz, feedOverrideDecLabel,
06645                             XtNfromVert, feedOverrideTitleLabel,
06646                             NULL);
06647 
06648   feedOverrideIncLabel =
06649     XtVaCreateManagedWidget("feedOverrideIncLabel",
06650                             labelWidgetClass,
06651                             feedOverrideForm,
06652                             XtNfromHoriz, feedOverrideLabel,
06653                             XtNfromVert, feedOverrideTitleLabel,
06654                             NULL);
06655 
06656   feedOverrideShell =
06657     XtVaCreatePopupShell("feedOverrideShell",
06658                          transientShellWidgetClass,
06659                          topLevel,
06660                          NULL);
06661 
06662   feedOverrideDialog =
06663     XtVaCreateManagedWidget("feedOverrideDialog",
06664                             dialogWidgetClass,
06665                             feedOverrideShell,
06666                             NULL);
06667 
06668   loggingStatusForm =
06669     XtVaCreateManagedWidget("loggingStatusForm",
06670                             formWidgetClass,
06671                             topForm,
06672                             XtNfromHoriz, feedOverrideForm,
06673                             XtNfromVert, posLabel[XEMC_NUM_AXES - 1],
06674                             NULL);
06675 
06676   loggingStatusTitleLabel =
06677     XtVaCreateManagedWidget("loggingStatusTitleLabel",
06678                             labelWidgetClass,
06679                             loggingStatusForm,
06680                             NULL);
06681 
06682   loggingStatusOpenLabel =
06683     XtVaCreateManagedWidget("loggingStatusOpenLabel",
06684                             labelWidgetClass,
06685                             loggingStatusForm,
06686                             XtNfromVert, loggingStatusTitleLabel,
06687                             NULL);
06688 
06689   loggingStatusStartedLabel =
06690     XtVaCreateManagedWidget("loggingStatusStartedLabel",
06691                             labelWidgetClass,
06692                             loggingStatusForm,
06693                             XtNfromHoriz, loggingStatusOpenLabel,
06694                             XtNfromVert, loggingStatusTitleLabel,
06695                             NULL);
06696 
06697   loggingStatusPointsLabel =
06698     XtVaCreateManagedWidget("loggingStatusPointsLabel",
06699                             labelWidgetClass,
06700                             loggingStatusForm,
06701                             XtNfromHoriz, loggingStatusStartedLabel,
06702                             XtNfromVert, loggingStatusTitleLabel,
06703                             NULL);
06704 
06705   mdiForm =
06706     XtVaCreateManagedWidget("mdiForm",
06707                             formWidgetClass,
06708                             topForm,
06709                             XtNfromVert, jogSpeedForm,
06710                             NULL);
06711 
06712   mdiFormTitle =
06713     XtVaCreateManagedWidget("mdiFormTitle",
06714                             labelWidgetClass,
06715                             mdiForm,
06716                             NULL);
06717 
06718   mdiFormText =
06719     XtVaCreateManagedWidget("mdiFormText",
06720                             asciiTextWidgetClass,
06721                             mdiForm,
06722                             XtNfromHoriz, mdiFormTitle,
06723                             XtNeditType, XawtextEdit,
06724                             NULL);
06725 
06726   mdiCodesLabel =
06727     XtVaCreateManagedWidget("mdiCodesLabel",
06728                             labelWidgetClass,
06729                             topForm,
06730                             XtNfromVert, mdiForm,
06731                             NULL);
06732 
06733   programForm =
06734     XtVaCreateManagedWidget("programForm",
06735                             formWidgetClass,
06736                             topForm,
06737                             XtNfromVert, mdiCodesLabel,
06738                             NULL);
06739 
06740   programFormTitle =
06741     XtVaCreateManagedWidget("programFormTitle",
06742                             labelWidgetClass,
06743                             programForm,
06744                             NULL);
06745 
06746   programFormName =
06747     XtVaCreateManagedWidget("programFormName",
06748                             labelWidgetClass,
06749                             programForm,
06750                             XtNfromHoriz, programFormTitle,
06751                             NULL);
06752 
06753   programFormStateTitle =
06754     XtVaCreateManagedWidget("programFormStateTitle",
06755                             labelWidgetClass,
06756                             programForm,
06757                             XtNfromHoriz, programFormName,
06758                             NULL);
06759 
06760   programFormState =
06761     XtVaCreateManagedWidget("programFormState",
06762                             labelWidgetClass,
06763                             programForm,
06764                             XtNfromHoriz, programFormStateTitle,
06765                             NULL);
06766 
06767   programOpenCommand =
06768     XtVaCreateManagedWidget("programOpenCommand",
06769                             commandWidgetClass,
06770                             programForm,
06771                             XtNfromVert, programFormTitle,
06772                             NULL);
06773 
06774   XtAddCallback(programOpenCommand, XtNcallback, dialogPopup, fileOpenShell);
06775 
06776   programRunCommand =
06777     XtVaCreateManagedWidget("programRunCommand",
06778                             commandWidgetClass,
06779                             programForm,
06780                             XtNfromHoriz, programOpenCommand,
06781                             XtNfromVert, programFormTitle,
06782                             NULL);
06783 
06784   XtAddCallback(programRunCommand, XtNcallback, programRunCB, NULL);
06785 
06786   programPauseCommand =
06787     XtVaCreateManagedWidget("programPauseCommand",
06788                             commandWidgetClass,
06789                             programForm,
06790                             XtNfromHoriz, programRunCommand,
06791                             XtNfromVert, programFormTitle,
06792                             NULL);
06793 
06794   XtAddCallback(programPauseCommand, XtNcallback, programPauseCB, NULL);
06795 
06796   programResumeCommand =
06797     XtVaCreateManagedWidget("programResumeCommand",
06798                             commandWidgetClass,
06799                             programForm,
06800                             XtNfromHoriz, programPauseCommand,
06801                             XtNfromVert, programFormTitle,
06802                             NULL);
06803 
06804   XtAddCallback(programResumeCommand, XtNcallback, programResumeCB, NULL);
06805 
06806   programStepCommand =
06807     XtVaCreateManagedWidget("programStepCommand",
06808                             commandWidgetClass,
06809                             programForm,
06810                             XtNfromHoriz, programResumeCommand,
06811                             XtNfromVert, programFormTitle,
06812                             NULL);
06813 
06814   XtAddCallback(programStepCommand, XtNcallback, programStepCB, NULL);
06815 
06816   programVerifyCommand =
06817     XtVaCreateManagedWidget("programVerifyCommand",
06818                             commandWidgetClass,
06819                             programForm,
06820                             XtNfromHoriz, programStepCommand,
06821                             XtNfromVert, programFormTitle,
06822                             NULL);
06823 
06824   XtAddCallback(programVerifyCommand, XtNcallback, programVerifyCB, NULL);
06825 
06826   programText =
06827     XtVaCreateManagedWidget("programText",
06828                             asciiTextWidgetClass,
06829                             topForm,
06830                             XtNfromVert, programForm,
06831                             NULL);
06832 
06833   // add actions table for all action functions
06834   XtAppAddActions(app_context, actionsTable, XtNumber(actionsTable));
06835 
06836   // create windows for widgets and map them
06837   XtRealizeWidget(topLevel);
06838 
06839   // init atom to catch window kills
06840   killAtom = XInternAtom(XtDisplay(topLevel), "WM_DELETE_WINDOW", False);
06841 
06842   // initialize hard-coded colors
06843   stringToPixel(topForm, "white", &pixelWhite);
06844   stringToPixel(topForm, "black", &pixelBlack);
06845   stringToPixel(topForm, "red", &pixelRed);
06846   stringToPixel(topForm, "yellow", &pixelYellow);
06847   stringToPixel(topForm, "green", &pixelGreen);
06848 
06849   for (t = 0; t < XEMC_NUM_AXES; t++) {
06850     // initialize diagnostics ferrors
06851     oldAxisFerror[t] = -1.0;
06852     // get position label background and border colors for toggling
06853     getColor(posLabel[t], &posLabelBackground[t], 0);
06854     getBorderColor(posLabel[t], &posLabelBorderColor[t]);
06855     // initialize pos label colors
06856     posColor[t] = 0;
06857   }
06858 
06859   // get border color for dialog buttons, for de-highlighting
06860 
06861   getBorderColor(fileOpenDialog, &fileOpenBorderColor);
06862   setBorderColor(fileOpenDone, pixelRed);
06863 
06864   getBorderColor(fileEditDialog, &fileEditBorderColor);
06865   setBorderColor(fileEditDone, pixelRed);
06866 
06867   getBorderColor(fileQuitDialog, &fileQuitBorderColor);
06868   setBorderColor(fileQuitDone, pixelRed);
06869 
06870   getBorderColor(toolSetOffsetForm, &toolSetOffsetFormBorderColor);
06871   setBorderColor(toolSetOffsetDone, pixelRed);
06872 
06873   getBorderColor(calibForm, &calibFormBorderColor);
06874   setBorderColor(calibDone, pixelRed);
06875 
06876   getBorderColor(loggingForm, &loggingFormBorderColor);
06877   setBorderColor(loggingDone, pixelRed);
06878 
06879   // set labels for dynamic labels we can't init in timeoutCB
06880   sprintf(string, "%d", jogSpeed);
06881   setLabel(jogSpeedLabel, string);
06882 
06883   // start X interval timer
06884   XtAppAddTimeOut(app_context, UPDATE_MSECS, timeoutCB, NULL);
06885 
06886   // trap window kill for top level
06887   XSetWMProtocols(XtDisplay(topLevel), XtWindow(topLevel), &killAtom, 1);
06888 
06889   // loop for events
06890   XtAppMainLoop(app_context);
06891 
06892   return 0;
06893 }

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