#!/bin/sh
# **********************************************
# *                                            *
# *    Firmware Upgrade of SIGMET PCI Cards    *
# *                                            *
# **********************************************
#                     COPYRIGHT (c) 2009 BY
#            VAISALA INC, WESTFORD MASSACHUSETTS, U.S.A.

# Script to upgrade (flash) the FPGA code in the SIGMET PCI cards, as
# well as in hardware that might be attached to them.
#
JAMDIR="${IRIS_BIN}"

NETFLASH_CMD="${JAMDIR}/netflash"
RVP901_BOOT_DIAG=0
RVP901_BOOT_FACTORY=1
RVP901_BOOT_CUSTOM=2

BYTEBLASTER="bb"

DEVDIR="/dev/rda"
PROC_NODEINFO="/proc/driver/rda/nodeinfo"
PROC_VERSION="/proc/driver/rda/version"
PROC_RECONFIG="/proc/driver/rda/reconfig"
PROC_CONSPACE="/proc/driver/rda/configspace"

PROGRAMMINGNOW="false"
trap ' if [ "${PROGRAMMINGNOW}" = "true" ] ; then
  echo "------------------------- CAUTION -------------------------" ; \
  echo "You have interrupted the normal operation of the flash upgrade" ; \
  echo "procedure for SIGMET PCI cards and hardware.   An interrupted" ; \
  echo "programming sequence could leave your boards unusable after the" ; \
  echo "next PC reboot.  Please insure that programming steps are always" ; \
  echo "allowed to run to completion." ;\
    fi ; exit 1' INT ;

netflash_rvp9wr ()
{
    if [ -z "${RVP9_IP}" ] && [ -f ${IRIS_CONFIG}/rvp9.conf ]; then
        RVP9_IP=`grep sIpAddrIFD ${IRIS_CONFIG}/rvp9.conf | \
                 sed -e "s/^.*= *\"\([0-9\.]*\)\"/\1/"`
    fi

    if [ -n "${RVP9_IP}" ] ; then
        NETFLASH_CMD="${NETFLASH_CMD} -i ${RVP9_IP}"    
        echo "RVP901 IP address: ${RVP9_IP}"
    fi

    ${NETFLASH_CMD} --op=read -a 0 -l 10 > /dev/null 2>&1

    if [ $? -ne 0 ]; then
        echo "Failed to establish connection with the RVP901!" 
        exit 1;
    fi

    if [ -n "${RVP9_NEW_IP}" ]; then
	echo "setting new IP: ${RVP9_NEW_IP}" 
	RVP9_NEW_MASK=${RVP9_NEW_IP#*:}
	if [ ${RVP9_NEW_MASK} != ${RVP9_NEW_IP} ]; then
	    RVP9_NEW_GW=${RVP9_NEW_MASK#*:}
	    RVP9_NEW_IP=${RVP9_NEW_IP%%:*}
	    if [ ${RVP9_NEW_GW} != ${RVP9_NEW_MASK} ]; then
		RVP9_NEW_MASK=${RVP9_NEW_MASK%%:*}
		${NETFLASH_CMD} -o set --ipaddr=${RVP9_NEW_IP} --netmask=${RVP9_NEW_MASK} --gateway=${RVP9_NEW_GW}
	    else
		${NETFLASH_CMD} -o set --ipaddr=${RVP9_NEW_IP} --netmask=${RVP9_NEW_MASK}
	    fi
	else
	    ${NETFLASH_CMD} -o set --ipaddr=${RVP9_NEW_IP}
	fi
    fi

    if [ "${PROGRAM}" = "true" ] ; then
      PROGRAMMINGNOW="true"  # = = = = = = = = = = = = =
      if [ -f ${JAMDIR}/rvp9wr-elf.srec ]; then
          ${NETFLASH_CMD} -f ${JAMDIR}/rvp9wr-elf.srec
      fi

      if [ $? -eq 0 ] && [ -f ${JAMDIR}/rvp9wr-sof.srec ]; then
          ${NETFLASH_CMD} -f ${JAMDIR}/rvp9wr-sof.srec
      fi
      PROGRAMMINGNOW="false" # = = = = = = = = = = = = =

      RET_VAL=$?

      if [ $? -eq 0 ] ; then
	  BOOT_ID=`${NETFLASH_CMD} --op=show | \
                   grep "Default boot image" | \
                   sed -e "s/^.*BootID = \([0-9]*\).*$/\1/"`
          echo "Device programming was successful. BootID = $BOOT_ID"

          case $BOOT_ID in
          ${RVP901_BOOT_DIAG})
              echo "Default boot image is a Diagnostic Image";
              echo "Skipping reboot!"
              ;;
          ${RVP901_BOOT_FACTORY})
              echo "Default boot image is a Factory Application Image";
              echo "Rebooting RVP901"
              ${NETFLASH_CMD} --op=boot
              RET_VAL=$?
              ;;
          ${RVP901_BOOT_CUSTOM})
              echo "Default boot image is a Factory Application Image";
              echo "Skipping reboot!"
              ;;
          *)
              echo "Unknown boot default!";
              echo "Skipping reboot!"
              exit 1;
              ;;
          esac
      fi

   else

      if [ -z "${RVP9_NEW_IP}" ]; then
      
