#!/bin/sh
# 2004-12-03 Wookey - general tidy-up to match docs
# modified to include audio-off stuff
# 20031110 Chris Jones
# added mega command line parsing
# 20031112 Chris Jones
# script to JTAG and program balloons - 
# use arguments to skip sections:
#   --noaudiooff - skip balloon-audio-off
#   --nocpld - skip CPLD programming
#   --nojflash - skip mini-bootldr jflashing
#   --nobootldr - skip bootldr upload
#   --nokernel - skip kernel upload
#   --noroot - skip root fs upload
#   --noprompt - don't prompt the user to hit a key
#   --usebootimage - use a boot yaffs image instead of kernel file
#   --erasenand - erase the NAND flash before programming boot and root
#   --getmachineid - get the machine id from /proc/machineid
#   --noscroll - don't output HTML/Javascript to make browser scroll
#   --commanddirectory <command directory>
#   --imagesdirectory <file directory> - location of boot loader,
#                                        kernel and root image files
#   --smallbootloaderfile <small boot loader file name>
#   --bootloaderfile <boot loader file name>
#   --bootimagefile <boot image file name>
#   --rootimagefile <root image file name>
#   --cplddirectory <cpld file directory>
#   --cpldfile <cpld file name>
#   --uploadfile <source file> <destination file>
#   --serialport <serial port name>
#   --jflashbaseaddr <jflash port base address>
#   --cpldbaseaddr <cpld port base address>

# Base directory to find files - if you arrange things to match you may not need to change anything else
# This script defaults to:
# $BALLOONBASE/imagefiles (for all files to be uploaded)
# $BALLOONBASE/bin (commands: balloon-audio-off, jflash, playxsvf suid nice, etc) 
BALLOONBASE="~/balloon"

# location of command binaries
#overridden by --commandsdirectory
COMMANDS="$BALLOONBASE/bin"

# location of boot loader, kernel and root image
#overridden by --imagesdirectory 
FILES="$BALLOONBASE/imagefiles"

# location of the CPLD code
#overridden by --cplddirectory
CPLDFILES="$FILES"

#overridden by --cpldfile
CPLD="balloonCPLDv11.xsvf"
#overridden by --smallbootloaderfile
SMALLBOOT="bootldr.small"
#overridden by --bootloaderfile
BOOTLOADER="bootldr.fast"
#overridden by --bootimagefile
KERNEL="zImage"
#overridden by --rootimagefile
ROOTFS="balloon-guralp.yaffs.gz"

# ports
# serial port for xmodem
#PORT=/dev/ttyS1
# overridden by --serialport
PORT=/dev/ttyS0
# parallel port for jflash dongle
# overridden by --jflashbaseaddr
JFLASHBASEADDR=378
# parallel port for Xilinx CPLD dongle
# overridden by --cpldbaseaddr
CPLDBASEADDR=9000

declare -a UPLOADFILESOURCES
declare -a UPLOADFILEDESTINATIONS

#CHATOPTIONS="-v -s" #Verbose logging to stderr
CHATOPTIONS="" #no logging for when things seem to be working
CHAT=/usr/sbin/chat

# file into which machine ID gets written
# also used, naughtily, as temporary processing place to figure out machine id
MACHINEIDFILE=/home/balloon/fillballoon-output/machineid

# nice value for sx, so that it takes priority over busy web
# servers, web browsers, and so on running on the same machine
# negative values are higher priority, positive ones are lower
# note that we're using a local copy of nice because it's setuid root
# naughty but, erm, nice
#SXNICE="/home/balloon/bin/nice --adjustment=-1"
SXNICE=

# function which emits HTML/Javascript to encourage
# web browser to scroll to bottom of page
function scrollToBottom
{
    if ! [[ $NOSCROLL ]]; then
        echo "<script language=\"Javascript\">"
        echo "<!--"
#	echo "document.write(\"Starting scroll\")"
        echo "self.scrollTo(0,200000)"
#	echo "document.write(\"Ending scroll\")"
        echo "-->"
        echo "</script>"
    fi
}

