:: windows batch script to update the firmware of a
:: V0.9/2.x.x Pulse Streamer via ssh connection
:: Christof Skupin <christof@swabianinstruments.com>
:: copyright Swabian Instruments 2023
@echo off

echo Pulse Streamer Firmware Updater
echo Repository commit pipelines-2162668314-0-g5df583a
echo.
if [%1] == [] (
    echo PSERROR_1: IP/hostname parameter is empty.
    echo.
    echo To update the Pulse Streamer, please use
    echo "update_system.bat pulsestreamer"
    echo in case the hostname is pulsestreamer or
    echo "update_system.bat IPADDRESS"
    echo and replace IPADDRESS by the IP address, e.g. 192.168.0.1
    pause
    exit /B 1
)
if [%2] == [] (
    echo PSERROR_1: Password parameter is empty.
    echo.
    echo To update the Pulse Streamer, please use
    echo "update_system.bat pulsestreamer xyz"
    echo in case the hostname is pulsestreamer or
    echo "update_system.bat IPADDRESS xyz"
    echo and replace IPADDRESS by the IP address, e.g. 192.168.0.1
    echo and xyz with the login password of your Pulse Streamer.
    echo.
    echo If you are using the PULSE STREAMER WINDOWS APPLICATION to 
    echo perform the firmware update, please ENSURE you have 
    echo version 2.1.0 or later INSTALLED.
    echo.
    echo To download the latest version of the Pulse Streamer Application, please
    echo visit https://www.swabianinstruments.com/pulse-streamer-8-2/downloads/
    echo or contact support@swabianinstruments.com for assistance.
    echo.
    pause
    exit /B 1
)

set HOST=%1
set UPDATE_VERSION=2.1.0
REM If it is a Beta firmware set this variable to Space+Beta
set BETA_SET=
set NEWPASS=%2

FOR /F "delims=. tokens=1,2,3" %%I IN ("%UPDATE_VERSION%") DO (
    SET MAIN=%%I
    SET Sub1=%%J
    SET Sub2=%%K
)

if %MAIN% GTR 1 (
    set tar_flags=xJf
) else if %Sub1% GTR 6 (
    set tar_flags=xJf
) else (
    set tar_flags=xzf
)


if not exist plink.exe (
    echo PSERROR_2: plink.exe is missing.
    exit /B 2
)

if not exist pscp.exe (
    echo PSERROR_2: pscp.exe is missing.
    exit /B 2
)

if not exist wget.exe (
    echo PSERROR_2: wget.exe is missing.
    exit /B 2
)

set "sd_repaired=false"
goto Check_firmware

:Repair_SD
set "sd_repaired=true"
:: make sure the old hostkey is added
cmd.exe /c echo y | plink root@%HOST% -pw %OLDPASS% " " >nul 2>&1
if %ERRORLEVEL% GEQ 1 (
    echo PSERROR_3: Connection Error: Could not establish a connection to Pulse Streamer %1. Aborting.
    pause
    exit /B 3
)

echo Checking state of device...
:: check whether device is in INITRAMFS-mode
plink root@%HOST% -pw !pulsestreamer "[ -f /usr/bin/pulser.elf ] && echo false || echo true" > tmp.txt
set /p answer_pulser_check = < tmp.txt
del tmp.txt
if "%answer_pulser_check%" == "false" (
    goto Check_firmware
)

plink root@%HOST% -pw !pulsestreamer "[ -d /mnt/boot_init ] && [ -d /mnt/root ] && [ -d /mnt/rootfs ] && [ -d /mnt/userconfig ] && echo true|| echo false" > tmp.txt
set /p answer_mnt_check = < tmp.txt
del tmp.txt
if "%answer_mnt_check%" == "false" (
    echo PSERROR_8: Check device state manually
    pause
    exit /B 8
)

