#!/bin/sh

NAME="aiot-sleep"

ems31_gpio25_path="/sys/devices/platform/ems31-reset/lte_gpio25/value"
port_uart="/dev/ttymxc3"
port_lpuart="/dev/ttyLP1"

put_log () {
    echo "$NAME: $*"
    logger -t "$NAME" -- "$@"
}

modem_sms_settings () {
    send-at /dev/ttyMux0 'AT+CMGF=1' echo ems31
    send-at /dev/ttyMux0 'AT^SIND="message",0' echo ems31
    send-at /dev/ttyMux0 'AT+CPMS="ME"' echo ems31
    send-at /dev/ttyMux0 'AT+CMGD=1,4' echo ems31
    send-at /dev/ttyMux0 'AT+CMGL="ALL"' echo ems31
    send-at /dev/ttyMux0 'AT^SIND="message",1' echo ems31
}

modem_sms_delete_one_item () {
    sms_num=$(mmcli -m $(mm-modem-num) --messaging-list-sms | tail -n 1 \
        | awk '{n=split($1, a, "/"); print a[n]}')
    if expr "$sms_num" + 1  >/dev/null 2>&1; then
        mmcli -m $(mm-modem-num) --messaging-delete-sms="$sms_num" >/dev/null 2>&1
    fi
}

wait_modemmanager () {
    i=0
    while [ "$i" -lt 20 ]
    do
        sleep 2
        if nmcli dev show ttyCommModem >/dev/null 2>&1; then
            return 0
        fi
        i=$((i+1))
    done
    put_log "wait_modemmanager timed out"
    return 1
}

get_module_model () {
    overlays="$(awk -F= '$1 == "fdt_overlays" { print $2 }' /boot/overlays.txt 2>/dev/null)"
    case " $overlays " in
    *" armadillo-iotg-a6e-ems31.dtbo "*)
        echo "ems31";;
    *" armadillo-iotg-a6e-sim7672.dtbo "* | *" armadillo_iotg_a9e-sim7672.dtbo "*)
        echo "sim7672";;
    *)
        echo "general";;
    esac
}

is_a900 () {
    case "$(cat /etc/hwrevision)" in
    iot-a9e*|armadillo-900*) return 0;;
    esac
    return 1
}

# On Armadillo-900, the TPM power is turned off during suspend,
# causing the counter to reset to 0. As a result, the time becomes
# incorrect after resume. To avoid this, temporarily use
# arch_sys_counter instead.
clocksource_path="/sys/devices/system/clocksource/clocksource0"
need_restore_clocksource=0
fixup_clocksource () {
    if ! is_a900; then
        return
    fi

    if [ "$(cat "$clocksource_path"/current_clocksource)" = "imx-tpm" ]; then
        need_restore_clocksource=1
        echo "arch_sys_counter" > "$clocksource_path"/current_clocksource
    fi
}

restore_clocksource () {
    if [ "$need_restore_clocksource" -ne 0 ] ; then
        echo "imx-tpm" > "$clocksource_path"/current_clocksource
        need_restore_clocksource=0
    fi
}

ain_trigger_enabled=""
ain_path="/sys/devices/platform/soc/2100000.bus/21f8000.i2c/i2c-3/3-0049/power/wakeup"
ain_set_wake_triggers_conf="/etc/atmark/ain-set-wake-triggers.conf"

ain_sleep_pre () {
    if [ -e "$ain_set_wake_triggers_conf" ]; then
        if [ -e "$ain_path" ];then
            if [ "$(cat $ain_path)" = "enabled" ]; then
                /usr/libexec/ain-set-wake-triggers
            fi
        else
            return 1
        fi
    fi

    return 0
}

ain_wakeup_after () {
    if [ "$ain_trigger_enabled" = "true" ]; then
        ain-set-wake-trigger -a
    fi
}

suspend_to_ram () {
    if ! ain_sleep_pre; then
        put_log "error: wakeup by ain is disabled."
        return 0
    fi

    put_log "Power Management suspend-to-ram"
    local WAKE_TRIGGER_RTC="/var/run/wake_trigger_rtc"
    local trigger_rtc
    local trigger_rtc_path
    [ -e "$WAKE_TRIGGER_RTC" ] && trigger_rtc="$(cat $WAKE_TRIGGER_RTC)"
    [ -n "$trigger_rtc" ] && trigger_rtc_path="/sys/class/rtc/$trigger_rtc"
    if [ -n "$trigger_rtc_path" ] && [ -e "$trigger_rtc_path" ]; then
        local restsecs="$(($(cat "$trigger_rtc_path"/wakealarm) - $(cat "$trigger_rtc_path"/since_epoch)))"
        if [ "$restsecs" -lt 4 ]; then
            local description="will expires now"
            [ "$restsecs" -lt 1 ] && description="has expired"
            put_log "WARNING: the RTC $trigger_rtc's wake alarm time $description, so don't sleep."
            put_log "To disable this RTC check, remove $WAKE_TRIGGER_RTC"
            return 0
        fi
    fi

    fixup_clocksource
    echo mem > /sys/power/state
    restore_clocksource
    put_log "change mode CPU Idle"
    rm -f "$WAKE_TRIGGER_RTC"
    ain_wakeup_after

    if is_a900 && pgrep hostapd >/dev/null; then
        # workaround buggy wlan driver for A900 AP
        ip link set uap0 down
        ip link set uap0 up
    fi
}