function doCPLD
{
#$1 is user prompt, $2 is stage info, $3 is programming command
   #issue prompt with a beep
   if ! [[ $NOPROMPT ]]; then
       echo -e "$1\a" 
       read KEY
   fi
   echo $2
   # if a balloon-audio-off command has been specified, then
   # execute it
   if ! [[ $NOAUDIOOFF ]]; then
        if $COMMANDS/balloon-audio-off -p $JFLASHBASEADDR 0
        then
            echo "balloon-audio-off OK"
        else
            echo "balloon-audio-off failed - aborting"; exit 1;
        fi
   fi
   # now do the actual CPLD programming
   if $3; then
     echo "OK" 
   else 
     echo "Failed - Aborting"; exit 1;
   fi
}

function doJFLASH
{
#$1 is user prompt, $2 is stage info, $3 is programming command
   #issue prompt with a beep
   if ! [[ $NOPROMPT ]]; then
       echo -e "$1\a" 
       read KEY
   fi
   echo $2

   # now do the actual jflashing
   if $3; then
     echo "OK" 
   else 
     echo "Failed - Aborting"; exit 1;
   fi
}

function resetwait
{
  #wait for boot prompt"
  sleep 0.5
  #'press space' in case there is a kernel present
  # chat: verbose,to stderr, timeout 4 seconds. 
  # Send space (without newline) and wait for boot> prompt
  # if return is 3 (timeout) should tell user.
  if  $CHAT $CHATOPTIONS -t 4 '' " " 'oot\>- -oot\>' <$PORT >$PORT
  then
    echo "Reset OK"
  else 
    echo "Reset failed - no \"boot>\" prompt detected - aborting"; exit 1;
  fi
  #we should have a prompt now 
  
}

function shellpromptwait
{
    # this function tries to get us to a shell prompt
    # first send a newline
    # if we get back a boot prompt, boot the OS
    # we use a trick here: chat exits with code 4 if it gets an abort string
    # but code 3 if it times out
    echo "Attempting to get shell prompt"
    $CHAT $CHATOPTIONS -t 4 ABORT 'oot>' '' '' ' $' < $PORT > $PORT
    STATUS=$?
    if [ $STATUS -eq 3 ]; then
        # it timed out
        echo "Failed to find shell prompt. Giving up."
        exit 1;
    fi
    if [ $STATUS -eq 4 ]; then
        # we got a boot prompt back
        echo "Booting operating system"
        if $CHAT $CHATOPTIONS -t 30 ABORT Unrecognized '' 'boot' '~ $' < $PORT > $PORT; then
            echo "Booted OK"
        else
            echo "Failed to boot. Giving up."
            exit 1;
        fi
    fi
    # if we get back a shell prompt, all is OK
    echo "Got shell prompt OK"
}

function upload
{
# $1 is name for status prompt, $2 is bootldr command, 
# $3 is file to upload, $4 is pause to allow flash programming
  echo "Uploading $1:"
  if $CHAT $CHATOPTIONS -E -t 4 '' ' ' 'oot\>- -oot\>' "$2" 'ready for xmodem download..' '\c' <$PORT >$PORT  
  then
    echo "\"boot>\" prompt found OK"
  else 
    echo "No \"boot>\" prompt detected - aborting"; exit 1;
  fi
# Xmodem send - timeout in 20 seconds
# note that sx's status messages come out on stderr
# so if this script is being run from a web server, it will
# need to do the 2>&1 thing to make them visible.
#  if $SXNICE sx -t 200 -vv $3 2>&1 > $PORT < $PORT
  if $SXNICE $COMMANDS/sz -X -t 200 -vv $3 2>&1 > $PORT < $PORT
  then
    echo "Uploaded $1 OK - Programming flash for next $4 seconds" 
  else 
    echo "Failed - Aborting script"; exit 1;
  fi
  #pause to program bootldr
  scrollToBottom
  sleep $4
}

