#!/bin/bash
#
# vpd_patch - patch the contents of VPD for Superhawk3 prototypes
#
#   only for early prototypes that didn't go through the orthodox
#   factory initialization

TFILE=/tmp/vpd.$$.txt

function vpd_write {
  /fabos/share/vpdWrite -tfile $TFILE
}

function vpd_read {
  /fabos/share/vpdRead -offset $1 -size $2 |
  sed -e 's/^....: //' -e 's/[[:blank:]]*$//' -e '/embeddedVpdRead/d'
}

function do_hex {
  printf "%s:" $1 > $TFILE
  shift
  printf " %s" $* >> $TFILE
  printf "\n" >> $TFILE
  vpd_write
}

function fpga_read {
  reg_ms=${1:0:1}
  reg_ls=${1:1:1}
  fpga_row="0x11f80000${reg_ms}0:"
  declare -i fpga_col=0x${reg_ls}+2
  grep "${fpga_row}" /proc/system/fpga | tr -s [:blank:] | cut -d' ' -f$fpga_col
}

function checksum_compute {
	declare -i SUM=0
	for x in $*
	do
		declare -i n=0x$x
		let "SUM-=n"
	done
	let "SUM&=0xff"
	printf "%.2x\n" $SUM
}

function checksum_write {
	DATA=`vpd_read $1 $2`
	CHECKSUM=`checksum_compute $DATA`
	echo "00$3: $CHECKSUM" > $TFILE
	vpd_write
}

function do_checksum {
  declare -i x_start=0x$1
  declare -i x_len=0x$2
  declare -i x_addr=0x$3
  declare -i x_end=x_start+x_len
  if [ $x_start -le $x_addr ] && [ $x_addr -le $x_end ]
  then
    echo "00$3: 00" > $TFILE
    vpd_write
  fi
  checksum_write $1 $2 $3
}

function hex_from_string {
  MAXLEN=$1
  shift
  echo "$*" | awk -F'	' -v MAXLEN=$MAXLEN '
  BEGIN {
    hex[" "] = 0x20
    chars = "()*+,-./0123456789:;<=>?@"
    chars = chars "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    chars = chars "[\\]^_`"
    chars = chars "abcdefghijklmnopqrstuvwxyz"
    chars = chars "{|}~"
    n = length(chars)
    for (i = 1; i <= n; ++i)
      hex[substr(chars,i,1)] = 0x27 + i
  }
  { string = $1
    string_len = length($1)
    if (string_len > MAXLEN)
      string = substr($1,1,MAXLEN)
    else if (string_len < MAXLEN)
      for (i = string_len + 1; i <= MAXLEN; ++i)
        string = string " "
    n = length(string)
    for (i = 1; i <= n; ++i)
      printf "%x ", hex[substr(string,i,1)]
  }'
}

function do_ascii {
cat > $TFILE << END_OF_ASCII
$1: $(hex_from_string $2 "$3")
END_OF_ASCII
vpd_write
}

function continue_yes_no {
  while true
  do
    read -ep "$* Continue? [y/n]" REPLY
    case $REPLY in
    n*|N*|"") exit 0 ;;
    y*|Y*)    break ;;
    esac
  done
}

function continue_yes_no_in_chassis {
  declare -i D0=0x$(fpga_read d0)
  declare -i testIObit
  let "testIObit = D0 & 0x80"
  if [ $testIObit = "0" ]
  then
    continue_yes_no "This operation is unusual in a chassis."
  fi
}

SCRIPT=${0##*/}

function usage {
  printf "usage:\n"
  printf "%s -[x|a|c|h]\n" $SCRIPT
  printf "  -x a b ..\t@ a write hex byte(s) b ..\n"
  printf "  -a x y z\t@ x write ASCII string z with max length y (decimal)\n"
  printf "  -c x y z\tcalculate checksum starting at x, length y, write it @ z\n"
  printf "  -h\t\tprint this usage message and exit\n"
  printf "  all numbers (except for max string length) are hex, without leading 0x\n"
  exit 1
}

if [ $# -eq 0 ]
then
  usage
fi

case $1 in
-x) if [ $# -lt 3 ]
    then
      usage
    fi
    continue_yes_no_in_chassis
    shift
    do_hex $*
    ;;
-a) if [ $# -lt 4 ]
    then
      usage
    fi
    continue_yes_no_in_chassis
    do_ascii $2 $3 $4
    ;;
-c) if [ $# -lt 4 ]
    then
      usage
    fi
    continue_yes_no_in_chassis
    do_checksum $2 $3 $4
    ;;
-h) usage ;;
*)  usage ;;
esac