REM copy tools to repair system
set fsck_ext4_tool=%~dp0\fsck\fsck.ext4
set fsck_fat_tool=%~dp0\fsck\fsck.fat
if not exist %fsck_ext4_tool% (
    echo PSERROR_2: fsck.ext4 tool not found
    pause
    exit /B 2  
)
if not exist %fsck_fat_tool% (
    echo PSERROR_2: fsck.fat tool not found
    pause
    exit /B 2  
)

echo Uploading fsck-tools
pscp -scp -pw !pulsestreamer %fsck_ext4_tool% root@%HOST%:/sbin/
pscp -scp -pw !pulsestreamer %fsck_fat_tool% root@%HOST%:/sbin/
if %ERRORLEVEL% GEQ 1 (
    echo PSERROR_6: Error during loading files
    echo For assistance contact support@swabianinstruments.com  
    echo.
    exit /B 6
    )

REM set permission
plink root@%HOST% -pw !pulsestreamer "chmod 755 /sbin/fsck.ext4"
plink root@%HOST% -pw !pulsestreamer "chmod 755 /sbin/fsck.fat"

REM repair system
plink root@%HOST% -pw !pulsestreamer "/sbin/fsck.ext4 -p -v /dev/mmcblk0p2"
plink root@%HOST% -pw !pulsestreamer "/sbin/fsck.fat -w -a -l -v /dev/mmcblk0p3"
plink root@%HOST% -pw !pulsestreamer "/sbin/fsck.fat -w -a -l -v /dev/mmcblk0p1"

echo.
echo Restart Pulse Streamer
plink root@%HOST% -pw !pulsestreamer "/sbin/reboot"

echo Rebooting Pulse Streamer, please wait ... (30s)
waitfor /t 30 placeholder > NUL 2>&1

