#!/bin/bash

# GPIO.sh
# Copyright © 2016 František Kučera (frantovo.cz)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

# GPIO.sh is a set of functions for controlling GPIO pins of Raspberry Pi or similar computer

_gpio_valid_port() {
	case $1 in 0|1|4|7|8|9|10|11|14|15|17|18|21|22|23|24|25)
		return 0;;
	*)
		return 1;;
	esac
}

# export -f _gpio_valid_port
# seq 0 30 | xargs -n1 bash -c 'printf "%4s" "$0: "; _gpio_valid_port $0 ; if [ $? -eq 0 ]; then echo "valid port number"; else echo; fi'


_gpio_log_error() {
	# TODO: $(date --rfc-3339=seconds) or ● ?
	echo -e "\e[1;31m$1\e[0m"; > /dev/stderr;
}

_gpio_log_warning() {
	echo -e "\e[2;33m$1 \e[0m"; > /dev/stderr;
}


# open (export) the port and set its direction
# parameters:
#	port number
#	direction: in/out
gpio_open() {
	local port="$1";
	local direction="$2";
	if [ $# -ne 2 ] || [[ "$direction" != @("in"|"out") ]]; then _gpio_log_error "usage: ${FUNCNAME[0]} <port> <in|out>"; return 1; fi
	if ! _gpio_valid_port "$port";                          then _gpio_log_error "invalid port number: $port";            return 1; fi;
	
	if [ -d  "/sys/class/gpio/gpio$port" ]; then 
		_gpio_log_warning "port $port is already exported → will just set direction: $direction";
	else
		echo "$port" > "/sys/class/gpio/export" || return 1;
	fi;
	
	echo "$direction" > "/sys/class/gpio/gpio$1/direction";
}


# close (unexport) the port and set its direction
# parameters:
#	port number
gpio_close() {
	local port="$1";
	if [ $# -ne 1 ];               then _gpio_log_error "usage: ${FUNCNAME[0]} <port>"; return 1; fi
	if ! _gpio_valid_port "$port"; then _gpio_log_error "invalid port number: $port";   return 1; fi;
	
	if [ -d  "/sys/class/gpio/gpio$port" ]; then 
		echo "$port" > "/sys/class/gpio/unexport";
	else
		_gpio_log_error "port $port is not open";
		return 1;
	fi;
}

# reads value of given port
# parameters:
#	port number
gpio_read() {
	local port="$1";
	if [ $# -ne 1 ];               then _gpio_log_error "usage: ${FUNCNAME[0]} <port>"; return 1; fi
	if ! _gpio_valid_port "$port"; then _gpio_log_error "invalid port number: $port";   return 1; fi;
	
	if ! cat "/sys/class/gpio/gpio$port/value"; then
		_gpio_log_error "unable to read value of port $port";
		return 1;
	fi
}

# writes the value to given port
# parameters:
#	port number
#	value: 0/1
gpio_write() {
	local port="$1";
	local value="$2";
	if [ $# -ne 2 ] || [[ "$value" != @("0"|"1") ]]; then _gpio_log_error "usage: ${FUNCNAME[0]} <port> <0|1>"; return 1; fi
	if ! _gpio_valid_port "$port";                   then _gpio_log_error "invalid port number: $port";         return 1; fi;
	
	if ! echo "$value" > "/sys/class/gpio/gpio$port/value"; then
		_gpio_log_error "unable to write value $value to port $port";
		return 1;
	fi
}

