#!/bin/bash
#Calibrates wl1271 Wifi Chip and Sets Power Levels

OEM_DIR="/var/oem"
NVS_DIR="mts"
NVS_OEM_FILE="$OEM_DIR/$NVS_DIR/wl1271-nvs.bin"
NVS_OEM_INI="$OEM_DIR/$NVS_DIR/TQS_S_2.6.ini"
NVS_FILE="/lib/firmware/ti-connectivity/wl1271-nvs.bin"
NVS_DEFAULT_FILE="$NVS_FILE.factory"
NVS_DEFAULT_INI="/usr/share/ti/wifi-utils/ini_files/127x/TQS_S_2.6.ini"
WIFI_PWR_LINE_B="FEM1_TxPerChannelPowerLimits_2_4G_11b ="
WIFI_PWR_LINE_OFDM="FEM1_TxPerChannelPowerLimits_2_4G_OFDM ="
WIFI_PWR_ARR_SIZE=14
WIFI_PWR_INDEX_START=2
WIFI_PWR_INDEX_END=$(( $WIFI_PWR_INDEX_START + $WIFI_PWR_ARR_SIZE))
WIFIMAC=$(mts-io-sysfs show mac-wifi)
CHANNEL="ALL"

# Reset in case getopts has been used previously in the shell.
OPTIND=1

function show_help() {
  echo "Usage: $0 -m <WIFI MAC> -c <CHANNEL> <POWER LIMIT mBm>"
  echo "  Example: $0 -c 1 1250"
  echo "  Sets max transmit power to 12.5 dBm on channel 1"
  echo "Note: Using no options will calibrate to factory settings"
}

while getopts "h?c:m:" opt; do
    case "$opt" in
    h|\?)
        show_help
        exit 0
        ;;
    c)  CHANNEL=$OPTARG
        ;;
    m)  WIFIMAC=$OPTARG
        ;;
    esac
done

shift $((OPTIND-1))
[ "$1" = "--" ] && shift

POWER=$1

regexIsNumber='^[0-9]+$'

if [ "$POWER" != "" ]; then
  if ! [[ $POWER =~ $regexIsNumber ]] ; then
    echo "Error: Power is Not a Number" >&2; exit 1
  fi
  if [ $POWER -lt 0 ]; then
    echo "Error: Minimum power lvl is 0 mBm" >&2; exit 1
  fi
  if [ $POWER -gt 3000 ]; then
    echo "Error: Maximum power lvl is 3000 mBm" >&2; exit 1
  fi
fi

if [ "$CHANNEL" != "ALL" ]; then
  if ! [[ $CHANNEL =~ $regexIsNumber ]] ; then
    echo "Error: Channel is Not a Number" >&2; exit 1
  fi
  if [ $CHANNEL -gt 14 ] || [ $CHANNEL -lt 1 ]; then
    echo "Error: Valid Channels are 1-14" >&2; exit 1
  fi
fi

echo "starting wifi calibration..."

/etc/init.d/wifi stop >/dev/null 2>&1

mts-io-sysfs store wlan-enabled 0
sleep 1
mts-io-sysfs store wlan-enabled 1
sleep 1

modprobe atmel_mci
sleep 5

mount -o remount,rw /var/oem
echo "removing $NVS_OEM_FILE"
# WARNING: need remove file after 'modprobe atmel_mci'
rm -f $NVS_OEM_FILE
mkdir -p $OEM_DIR/$NVS_DIR

if [ ! -f $NVS_OEM_INI ]; then
  cp $NVS_DEFAULT_INI $NVS_OEM_INI
fi

#Pull Applicable Fields
lineB=$(grep "$WIFI_PWR_LINE_B" $NVS_OEM_INI)		#GET B TX PWR LMT LINE
lineOFDM=$(grep "$WIFI_PWR_LINE_OFDM" $NVS_OEM_INI)	#GET OFDM TX PWR LMT LINE
lineB=${lineB%%#*}					#REMOVE TRAILING COMMENT LINE
lineOFDM=${lineOFDM%%#*}				#REMOVE TRAILING COMMENT LINE

if [ "$POWER" != "" ]; then
  POWER=$((($POWER * 2) / 100 ))			#POWER NEEDS TO BE IN 1/2 dB 

  if [ "$CHANNEL" == "ALL" ]; then
      echo "setting power levels on all channels..."
      for ((i=$WIFI_PWR_INDEX_START; i < $WIFI_PWR_INDEX_END; i++)); do   
        pwrLine="$pwrLine $POWER"
      done
  else
      echo "setting power level on channel $CHANNEL..."
      channelIndex=$(( $WIFI_PWR_INDEX_START + $CHANNEL - 1 ))
      IFS=', ' read -a array <<< "$lineB"
      for ((i=$WIFI_PWR_INDEX_START; i < $WIFI_PWR_INDEX_END; i++)); do   
        if [ "$i" == "$channelIndex" ]; then
          pwr=$POWER
        else
          pwr=${array[$i]}
        fi
        pwrLine="$pwrLine $pwr"
      done
  fi
  newLineB="$WIFI_PWR_LINE_B $pwrLine"
  newLineOFDM="$WIFI_PWR_LINE_OFDM $pwrLine"
  sed -i "s/$lineB/$newLineB/g" "$NVS_OEM_INI"
  sed -i "s/$lineOFDM/$newLineOFDM/g" "$NVS_OEM_INI"
else
  #FACTORY SETTINGS
  #960 mBm WAS MEASURED IN LAB TO PRODUCE 12.5 dBm on DEC2013
  #960 mBm => 19 steps in 1/2 dB
  POWER=19						
  echo "setting power levels to factory settings..."
  channel=1
  for ((i=$WIFI_PWR_INDEX_START; i < $WIFI_PWR_INDEX_END; i++)); do
    if [ $channel -gt 11 ]; then
      #Set Channels 12 - 14 to zero power output
      pwrLine="$pwrLine 0"
    else
      pwrLine="$pwrLine $POWER"
    fi
    let channel=channel+1
  done
  newLineB="$WIFI_PWR_LINE_B $pwrLine"
  newLineOFDM="$WIFI_PWR_LINE_OFDM $pwrLine"
  sed -i "s/$lineB/$newLineB/g" "$NVS_OEM_INI"
  sed -i "s/$lineOFDM/$newLineOFDM/g" "$NVS_OEM_INI"
fi

sync

echo "calibrating..."
calibrator plt autocalibrate wlan0 \
    /lib/modules/$(uname -r)/kernel/drivers/net/wireless/ti/wlcore/wlcore_sdio.ko \
    $NVS_OEM_INI \
    $NVS_FILE $WIFIMAC

sync

/etc/init.d/wifi restart >/dev/null 2>&1

mount -o remount,ro /var/oem

echo "...calibration finished"