REM Check firmware version
:Check_firmware
echo Connect to Pulse Streamer %1
wget --timeout 5 --tries=10 -q -O - --post-data={\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"getFirmwareVersion\"} --header=Content-Type:application/json http://%HOST%:8050/json-rpc > tmp.txt
if %ERRORLEVEL% GEQ 1 (
    del tmp.txt
    if %sd_repaired% == true (
        echo PSERROR_3: Connection Error: Could not establish a connection for RPC to Pulse Streamer %1. Aborting.
        exit /B 3
    )
    echo Connection Error: Could not establish a connection for RPC to Pulse Streamer %1. Try to repair system...
    goto Repair_SD
)
set /p version_resp= < tmp.txt
del tmp.txt

REM echo %version_resp%

for /F "tokens=3 delims=," %%a in ("%version_resp%") do (
   REM echo %%a
   set version_field=%%a
)
REM echo %version%
for /F "tokens=1,2 delims=:}" %%b in ("%version_field%") do (
    set result=%%b
    set version=%%c
)
set current_version=%version:"=%
REM echo %result%
REM echo %current_version%
REM echo %UPDATE_VERSION%

if %result%=="error" (
    echo Detected firmware 0.9
    echo.
    goto UPDATE_0.9
)


::update version
if not exist update_v"%UPDATE_VERSION%" (
    echo New firmware file'update_v%UPDATE_VERSION%' must be present in the current directory!
    pause
    exit /B 2
) else (
    set file_path=update_v%UPDATE_VERSION%
    set updater=update_v%UPDATE_VERSION%
)
REM echo %file_path%

REM Estimate old password
SET key=dev
CALL SET keyRemoved=%%current_version:%key%=%%
if NOT "x%keyRemoved%"=="x%current_version%" (
    set OLDPASS=!pulsestreamer
) else if %current_version:~0,5%==2.0.0 (
    set OLDPASS=!pulsestreamer
) else if %current_version:~0,1%==1 (
    set OLDPASS=!pulsestreamer
) else (
    set OLDPASS=%2
)


:: make sure the old hostkey is added
cmd.exe /c echo y | plink root@%HOST% -pw %OLDPASS% " " >nul 2>&1
if %ERRORLEVEL% GEQ 1 (
    echo PSERROR_3: Connection Error: Could not establish a connection to Pulse Streamer %1. Aborting.
    pause
    exit /B 3
)

plink root@%HOST% -pw %OLDPASS% "[ -f /userconfig/network/network.conf ] || echo Custom version" > tmp.txt
set /p answer_custom= < tmp.txt
del tmp.txt
if "%answer_custom%"=="Custom version" (
    echo PSERROR_4: Detected Custom firmware version
    echo Please contact support@swabianinstruments.com
    pause
    EXIT /B 4
)

echo Update firmware version %current_version% to firmware version %UPDATE_VERSION%%BETA_SET%
echo.

:: wait for user confirmation
:again_>1.0
   echo We will update the firmware of your
   echo Pulse Streamer 8/2 over your network.
   echo This will take about 5 min.
   echo 1. DO NOT INTERRUPT YOUR NETWORK CONNECTION!
   echo 2. Do NOT TURN OFF YOUR COMPUTER OR PULSE STREAMER!
   echo Are you ready (y/n)
   set /p answer=
   if /i "%answer:~,1%" EQU "y" goto continue_>1.0
   if /i "%answer:~,1%" EQU "n" exit /B 5
   echo Please type y for Yes or n for No
   goto again_>1.0

:continue_>1.0

REM copy files
echo Check space on user partition
::get update file size
set "filename=%file_path%"
for %%A in (%filename%) do set filesize= %%~zA
::get space on user partition
plink root@%HOST% -pw %OLDPASS% "df -m /dev/mmcblk0p3 | grep -n 2 | awk -F ' ' '{print $4}'" > tmp.txt
set /p space= < tmp.txt
del tmp.txt
set /A space= (%space%-12)*1024*1024
::check and delete
if %filesize% gtr %space% (
    echo Not enough space left
    echo Deleting unnecessary files and directories 
    plink root@%HOST% -pw %OLDPASS% "cd /userconfig; find . ! -name README ! -name network ! -name hardware ! -name . ! -name .. -maxdepth 1 -exec rm -r {} \;"
    )
echo.

::upload update file
echo Uploading update-tar-archive
pscp -scp -pw %OLDPASS% %filename% root@%HOST%:/userconfig/
if %ERRORLEVEL% GEQ 1 (
    echo PSERROR_6: Error during loading files
    echo For assistance contact support@swabianinstruments.com  
    echo.
    exit /B 6
    )
echo.

FOR /F "delims=. tokens=1,2,3" %%I IN ("%current_version%") DO (
    SET main_current=%%I
    SET sub1_current=%%J
    SET sub2_current=%%K
)

FOR /F "delims=. tokens=1,2,3" %%I IN ("%UPDATE_VERSION%") DO (
    SET main_update=%%I
    SET sub1_update=%%J
    SET sub2_update=%%K
)

REM Decide on optimal update steps
if %main_update% geq 2 if %main_current%==1 if %sub1_current% geq 2 if %sub1_current% lss 7 goto SAFE_FOR_INCMP_KERNEL
if %main_update%==1 if %sub1_update% geq 7 if %main_current%==1 if %sub1_current% geq 2 if %sub1_current% lss 7 goto SAFE_FOR_INCMP_KERNEL

:COMMON_WAY
REM First update the boot partition and then enter update mode
REM mount and delete boot partition
echo Deleting boot partition
plink root@%HOST% -pw %OLDPASS% "mkdir /mnt/boot_init"
plink root@%HOST% -pw %OLDPASS% "mount /dev/mmcblk0p1 /mnt/boot_init"
plink root@%HOST% -pw %OLDPASS% "rm -rf /mnt/boot_init/*
echo DONE

REM unpacking archive and install files for boot partition
echo Updating boot partition
plink root@%HOST% -pw %OLDPASS% "tar -%tar_flags% /userconfig/%updater% boot_init/ -C /mnt/boot_init/ --strip-components=1"
plink root@%HOST% -pw %OLDPASS% "umount /dev/mmcblk0p1"
echo DONE
echo.

if %current_version:~0,4%==1.4. (
    echo Preparing reboot
    echo Disabling analog and digital outputs as well as output driver power supply
    plink root@%HOST% -pw %OLDPASS% "echo 0 > /sys/class/gpio/gpio909/value"
    plink root@%HOST% -pw %OLDPASS% "echo 0 > /sys/class/gpio/gpio915/value"
    plink root@%HOST% -pw %OLDPASS% "echo 0 > /sys/class/gpio/gpio914/value"
    echo.
)

echo Restart Pulse Streamer in update-mode
plink root@%HOST% -pw %OLDPASS% "/usr/sbin/update"

echo Rebooting Pulse Streamer, please wait ... (50s)
waitfor /t 50 placeholder > NUL 2>&1

:hostkey_check_0
if /i "%HOST%" == "q" exit /B 5
:: make sure the new hostkey is added - add new hostkey
cmd.exe /c echo y | plink root@%HOST% -pw !pulsestreamer " " >nul 2>&1
if %ERRORLEVEL% GEQ 1 (
    echo CONNECTION ERROR: Could not establish a connection to Pulse Streamer %HOST%.
    echo You may have performed the update with incompatible network settings. 
    echo In that case, you must enter a valid IP address for your device.
    echo DO NOT DISCONNECT THE PULSE STREAMER FROM THE POWER SUPPLY.
    echo Try the connection with the last known IP address of the device: %HOST%
    echo If this does not work, please plug the Pulse Streamer directly into your
    echo computer, open a second instance of the Pulse Streamer Application and 
    echo search for a Pulse Streamer marked as PS 8/2 in update mode.
    echo For assistance, contact support@swabianinstruments.com  
    echo.
    echo Enter Pulse Streamer IP address or quit(q^) to cancel update process^:
    set /p HOST=
    goto hostkey_check_0
)
echo.
goto SAFE_FROM_HERE

:SAFE_FOR_INCMP_KERNEL
REM First, enter update mode. Then update all partitions - keeps boot and rootfs compatible
if %current_version:~0,4%==1.4. (
    echo Preparing reboot
    echo Disabling analog and digital outputs as well as output driver power supply
    plink root@%HOST% -pw %OLDPASS% "echo 0 > /sys/class/gpio/gpio909/value"
    plink root@%HOST% -pw %OLDPASS% "echo 0 > /sys/class/gpio/gpio915/value"
    plink root@%HOST% -pw %OLDPASS% "echo 0 > /sys/class/gpio/gpio914/value"
    echo.
)

echo Restart Pulse Streamer in update-mode
plink root@%HOST% -pw %OLDPASS% "/usr/sbin/update"

echo Rebooting Pulse Streamer, please wait ... (30s)
waitfor /t 30 placeholder > NUL 2>&1

:hostkey_check_1
if /i "%HOST%" == "q" exit /B 5
:: make sure the new hostkey is added - add new hostkey
cmd.exe /c echo y | plink root@%HOST% -pw !pulsestreamer " " >nul 2>&1
if %ERRORLEVEL% GEQ 1 (
    echo CONNECTION ERROR: Could not establish a connection to Pulse Streamer %HOST%.
    echo You may have performed the update with incompatible network settings. 
    echo In that case, you must enter a valid IP address for your device.
    echo DO NOT DISCONNECT THE PULSE STREAMER FROM THE POWER SUPPLY.
    echo Try the connection with the last known IP address of the device: %HOST%
    echo If this does not work, please plug the Pulse Streamer directly into your
    echo computer, open a second instance of the Pulse Streamer Application and 
    echo search for a Pulse Streamer marked as PS 8/2 in update mode.
    echo For assistance, contact support@swabianinstruments.com  
    echo.
    echo Enter Pulse Streamer IP address or quit(q^) to cancel update process^:
    set /p HOST=
    goto hostkey_check_1
)
echo.

REM delete boot partition
echo Deleting boot partition
plink root@%HOST% -pw !pulsestreamer "rm -rf /mnt/boot_init/*
echo DONE

REM unpacking archive and install files for boot partition
echo Updating boot partition
plink root@%HOST% -pw !pulsestreamer "tar -%tar_flags% /mnt/userconfig/%updater% boot_init/ -C /mnt/boot_init/ --strip-components=1"
echo DONE
echo.

:SAFE_FROM_HERE
REM Common update part
REM removing old firmware
echo Removing old firmware...
plink root@%HOST% -pw !pulsestreamer "rm -rf /mnt/rootfs/*"
echo DONE

REM Update root file system
echo Installing new firmware...
plink root@%HOST% -pw !pulsestreamer "tar -%tar_flags% /mnt/userconfig/%updater% root_fs/ -C /mnt/rootfs/ --strip-components=1"
echo DONE

if %current_version:~0,4%==1.0. (
    goto :userconf_completion
)
if %current_version:~0,4%==1.1. (
    goto :userconf_completion
)
if %current_version:~0,4%==1.2. (
    REM Add files to userconfig partition
    echo Adding files to userconfig partition...
    plink root@%HOST% -pw !pulsestreamer "tar -%tar_flags% /mnt/userconfig/%updater% userconfig/hardware -C /mnt/"
    echo DONE
)
goto :end_userconf

:userconf_completion
REM Add files to userconfig partition
echo Adding files to userconfig partition...
plink root@%HOST% -pw !pulsestreamer "tar -%tar_flags% /mnt/userconfig/%updater% userconfig/network/hostname -C /mnt/"
plink root@%HOST% -pw !pulsestreamer "tar -%tar_flags% /mnt/userconfig/%updater% userconfig/hardware -C /mnt/"
echo DONE
:end_userconf

REM deleting update stuff
echo Remove update files...
plink root@%HOST% -pw !pulsestreamer "rm -rf /mnt/userconfig/%updater%"
echo DONE
echo.
)