#	if [ -n "${RVP9_IP}" ] ; then
#            echo ${NETFLASH_CMD} --op=boot
#	fi

	if [ -f ${JAMDIR}/rvp9wr-elf.srec ]; then
            ${NETFLASH_CMD} -o info -f ${JAMDIR}/rvp9wr-elf.srec
	fi

	if [ -f ${JAMDIR}/rvp9wr-sof.srec ]; then
            ${NETFLASH_CMD} -o info -f ${JAMDIR}/rvp9wr-sof.srec
	fi

	RET_VAL=$?
      else
	  echo "IP changed: rebooting!"
	  ${NETFLASH_CMD} --op=boot
      fi
    fi

    return $RET_VAL
}

reconfig() {
    # Reload the volatile PCI configuration space of all RDA devices,
    # to match the values that were seen when the driver was first
    # started.  This permits power cycling and dynamic reconfiguration
    # of the FPGA chips without the need to reboot each time.
    #
    if [ ! -w ${PROC_RECONFIG} ] ; then
      echo "Could not locate ${PROC_RECONFIG} entry" 1>&2 ; exit 1
    else
      echo "reconfig" > ${PROC_RECONFIG}
      return 1
    fi
}

testbusy() {
    # Test whether any of the PCI cards are busy right now, i.e.,
    # whether any of them have a nonzero open count.  Exit status is
    # zero if busy.
    #
    RETVAL=`egrep 'Opens:[^0]' ${PROC_CONSPACE}`
    if [ ! -z "$RETVAL" ] ; then
	echo "Busy PCI card(s):"
	echo "${RETVAL}"
	return 0
    else
	echo "No Busy PCI card(s)"
        return 1
    fi 
}


# ------------------------------
# Process command line options
#
ARGLIST="" ; PROGRAM="false" ; FORCEPROG="false"

if [ "$1" = "" ] ; then HELP="true" ; else HELP="false" ; fi

while [ ! "$1" = "" ] ; do
  ARG="$1" ; shift

  if [ "${ARG#-}" = "${ARG}" ] ; then
    ARGLIST="${ARGLIST} ${ARG}"

  else
    if   [ "${ARG}" = "-help" -o "${ARG}" = "-?" ] ; then
      HELP="true"
    elif [ "${ARG}" = "-program" ] ; then
      PROGRAM="true"
    elif [ "${ARG}" = "-force" ] ; then
      PROGRAM="true" ; FORCEPROG="true"
    elif [ "${ARG}" = "-ipaddr" ] ; then
        RVP9_IP=$1;
        shift;
    elif [ "${ARG}" = "-rvp901_ip" ] ; then
        RVP9_NEW_IP=$1;
        shift;
    else
      echo "Unknown option: '${ARG}'\n" ; HELP="true"
    fi
  fi
done

if [ "${HELP}" = "true" ] ; then
  echo "rdaflash [-program|-rvp901_ip x.x.x.x[:m.m.m.m[:g.g.g.g]]] [rvp901-0] [rvp8rx-N] [rvp8ifd-N] [rvp8tx-N] [io62-N] [io62cp-N]"
  echo "Replace numerical suffix with '-${BYTEBLASTER}' to use ByteBlaster" \
       "parallel port pod."
  exit 0
