- #!/bin/bash
- ################################################################################
- # usage: emc [options] [<ini-file>]
- #
- # 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-2009 All rights reserved.
- ################################################################################
- ################################################################################
- # 0. Values that come from configure
- ################################################################################
- prefix=/home/dave/emc2-dev
- exec_prefix=${prefix}
- LSMOD=/sbin/lsmod
- PIDOF="/bin/pidof -x"
- PS=/bin/ps
- AWK=/usr/bin/awk
- IPCS=/usr/bin/ipcs
- KILL=/bin/kill
- EMC2_HOME=/home/dave/emc2-dev; export EMC2_HOME
- EMC2_BIN_DIR=/home/dave/emc2-dev/bin
- EMC2_TCL_DIR=/home/dave/emc2-dev/tcl
- EMC2_HELP_DIR=/home/dave/emc2-dev/docs/help
- EMC2_RTLIB_DIR=/home/dave/emc2-dev/rtlib
- EMC2_CONFIG_PATH="~/emc2/configs:/home/dave/emc2-dev/configs"
- EMC2_NCFILES_DIR=/home/dave/emc2-dev/nc_files
- EMC2_LANG_DIR=/home/dave/emc2-dev/src/objects
- REALTIME=/home/dave/emc2-dev/scripts/realtime
- EMC2_IMAGEDIR=/home/dave/emc2-dev
- #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:/home/dave/emc2-dev/%T/%N%C:/home/dave/emc2-dev/%T/%N
- export XFILESEARCHPATH
- MODULE_EXT=.ko # module extension, used when insmod'ing
- DEBUG_FILE=$(mktemp /tmp/emc.debug.XXXXXX)
- PRINT_FILE=$(mktemp /tmp/emc.print.XXXXXX)
- program_available () {
- type -path "$1" > /dev/null 2>&1
- }
- usage () {
- P=${0##*/}
- cat <<EOF
- $P: Run EMC2
- Usage:
- $P [-d] [-v]
- Choose the configuration file graphically
- $P [-k] [-d] [-v] path/to/your.ini
- Name the configuration file using its path
- $P [-k] [-d] [-v] -l
- Use the previous configuration file
- -d: Turn on "debug" mode
- -v: Turn on "verbose" mode
- -k: Continue in the presence of errors in .hal files
- EOF
- }
- ################################################################################
- # 1.1. strip and process command line options
- ################################################################################
- while getopts "dvlhk" opt
- do
- case "$opt" in
- d)
- # enable echoing of script and command output
- if tty -s; then
- DEBUG_FILE=/dev/fd/2
- echo "Debug mode on" >$DEBUG_FILE
- fi
- set -x;;
- v)
- # enable printing of verbose messages
- if tty -s; then
- PRINT_FILE=/dev/fd/1
- echo "Verbose mode on" >$PRINT_FILE
- fi;;
- l)
- USE_LAST_INIFILE=1;;
- k) DASHK=-k;;
- h)
- usage
- exit 0;;
- *)
- usage
- exit 1
- esac
- done
- shift $(($OPTIND-1))
- case "2.6.24-16-rtai" in
- "") ;;
- *)
- if [ `uname -r` != "2.6.24-16-rtai" ]; then
- if tty -s; then
- echo "EMC2 requires the real-time kernel 2.6.24-16-rtai to run."
- echo "Before running EMC2, reboot and choose this kernel at the boot menu."
- else
- /usr/bin/wish8.4 <<EOF
- wm wi .
- tk_messageBox -type ok \
- -title EMC2 -icon error -title "Realtime Kernel Required" \
- -message {EMC2 requires the real-time kernel 2.6.24-16-rtai to run. Before running EMC2, reboot and choose this kernel at the boot menu.}
- exit
- EOF
- fi
- exit
- fi
- esac
- if ! tty -s; then
- exec 2>> $DEBUG_FILE
- exec >> $PRINT_FILE
- fi
- function ErrorCheck () {
- result=$?
- if [ ! -z "$DISPLAY" ]; then
- echo "catch {send -async popimage destroy .}; destroy ." | /usr/bin/wish8.4
- fi
- if [ $result -ne 0 ]; then
- if tty -s || [ -z "$DISPLAY" ] ; then
- if [ -f $DEBUG_FILE ]; then
- cp $DEBUG_FILE $HOME/emc_debug.txt
- else
- echo "(debug information was sent to stderr)" \
- > $HOME/emc_debug.txt
- fi
- if [ -f $PRINT_FILE ]; then
- cp $PRINT_FILE $HOME/emc_print.txt
- else
- echo "(print information was sent to stdout)" \
- > $HOME/emc_print.txt
- fi
- echo "\
- EMC terminated with an error. You can find more information in the log:
- $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
- /usr/bin/wish8.4 $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
- -) USE_LAST_INIFILE=1;;
- /*) 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=yes
- echo RUN_IN_PLACE=$RUN_IN_PLACE >>$PRINT_FILE
- EMC2VERSION="2.4.0~pre"; export EMC2VERSION
- # common from here..
- INIVAR=inivar
- HALCMD="halcmd $DASHK"
- PICKCONFIG="/usr/bin/wish8.4 $EMC2_TCL_DIR/bin/pickconfig.tcl"
- EMC2_EMCSH=/usr/bin/wish8.4
- 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 - $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'"
- trap '' EXIT
- 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
- if [ -z "$NMLFILE" ]; then NMLFILE=/home/dave/emc2-dev/configs/common/emc.nml; fi
- ################################################################################
- # 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 program_available axis-remote ; then
- if [ ! -z "$DISPLAY" ]; then
- axis-remote --ping && axis-remote --quit
- fi
- 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
- for i in `seq 10`; do
- # (the one component is the halcmd itself)
- if [ `$HALCMD list comp | wc -w` = 1 ]; then break; fi
- sleep .2
- done
- 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=$(/usr/bin/wish8.4 <<EOF
- wm wi .
- puts [tk_messageBox -title EMC2 -message "EMC2 is still running. Restart it?" -type yesno]
- exit
- EOF
- )
- fi
- case $input in
- y|Y|yes)
- echo Cleaning up old EMC2...
- Cleanup other
- ;;
- *)
- echo Not starting new EMC2
- exit 0
- ;;
- esac
- fi
- echo Starting EMC2...
- # trap ^C so that it's called if user interrupts script
- trap 'Cleanup ; exit 0' SIGINT SIGTERM
- # go to the dir where the ini file is
- # either configs/<specific-config> when run-in-place, or
- # /usr/local/share/emc/configs/<specific-config> (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 [ -e "$img" ]; then
- true
- elif [ -e "$INI_DIR/$img" ]; then
- img="$INI_DIR/$img"
- elif [ -e "$EMC2_IMAGEDIR/$img" ]; then
- img="$EMC2_IMAGEDIR/$img"
- else
- img=
- fi
- fi
- if [ "$img" != "" ] ; then
- if [ -x $EMC2_TCL_DIR/bin/popimage ] ; then
- $EMC2_TCL_DIR/bin/popimage $img $imgtime &
- fi
- fi
- ################################################################################
- # 4.2. Now we can finally start loading EMC
- ################################################################################
- # 4.3.1. Run emcserver in background, always (it owns/creates the NML buffers)
- echo "Starting EMC2 server program: $EMCSERVER" >>$PRINT_FILE
- if ! program_available $EMCSERVER; then
- echo "Can't execute server program $EMCSERVER"
- Cleanup
- exit 1
- fi
- export INI_FILE_NAME="$INIFILE"
- $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 ! program_available $EMCIO ; then
- echo "Can't execute IO program $EMCIO"
- Cleanup
- exit 1
- fi
- $HALCMD loadusr -Wn iocontrol $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 ! program_available $HALUI ; then
- echo "Can't execute halui program $HALUI"
- Cleanup
- exit 1
- fi
- $HALCMD loadusr -Wn halui $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
- case $CFGFILE in
- *.tcl)
- if ! haltcl -ini "$INIFILE" $CFGFILE && [ "$DASHK" = "" ]; then
- Cleanup
- exit -1
- fi
- ;;
- *)
- if ! $HALCMD -i "$INIFILE" -f $CFGFILE && [ "$DASHK" = "" ]; then
- Cleanup
- exit -1
- fi
- esac
- # 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 && [ "$DASHK" = "" ]; 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 ! program_available $EMCTASK ; then
- echo "Can't execute TASK program $EMCTASK"
- Cleanup
- exit 1
- fi
- $EMCTASK -ini "$INIFILE" &
- #export some common directories, used by some of the GUI's
- export EMC2_TCL_DIR
- export EMC2_EMCSH
- export EMC2_HELP_DIR
- export EMC2_LANG_DIR
- export REALTIME
- export HALCMD
- export 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 <ENTER>
- echo "DUMMY DISPLAY MODULE, press <ENTER> to continue."
- read foo;
- ;;
- keystick)
- if ! program_available keystick ; then
- echo "Can't execute DISPLAY program $EMCDISPLAY $EMCDISPLAYARGS $EXTRA_ARGS"
- Cleanup
- exit 1
- fi
- if [ ! -z "$DISPLAY" ]; then
- xterm -xrm 'XTerm*metaSendsEscape:false' -ls -e keystick -ini "$INIFILE"
- else
- keystick -ini "$INIFILE"
- fi
- result=$?
- ;;
- *)
- # all other displays are assumed to be commands on the PATH
- if ! program_available $EMCDISPLAY; then
- echo "Can't execute DISPLAY program $EMCDISPLAY $EMCDISPLAYARGS $EXTRA_ARGS"
- Cleanup
- exit 1
- fi
- $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