function uploadzmodem
{
  $1 is name for status prompt
  $2 is filename to upload
  echo "Uploading $1:"
# Zmodem send - timeout in 20 seconds
# note that sz's status messages come out on stderr
# so if this script is being run from a web server, it will
# need to do the 2>&1 thing to make them visible.
  if sz -t 200 -v $2 2>&1 > $PORT < $PORT
  then
    echoM "Uploaded $1 OK" 
  else 
    echo "Failed - Aborting script"; exit 1;
  fi
}

function usage
{
    echo "usage: fillballoon [--noaudiooff]"
    echo "                   [--nocpld]"
    echo "                   [--nojflash]"
    echo "                   [--nobootldr]"
    echo "                   [--nokernel]"
    echo "                   [--noroot]"
    echo "                   [--noprompt]"
    echo "                   [--usebootimage]"
    echo "                   [--erasenand]"
    echo "                   [--getmachineid]"
    echo "                   [--noscroll]"
    echo "                   [--commanddirectory <command directory>]"
    echo "                   [--imagesdirectory <images directory>]"
    echo "                   [--smallbootloaderfile <small boot loader file>]"
    echo "                   [--bootloaderfile <boot loader file>]"
    echo "                   [--bootimagefile <boot image file>]"
    echo "                   [--rootimagefile <root image file>]"
    echo "                   [--cplddirectory <cpld directory>]"
    echo "                   [--cpldfile <cpld file>]"
    echo "                   [--uploadfile <source> <destination>]"
    echo "                   [--serialport <serial port device>]"
    echo "                   [--jflashbaseaddr <jflash dongle base address>]"
    echo "                   [--cpldbaseaddr <cpld dongle base address>]"
    echo "                   [--help] [-?]"
}

######### Program starts here #########

# parse command line
while [ $# -ge 1 ]; do
    case $1 in
        --noaudiooff)
            NOAUDIOOFF=yes
            ;;
        --nocpld)
            NOCPLD=yes
            ;;
        --nojflash)
            NOJFLASH=yes
            ;;
        --nobootldr)
            NOBOOTLDR=yes
            ;;
        --nokernel)
            NOKERNEL=yes
            ;;
        --noroot)
            NOROOT=yes
            ;;
        --noprompt)
            NOPROMPT=yes
            ;;
        --usebootimage)
            USEBOOTIMAGE=yes
            ;;
        --erasenand)
            ERASENAND=yes
            ;;
        --getmachineid)
            GETMACHINEID=yes
            ;;
	--noscroll)
	    NOSCROLL=yes
	    ;;
        --shellprompttest)
            SHELLPROMPTTEST=yes
            ;;
        --commanddirectory)
            shift
            COMMANDS=$1
            ;;
        --imagesdirectory)
            shift
            FILES=$1
            ;;
        --smallbootloaderfile)
            shift
            SMALLBOOT=$1
            ;;
        --bootloaderfile)
            shift
            BOOTLOADER=$1
            ;;
        --bootimagefile)
            shift
            KERNEL=$1
            ;;
        --rootimagefile)
            shift
            ROOTFS=$1
            ;;
        --cplddirectory)
            shift
            CPLDFILES=$1
            ;;
        --cpldfile)
            shift
            CPLD=$1
            ;;
        --uploadfile)
            shift
            # append the two parameters to the arrays of source and destination files
            UPLOADFILESOURCES[${#UPLOADFILESOURCES[@]}]=$1
            shift
            UPLOADFILEDESTINATIONS[${#UPLOADFILEDESTINATIONS[@]}]=$1
            ;;
        --serialport)
            shift
            PORT=$1
            ;;
        --jflashbaseaddr)
            shift
            JFLASHBASEADDR=$1
            ;;
        --cpldbaseaddr)
            shift
            CPLDBASEADDR=$1
            ;;
        --help | -?)
            usage
            exit
            ;;
        *)
            echo unknown option: $1
            usage
            exit 1
            ;;
    esac
    shift
done

#set 115200,8N1, no hardware etc.
if ! stty 1:0:1cb2:0:3:1c:7f:15:4:5:1:0:11:13:1a:0:12:f:17:16:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0 < $PORT
then
    echo "Could not access serial port $SERIALPORT - are you root?"
    exit 1