:restart_and_check
REM Reboot Pulse Streamer
plink root@%HOST% -pw !pulsestreamer "/sbin/reboot"

echo Rebooting Pulse Streamer, please wait ... (30s)
waitfor /t 30 placeholder > NUL 2>&1

:hostkey_check_2
if /i "%HOST%" == "q" exit /B 5
:: make sure the new hostkey is added - add new hostkey
cmd.exe /c echo y | plink root@%HOST% -pw %NEWPASS% " " >nul 2>&1
if %ERRORLEVEL% GEQ 1 (%NEWPASS%
    echo CONNECTION ERROR: Could not establish a connection to Pulse Streamer %HOST%.
    echo Possibly, the IP address of your Pulse Streamer changed after reboot.
    echo If this is the case, you must enter a valid IP address for your device.
    echo DO NOT DISCONNECT THE PULSE STREAMER FROM THE POWER SUPPLY.
    echo Try the connection with the last known IP address of the device: %HOST%
    echo If this does not work, open a second instance of the Pulse Streamer Application and 
    echo scan the network for your Pulse Streamer.
    echo For assistance, contact support@swabianinstruments.com  
    echo.
    echo Enter Pulse Streamer IP address or quit(q^) to cancel update process^:
    set /p HOST=
    goto hostkey_check_2
)
:: check new password by testing if pulser.elf is in the right place
plink root@%HOST% -pw %NEWPASS% "[ -f /usr/bin/pulser.elf ] || echo pulser.elf is missing"

