#!/bin/bash

#==============================================================================
# This script build Linux kernel for 4000.
# Assuming the kernel source were cloned from SLA git.
# (see https://docs.google.com/document/d/15YPRXXT9w3EfO8qJUdFgwdnKlGynnOgChCMhIkWnxJo/preview)
# usage: 
# 0. Optionally:
#    a) export gccRoot=...  to use different gcc.
#       ex:  export gccRoot=/home/slroot/820cSourceBuild/toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu
#    b) export RELEASE=...  to use different release name.
#       ex:  export RELEASE=4.14.0-qcomlt-arm64
# 1. CD to your working directory where kernel sources are cloned, e.g.
#    > cd 5.xkrn/kernel
# 2  > $SLWSL_SDK/IFC.../buildGitKernel.sh
#==============================================================================
trap 'exit 130' INT		  # Terminate script with Ctrl-C.
JENKINS_MODE=false; BUILD_CONFIG=true; FORCE_BUILD=false; FORCE_BUILD_REBOOT=false; ROOTFS=rootfs

# For Jenkins mode. copy destination.
NIGHTLY_DIR=/mnt/s/Downloads/LinuxDev/SLA4000/upgrade/VideoTrack4000_nightly_trunk


for i in "$@"; do
case $i in
    -D) # "Building Linux Kernel for Dragonboard-820c"
    gccRoot=/home/slroot/820cSourceBuild/toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu
    RELEASE=5.15.0-qcomlt-arm64
    #ROOTFS=userdata
    shift
    ;;
    -j)
    JENKINS_MODE=true
    shift
    ;;
    -k)
    BUILD_CONFIG=false
    shift
    ;;
    -y)
    FORCE_BUILD=true
    shift
    ;;
    -Y)
    FORCE_BUILD=true
    FORCE_BUILD_REBOOT=true
    shift
    ;;
    *)
    echo usage: ${0##*/} [-j] [-y] [-Y]
    echo 1. CD to your working direcoty where kernel source are cloned, e.g. ~/build/kernel
    echo 2. Run this script, e.g. $SLWSL_SDK/IFC.../buildGitKernel.sh
    echo " Options:"
    echo "  j=Jenkins mode, y=build all, Y=build all + Copy&reboot, k=don't build config."
    echo "  -k -y :Handly when rebuilding kernel and burn it to HW."
    echo " Optional exports:"
    echo "   gccRoot=<gcc dir>              # Use different gcc."
    echo "   outDir=<output dir>            # e.g. '/mnt/c/sl/tmp', defualt is '../..'"
    echo "   RELEASE=<release version>      # e.g. 4.14.0-qcomlt-arm64 for Dragonboard820c"
    exit 0
    ;;
esac
done

# Variable Definitions: 
if [ -z "$RELEASE" ]; then
  RELEASE=5.15.0-ifc6601-arm64
fi
scriptDir=$(dirname "$0")   # Get this script's directory.

if [ -z "$outDir" ]; then
  outDir=../..              # Output directory for module tarball and kernel image (relative to kerRoot, i.e. myBuild/kernel/kernel).
fi

toolDir=/mnt/s/Downloads/InForce/IFC6601_Debian_Linux_BSP_880519_V1.1/source/build-tools # InForce tools.
#if ! ls $toolDir &> /dev/null; then # Is toolDir accessible?
  # S: drive is not accessible, use the one in local directory.
  toolDir=$SLWSL_SDK/IFC6601_Debian_Linux_BSP_880519_V1.1/buildTools/build-tools # InForce tools.
#fi

slToolDir=~/z_SL            # gcc will be extracted under this directory.


#==============================================================================
# FUNCTION: Print
#==============================================================================
function Print(){
  SKIP=false; echo ""
  if ! $JENKINS_MODE && ! $FORCE_BUILD ; then
    read -p "$* ([y]/n): " answer
    if [ "${answer:0:1}" == "N" ] || [ "${answer:0:1}" == "n" ]; then SKIP=true; fi
  else
    echo "$*"
  fi
}

#==============================================================================
# Find kernel root directory by finding the first 'CREDITS' file, and CD to it.
#==============================================================================
kerRoot=$(dirname $(find ./ -name 'CREDITS' -print -quit))
pushd $kerRoot > /dev/null                         # <build-dir>/kernel/kernel
SECONDS=0

#==============================================================================
# In Jenkins, checkout the latest from git repository.
#==============================================================================
if $JENKINS_MODE; then
  git pull origin master
fi

# For debugging.
#if false; then                                    # Start of if (false) {
#fi # END OF: if false                             # } // End of if (false).
#set -x                                            # echo on
#set +x                                            # echo off

#==============================================================================
# Extract GCC (if it hasn't been extracted).
#==============================================================================
if [ -z "$gccRoot" ]; then
  gccRoot=$slToolDir/gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu #gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu # Default gcc directory.
  if [ ! -f $gccRoot/bin/aarch64-none-linux-gnu-cpp ]; then # If gcc doesn't exist, then...
    echo "Extracting GCC tools..."
    gccTar=$toolDir/gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu.tar.xz #gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar.xz
    mkdir -p $slToolDir
    pushd $slToolDir > /dev/null
    tar -xf $gccTar
    popd > /dev/null
  fi
fi

#==============================================================================
# Setup build variables
#==============================================================================
export ARCH=arm64
export CROSS_COMPILE=$gccRoot/bin/aarch64-none-linux-gnu- #aarch64-linux-gnu-
echo "RELEASE: [$RELEASE]"
echo "gccRoot: [$gccRoot]"
echo "outDir:  [$outDir]"
echo "toolDir: [$toolDir]"
kernelBuilt=false

#==============================================================================
printf "\nStart building..."
#==============================================================================

if $BUILD_CONFIG; then 
  if $JENKINS_MODE || $FORCE_BUILD; then 
    answer=y;
  else
    read -p "Generate .config? (y/[n]): " answer
  fi
  if [ "${answer:0:1}" != "Y" ] && [ "${answer:0:1}" != "y" ]; then
    echo "Skip .config..."
  else
    make db820c_defconfig #defconfig #distro.config
  fi
fi

Print "Building Kernel, DTB, modules"                        # Build kernel, DTB, modules.
if ! $SKIP; then
  if $JENKINS_MODE; then
    make clean
  fi
  for i in {0..0}; do   # In WSL env, sometimes make just fails, so retry a few times.S
    make -j4 Image.gz dtbs modules KERNELRELEASE=$RELEASE && break
  done
  if [ $? -ne 0 ]; then echo "make kernel failed"; exit 1; fi    # Exit if error.
fi

duration=$SECONDS
echo   "---------------------------------"
printf "Took %02d:%02d to build.\n\n" $(($duration / 60)) $(($duration % 60))


# Install built module locally on WSL.
# - Destination is 2 up so that it goes outside of git! (different from InForce instructions).
#==============================================================================
Print "Preparing modules and making a tarball on WSL..."
#==============================================================================
if ! $SKIP; then
  rm -rf $outDir/lib
  make KERNELRELEASE=$RELEASE modules_install INSTALL_MOD_PATH=$outDir > /dev/null
  if [ $? -ne 0 ]; then echo "make modules failed"; exit 1; fi
  tar cf -  $outDir/lib/modules/$RELEASE | lz4 > $outDir/$RELEASE.tar.lz4 # Create module tar ball w/ LZ4.
  if [ $? -ne 0 ]; then echo "tar failed"; exit 1; fi    # Exit if error.
fi

#==============================================================================
if ! $kernelBuilt; then
  Print "Making the kernel boot image..."
fi
#==============================================================================
if $kernelBuilt || ! $SKIP; then
  #$toolDir/skales/dtbTool -o $outDir/dt.img -s 4096 arch/arm64/boot/dts/qcom/ # Create DTB image.
  if [ $? -ne 0 ]; then echo "dtbTool failed"; exit 1; fi    # Exit if error.
  export cmdline="root=/dev/sda1 rootwait console=ttyMSM0,115200n8"
  cat arch/arm64/boot/Image.gz arch/arm64/boot/dts/qcom/apq8096-db820c.dtb > arch/arm64/boot/Image-dtb
  $toolDir/skales/mkbootimg --kernel arch/arm64/boot/Image-dtb --ramdisk $toolDir/../initramfs-firmware-dragonboard820c-image-qcom-armv8a.cpio.gz --output $outDir/boot-$RELEASE.img --pagesize 4096 --base 0x80000000 --cmdline "$cmdline"     
fi

#==============================================================================
# Copying files to target.
#==============================================================================

# Generate ssh key and copy it to target.
function PrepareSsh {
  if [ ! -f ~/.ssh/id_rsa ] || [ "$2" == "force" ]; then
    ssh-keygen    # generate key.
  fi
  ssh-copy-id slroot@$1 2> /dev/null
}

# Get Target IP address, returned in ipAddr. ipAddr will be undefined if it cannot be reached.
function GetIpAddr {
  if [ -f ~/.sl_q_ip ]; then
    ipAddr=`cat ~/.sl_q_ip`
  else
    ipAddr=$SL_Q_IP
  fi
  answer=N
  while true; do
    # Get target IP address.
    strlen=${#ipAddr}
    if [ "$strlen" -gt 6 ]; then # assume it is a valid IP address.
      if $FORCE_BUILD_REBOOT ; then
        answer=y
      else
        read -p "Copy to $ipAddr? ([y]/n/skip): " answer
      fi
    fi
    ans=$answer; answer=N
    if [ "${ans:0:1}" == "S" ] || [ "${ans:0:1}" == "s" ]; then
      echo "Skipping copy..."; ipAddr=; break;
    elif [ "${ans:0:1}" == "N" ] || [ "${ans:0:1}" == "n" ]; then
      read -p "Enter IP Address, or just ENTER to skip Copy: " ans
      ipAddr=$(echo $ans | grep -o '[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*')
      if [ -z "$ans" ]; then
        answer=S  # If ENTER, then skip copy.
      fi
    else
      # Test if the target is there.
      if ! ping -W 1 -c 1 $ipAddr > /dev/null; then
        printf "WRN: $ipAddr is not accessible.\n\n"
        ipAddr=     # undefine variable.
      else
        PrepareSsh $ipAddr
        echo $ipAddr > ~/.sl_q_ip # Remember the last IP address.
        break;
      fi
    fi
  done
}

#==============================================================================
# Copy kernel & modules to InForce.
#==============================================================================
if ! $JENKINS_MODE; then
  Print "SCP copy files to InForce?"
  if $SKIP; then
    echo "Skip flashing..."
  else
    GetIpAddr
    if [ ! -z "$ipAddr" ]; then
      while true; do
        echo "Copying to $ipAddr..."
        # Try scp, stderr is redirected to scp_err.txt.
        scp $outDir/$RELEASE.tar.lz4 $outDir/boot-$RELEASE.img  slroot@$ipAddr:/home/slroot/Downloads/  2> ~/scp_err.txt
        if [ $? -eq 0 ]; then # success.
          Print "Burn kernel & mudules on InForce?"
          if $SKIP; then
            echo "Skip extracting..."
          else
            echo "Extracting modules & burning kernel to boot partition..." # /dev/sde17 seems to be the kernel partition.
            ssh slroot@$ipAddr "
              sudo mkdir -p /lib/modules/5.15.0-ifc6601-arm64
              sudo chown -R slroot:linaro /lib/modules/5.15.0-ifc6601-arm64
              lz4 -dc --no-sparse /home/slroot/Downloads/$RELEASE.tar.lz4 | sudo tar xf - -C /
              sudo dd if=/home/slroot/Downloads/boot-$RELEASE.img of=/dev/disk/by-partlabel/boot
            "
            # Test code (single file): tar xvf /home/slroot/Downloads/$RELEASE.tar -C /  lib/modules/4.14-ifc6601-v1.0/kernel/drivers/bluetooth/btusb.ko        
            if [ $? -ne 0 ]; then exit 1; fi    # Exit if error.
          fi
          if $FORCE_BUILD_REBOOT; then
            answer=y
          else
            read -p "Reboot InForce? (y/[n]): " answer
          fi
          if [ "${answer:0:1}" == "Y" ] || [ "${answer:0:1}" == "y" ]; then
            ssh slroot@$ipAddr sudo reboot
          fi
          SKIP_FASTBOOT=1
          break # Success!
        else
          # Check ssh error case:
          # @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
          # @    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
          # @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
          # remove SSH key, and try again.
          if grep 'ECDSA' ~/scp_err.txt; then 
            echo "WRN: ssh key might have been changed, retrying..."
            ssh-keygen -f ~/.ssh/known_hosts -R $ipAddr
          else
            echo "ERR: scp failed."
            break
          fi
        fi
      done # while
    fi
  fi
fi

#==============================================================================
# Flash to InForce using FASTBOOT.
#==============================================================================
if [ $JENKINS_MODE == "false" ] && [ -z $SKIP_FASTBOOT ]; then
  read -p "FASTBOOT flash kernel image to InForce? (y/[n]): " answer
  if [ "${answer:0:1}" != "Y" ] && [ "${answer:0:1}" != "y" ]; then
    echo "Skip flashing..."
  else
    # Use FASTBOOT.
    mkdir -p $SLWSL_SDK/$SLWSL_SDK_InForce/tmp # Copy image to a temporary directory which can be accessed from CMD.
    set -x
    cp $outDir/boot-$RELEASE.img $SLWSL_SDK/$SLWSL_SDK_InForce/tmp
    pushd $SLWSL_SDK/$SLWSL_SDK_InForce/tmp > /dev/null
    fastboot.exe  flash boot boot-$RELEASE.img
    set +x
    popd > /dev/null
    printf "\n*** NOTE*** You need to copy & install modules to the HW.\n"
    read -p "Reboot InForce? ([y]/n): " answer
    if [ "${answer:0:1}" != "N" ] && [ "${answer:0:1}" != "n" ]; then
      fastboot.exe  reboot
    fi
  fi
fi


#==============================================================================
# Copy to SVN bin directory (for checking-in kernel binary image).
#==============================================================================
if $JENKINS_MODE; then          # Jenkins mode: copy to nightly directory.
  cp -v $outDir/boot-$RELEASE.img  $NIGHTLY_DIR/
  cp -v $outDir/$RELEASE.tar.lz4   $NIGHTLY_DIR/
  date
fi

exit
