#!/bin/bash

I2C_BUS=1

input_file="test.txt"
output_file="output.txt"
output_file_ri="results.txt"
threshold="1000"

rm -f "$output_file"
rm -f "$output_file_ri"
rm -f "$output_file.expected"

adc_read() {    #Configure 12b resolution, continuous mode, mux channel, pga 1
        CHAN="$1"
        DELAY=0.4
        if [ "$CHAN" == 1 ]; then
                ADC_CFG_INIT=0x18
        elif [ "$CHAN" == 2 ]; then
                ADC_CFG_INIT=0x38
        elif [ "$CHAN" == 3 ]; then
                ADC_CFG_INIT=0x58
        elif [ "$CHAN" == 4 ]; then
                ADC_CFG_INIT=0x78
        else
                echo 1>&2 "Error: Invalid ADC channel $CHAN"
                exit 1
        fi

        #Write configuration
        i2cset -y "$I2C_BUS" 0x68 "$ADC_CFG_INIT" || exit 1
        sleep "$DELAY"

        #Read 3 bytes (2 value, 1 cfg)
        RAW=$(i2ctransfer -y "$I2C_BUS" r3@0x68)
        if [ "$?" != 0 ]; then
                exit 2
        fi

        #Extract 12 bit hex value
        HEX=$(echo ${RAW^^} | cut -c 1-9 | sed 's# 0X##1' | cut -c 3-6) #| cut -c 4-9 for 12-bit
        DEC=$(echo "ibase=16; $HEX" | bc)

        #Convert to voltage in V
        V_meas=$(echo "scale=10; res=5/65536*$DEC; if(res<1 && res > 0) print 0; res" | bc)
        DELAY=0.005
}

gpio_init_low() {
        echo "20" > /sys/class/gpio/export #1>\dev\null
        echo "21" > /sys/class/gpio/export #1>\dev\null

        sleep 0.1

        echo "out"   > /sys/class/gpio/gpio20/direction || exit 1
        echo "out"   > /sys/class/gpio/gpio21/direction || exit 1

        echo "0"   > /sys/class/gpio/gpio20/value || exit 1
        echo "0"   > /sys/class/gpio/gpio21/value || exit 1
}

gpio_init_high() {
        echo "10" > /sys/class/gpio/export #1>\dev\null
        echo "11"  > /sys/class/gpio/export #1>\dev\null

        sleep 0.1

        echo "out"   > /sys/class/gpio/gpio10/direction || exit 1
        echo "out"   > /sys/class/gpio/gpio11/direction || exit 1

        echo "1"   > /sys/class/gpio/gpio10/value || exit 1
        echo "1"   > /sys/class/gpio/gpio11/value || exit 1
}

invert() {

        if [ "$1" == 0 ]; then
                echo "1"
        else
                echo "0"
        fi
}

CLK_H() {
        echo $(invert "$1")   > /sys/class/gpio/gpio11/value || exit 1
}

DATA_H() {
        echo $(invert "$1")   > /sys/class/gpio/gpio10/value || exit 1
}

CLK_L() {
        echo "$1"   > /sys/class/gpio/gpio21/value || exit 1
}

DATA_L() {
        echo "$1"   > /sys/class/gpio/gpio20/value || exit 1
}

bitbang_low() {
        BIT_L="$1"
        CLK_L 0
        DATA_L "$BIT_L"
        sleep "$DELAY"
        CLK_L 1
        sleep "$DELAY"

        DATA_L 0
}

bitbang_high() {
        BIT_H="$1"
        CLK_H 0
        DATA_H "$BIT_H"
        sleep "$DELAY"
        CLK_H 1
        sleep "$DELAY"

        DATA_H 1
}