fi

# ------------------------------
# Run through each of the args
#
if [ ".${ARGLIST}" = "." ] ; then
    if [ -n ${RVP9_NEW_IP} ] ; then
	netflash_rvp9wr;
	exit $?;
    fi
    exit 0;
fi

# Restore volatile PCI registers (just in case), and verify that none
# of the RDA boards are being used right now.  It would be a bad idea
# to reflash a PCI board that is actively inuse.
#
reconfig
testbusy
if [ "$?" = "0" ] ; then
  echo "Sorry, some of the PCI cards are still inuse.  Please try again"
  echo "  after quitting all applications (RVP8, RCP8, etc) that use any"
  echo "  of this hardware."
  exit 1 
fi

for ARG in ${ARGLIST} ; do
  # Convert programming device name to actual PCI hardware name, and
  # number of the JTAG chain required to access it.
  #
  BASENAME="${ARG%-*}" ; UNIT="${ARG##*-}"

  if [ ".${BASENAME}" = "."       -o ".${UNIT}" = "."       -o \
       ".${BASENAME}" = ".${ARG}" -o ".${UNIT}" = ".${ARG}" ] ; then
    echo "Bad device name format: '${ARG}'" ; exit 1

  elif [ "${UNIT}" = "${BYTEBLASTER}" ] ; then
    PCINAME="" ; JTAG="" ;
  else
    if   [ "${BASENAME}" = "rvp8rx"  ] ; then
      PCINAME="rvp8rx-${UNIT}" ; JTAG="0" ;
    elif [ "${BASENAME}" = "rvp8ifd" ] ; then
      PCINAME="rvp8rx-${UNIT}" ; JTAG="1" ;
    elif [ "${BASENAME}" = "rvp8tx"  ] ; then
      PCINAME="rvp8tx-${UNIT}" ; JTAG="0" ;
    elif [ "${BASENAME}" = "io62"    ] ; then
      PCINAME="io62-${UNIT}"   ; JTAG="0" ;
    elif [ "${BASENAME}" = "io62cp"  ] ; then
      PCINAME="io62-${UNIT}"   ; JTAG="1" ;
    elif [ "${BASENAME}" = "rvp901"  ] ; then
      netflash_rvp9wr;
      exit $?;
    else
      echo "Unrecognized argument: '${ARG}'" ; exit 1
    fi
  fi
 

  # Verify that the device through which the JTAG I/O will pass does
  # indeed exist.  For PCI devices the I/O device is the PCI board
  # itself.  For parallel port ByteBlaster its the raw parallel port.
  #
  if [ "${UNIT}" = "${BYTEBLASTER}" ] ; then
    JAMIODEV="/dev/parport0"
    if [ ! -r "${JAMIODEV}" ] ; then
      echo "Could not open hardware device: ${JAMIODEV}" ; exit 1
    fi
  else
    JAMIODEV="${PCINAME}"
    if [ ! -r "${DEVDIR}/${PCINAME}" ] ; then
      echo "Could not open hardware device: ${DEVDIR}/${PCINAME}" ; exit 1
    fi
  fi

  # Make the name of the JAM file that has the programming info for
  # the targeted device.  We generally just refer to the basename, but
  # in some cases we have to check the board version to know the
  # proper file name.
  #
  JAMFILE="${BASENAME}.jbc"

  if [ "${UNIT}" != "${BYTEBLASTER}" ] ; then
    CONLINE="`cat ${PROC_CONSPACE} | grep ${PCINAME}`"
    REVLETTER="${CONLINE##*Rev.}" ; REVLETTER="${REVLETTER%% *}"

    if [ "${#REVLETTER}" != "1" ] ; then
      echo "Could not deduce the board version for ${PCINAME}" ; exit 1 ;
    fi

    if [ "${REVLETTER}" = "A" -o "${REVLETTER}" = "B" ] ; then
      if [ "${BASENAME}" = "rvp8rx"  ] ; then JAMFILE="rvp8rx-ab.jbc" ; fi
      if [ "${BASENAME}" = "rvp8ifd" ] ; then
        echo "Fiber/Coax IFDs are not field programmable" ; exit 1 ;
      fi
    fi
  fi

  # Verify that the programming file can be found either in the
  # current directory or in the standard release location.
  #
  JAMPATH=""    
  if   [ -r "./${JAMFILE}"         ] ; then JAMPATH="./${JAMFILE}"
  elif [ -r "${JAMDIR}/${JAMFILE}" ] ; then JAMPATH="${JAMDIR}/${JAMFILE}"
  fi

  if [ ".${JAMPATH}" = "." ] ; then
    echo "Could not locate programming file: ${JAMFILE}" ; exit 1
  fi

  # If we are reprogramming a backpanel card via its IO62 PCI card,
  # then setup the IO62 to access the remote JTAG chain.  CAUTION:
  # This uses constants that are properly defined only in io62.h.
  #
  if [ "${UNIT}" != "${BYTEBLASTER}" ] ; then
    if [ "${BASENAME}" = "io62cp" ] ; then
      rdaport ${PCINAME} 0  00B9 > /dev/null ; sleep 0.5 # Reset IO62
      rdaport ${PCINAME} 10 6FF7 > /dev/null             # RS422 Tx/Rx
      rdaport ${PCINAME} 20 0007 > /dev/null             # Enable backpanel I/O
    fi
  fi

  # Try to verify what's programmed there already.  This verifies
  # both the programming file and the hardware JTAG chain.
  #
  if [ "${UNIT}" == "${BYTEBLASTER}" ] ; then
    echo "========  Flashing device '${BASENAME}' via ByteBlaster  ========"
  else
    echo "==========  Flashing device '${ARG}' via PCI Bus  =========="
  fi

  echo "Verifying device (may take several minutes)..."
  jamplayer ${JAMPATH} -# -averify -t${JAMIODEV} -q${JTAG}
  EXITNUM="$?"

  if [ "${EXITNUM}" = "11" -o "${FORCEPROG}" = "true" ] ; then
    # If we get a verification error, that means that the JTAG chain
    # is working properly, and the device really does need to be
    # reprogrammed.
    #
    if [ "${EXITNUM}" = "11" ] ; then
      echo "The board's firmware does not match the latest release."
    fi
    if [ "${PROGRAM}" = "true" ] ; then

      PROGRAMMINGNOW="true"  # = = = = = = = = = = = = =

      echo "Reprogramming device (may take several minutes)..."
      jamplayer ${JAMPATH} -# -aprogram -dDO_VERIFY=0 -t${JAMIODEV} -q${JTAG}
      EXITNUM="$?"

      if [ "${EXITNUM}" = "0" ] ; then
        echo "Verifying programming (may take several minutes)..."
        jamplayer ${JAMPATH} -# -averify -t${JAMIODEV} -q${JTAG}
        EXITNUM="$?"
      fi
      PROGRAMMINGNOW="false" # = = = = = = = = = = = = =

      if [ "${EXITNUM}" = "0" ] ; then  # Programmed successfully
	echo "Device programming was successful."

        if [ "${UNIT}" != "${BYTEBLASTER}" ] ; then
	  echo "Rebooting into the code that was just installed.\n"
	  if [ "${JTAG}" = "0" ] ; then
	    rdaport -bootPage ${PCINAME} 0        ; sleep 2.0
	    reconfig                              ; sleep 0.5
	    rdaport ${PCINAME}  0  B9 > /dev/null ; sleep 0.5

	  elif [ "${BASENAME}" = "rvp8ifd" ] ; then
	    rdaport ${PCINAME}  7 102 > /dev/null
	    rdaport ${PCINAME}  7  20 > /dev/null ; sleep 0.5
	  fi
        fi
      else
        echo ""
        echo "Device programming failed.  The card is (most likely) still"
        echo "running properly with its original firmware, but it would"
        echo "be non-operational after a PC reboot.  This is potentially"
        echo "a serious problem.  Please try reprogramming IMMEDIATELY."
        exit 1
      fi
    fi
  elif [ "${EXITNUM}" = "0" ] ; then  # Success
    echo "The firmware residing on the board is up to date."

  elif [ "${EXITNUM}" = "6" ] ; then  # Unrecognized device
    echo "JTAG chain does not match the programming file."
    echo "Please check board jumpers and connecting cables."
    exit 1
  else                                # Unknown exit code
    echo "Could not verify the device" ; exit 1
  fi
done