aiot_sleep_ems31 () {

    if [ "$1" = "sms" ]; then
        NAME="aiot-sleep-sms"
    fi

    REDIAL=0
    if nmcli d | grep gsm-ttyCommModem | grep connected >/dev/null 2>&1; then
        REDIAL=1
        put_log "terminate dialup"
        if ! nmcli c down gsm-ttyCommModem; then
            put_log "error: terminate dialup"
        fi
    elif nmcli c | grep gsm-ttyCommModem >/dev/null 2>&1; then
        REDIAL=1
    fi

    # If send-at process remains, kill it.
    # If the send-at process is left running when going into sleep mode,
    # LTE will not connect when wake up.
    NEED_CATM1_ALIVE=0
    if pkill -f send-at >/dev/null 2>&1; then
        NEED_CATM1_ALIVE=1
    fi

    # kill an old aiot-catm1-alive process, if exists.
    pkill -f aiot-catm1-alive >/dev/null 2>&1;

    rc-service modemmanager stop
    if [ "$NAME" = "aiot-sleep-sms" ]; then
        modem_sms_settings
        echo "enabled" > /sys/devices/platform/gpio-wakeup/power/wakeup
    else
        echo 0 > "$ems31_gpio25_path"
        echo "disabled" > /sys/devices/platform/gpio-wakeup/power/wakeup
    fi

    STOPPED_CR=0
    case "$(rc-service connection-recover status)" in
    *started)
        rc-service connection-recover stop
        STOPPED_CR=1;;
    esac

    suspend_to_ram

    if [ "$NAME" != "aiot-sleep-sms" ]; then
        echo 1 > "$ems31_gpio25_path"
        sleep 1
    fi
    rc-service modemmanager start

    if [ "$REDIAL" = 1 ] || [ "$NEED_CATM1_ALIVE" = 1 ]; then
        put_log "redial."
        wait_modemmanager && nmcli c up gsm-ttyCommModem &
        aiot-catm1-alive &
    fi

    if [ "$STOPPED_CR" = 1 ]; then
        rc-service connection-recover start
    fi
}

aiot_sleep_sim7672 () {

    if [ "$1" = "sms" ]; then
        NAME="aiot-sleep-sms"
    fi

    if [ -e "$port_lpuart" ]; then
        port_uart="$port_lpuart"
    fi

    REDIAL=0
    if nmcli d | grep gsm-ttyCommModem | grep connected >/dev/null 2>&1; then
        REDIAL=1
        put_log "terminate dialup"
        if ! nmcli c down gsm-ttyCommModem; then
            put_log "error: terminate dialup"
        fi
    elif nmcli c | grep gsm-ttyCommModem >/dev/null 2>&1; then
        REDIAL=1
    fi

    # If send-at process remains, kill it.
    # If the send-at process is left running when going into sleep mode,
    # LTE will not connect when wake up.
    NEED_CAT1BIS_ALIVE=0
    if pkill -f send-at >/dev/null 2>&1; then
        NEED_CAT1BIS_ALIVE=1
    fi

    # kill an old aiot-cat1bis-alive process, if exists.
    pkill -f aiot-cat1bis-alive >/dev/null 2>&1;

    if [ "$1" = "sms" ]; then
        modem_sms_delete_one_item
    fi
    rc-service modemmanager stop

    STOPPED_CR=0
    case "$(rc-service connection-recover status)" in
    *started)
        rc-service connection-recover stop
        STOPPED_CR=1;;
    esac

    send-at "$port_uart" AT\$QCPMUCFG=1,3 sim7672
    echo 0 > /sys/devices/platform/sim7672-reset/reset/vbus

    if [ "$1" = "sms" ]; then
        echo "enabled" > /sys/devices/platform/gpio-wakeup/power/wakeup
    else
        echo "disabled" > /sys/devices/platform/gpio-wakeup/power/wakeup
    fi

    suspend_to_ram

    echo 1 > /sys/devices/platform/sim7672-reset/reset/vbus
    send-at "$port_uart" AT\$QCPMUCFG=1,1 sim7672

    rc-service modemmanager start

    if [ "$REDIAL" = 1 ] || [ "$NEED_CAT1BIS_ALIVE" = 1 ]; then
        put_log "redial."
        wait_modemmanager && nmcli c up gsm-ttyCommModem &
        aiot-cat1bis-alive &
    fi

    if [ "$STOPPED_CR" = 1 ]; then
        rc-service connection-recover start
    fi
}

aiot_sleep_general () {
    if [ "$1" = "sms" ]; then
        put_log "aiot-sleep-sms supports Cat.M1 or Cat.1 bis model."
        exit 1
    fi
    suspend_to_ram
}

if [ $$ -ne "$(pgrep -fo "$0")" ]; then
    put_log "Already running"
    exit 1
fi

if [ ! -e /var/run/power-utils.pid ]; then
    echo "WARNING; atmark-power-utils service seems not running."
    do_notify_wakeup=0
else
    if ! power-utils enter_sleep; then
        exit 1  # may be sleep is disabled
    fi
    do_notify_wakeup=1
fi

sleep_func="aiot_sleep_$(get_module_model)"
"$sleep_func" "$1"

[ "$do_notify_wakeup" = 1 ] && power-utils leave_sleep