wget -q -O - --post-data={\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"getFirmwareVersion\"} --header=Content-Type:application/json http://%HOST%:8050/json-rpc
echo.
wget -q -O - --post-data={\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"getFirmwareVersion\"} --header=Content-Type:application/json http://%HOST%:8050/json-rpc > tmp.txt
set /p lic_resp= < tmp.txt
del tmp.txt
for /F "tokens=3 delims=," %%a in ("%lic_resp%") do (
   REM echo %%a
   set version_field=%%a
)

for /F "tokens=1,2 delims=:}" %%b in ("%version_field%") do (
    set result=%%b
    set version=%%c
)

if %version%=="%UPDATE_VERSION%%BETA_SET%" (
    echo PSOK: Firmware successfully updated
    pause
    EXIT /B 0
)
echo PSERROR_7: Update not successful! For support contact support@swabianinstruments.com
echo.
echo.
pause
exit /B 7


:UPDATE_0.9
::0.9

:: make sure the old hostkey is added
cmd.exe /c echo y | plink root@%HOST% -pw root " " >nul 2>&1
if %ERRORLEVEL% GEQ 1 (
    echo PSERROR_3: Connection Error: Could not establish a connection to Pulse Streamer %1. Aborting.
    pause
    exit /B 3
)

echo Update firmware version v0.9 to firmware version %UPDATE_VERSION%
echo.

::update version
if not exist update_v"%UPDATE_VERSION%".img (
    echo PSERROR_2: New firmware image file'update_v%UPDATE_VERSION%.img' must be present in the current directory!
    pause
    exit /B 2
) else (
        set file_path=update_v%UPDATE_VERSION%.img
)

:: wait for user confirmation
:again_0.9
    echo We will update the firmware of your
    echo Pulse Streamer 8/2 over your network.
    echo This will take about 5 min.
    echo 1. DO NOT INTERRUPT YOUR NETWORK CONNECTION!
    echo 2. Do NOT TURN OFF YOUR COMPUTER OR PULSE STREAMER!
    set /p answer=Are you ready (y/n)
    if /i "%answer:~,1%" EQU "y" goto continue_0.9
    if /i "%answer:~,1%" EQU "n" exit /B 5
    echo Please type y for Yes or n for No
    goto again_0.9

:continue_0.9

echo Stop pulser.elf
plink root@%HOST% -pw root "killall -9 pulser.elf"

echo Unmounting SD-card
plink root@%HOST% -pw root "umount /dev/mmcblk0p1"

echo Writing new image. This will take about 5 min ...
plink root@%HOST% -pw root "dd of=/dev/mmcblk0 obs=32M" < %file_path%
echo Image written.

REM Reboot Pulse Streamer
plink root@%HOST% -pw root "/sbin/reboot"

echo Rebooting Pulse Streamer, please wait ... (30s)
waitfor /t 30 placeholder > NUL 2>&1

:hostkey_check
if /i "%HOST%" == "q" exit /B 5
:: make sure the new hostkey is added - add new hostkey
cmd.exe /c echo y | plink root@%HOST% -pw %NEWPASS% " " >nul 2>&1
if %ERRORLEVEL% GEQ 1 (
    echo CONNECTION ERROR: Could not establish a connection to Pulse Streamer %HOST%.
    echo Possibly, the IP address of your Pulse Streamer changed after reboot.
    echo If this is the case, you must enter a valid IP address for your device.
    echo DO NOT DISCONNECT THE PULSE STREAMER FROM THE POWER SUPPLY.
    echo Try the connection with the last known IP address of the device: %HOST%
    echo If this does not work, open a second instance of the Pulse Streamer Application and 
    echo scan the network for your Pulse Streamer.
    echo For assistance, contact support@swabianinstruments.com    
    echo.
    echo Enter Pulse Streamer IP address or quit(q^) to cancel update process^:
    set /p "HOST= "
    goto hostkey_check
)


:: check whether the pulser is running
plink root@%HOST% -pw %NEWPASS% "[ -f /usr/bin/pulser.elf ] && echo System updated successfully || echo System update failed"

echo.
echo Please contact support@swabianinstruments.com to receive the licence which activates the pulse streamer.
echo Copy the following lines to the email:
:: read ID Number
wget -q -O - --post-data={\"jsonrpc\":\"2.0\",\"id\":\"1\",\"method\":\"getSerial\",\"params\":[0]} --header=Content-Type:application/json http://%HOST%:8050/json-rpc
echo.
wget -q -O - --post-data={\"jsonrpc\":\"2.0\",\"id\":\"1\",\"method\":\"getSerial\",\"params\":[1]} --header=Content-Type:application/json http://%HOST%:8050/json-rpc 
echo.
echo PSOK
echo.
pause
EXIT /B 0
)