convert_r() {
        voltage="$1"
        if [ $(echo "$1" '>=' "1.27478" | bc -l) -eq 1 ]; then
                R_isol="10000000"
        elif [ $(echo "$1" '>=' "1.27335" | bc -l) -eq 1 ]; then
                R_isol=$(echo "($1-0.9879)/0.00000003" | bc -l)
        elif [ $(echo "$1" '>=' "1.25795" | bc -l) -eq 1 ]; then
                R_isol=$(echo "($1-1.1948)/0.000000008" | bc -l)
        elif [ $(echo "$1" '>=' "1.25372" | bc -l) -eq 1 ]; then
                R_isol=$(echo "($1-1.2368)/0.000000003" | bc -l)
        elif [ $(echo "$1" '>=' "1.24466" | bc -l) -eq 1 ]; then
                R_isol=$(echo "($1-1.2258)/0.000000004" | bc -l)
        elif [ $(echo "$1" '>=' "1.2125" | bc -l) -eq 1 ]; then
                R_isol=$(echo "($1-1.1848)/0.00000001" | bc -l)
        elif [ $(echo "$1" '>=' "1.15527" | bc -l) -eq 1 ]; then
                R_isol=$(echo "($1-1.098)/0.00000006" | bc -l)
        elif [ $(echo "$1" '>=' "1.06075" | bc -l) -eq 1 ]; then
                R_isol=$(echo "($1-0.9632)/0.0000002" | bc -l)
        elif [ $(echo "$1" '>=' "0.11572" | bc -l) -eq 1 ]; then
                R_isol=$(echo "($1-0.0969)/0.000002" | bc -l)
        elif [ $(echo "$1" '>=' "0.0176" | bc -l) -eq 1 ]; then
                R_isol=$(echo "($1-0.0053)/0.00001" | bc -l)
        elif [ $(echo "$1" '>=' "0" | bc -l) -eq 1 ]; then
                R_isol=$(echo "$1/0.00002" | bc -l)
        else
                echo "An error occured while measuring an insulation resistance" 1>&2;
                exit -1
        fi

        if [ $(echo "$R_isol" '>=' "1000000" | bc -l) -eq 1 ]; then
                R_OUT=$(echo "$R_isol"/1000000 | bc -l)
                order="M"
        elif [ $(echo "$R_isol" '>=' "1000" | bc -l) -eq 1 ]; then
                R_OUT=$(echo "$R_isol"/1000 | bc -l)
                order="k"
        else
                R_OUT="$R_isol"
                order="R"
        fi
}

N=$(cat "$input_file" | head -n 1)
T=$(cat "$input_file" | head -n 2 | tail -n 1)


if [ "$N" -gt "$T" ];
then
        echo "N cannot be greater than T" 1>&2;
        exit -1
fi;

if [ "$N" -lt 0 ];
then
        echo "N cannot be lower than 0" 1>&2;
        exit -1
fi;

if [ "$T" -lt 0 -a $(("$T" % 16)) -ne 0 ];
then
        echo "T in wrong format" 1>&2;
        exit -1
fi;

#---------------------------#
#---------INIT--------------#
#---------------------------#
DELAY=0.02
gpio_init_high
for i in $(seq 0 "$T")
do
        bitbang_high "1"
done

gpio_init_low
for i in $(seq 0 "$T")
do
        bitbang_low "0"
done


for i in $(seq 1 "$N")
do
        printf "\t%d" "$i" >> "$output_file_ri"
done
echo "" >> "$output_file_ri"



echo "-------------START---------------"
i=0

gpio_init_high
bitbang_high "0"

for i in $(seq 1 "$N")
do
        echo "Testing channel: $i"
        printf "%d\t" "$i" >> "$output_file_ri"

        gpio_init_low
        bitbang_low "1"

        for j in $(seq 1 "$T")
        do
                if [[ "$j" -le "$N" ]]
                then
                        adc_read 3
                        convert_r "$V_meas"
                        cmp_result=$(echo "$R_isol < $threshold" | bc -l)
                        printf "%.1f $order\t" "$R_OUT" >> "$output_file_ri"
                        if [[ "$cmp_result" -eq "1" ]]
                        then
                                echo -n "1" >> "$output_file"
                        else
                                echo -n "0" >> "$output_file"
                        fi

                fi
                bitbang_low "0"
        done

        gpio_init_high
        bitbang_high "1"

        echo "" >> "$output_file"
        echo "" >> "$output_file_ri"
done
echo "-------------END---------------"


cat "$input_file" | tail -n +3 > "$output_file.expected"
diff --strip-trailing-cr "$output_file" "$output_file.expected" 1>/dev/null 2>/dev/null
are_different="$?"

if [ "$are_different" -eq 0 ];
then
        echo "Test result: PASS"
        exit 0
fi;

echo "Test result: FAIL"
exit -1