#!/bin/bash
# Copyright (C) 2024 MOXA Inc. All rights reserved.
# This software is distributed under the terms of the MOXA SOFTWARE NOTICE.
# See the file LICENSE for details.
#
# Name:
#       MOXA GPIO Library
#
# Authors:
#       2024    Wilson Huang <WilsonYS.Huang@moxa.com>
#

source "/usr/lib/mx-common-lib"

LIBGPIOD_TOOLS_PATH="/usr/local/bin"

function gpio_get_gpiochip_name() {
        local driver_name
        driver_name=${1}

        if [[ ! -e "$LIBGPIOD_TOOLS_PATH"/gpiodetect ]]; then
                return 1
        fi

        "$LIBGPIOD_TOOLS_PATH"/gpiodetect | grep "${driver_name}" | awk -F " " '{print $1}' 2>/dev/null
}

function gpio_get_libgpiod_version() {
        echo $("$LIBGPIOD_TOOLS_PATH"/gpioinfo -v | grep gpioinfo | awk -F ' ' '{print $3}')
}

function get_major() {
        local version
        version="$1"

        echo "$version" | awk -F '.' '{print $1}'
}

function get_i2c_slave_gpiochip_label() {
        local i2c_master_name
        local i2c_slave_addr

        i2c_master_name=$1
        i2c_slave_addr=$2

        echo $(format_as_i2c_directory_name \
                $(get_i2c_device_minor_number_list ${i2c_master_name}) \
                ${i2c_slave_addr})
}

function gpio_get_value_i2c_gpiochip_libgpiod() {
        local gpio_pin
        local i2c_gpc_label
        local gpc_name

        gpio_pin=$1
        i2c_gpc_label=$2
        gpc_name=$(gpio_get_gpiochip_name ${i2c_gpc_label})

        echo $(gpio_get_value_libgpiod ${gpio_pin} ${gpc_name})
}

function gpio_set_value_i2c_gpiochip_libgpiod() {
        local gpio_pin
        local gpio_val
        local i2c_gpc_label
        local gpc_name

        gpio_pin=$1
        gpio_val=$2
        i2c_gpc_label=$3
        gpc_name=$(gpio_get_gpiochip_name ${i2c_gpc_label})

        gpio_set_value_libgpiod ${gpio_pin} ${gpio_val} ${gpc_name}
}


function gpio_get_value_libgpiod() {
        local gpio
        local gpc_name
        local libgpiod_version
        local libgpiod_version_major

        gpio=${1}
        gpc_name=${2}

        if [[ ! -e "$LIBGPIOD_TOOLS_PATH"/gpioget ]]; then
                return 1
        fi

        libgpiod_version=$(gpio_get_libgpiod_version)
        libgpiod_major_version=$(get_major $libgpiod_version)
        if [[ "$libgpiod_major_version" == "v1" ]]; then
                "$LIBGPIOD_TOOLS_PATH"/gpioget $gpc_name $gpio 2>/dev/null
        else
                "$LIBGPIOD_TOOLS_PATH"/gpioget --as-is --numeric -c $gpc_name $gpio 2>/dev/null
        fi
}

function gpio_set_value_libgpiod() {
        local gpio=${1}
        local value=${2}
        local gpc_name=${3}
        local libgpiod_version
        local libgpiod_version_major

        if [[ ! -e "$LIBGPIOD_TOOLS_PATH"/gpioset ]]; then
                return 1
        fi

        libgpiod_version=$(gpio_get_libgpiod_version)
        libgpiod_major_version=$(get_major $libgpiod_version)
        if [[ "$libgpiod_major_version" == "v1" ]]; then
                $LIBGPIOD_TOOLS_PATH/gpioset $gpc_name "${gpio}=${value}" 2>/dev/null
        else
                $LIBGPIOD_TOOLS_PATH/gpioset -p 20ms -t 0 -c $gpc_name "${gpio}=${value}" 2>/dev/null
        fi
}

function gpc_it8786_remap() {
        local orig_pin
        local new_pin
        orig_pin=$1

        group=$(($orig_pin / 10 - 1))
        bit=$(($orig_pin % 10))
        new_pin=$((8 * group + bit))

        echo $new_pin
}

function gpc_it8786() {
        local gpio
        local gpio_remap
        local gpio_tbl
        local base

        base=-1
        gpio=${1}
        gpio_tbl=(
                10 11 12 13 14 15 16 17
                20 21 22 23 24 25 26 27
                30 31 32 33 34 35 36 37
                40 41 42 43 44 45 46 47
                50 51 52 53 54 55 56 57
                60 61 62 63 64 65 66 67
                70 71 72 73 74 75 76 77
                80 81 82 83 84 85 86 87
                90 91 92 93 94 95 96 97
                100 101 102 103 104 105
        )

        if ! is_module_loaded gpio_it87; then
                return 1
        fi

        if [[ ! ${gpio_tbl[*]} =~ $gpio ]]; then
                return 2
        fi

        for gpiochip in /sys/class/gpio/gpiochip*; do
                if cat "${gpiochip}"/label | grep -q "gpio_it87"; then
                        base=$(cat "${gpiochip}"/base)
                        break
                fi
        done

        if [[ $base -eq -1 ]]; then
                return 3
        fi

        gpio_remap=$(gpc_it8786_remap $gpio)

        echo $((base + gpio_remap))
}

gpc_pca953x() {
	local gpio=$1

	if ! $(is_module_loaded gpio_pca953x); then
		echo "gpio_pca953x driver is not loaded."
		exit 1
	fi

	for gpc in /sys/class/gpio/gpiochip*
	do
		if [ -f "${gpc}/device/name" ]; then
			if [[ $(cat $gpc/device/name) == "pca9535" ]]; then
				base=$(cat $gpc/base)
				break
			fi
		fi
	done

	echo $((base + $gpio))
}

function gpio_request_sysfs() {
        local gpio
        gpio=${1}

        if [[ ! -e "/sys/class/gpio/gpio${gpio}" ]]; then
                echo "${gpio}" 2>/dev/null >/sys/class/gpio/export
        fi
}

function gpio_get_value_sysfs() {
        local gpio=${1}

        if ! gpio_request_sysfs "${gpio}"; then
                return 1
        fi

        cat "/sys/class/gpio/gpio${gpio}/value" 2>/dev/null
}

function gpio_set_value_sysfs() {
        local gpio=${1}
        local value=${2}

        if ! gpio_request_sysfs "${gpio}"; then
                return 1
        fi

        case "${value}" in
        0)
                echo "low" 2>/dev/null >"/sys/class/gpio/gpio${gpio}/direction"
                ;;
        1)
                echo "high" 2>/dev/null >"/sys/class/gpio/gpio${gpio}/direction"
                ;;
        esac
}
