# Basic Pi libraries
import time
from time import sleep
import termios, fcntl, sys, os


# For PWM
import RPi.GPIO as GPIO
from RPIO import PWM

# For socket connections
import socket   


# Set up pins
# NOTE - THESE ARE BASED ON PI REVISION 2 GPIO PINOUTS

PIN_RIGHT_POWER=7           # if this is on, then send power to the right tread
PIN_RIGHT_DIRECTION=11      # if this is on, then relay for the right tread will be on (sending the tread into reverse)

PIN_LEFT_POWER=13           # if this is on, then send power to the left tread
PIN_LEFT_DIRECTION=15       # if this is on, then relay for the left tread will be on (sending the tread into reverse)


# Initialize these GPIO pins as GPIO.OUT
GPIO.setmode(GPIO.BOARD)
GPIO.setup(7, GPIO.OUT)
GPIO.setup(11, GPIO.OUT)
GPIO.setup(13, GPIO.OUT)
GPIO.setup(15, GPIO.OUT)


# Initialize the servo library
servo = PWM.Servo()

# NOTE - the RPIO.PWM pin outs refer to the BCM GPIO layout numbers
# See: http://www.hobbytronics.co.uk/raspberry-pi-gpio-pinout
# Example: Pin 18 is actually BCM GPIO 24 on the Revision 2 Pi (5th from bottom on the right)

# Initialize the servo position for gun
pos=1500



# Define functions for pins

# Turn on a pin
def powerOn(pin):
    GPIO.output(pin, GPIO.HIGH)
    return

# Turn off a pin
def powerOff(pin):
    GPIO.output(pin, GPIO.LOW)
    # time.sleep(1)
    return

# Fire the gun. NOTE - RPIO PWM uses the 
def fireGun():
    # See note about about BCM GPIO pin
    servo.set_servo(23, 1800)
    sleep(0.5)
    servo.set_servo(23, 1000)
    return

# Set the turret to a position using PWM
def turretX(pos):
    servo.set_servo(24, pos)
    return

# Set the right tread into forawrd mode
def rightForward():
    powerOff(PIN_RIGHT_DIRECTION)
    # time.sleep(0.5)
    sleep(0.5)
    return

# Set the right tread into reverse mode
def rightReverse():
    powerOn(PIN_RIGHT_DIRECTION)
    sleep(0.5)
    return

# Set the left tread into forward mode
def leftForward():
    powerOff(PIN_LEFT_DIRECTION)
    sleep(0.5)
    return

# Set the left tread into reverse mode
def leftReverse():
    powerOn(PIN_LEFT_DIRECTION)
    sleep(0.5)
    return

# Set both treads into forward mode
def setForward():
    rightForward()
    leftForward()
    sleep(0.5)
    return

# Set both treads into reverse mode
def setReverse():
    rightReverse()
    leftReverse()
    sleep(0.5)
    return

# Run both left and right motors (regardless of direction)
def runMotors():
    powerOn(PIN_LEFT_POWER)
    powerOn(PIN_RIGHT_POWER)
    return

# Turn off treads
def fullStop():
    powerOff(PIN_LEFT_DIRECTION)
    powerOff(PIN_RIGHT_DIRECTION)
    powerOff(PIN_LEFT_POWER)
    powerOff(PIN_RIGHT_POWER)
    return

# Move the treads forward
def moveForward(duration=1):
    setForward()
    runMotors()
    return

# Move the treads in reverse
def moveReverse(duration=1):
    powerOn(PIN_RIGHT_DIRECTION)
    sleep(0.2)
    powerOn(PIN_LEFT_DIRECTION)
    sleep(0.2)
    powerOn(PIN_LEFT_POWER)
    powerOn(PIN_RIGHT_POWER)
    return


# Turn the vehicle right
def spinRight(duration=1):
    powerOn(PIN_RIGHT_DIRECTION)
    sleep(0.2)
    powerOff(PIN_LEFT_DIRECTION)
    sleep(0.2)
    powerOn(PIN_RIGHT_POWER)
    sleep(0.2)
    powerOn(PIN_LEFT_POWER)
    sleep(duration)
    fullStop()
    return

# Turn the vehicle left
def spinLeft(duration=1):
    powerOn(PIN_LEFT_DIRECTION)
    sleep(0.2)
    powerOff(PIN_RIGHT_DIRECTION)
    sleep(0.2)
    powerOn(PIN_LEFT_POWER)
    sleep(0.2)
    powerOn(PIN_RIGHT_POWER)
    sleep(duration)
    fullStop()
    return


# SOCKET SET UP 
# We use TCP to communicate with the Pi

s = socket.socket()                                         # Create a socket object
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)     # Keep the socket open to re-use
host = '10.0.0.101'                                         # The local IP address of your Pi. Run `ifconfig /all` to see your WiFi address
port = 12345                                                # Reserve a port for your service.
s.bind(('', port))                                          # Bind to the port and accept connections from anywhere

s.listen(5)                                                 # Now wait for client connection, with a backlog queue size of 5



# Establish connection
connection, address = s.accept()
print "Got a connection from", address
message = "Thanks for connecting to " + str(host) + " at port " + str(port)
connection.send(message)


# Use this to parse the data.
# Our incoming data protocol comes first with a single capital letter signifying the type of command
# It then comes with the value, whose ending is marked by a '|'
# The '|' is necessary to prevent bunching together of network packets

# For example: `Y1320|` tells the Pi that this is a 'Y' command (turret), set it to a value of 1320, and the '|' indicates end of this command
# We need the '|' to demarcate the end of a command to prevent bunching together of data
# For example, we might accidentally have commands like `Y1230X343` without the pipe, and the pi wouldn't know what to do with the command

def parse_data(raw_data):
    pipe_pos = raw_data.find('|')
    command_key = raw_data[0]
    command_value = raw_data[1:pipe_pos]
    return [command_key, command_value]


while True:

    # Read in data
    raw_data = connection.recv(1024).rstrip() # rstrip removes trailing spaces

    print "Received raw data of " + str(raw_data)

    data = parse_data(raw_data)

    # Y commands the turret angle
    if data[0] == "Y":
        print "Received Y direction for: " + str(data[1])
        turretX(int(data[1]))

    # X commands the spin of the vehicle (left or right)
    elif data[0] == "X":
        if (float(data[1]) < 0):
            # negative, spin left
            print "Received LEFT X direction for: " + str(data[1])
            spinLeft(abs(float(data[1])))

        elif (float(data[1]) > 0):
            # positive, spin right
            print "Received RIGHT X direction for: " + str(data[1])
            spinRight(abs(float(data[1])))

        else:
            # Full stop
            print "received 0 X - full stop!"
            # fullStop()

    # F commands firing
    elif data[0] == "F":
        print "Received Firing command"
        fireGun()

    # W commands forward
    elif data[0] == "W":
        print "FORWARD"
        moveForward()

    # S commands reverse
    elif data[0] == "S":
        print "REVERSE"
        moveReverse()

    # P commands full-stop
    elif data[0] == "P":
        print "FULLSTOP"
        fullStop()
        
    else:
        print "No mapped command: (Key/Value) = " + str(data[0]) + "/" + str(data[1])

    

print 'Closed'
connection.close()

