#!/bin/bash

DEVICE=/dev/ttyACM0

ESC="\033"

TICK_RATE=100000000 # 100MHz CPU
DEFAULT_DS101_BAUD=64000
DEFAULT_DS102_BAUD=3000
DEFAULT_RS232_BAUD=9600

# Default device settings are to use double the standard number
# of 7Es. DS101 only.
STANDARD_7E_START=
STANDARD_7E_END=

SEND_WAKEUP=
BAUD=
MODE=

function set_baud
{
    let "TICKS_PER_SYMBOL = $TICK_RATE / $BAUD"
    let "TPS_B0 = $TICKS_PER_SYMBOL & 255"
    let "TPS_B1 = ($TICKS_PER_SYMBOL >> 8) & 255"
    let "TPS_B2 = ($TICKS_PER_SYMBOL >> 16) & 255"
    let "TPS_B3 = ($TICKS_PER_SYMBOL >> 24) & 255"

    printf "AT${ESC}30%02x\r" $TPS_B3 >> "$DEVICE"
    printf "AT${ESC}31%02x\r" $TPS_B2 >> "$DEVICE"
    printf "AT${ESC}32%02x\r" $TPS_B1 >> "$DEVICE"
    printf "AT${ESC}33%02x\r" $TPS_B0 >> "$DEVICE"

    echo "BAUD $BAUD"
}

function set_rs232
{
    # if unset use default
    BAUD=${BAUD:-$DEFAULT_RS232_BAUD}

    set_baud

    # 1 stop bit, no parity, 8 data bits
    printf "AT${ESC}3602\rAT${ESC}3500\rAT${ESC}3408\r" >> "$DEVICE"

    if [ -n "$NULL_MODEM" ]; then
        # set rs232 null modem mode
        printf "AT${ESC}0108\r" >> "$DEVICE"

        echo "NULL MODEM"
    else
        # set rs232 mode
        printf "AT${ESC}0101\r" >> "$DEVICE"
    fi

    # set LED red (FF0000)
    printf "AT${ESC}20FF\rAT${ESC}2100\rAT${ESC}2200\r" >> "$DEVICE"

    echo "RS232"
}

function set_wakeup
{
    if [ -n "$SEND_WAKEUP" ]; then
        printf "AT${ESC}0D00\rAT${ESC}0E00\r" >> "$DEVICE"

        echo "WAKEUP"
    else
        # No wakeup is supposed to be the default but
        # isn't in the firmware yet, so set it here.
        printf "AT${ESC}0E01\rAT${ESC}0D01\r" >> "$DEVICE"

        echo "NO WAKEUP"
    fi
}

function set_ds101
{
    # if unset use default
    BAUD=${BAUD:-$DEFAULT_DS101_BAUD}
    SEND_WAKEUP=${SEND_WAKEUP:-}

    set_baud
    set_wakeup

    if [ -n "$STANDARD_7E_START" ]; then
        # Otherwise the default is to double the leading 7Es
        printf "AT${ESC}1901\r" >> "$DEVICE"

        echo "STANDARD 7E START"
    fi

    if [ -n "$STANDARD_7E_END" ]; then
        # Otherwise the default is to double the trailing 7Es
        printf "AT${ESC}1A01\r" >> "$DEVICE"

        echo "STANDARD 7E END"
    fi

    # set ds101 mode
    printf "AT${ESC}0102\r" >> "$DEVICE"

    # set LED green (00FF00)
    printf "AT${ESC}2000\rAT${ESC}21FF\rAT${ESC}2200\r" >> "$DEVICE"

    echo "DS101"
}

function set_ds102
{
    # if unset use default
    BAUD=${BAUD:-$DEFAULT_DS102_BAUD}

    set_baud
    set_wakeup

    # set ds102 mode
    printf "AT${ESC}0104\r" >> "$DEVICE"

    # set LED blue (0000FF)
    printf "AT${ESC}2000\rAT${ESC}2100\rAT${ESC}22FF\r" >> "$DEVICE"

    echo "DS102"
}

function set_off
{
    # set "off" mode
    printf "AT${ESC}0100\r" >> "$DEVICE"

    # set LED black (000000)
    printf "AT${ESC}2000\rAT${ESC}2100\rAT${ESC}2200\r" >> "$DEVICE"

    echo "OFF"
}

function usage
{
    echo "usage: uphil [<mode>] ([--device | -d] <device>) ([--baud | -b] <baud>)"
    echo "           (-w | --wakeup) (--standard_7e_start) (--standard_7e_end)"
    echo "           (-n | --null) (-h | --help)"
    echo ""
    echo "<mode>"
    echo "       rs232 | 232 | ds101 | 101 | ds102 | 102 | off"
    echo ""
    echo "<device>"
    echo "       Device path, default is /dev/ttyACM0."
    echo ""
    echo "<baud>"
    echo "       Standard bauds, e.g., 9600, 38400, 115200, etc. Uphil will accept odd-"
    echo "       ball bauds up to $TICK_RATE, though stability at extreme rates has not"
    echo "       been tested."
    echo "       Default DS101 baud is $DEFAULT_DS101_BAUD."
    echo "       Default DS102 baud is $DEFAULT_DS102_BAUD."
    echo "       Default RS232 baud is $DEFAULT_RS232_BAUD."
    echo ""
    echo "-w | --wakeup"
    echo "       Send wakeup; default is to not. DS101 and DS102 only."
    echo ""
    echo "--standard_7e_start, --standard_7e_end"
    echo "       Send the standard number of flag symbols. Default is to double-up;"
    echo "       helpfull because initial line signals can be a little rough / hard"
    echo "       for some devices to recognize. DS101 only."
    echo ""
    echo "-n | --null"
    echo "       Apply NULL MODEM adapter. Default is straight-through. RS232 only."
    echo ""
}

while [ -n "$1" ]; do
    case $1 in
        rs232 | 232 )
            MODE=rs232
            ;;
        ds101 | 101 )
            MODE=ds101
            ;;
        ds102 | 102 )
            MODE=ds102
            ;;
        off )
            MODE=off
            ;;
        -d | --device )
            shift
            DEVICE=$1
            ;;
        -b | --baud )
            shift
            BAUD=$1
            ;;
        -w | --wakeup )
            SEND_WAKEUP=y
            ;;
        --standard_7e_start )
            STANDARD_7E_START=y
            ;;
        --standard_7e_end )
            STANDARD_7E_END=y
            ;;
        -n | --null )
            NULL_MODEM=y
            ;;
        -h | --help )
            usage
            exit
            ;;
        * )
            usage
            exit 1
    esac
    shift
done

if [ -z "$MODE" ]; then
    usage
    exit 1
fi

case $MODE in
    rs232 )
        set_rs232
        ;;
    ds101 )
        set_ds101
        ;;
    ds102 )
        set_ds102
        ;;
    off )
        set_off
        ;;
    * )
        usage
        exit 1
esac
