#!/bin/sh ########################################################################### # # Copyright (c) 2022-2023 Diality Inc. - All Rights Reserved. # # THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN # WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. # # @file globals.sh # # @author (last) Behrouz NematiPour # @date (last) 15-Dec-2022 # @author (original) Behrouz NematiPour # @date (original) 15-Dec-2022 # ############################################################################ # @details # This script includes the global variables and functions to be used in the setup and start scripts. TRUE=1 FALSE=0 COMMENT_STAR="********************************************************************************" COMMENT_DASH="--------------------------------------------------------------------------------" DATETIME="$1 $2" #DO NOT MODIFY VARIABLES, unless the denali application is updated as well to match. SDCARD_DEV=/dev/mmcblk1 SDCARD_PRT=/dev/mmcblk1p1 SDCARD_MNT=/media/sd-card SDCARD_TYP_NAME=ext4 SDCARD_TYP_NUMB=83 USB_DEV=/dev/sda1 USB_MNT=/media/usb CLOUDSYNC_FOLDER=cloudsync # both for log and application LOG_LOCATION=$HOME/Desktop LOG_OUT_FILE="" LOG_ERR_FILE="" LOG_BASE=$SDCARD_MNT LOG_LOC_LOG=log LOG_LOC_ERR=service EXT_GZIP=gz EXT_PEND=u ERR_MISSING_FOLDER=101 ERR_MISSING_FILE=102 ERR_CONNECTION=103 ERR_DENALI_BIN=104 ERR_FONTS_EMTY=105 ERR_FONTS_PATH=106 ERR_KILLPROMPT=107 ERR_MISSING_KEY=109 ERR_SCP_FAIL=110 ERR_INVALID_IP=111 ERR_SD_CARD=112 ERR_LOGBACKUP_PATH=113 SRC_FILE_SSHKEY="$HOME/.ssh/id_rsa" SRC_FILE_SSHKEY_PUB=$SRC_FILE_SSHKEY.pub SRC_PATH_SCRIPTS="scripts" SRC_PATH_CONFIG="settings" SRC_PATH_CLOUDSYNC="cloudsync" SRC_PATH_DRYDEMO="dry-demo" SRC_PATH_FONTS="fonts" DST_IP="" DST_USER=root DST_PATH_CONFIG="/home/$DST_USER/.config" DST_PATH_HOME="/home/$DST_USER" DST_PATH_SCRIPTS="/home/$DST_USER/scripts" DST_PATH_CLOUDSYNC="/home/$DST_USER/cloudsync" DST_PATH_DRYDEMO="/home/$DST_USER/dry-demo" DST_PATH_FONTS="/usr/share/fonts/truetype" POSTLOG=/tmp/post.log POSTERR=/tmp/post.err POSTOUT=/tmp/post.out POSTMSG_POSTFIX_PASSED=" passed" POSTMSG_POSTFIX_FAILED=" failed" POSTMSG_CANBUS="CANBus" POSTMSG_SDCARD="SD-CARD" POSTMSG_TOUCH="Touch" POSTMSG_RTC="RTC" POSTMSG_WIFI="WiFi" POSTMSG_BLUETOOTH="Bluetooth" POSTMSG_SHASUM="App shasum" POSTMSG_CLOUDSYNC="CloudSync" POSTMSG_SETTINGSCRC="SettingsCRC" TDCTL_NTP_USED=$FALSE TDCTL_RTC_LOCL=$TRUE TDCTL_TIMEZONE=America/Los_Angeles IP_SEG_MAX_LEN=3 IP_EMT="192.168.10." SSH_PARAM="-oUserKnownHostsFile=/dev/null -oStrictHostKeyChecking=no -oLogLevel=ERROR -oConnectTimeout=2" CMD_RTC_EPOCH="cat /sys/class/rtc/rtc0/since_epoch" CMD_SDCARD_DEV="ls $SDCARD_DEV" CMD_SDCARD_PRT="ls $SDCARD_PRT" CMD_LINUX_TYPE="sfdisk --part-type $SDCARD_DEV 1" INITD_LOCATION=/etc/init.d/ INITD_AUTOSTART=autostart DENALI_BIN=denali LAUNCH_SCR=run.sh SETUP_CONF_FILE="setup.conf" SETUP_ENABLE_MANUFACTURING_MODE="ManufacturingMode" SETUP_ENABLE_UpdatingING_MODE="UpdatingMode" # Log cli options # x: enable long name (IMPORTANT: removed for the impact on Test Protocols, and timeline) # y: enable upload # z: enable compression APPLICATION_PARAMS_DEFAULT="-yz" APPLICATION_PARAMS="" CloudSync_DRT_SERVER_IP="" CloudSync_DRT_SERVER_PORT=80 CLOUD_USER=cloud CLOUD_HOME=/home/$CLOUD_USER DENALI_USER=denali DENALI_HOME=/home/$DENALI_USER DEMO_USER=root DEMO_HOME=/home/$DEMO_USER SETTING_CONF_FOLDER_PATH=/var/configurations SETTINGS_CRC_FILE_PATH=$DENALI_HOME/settings.crc CLOUDSYNC_CONFIG_SRC=$CLOUD_HOME/cloudsync/cloudsync/config/config.json CLOUDSYNC_CONFIG_DST=$SETTING_CONF_FOLDER_PATH/CloudSync/config/config.json DEMO_MODE=0 P_CANBUS=can0 V_CANBUS=can1 D_CANBUS=$P_CANBUS function checkDemoMode() { if [ -d "$DEMO_HOME/$SRC_PATH_DRYDEMO" ]; then DEMO_MODE=1 fi } # *** this function should be used without brackets in the if to be effective. function isDemoMode() { if [ $DEMO_MODE -eq 1 ]; then echo $TRUE else echo $FALSE fi } function user_input() { read -p "$1? $2" -n 1 -r if [ "$CONTINUE" == "y" ]; then echo "" return $TRUE else echo "" return $FALSE fi } function confirm() { read -p "$1? [y,n]" -n 1 -r CONTINUE if [ "$CONTINUE" == "y" ]; then echo "" return $TRUE else echo "" return $FALSE fi } function string_trim() { local var="$*" # remove leading whitespace characters var="${var#"${var%%[![:space:]]*}"}" # remove trailing whitespace characters var="${var%"${var##*[![:space:]]}"}" printf '%s' "$var" } function echo_star_comment() { echo "$COMMENT_STAR"" $1 " } function echo_star_message() { echo " * $1" } function echo_dash_comment() { echo "$COMMENT_DASH"" $1 " } function echo_dash_message() { echo " $1" } function timestamp() { echo $(date +"%Y%m%d-%H%M%S") } function validIP() { local ip=$1 if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then OIFS=$IFS IFS='.' ip=($ip) IFS=$OIFS if [[ ${ip[0]} -gt 255 && \ ${ip[1]} -gt 255 && \ ${ip[2]} -gt 255 && \ ${ip[3]} -gt 255 ]]; then return $ERR_INVALID_IP fi else return $ERR_INVALID_IP fi return 0 } # Does the file contain a string? if # not, add a line at end. # If $1 not in $2 then append line $3 to end. # $1 What to look for. # $2 File name. # $3 What to add. function appendIfMissing() { # q for quiet, F for regular string match, not -x because not full line. # Done as one command because this is done remotely. grep -qF $1 $2 || echo $3 >> $2 } # Remove all lines that contain $1 in file $2 then append $3. # $1 What to look for. # $2 File name. function removeIfFound() { sed -i /${1}/d $2 } function existsFolder() { if [ ! -d "$1" ]; then return "$ERR_MISSING_FOLDER" fi } function existsFile() { if [ ! -f "$1" ]; then return "$ERR_MISSING_FILE" fi } COUT="/dev/null" function setupConsoleout() { # /dev/ttymxc1 COUT="/dev/$(echo $(dmesg | grep "printk: console") | sed 's/.*printk: console.*\(tty.*\)].*/\1/')" } function post_log_clear () { echo "" > $POSTLOG; } function post_err_clear () { echo "" > $POSTERR; } function post_out_clear () { echo "" > $POSTOUT; } function post_log_pass () { echo "$1" >> $POSTLOG; echo "[ OK ] $1" > "$COUT"; } function post_log_fail () { echo "$1" >> $POSTLOG; echo "[FAILED] $1" > "$COUT"; } function post_log_dash () { echo "$COMMENT_DASH$1" >> $POSTLOG; echo "$COMMENT_DASH$1" > "$COUT"; } function post_log_star () { echo "$COMMENT_DASH$1" >> $POSTLOG; echo "$COMMENT_STAR$1" > "$COUT"; } function post_log () { echo "$1" >> $POSTLOG; echo " $1" > "$COUT"; } function post_err () { echo "$1" >> $POSTERR; } function post_err_dash () { echo "$COMMENT_DASH$1" >> $POSTERR; } function post_out () { echo "$1" >> $POSTOUT; } function post_out_dash () { echo "$COMMENT_DASH$1" >> $POSTOUT; } function debug () { echo_dash_comment echo_dash_message "$1" echo_dash_comment } function disableRootSSH() { local SSHD_CONFIG="/etc/ssh/sshd_config" sudo sed -i '/PermitRootLogin/c\PermitRootLogin no' $SSHD_CONFIG } function setupResolved() { echo nameserver 8.8.8.8 > /etc/resolv.conf systemctl start systemd-resolved.service } function cleanupPOSTLogs() { # cleanup the POST log file post_log_clear post_err_clear post_out_clear post_log_star " ***** " post_log "Start: $(timestamp)" # log the current date, time } function killApplication() { # ---------------------------------------- STOP denali in case running (sys not rebooted) killall $DENALI_BIN } function queryOSVersion() { #get the OS version ----------------------- OS Version post_log_dash " OS Version " post_log "$(cat /etc/os-release)" } function setupEthernet() { #setting up ethernet----------------------- Ethernet post_log_dash " Ethernet " ieth=eth0 udhcpc --timeout=5 --retries=2 -n -i $ieth post_log "$(ip addr show $ieth)" # -details -statistics } function setupPCAN() { #setting up can interface ----------------- CANBus post_log_dash " CANBus " #current settings can be retrieved by the command below #$ ip -details -statistics link show $P_CANBUS ip link set $P_CANBUS up type can bitrate 250000 restart-ms 100 ifconfig $P_CANBUS txqueuelen 4000 } function setupVCAN() { modprobe vcan ip link add dev $V_CANBUS type vcan ip link set $V_CANBUS up } function checkCANBus() { candump $D_CANBUS -T1 # check if candump can successfully use the port. will terminate in 1ms if [ $? -eq 0 ]; then post_log_pass "$POSTMSG_CANBUS$POSTMSG_POSTFIX_PASSED" post_log "$(ip link show $D_CANBUS)" # -details -statistics else post_log_fail "$POSTMSG_CANBUS$POSTMSG_POSTFIX_FAILED" fi } function setupCANBus() { if [ "$1" == "setup" ];then D_CANBUS=$P_CANBUS # it is the default but kept to be consistent. setupPCAN else if [ $(isDemoMode) -eq $TRUE ]; then D_CANBUS=$V_CANBUS setupVCAN else D_CANBUS=$P_CANBUS # it is the default but kept to be consistent. setupPCAN fi fi checkCANBus } function setupSDCard() { #mounting sdcard -------------------------- SD-CARD post_log_dash " SD-CARD " mkdir -p $SDCARD_MNT mount -o noexec,nodev,nosuid $SDCARD_PRT $SDCARD_MNT SDCTEST="$(mount | grep "$SDCARD_PRT on $SDCARD_MNT type $SDCARD_TYP_NAME (rw,")" if ! [ -z "$SDCTEST" ]; then SDINFO="$(df -h | grep -i $SDCARD_MNT)" post_log_pass "$POSTMSG_SDCARD$POSTMSG_POSTFIX_PASSED" post_log "$SDCTEST" post_log "$SDINFO" else post_log_fail "$POSTMSG_SDCARD$POSTMSG_POSTFIX_FAILED" fi } function testRTC() { #test the RTC ----------------------------- RTC post_log_dash " RTC" #may not be an accurate test but sufficient for now #and could not find a way to get the rtc clock with the higher resolusion #it should not be confused with date command which is system date/time and not hwclock hwclock -r # if there is any issue with rtc hwclock will show errors if [ $? -eq 0 ]; then RTC1=$($CMD_RTC_EPOCH) sleep 1 RTC2=$($CMD_RTC_EPOCH) if [ $(($RTC2 - $RTC1)) -eq 1 ]; then post_log_pass "$POSTMSG_RTC$POSTMSG_POSTFIX_PASSED" else post_log_fail "$POSTMSG_RTC$POSTMSG_POSTFIX_FAILED" fi fi } function setupWiFi() { # ----------------------------------------- WiFi post_log_dash " WiFi " # create the wpa supplicant folder for conf storing iwlan=wlan0 WPA_SUPPLICANT_DIR="/etc/wpa_supplicant/" WPA_SUPPLICANT_CNF="wpa_supplicant-$iwlan.conf" mkdir -p $WPA_SUPPLICANT_DIR # remove any software blocks rfkill unblock wlan if [[ ! -z $(dmesg | grep "wlan: driver loaded") ]]; then post_log_pass "$POSTMSG_WIFI$POSTMSG_POSTFIX_PASSED [driver]" post_log "$(dmesg | grep -i wlan:)" # start the wpa_supplicant service post_log "start wpa_supplicant service" systemctl start wpa_supplicant@$iwlan.service if [ $? -eq 0 ]; then post_log_pass "$POSTMSG_WIFI$POSTMSG_POSTFIX_PASSED [service]" # try to connect to WiFi if [ -f $WPA_SUPPLICANT_DIR$WPA_SUPPLICANT_CNF ]; then post_log_dash " WiFi Connection " killall udhcpc post_log "connecting to WiFi" # run this manually in terminal if didn't work on bootup udhcpc --timeout=5 --retries=2 -n -i $iwlan fi post_log "$(ip link show $iwlan)" # -details -statistics else post_log_fail "$POSTMSG_WIFI$POSTMSG_POSTFIX_FAILED" post_log "$(systemctl --failed | grep wpa)" fi else post_log_fail "$POSTMSG_WIFI$POSTMSG_POSTFIX_FAILED" fi } function setupBluetooth() { # ----------------------------------------- Bluetooth post_log_dash " Bluetooth " /usr/share/silex-uart/silex-uart.sh stop 1>> $POSTOUT 2>> $POSTERR sleep 1 /usr/share/silex-uart/silex-uart.sh start 1>> $POSTOUT 2>> $POSTERR sleep 5 hciconfig hci0 up if [ $? -eq 0 ]; then post_log_pass "$POSTMSG_BLUETOOTH$POSTMSG_POSTFIX_PASSED" post_log "$(hciconfig hci0)" else post_log_fail "$POSTMSG_BLUETOOTH$POSTMSG_POSTFIX_FAILED" fi } function testTouchscreen() { #test the touch screen -------------------- Touch post_log_dash " Touch " # when successfully connected and can be loaded # Sitronix touch driver 2.10.2 Release date: 20180809 # atmel_mxt_ts 3-004a: Direct firmware load for maxtouch.cfg failed with error -2 # atmel_mxt_ts 3-004a: Touchscreen size X1279Y799 # input: Atmel maXTouch Touchscreen as /devices/platform/soc@0/soc@0:bus@30800000/30a50000.i2c/i2c-3/3-004a/input/input2 # When NOT connected # Sitronix touch driver 2.10.2 Release date: 20180809 TSTEST="$(dmesg | grep "input: Atmel maXTouch Touchscreen as ")" if [ "$?" -eq 0 ]; then post_log_pass "$POSTMSG_TOUCH$POSTMSG_POSTFIX_PASSED" post_log "$TSTEST" else post_log_fail "$POSTMSG_TOUCH$POSTMSG_POSTFIX_FAILED" fi } function testApplicationShasum_setup() { # ----------------------------------------- Sha256Sum post_log_dash " Sha256Sum " #check the denali applicatoin checksum SHA_ACT=$(tail -c 83 $HOME/$DENALI_BIN | cut -c19-82) SHA_EXP=$(head -c -83 $HOME/$DENALI_BIN | sha256sum -b --tag | cut -c14-77) if [ "$SHA_ACT" == "$SHA_EXP" ]; then post_log_pass "$POSTMSG_SHASUM$POSTMSG_POSTFIX_PASSED" else post_log_fail "$POSTMSG_SHASUM$POSTMSG_POSTFIX_FAILED" fi } function testApplicationShasum_local() { # ----------------------------------------- Sha256Sum post_log_dash " Sha256Sum " #check the denali applicatoin checksum SHA_ACT=$(tail -c 83 $DENALI_HOME/$DENALI_BIN | cut -c19-82) SHA_EXP=$(head -c -83 $DENALI_HOME/$DENALI_BIN | sha256sum -b --tag | cut -c14-77) if [ "$SHA_ACT" == "$SHA_EXP" ]; then post_log_pass "$POSTMSG_SHASUM$POSTMSG_POSTFIX_PASSED" else post_log_fail "$POSTMSG_SHASUM$POSTMSG_POSTFIX_FAILED" fi } function testCloudSystem() { # ----------------------------------------- CloudSystem post_log_dash " CloudSystem " post_log "$(ip addr show $iwlan)" # -details -statistics post_log "$(ping www.diality.staging.kebormed.com -I $iwlan -c 3 -4)" } function startCloudSync_setup() { # ----------------------------------------- CloudSync post_log_dash " CloudSync " local CLOUDSYNC_PATH=$HOME/$CLOUDSYNC_FOLDER if [ -d $CLOUDSYNC_PATH ]; then # removing the previous treatment logs so the new buff starts with fresh sequence echo "Removing CloudSync I/O buff" local CLOUDSYNC_LOGS="$SDCARD_MNT/$CLOUDSYNC_FOLDER/" local CLOUDSYNC_CONF="$CLOUDSYNC_PATH/cloudsync/config/" local CLOUDSYNC_MODE="" if [[ "$APPLICATION_PARAMS" == *"-E"* ]]; then CLOUDSYNC_MODE="upgrade" else CLOUDSYNC_MODE="update" fi rm $(find $CLOUDSYNC_LOGS -name "*[_inp,_out].buf" ) 1>> $POSTOUT 2>> $POSTERR rm $(find $CLOUDSYNC_CONF -name "config_*.json" ) 1>> $POSTOUT 2>> $POSTERR echo "Executing the CloudSync" cd $CLOUDSYNC_PATH ./cs.py start debug $CLOUDSYNC_MODE & CLOUDSYNC_STATUS="$(ps ax | grep -e cs.py -e cloud_sync.py | grep -v grep)" if [ -n "$CLOUDSYNC_STATUS" ]; then post_log_pass "$POSTMSG_CLOUDSYNC$POSTMSG_POSTFIX_PASSED" else post_log_fail "$POSTMSG_CLOUDSYNC$POSTMSG_POSTFIX_FAILED" fi post_log "$CLOUDSYNC_STATUS" cd else post_log_fail "$POSTMSG_CLOUDSYNC$POSTMSG_POSTFIX_FAILED" fi } function startApplication_setup() { # ----------------------------------------- Denali post_log_dash " Denali " #launching denali application DENALI_VERSION="$($HOME/$DENALI_BIN -v)" if [[ -n "$DENALI_VERSION" ]]; then post_log_pass "$($HOME/$DENALI_BIN -v)" # log UI Software version if [[ "$APPLICATION_PARAMS" == *"-E"* ]]; then $HOME/$DENALI_BIN $APPLICATION_PARAMS & # do not enclose the APPLICATION_PARAMS in "", then it becomes an empty parameter to the denali which is not accepted. else $HOME/$DENALI_BIN $APPLICATION_PARAMS & fi else post_log_fail "Unknown Applicaion Version" fi } function confirm_reboot() { read -p "ready to reboot? [y,n]" -n 1 -r CONFIRM if [ "$CONFIRM" == "y" ]; then reboot fi echo "" } function cleanCloudSyncBufs() { # ----------------------------------------- CloudSync buffs cleanup post_log_dash " CloudSync buffs cleanup" local CLOUDSYNC_PATH=$CLOUD_HOME/$CLOUDSYNC_FOLDER local DATE_UTC=$(date -u +%Y_%m_%d) if [ -d $CLOUDSYNC_PATH ]; then # removing the previous treatment logs so the new buff starts with fresh sequence echo "Removing CloudSync I/O buff" local CLOUDSYNC_LOGS="$SDCARD_MNT/$CLOUDSYNC_FOLDER/" sudo -u $CLOUD_USER rm $(find $CLOUDSYNC_LOGS -name "*[_inp,_out].buf" ) 1>> $POSTOUT 2>> $POSTERR echo "Creating new bufs for the denali and cloud user" sudo -u $CLOUD_USER touch "$CLOUDSYNC_LOGS/$DATE_UTC"_out.buf sudo -u $DENALI_USER touch "$CLOUDSYNC_LOGS/$DATE_UTC"_inp.buf fi } function startCloudSync_local() { # ----------------------------------------- CloudSync post_log_dash " CloudSync " local CLOUDSYNC_PATH=$CLOUD_HOME/$CLOUDSYNC_FOLDER local DATE_UTC=$(date -u +%Y_%m_%d) if [ -d $CLOUDSYNC_PATH ]; then post_log "Verify the CloudSync config" if [ "$( diff $CLOUDSYNC_CONFIG_SRC $CLOUDSYNC_CONFIG_DST )" != "" ]; then post_log "CloudSync configuration updated" sudo -u $CLOUD_USER cp $CLOUDSYNC_CONFIG_SRC $CLOUDSYNC_CONFIG_DST 1>> $POSTOUT 2>> $POSTERR else post_log "CloudSync configuration verified" fi echo "Executing the CloudSync" cd $CLOUDSYNC_PATH sudo -u $CLOUD_USER ./cs.py start CLOUDSYNC_STATUS="$(ps ax | grep -e cs.py -e cloud_sync.py | grep -v grep)" if [ -n "$CLOUDSYNC_STATUS" ]; then post_log_pass "$POSTMSG_CLOUDSYNC$POSTMSG_POSTFIX_PASSED" else post_log_fail "$POSTMSG_CLOUDSYNC$POSTMSG_POSTFIX_FAILED" fi post_log "$CLOUDSYNC_STATUS" cd else post_log_fail "$POSTMSG_CLOUDSYNC$POSTMSG_POSTFIX_FAILED" fi } function startApplication_local() { # ----------------------------------------- Denali post_log_dash " Denali " #launching denali application DENALI_VERSION="$($DENALI_HOME/$DENALI_BIN -v)" if [ -n "$DENALI_VERSION" ]; then post_log_pass "$DENALI_VERSION" # log UI Software version if [ $(isDemoMode) -eq $TRUE ]; then APPLICATION_PARAMS="$APPLICATION_PARAMS"" -q -D -A $D_CANBUS" fi sudo -u $DENALI_USER $DENALI_HOME/$DENALI_BIN $APPLICATION_PARAMS_DEFAULT $APPLICATION_PARAMS -C 1>> /tmp/denali.out 2>> /tmp/denali.out & else post_log_fail "Unknown Applicaion Version for $DENALI_HOME/$DENALI_BIN" fi } function startDemoMode_local() { # *** eliminated brackets are intentional. *** if [ $(isDemoMode) -eq $TRUE ]; then # ----------------------------------------- Demo Mode post_log_dash " Demo Mode " local DRYDEMO_PATH=$DEMO_HOME/$SRC_PATH_DRYDEMO cd $DRYDEMO_PATH ./drydemo "-A $D_CANBUS" post_log "Dry-Demo Started" fi } function log_backup() { if [[ "$1" == "" ]]; then post_log "Log Backup failed: Missing log location" return $ERR_LOGBACKUP_PATH; fi local LOG_PATH="$LOG_BASE"/"$1" cd "$LOG_PATH" for logname in $(find -type f ! -name "*.$EXT_PEND.*"); do name=$(basename $logname) base="${name%%.*}" ext="${name##*.}" exts="${name#*.}" #DEBUG echo name: $base #DEBUG echo ext : $ext #DEBUG echo exts: $exts if [[ "$ext" == "$EXT_GZIP" ]]; then mv "$name" "$base.u.$exts" else echo gzip "$name" echo mv "$name.$EXT_GZIP" "$base.$EXT_PEND.$exts.$EXT_GZIP" fi echo done } function log_backup_logApp() { log_backup $LOG_LOC_LOG } function log_backup_logErr() { log_backup $LOG_LOC_ERR } function backupApplicationLogs() { log_backup_logApp log_backup_logErr } function timerStart() { time_start=$(date +%s) } function timerEndLog() { # ----------------------------------------- END # tag the end time in the POST log file post_log "End: $(timestamp)" time_end=$(date +%s) post_log "time spent: "$(( $time_end - $time_start ))" seconds" post_log_star " ***** " } function applicationPOST() { setupConsoleout disableRootSSH cleanupPOSTLogs backupApplicationLogs checkDemoMode queryOSVersion setupCANBus $1 setupResolved killApplication setupEthernet setupSDCard testRTC setupWiFi setupBluetooth testTouchscreen testCloudSystem }