fi

# if 'nocpld' on command line then skip

if ! [[ $NOCPLD ]]; then
  doCPLD "**Check Power On, Connect CPLD JTAG - then hit Return**" \
   "Programming CPLD:" "$COMMANDS/playxsvf -p $CPLDBASEADDR $CPLDFILES/$CPLD";
  scrollToBottom
fi


# if 'nojflash' on command line then skip
if ! [[ $NOJFLASH ]]; then
  echo Jflashing from $FILES/$SMALLBOOT
  doJFLASH "**Change to main JTAG - then hit Return**" \
   "Jflashing Small Bootloader:" \
   "$COMMANDS/Jflash-balloon -p $JFLASHBASEADDR --noverify $FILES/$SMALLBOOT";
  scrollToBottom
fi

#does bootldr reset automatically? assume not:
if ! [[ $NOPROMPT ]]; then
    echo -e "**Check serial cable attached, Reset board - then hit Return**\a" 
    read KEY
fi
resetwait

if ! [[ $NOBOOTLDR ]]; then
  upload "Bootloader" "load bootldr" $FILES/$BOOTLOADER 5
# start new bootldr - if we get "MINIMAL FUNCTION" then old bootldr is still running = gone wrong!
  $CHAT $CHATOPTIONS -t 5 ABORT "MINIMAL FUNCTION" boot\>--boot\> reset ooting... '\c' <$PORT >$PORT  
  case "$?" in
    #OK
    0 )
     echo "Bootloader reset OK" ;;
    #timed out 
    3 ) 
     echo "No \"boot>\" prompt detected - Aborting"; exit 1 ;;
    #first ABORT string found 
    4 )  
     echo "Wrong (too stupid) Bootloader running - reset and try again (with nocpld nojflash)"; exit 1 ;;
    * )
     echo "Unspecified error - No \"boot>\" prompt detected - Aborting"; exit 1 ;;
  esac     
  scrollToBottom
#  echo -e "\rreset" > $PORT
  resetwait
  scrollToBottom
fi

if [[ $ERASENAND ]]; then
    echo Erasing NAND
    if $CHAT $CHATOPTIONS -t 5 oot\>--oot\> 'nand erasechip' chip '\c' TIMEOUT 30 passed '\c' TIMEOUT 5 oot\> 'yaffs reset' < $PORT > $PORT
        then
            echo NAND erased OK
        else
            echo NAND erase failed
            exit 1
    fi
    scrollToBottom
fi

if ! [[ $NOKERNEL ]]; then
    if [[ $USEBOOTIMAGE ]]; then
        upload "Boot image" "load boot" $FILES/$KERNEL 30
    else
        upload "Kernel" "yaffs write zImage" $FILES/$KERNEL 30
    fi
    scrollToBottom
fi

if ! [[ $NOROOT ]]; then
  upload "Root Filesystem" "load root" $FILES/$ROOTFS 80
  scrollToBottom
fi

if [[ $GETMACHINEID ]]; then
    echo Detecting machine ID
    rm -f $MACHINEIDFILE
    $CHAT $CHATOPTIONS -t 5 -r $MACHINEIDFILE REPORT id: '' id  'id:' '' < $PORT > $PORT
    MACHINEID=`cat $MACHINEIDFILE | grep chat | awk '// {print $6;}'`
    echo Machine ID is $MACHINEID
    echo $MACHINEID>$MACHINEIDFILE
    scrollToBottom
fi

if [[ $UPLOADFILESOURCES ]]; then
    echo Uploading files
    # we need to upload some files
    for (( INDEX=0; INDEX<${#UPLOADFILESOURCES[@]}; INDEX++ )); do
        upload "${UPLOADFILESOURCES[$INDEX]}" \
        "yaffs write root:${UPLOADFILEDESTINATIONS[$INDEX]}" \
        "${UPLOADFILESOURCES[$INDEX]}" \
        30
    done
    scrollToBottom
fi
echo
echo -e "**Balloon board programming complete**\a"

