#!/bin/bash ################################################################################ # usage: emc [options] [] # # options: # -v = verbose - prints info as it works # -d = echos script commands to screen for debugging # # this version calls emc2/tcl/bin/pickconfig.tcl to pick an ini file if one # is not specified on the command line # ################################################################################ # Author: # License: GPL Version 2 # System: Linux # # Copyright (c) 2004 All rights reserved. # # Last change: # $Revision$ # $Author$ # $Date$ ################################################################################ ################################################################################ # 0. Values that come from configure ################################################################################ prefix=@prefix@ exec_prefix=@exec_prefix@ LSMOD=@LSMOD@ PIDOF="@PIDOF@ -x" PS=@PS@ AWK=@AWK@ IPCS=@IPCS@ KILL=@KILL@ EMC2_HOME=@EMC2_HOME@; export EMC2_HOME EMC2_BIN_DIR=@EMC2_BIN_DIR@ EMC2_TCL_DIR=@EMC2_TCL_DIR@ EMC2_HELP_DIR=@EMC2_HELP_DIR@ EMC2_RTLIB_DIR=@EMC2_RTLIB_DIR@ EMC2_CONFIG_PATH="@EMC2_CONFIG_PATH@" EMC2_NCFILES_DIR=@EMC2_NCFILES_DIR@ EMC2_LANG_DIR=@EMC2_LANG_DIR@ REALTIME=@REALTIME@ EMC2_IMAGEDIR=@EMC2_IMAGE_DIR@ #put the EMC2_BIN_DIR in PATH PATH=$EMC2_BIN_DIR:$PATH #ditto scripts if not RIP [ -d $EMC2_HOME/scripts ] && PATH=$EMC2_HOME/scripts:$PATH if [ -z "$PYTHONPATH" ]; then PYTHONPATH=$EMC2_HOME/lib/python else PYTHONPATH=$EMC2_HOME/lib/python:"$PYTHONPATH" fi export PYTHONPATH XFILESEARCHPATH=%D:@EMC2_HOME@/%T/%N%C:@EMC2_HOME@/%T/%N export XFILESEARCHPATH MODULE_EXT=@MODEXT@ # module extension, used when insmod'ing DEBUG_FILE=$(mktemp /tmp/emc.debug.XXXXXX) PRINT_FILE=$(mktemp /tmp/emc.print.XXXXXX) usage () { P=${0##*/} cat <$DEBUG_FILE fi set -x;; v) # enable printing of verbose messages if tty -s; then PRINT_FILE=/dev/tty echo "Verbose mode on" >$PRINT_FILE fi;; l) USE_LAST_INIFILE=1;; h) usage exit 0;; *) usage exit 1 esac done shift $(($OPTIND-1)) if ! tty -s; then exec 2>> $DEBUG_FILE exec >> $PRINT_FILE fi function ErrorCheck () { result=$? echo "catch {send -async popimage destroy .}; destroy ." | @WISH@ if [ $result -ne 0 ]; then if tty -s; then case $DEBUG_FILE in /dev/tty) rm -f $HOME/emc_debug.txt;; *) cp $DEBUG_FILE $HOME/emc_debug.txt esac case $PRINT_FILE in /dev/tty) rm -f $HOME/emc_print.txt;; *) cp $PRINT_FILE $HOME/emc_print.txt esac echo "\ EMC terminated with an error. You can find more information in the log files $HOME/emc_debug.txt and $HOME/emc_print.txt as well as in the output of the shell command 'dmesg' and in the terminal" else @WISH@ $EMC2_TCL_DIR/show_errors.tcl $DEBUG_FILE $PRINT_FILE fi fi rm -f $DEBUG_FILE $PRINT_FILE 2>/dev/null exit $result } trap ErrorCheck EXIT ################################################################################ # 1.3. INIFILE find inifile to use # ################################################################################ if [ ! -z $1 ]; then case $1 in /*) INIFILE=$1 ;; *) INIFILE=`pwd`/$1;; esac shift fi EXTRA_ARGS="$@" # 1.3.1. Determine if we have run-in place or installed system RUN_IN_PLACE=@RUN_IN_PLACE@ echo RUN_IN_PLACE=$RUN_IN_PLACE >>$PRINT_FILE EMC2VERSION="@EMC2VERSION@"; export EMC2VERSION # common from here.. INIVAR=$EMC2_BIN_DIR/inivar HALCMD=$EMC2_BIN_DIR/halcmd PICKCONFIG="@WISH@ $EMC2_TCL_DIR/bin/pickconfig.tcl" EMC2_EMCSH=$EMC2_BIN_DIR/emcsh EMC2_IOSH=$EMC2_BIN_DIR/iosh echo EMC2_DIR=$EMC2_DIR >>$PRINT_FILE echo EMC2_BIN_DIR=$EMC2_BIN_DIR >>$PRINT_FILE echo EMC2_TCL_DIR=$EMC2_TCL_DIR >>$PRINT_FILE echo EMC2_SCRIPT_DIR=$EMC2_SCRIPT_DIR >>$PRINT_FILE echo EMC2_RTLIB_DIR=$EMC2_RTLIB_DIR >>$PRINT_FILE echo EMC2_CONFIG_DIR=$EMC2_CONFIG_DIR >>$PRINT_FILE echo EMC2_LANG_DIR=$EMC2_LANG_DIR >>$PRINT_FILE echo INIVAR=$INIVAR >>$PRINT_FILE echo HALCMD=$HALCMD >>$PRINT_FILE echo EMC2_EMCSH=$EMC2_EMCSH >>$PRINT_FILE echo EMC2_IOSH=$EMC2_IOSH >>$PRINT_FILE echo "EMC2 - $EMC2VERSION" # was an inifile specified on the command line? if [ ! -z "$USE_LAST_INIFILE" ]; then INIFILE=$($INIVAR -ini ~/.emcrc -var LAST_CONFIG -sec PICKCONFIG 2>>$DEBUG_FILE) echo "Using previous inifile: $INIFILE" >> $PRINT_FILE fi if [ ! -n "$INIFILE" ] ; then # nothing specified, get from the user INIFILE=$($PICKCONFIG "$EMC2_CONFIG_PATH") # it returns either a path, or nothing at all fi if [ ! -n "$INIFILE" ] ; then # still nothing specified, exit exit 0 fi # delete directories from path, save name only INI_NAME=${INIFILE##*/} INI_DIR=${INIFILE%/*} echo "Machine configuration directory is '$INI_DIR'" echo "Machine configuration file is '$INI_NAME'" # make sure ini file exists (the tcl script just did this, so we could # eliminate this test, but it does no harm) if [ ! -f $INIFILE ] ; then echo "Could not find ini file '$INIFILE'" exit -1 fi echo INIFILE=$INIFILE >>$PRINT_FILE ################################################################################ # 2. extract info from the ini file that we will need later ################################################################################ retval= # 2.1. define helper function function GetFromIniQuiet { #$1 var name $2 - section name name=$1 retval=`$INIVAR -ini $INIFILE -var $1 -sec $2 2> /dev/null` if [ ! -n "$1" ] ; then exit -1 fi echo "$name=$retval" >>$PRINT_FILE } function GetFromIni { #$1 var name $2 - section name name=$1 retval=`$INIVAR -ini $INIFILE -var $1 -sec $2 2>>$DEBUG_FILE` if [ ! -n "$1" ] ; then echo "Can't find variable $1 in section [$2] of file $INIFILE." exit -1 fi echo "$name=$retval" >>$PRINT_FILE } # 2.2. get param file GetFromIni PARAMETER_FILE RS274NGC RS274NGC_PARAMFILE=$retval # 2.3. get emcmot information GetFromIni EMCMOT EMCMOT EMCMOT=$retval$MODULE_EXT # add module extension # 2.4. get emcio information GetFromIni EMCIO EMCIO EMCIO=$retval # 2.5. get emctask information GetFromIni TASK TASK EMCTASK=$retval # 2.6. we know the emc server name, change if needed # emcsvr now holds/creates all the NML channels, # so it needs to start by default, as the first process EMCSERVER=emcsvr # 2.7. get halui information GetFromIniQuiet HALUI HAL HALUI=$retval # 2.9. get display information GetFromIni DISPLAY DISPLAY EMCDISPLAY=`(set -- $retval ; echo $1 )` EMCDISPLAYARGS=`(set -- $retval ; shift ; echo $* )` # 2.10. get NML config information GetFromIni NML_FILE EMC NMLFILE=$retval ################################################################################ # 3. Done gathering information, define a few functions # Execution resumes after function definitions... ################################################################################ KILL_TASK= KILL_TIMEOUT=20 ################################################################################ # 3.1. Kills a list of tasks with timeout # if it doesn't work, kill -9 is used ################################################################################ function KillTaskWithTimeout() { if [ ! -n "$KILL_PIDS" ] ; then KILL_PIDS=`$PIDOF $KILL_TASK` fi if [ ! -n "$KILL_PIDS" ] ; then echo "Could not find pid(s) for task $KILL_TASK" return -1 fi for KILL_PID in $KILL_PIDS ; do echo "Killing task $KILL_TASK, PID=$KILL_PID" >>$PRINT_FILE # first a "gentle" kill with signal TERM $KILL $KILL_PID WAIT=$KILL_TIMEOUT # wait and see if it dissappears while [ $WAIT -gt 1 ] ; do # see if it's still alive if $PS $KILL_PID >>$DEBUG_FILE ; then WAIT=$(($WAIT-1)) sleep .1 else WAIT=0 fi done if [ $WAIT -gt 0 ] ; then # gentle didn't work, get serious echo "Timeout, trying kill -9" >>$PRINT_FILE $KILL -9 $KILL_PID WAIT=$KILL_TIMEOUT # wait and see if it dissappears while [ $WAIT -gt 1 ] ; do # see if it's still alive if $PS $KILL_PID >>$DEBUG_FILE ; then WAIT=$(($WAIT-1)) sleep .1 else WAIT=0 fi done fi if [ $WAIT -gt 0 ] ; then echo "Could not kill task $KILL_TASK, PID=$KILL_PID" fi KILL_PIDS= KILL_TASK= done } ################################################################################ # 3.2. define the cleanup function # # this cleanup function doesn't know or care what was actually # loaded - it simply kills _any_ processes in it's list of emc # components ################################################################################ function Cleanup() { echo "Shutting down and cleaning up EMC2..." # Kill displays first - that should cause an orderly # shutdown of the rest of emc2 for KILL_TASK in xemc yemc emcpanel keystick iosh emcsh emcrsh emctop mdi debuglevel; do if $PIDOF $KILL_TASK >>$DEBUG_FILE ; then KillTaskWithTimeout fi done if [ -x EMC2_BIN_DIR/axis-remote ]; then axis-remote --ping && axis-remote --quit fi if [ "$1" = "other" ]; then echo -n "Waiting for other session to finish exiting..." WAIT=$KILL_TIMEOUT while [ $WAIT -gt 1 ]; do if ! [ -f $LOCKFILE ]; then echo " Ok" return 0 fi WAIT=$(($WAIT-1)) sleep .1 done echo "lockfile still not removed" fi SHUTDOWN=`$INIVAR -ini $INIFILE -var SHUTDOWN -sec HAL 2> /dev/null` if [ -n "$SHUTDOWN" ]; then echo "Running HAL shutdown script" $HALCMD -f $SHUTDOWN fi # now kill all the other user space components of emc for KILL_TASK in emcsvr milltask; do if $PIDOF $KILL_TASK >>$DEBUG_FILE ; then KillTaskWithTimeout fi done echo "Stopping realtime threads" >> $DEBUG_FILE $HALCMD stop echo "Unloading hal components" >> $DEBUG_FILE $HALCMD unload all echo "Removing HAL_LIB, RTAPI, and Real Time OS modules" >>$PRINT_FILE $REALTIME stop echo "Removing NML shared memory segments" >> $PRINT_FILE while read b x t x x x x x x m x; do case $b$t in BSHMEM) ipcrm -M $m 2>/dev/null;; esac done < $NMLFILE # remove lock file if [ -f $LOCKFILE ] ; then rm $LOCKFILE fi echo "Cleanup done" } ################################################################################ # 4. done with function definitions, execution resumes here ################################################################################ # Name of lock file to check for that signifies that EMC is up, # to prevent multiple copies of controller LOCKFILE=/tmp/emc.lock # Check for lock file if [ -f $LOCKFILE ]; then if tty -s; then echo -n "EMC2 is still running. Restart it? [Y/n] " read input; [ -z $input ] && input=y else input=$(@WISH@ < when run-in-place, or # /usr/local/share/emc/configs/ (wherever it was installed) cd $INI_DIR # Create the lock file touch $LOCKFILE ################################################################################ # 4.1. pop up intro graphic ################################################################################ img=`$INIVAR -ini $INIFILE -var INTRO_GRAPHIC -sec DISPLAY 2>>$DEBUG_FILE` imgtime=`$INIVAR -ini $INIFILE -var INTRO_TIME -sec DISPLAY 2>>$DEBUG_FILE` if [ "$imgtime" = "" ] ; then imgtime=5 fi if [ "$img" != "" ] ; then if [ -x $EMC2_TCL_DIR/bin/popimage ] ; then $EMC2_TCL_DIR/bin/popimage $EMC2_IMAGEDIR/$img $imgtime & fi fi ################################################################################ # 4.2. Now we can finally start loading EMC ################################################################################ # 4.3.1. Run emcserver in background, always (it owns/createas the NML buffers) echo "Starting EMC2 server program: $EMCSERVER" >>$PRINT_FILE if [ ! -x $EMC2_BIN_DIR/$EMCSERVER ] ; then echo "Can't execute server program $EMC2_BIN_DIR/$EMCSERVER" Cleanup exit 1 fi export INI_FILE_NAME=$INIFILE $EMC2_BIN_DIR/$EMCSERVER -ini $INIFILE & sleep 1 # 4.3.2. Start REALTIME echo "Loading Real Time OS, RTAPI, and HAL_LIB modules" >>$PRINT_FILE if ! $REALTIME start ; then echo "Realtime system did not load" Cleanup exit -1 fi # 4.3.3. export the location of the HAL realtime modules so that # "halcmd loadrt" can find them export HAL_RTMOD_DIR=$EMC2_RTLIB_DIR # 4.3.4. Run emcio in background echo "Starting EMC2 IO program: $EMCIO" >>$PRINT_FILE if [ ! -x $EMC2_BIN_DIR/$EMCIO ] ; then echo "Can't execute IO program $EMC2_BIN_DIR/$EMCIO" Cleanup exit 1 fi $HALCMD loadusr -Wn iocontrol $EMC2_BIN_DIR/$EMCIO -ini $INIFILE # 4.3.5. Run halui in background, if necessary if [ -n "$HALUI" ] ; then echo "Starting HAL User Interface program: $HALUI" >>$PRINT_FILE if [ ! -x $EMC2_BIN_DIR/$HALUI ] ; then echo "Can't execute halui program $EMC2_BIN_DIR/$HALUI" Cleanup exit 1 fi $HALCMD loadusr -Wn halui $EMC2_BIN_DIR/$HALUI -ini $INIFILE fi # 4.3.6. execute HALCMD config files (if any) # get first config file name from ini file NUM=1 CFGFILE=`$INIVAR -ini $INIFILE -var HALFILE -sec HAL -num $NUM 2> /dev/null` while [ -n "$CFGFILE" ] ; do if ! $HALCMD -i $INIFILE -f $CFGFILE ; then Cleanup exit -1 fi # get next config file name from ini file NUM=$(($NUM+1)) CFGFILE=`$INIVAR -ini $INIFILE -var HALFILE -sec HAL -num $NUM 2> /dev/null` done # 4.3.7. execute discrete HAL commands from ini file (if any) # get first command from ini file NUM=1 HALCOMMAND=`$INIVAR -ini $INIFILE -var HALCMD -sec HAL -num $NUM 2> /dev/null` while [ -n "$HALCOMMAND" ] ; do if [ -n "$HALCOMMAND" ] ; then echo "Running HAL command: $HALCOMMAND" >>$PRINT_FILE if ! $HALCMD $HALCOMMAND ; then echo "ini file HAL command $HALCOMMAND failed." Cleanup exit -1 fi fi # get next command from ini file NUM=$(($NUM+1)) HALCOMMAND=`$INIVAR -ini $INIFILE -var HALCMD -sec HAL -num $NUM 2> /dev/null` done # 4.3.8. start the realtime stuff ticking $HALCMD start # 4.3.9. Run emctask in background echo "Starting EMC2 TASK program: $EMCTASK" >>$PRINT_FILE if [ ! -x $EMC2_BIN_DIR/$EMCTASK ] ; then echo "Can't execute TASK program $EMC2_BIN_DIR/$EMCTASK" Cleanup exit 1 fi $EMC2_BIN_DIR/$EMCTASK -ini $INIFILE & #export some common directories, used by some of the GUI's export EMC2_TCL_DIR=$EMC2_TCL_DIR export EMC2_EMCSH=$EMC2_EMCSH export EMC2_IOSH=$EMC2_IOSH export EMC2_HELP_DIR=$EMC2_HELP_DIR export EMC2_LANG_DIR=$EMC2_LANG_DIR export REALTIME=$REALTIME export HALCMD=$HALCMD export NMLFILE=$NMLFILE # 4.3.10. Run display in foreground echo "Starting EMC2 DISPLAY program: $EMCDISPLAY" >>$PRINT_FILE result=0 case $EMCDISPLAY in tkemc|mini) # tkemc and mini are in the tcl directory, not the bin directory if [ ! -x $EMC2_TCL_DIR/$EMCDISPLAY.tcl ] ; then echo "Can't execute DISPLAY program $EMC2_TCL_DIR/$EMCDISPLAY.tcl $EMCDISPLAYARGS" Cleanup exit 1 fi $EMC2_TCL_DIR/$EMCDISPLAY.tcl -ini $INIFILE $EMCDISPLAYARGS result=$? ;; dummy) # dummy display just waits for echo "DUMMY DISPLAY MODULE, press to continue." read foo; ;; keystick) if [ ! -x $EMC2_BIN_DIR/keystick ] ; then echo "Can't execute DISPLAY program $EMC2_BIN_DIR/$EMCDISPLAY $EMCDISPLAYARGS $EXTRA_ARGS" Cleanup exit 1 fi # xterm -xrm 'XTerm*metaSendsEscape:false' -xrm 'XTerm*VT100.Translations: #override Home: string("\033[1~")\n End: string("\033[4~")' -ls -e $EMC2_BIN_DIR/keystick -ini $INIFILE xterm -xrm 'XTerm*metaSendsEscape:false' -ls -e $EMC2_BIN_DIR/keystick -ini $INIFILE result=$? ;; axis) if [ ! -x $EMC2_BIN_DIR/$EMCDISPLAY ] ; then echo "Can't execute DISPLAY program $EMC2_BIN_DIR/$EMCDISPLAY $EMCDISPLAYARGS $EXTRA_ARGS" Cleanup exit 1 fi $EMC2_BIN_DIR/$EMCDISPLAY -ini $INIFILE $EMCDISPLAYARGS $EXTRA_ARGS result=$? ;; *) # all other displays are assumed to be in the bin directory if [ ! -x $EMC2_BIN_DIR/$EMCDISPLAY ] ; then echo "Can't execute DISPLAY program $EMC2_BIN_DIR/$EMCDISPLAY $EMCDISPLAYARGS $EXTRA_ARGS" Cleanup exit 1 fi $EMC2_BIN_DIR/$EMCDISPLAY -ini $INIFILE $EMCDISPLAYARGS $EXTRA_ARGS result=$? ;; esac # the display won't return until you shut it down, # so when you get here it's time to clean up Cleanup exit $result