#import the required libraries
import RPi.GPIO as GPIO
import time
import datetime
import thread
import SocketServer


#setup the connection handler.  This will handle all of the communication with the network clients.
class MyTCPHandler(SocketServer.StreamRequestHandler):
    #static variables
    #reed switch connections
    sensor1 = 18	
    sensor2 = 23
    #LED lights that indicate status, not used
    RED_LED = 4
    GREEN_LED = 14
    #Pin used to fire the solenoid
    solenoid = 5
    #status variables
    armed = False
    current_count = 0
    count_trigger = 3
    solenoid_triggered = False
    start_time = 0
    DEBUG = False
    trigger_delay = 0
    
    def handle(self):
        #On an initial connection by the client, setup the Pi
        self.GPIO_setup()
        self.initialize()
        self.sendClient("Catapult ready")
        notDone = True
        #Loop used to handle network communication
        while notDone:
            #Read commands from the client
            choice = self.rfile.readline().strip()
            choice = choice.lower()
            #handle the command
            if choice != "":
		print "Choice:",choice
            else:
                return
            if choice == "arm":
                self.arm()
            if choice == "disarm":
                self.disarm()
            if "count" in choice:
                text,trigger = choice.split(":")
		self.count_trigger = int(trigger)
	    #This choice is used to test the triggering of the catpult
            if choice == "trigger":
                GPIO.output(self.solenoid,GPIO.HIGH)
                time.sleep(.5)
                GPIO.output(self.solenoid,GPIO.LOW)
                self.sendClient("Triggered")
            if choice == "status":
                arm_status = "Armed:"+str(self.armed)
                self.sendClient( arm_status)
                trigger_status = "Trigger count:"+str(self.count_trigger)
                self.sendClient(trigger_status)
            if "delay:" in choice:
                text,delay = choice.split(":")
                trigger_delay = int(delay)
            if choice == "quit":
                notDone = False

    #Send the status of the variables to the client
    def sendStatus(self):
        global armed,current_count,count_trigger,trigger_delay
        self.sendClient("----------Status---------")
        text = "Armed:" + str(self.armed)
        self.sendClient(text)
        text = "Trigger:" + str(count_trigger)
        self.sendClient(text)
        text = "Delay:"+ str(trigger_delay)
        self.sendClient(text)

    #Send to the client
    def sendClient(self,data):
        data = data + "\n"
        self.wfile.write(data)

    #Every time the reed switch is tripped, this function is called
    def sensorCallback(self,sensor):
        global armed,current_count,count_trigger,solenoid_triggered, solenoid, start_time, total_time, DEBUG, trigger_delay
        #check to see if the solenoid was already triggered
        if self.solenoid_triggered:
            return
        #if the catapult is armed, increment the current count
        if self.armed:
            self.current_count = self.current_count + 1
            if self.start_time == 0:
                self.start_time = time.time()
        #if the current count is equal to or greater then the trigger count, trigger the solenoid
        if self.current_count >= self.count_trigger:
            if self.armed:
                print "triggered"
                time.sleep(trigger_delay)
                self.duration = time.time() - self.start_time
                self.solenoid_triggered = True
                GPIO.output(self.solenoid,GPIO.HIGH)
                time.sleep(.5)
                GPIO.output(self.solenoid,GPIO.LOW)
                self.current_count = 0
                self.armed = False
                #do some calculations for speed, time, etc, and send to the client
                self.mps = (0.2392 * self.count_trigger)/self.duration
                totalTime = "Time:" + str(self.duration)
                mpsData =  "meters per second:" + str(self.mps)
                self.sendClient(totalTime)
                self.sendClient(mpsData)
                self.start_time = 0

    #Arm the catapult
    def arm(self):
        global GREEN_LED,armed,current_count,solenoid_triggered
        self.armed = True
        self.solenoid_triggered = False
        self.current_count = 0
        print "Armed"
        self.LED_one_on(self.GREEN_LED)
        self.sendClient("Armed")


    #Disarm the catapult
    def disarm(self):
        global RED_LED,armed
        print "Disarmed"
        self.armed = False
        self.LED_one_on(self.RED_LED)
        self.sendClient("Disarmed")

    #initialize the catapult
    def initialize(self):
        global armed
        self.LED_all_on()
        time.sleep(1.0)
        self.LED_all_off()
        self.arm()
        self.disarm()

    #turn one LED on and the other off
    def LED_one_on(self,button):
        global RED_LED,GREEN_LED
        ON = GPIO.HIGH
        OFF = GPIO.LOW
        button = 1
        
        if button is self.RED_LED:
            GPIO.output(self.RED_LED,ON)
        else:
            GPIO.output(self.RED_LED,OFF)
                    
        if button is self.GREEN_LED:
            GPIO.output(self.GREEN_LED,ON)
        else:
            GPIO.output(self.GREEN_LED,OFF)

    #turn on all the LEDs
    def LED_all_on(self):
        global RED_LED,GREEN_LED
        ON = GPIO.HIGH
        GPIO.output(self.RED_LED,ON)
        GPIO.output(self.GREEN_LED,ON)

    #turn off all the LEDs
    def LED_all_off(self):
        global RED_LED,GREEN_LED
        OFF = GPIO.LOW
        GPIO.output(self.RED_LED,OFF)
        GPIO.output(self.GREEN_LED,OFF)

    #setup the GPIO pins
    def GPIO_setup(self):
        global sensorCallback,sensor1,sensor2,RED_LED,GREEN_LED,solenoid
        #Global Initialization
        print "GPIO initalization started"
        count = 0
        GPIO.setmode(GPIO.BCM)
        GPIO.setup(self.sensor1,GPIO.IN,pull_up_down=GPIO.PUD_UP) 
        GPIO.setup(self.sensor2,GPIO.IN,pull_up_down=GPIO.PUD_UP)
        #setup the call back functions for the input pins
        GPIO.add_event_detect(self.sensor1, GPIO.FALLING, callback=self.sensorCallback,bouncetime=100)
        GPIO.add_event_detect(self.sensor2, GPIO.FALLING, callback=self.sensorCallback,bouncetime=100)
        #setup the output pins
        GPIO.setup(self.RED_LED, GPIO.OUT)
        GPIO.setup(self.GREEN_LED, GPIO.OUT)
        GPIO.setup(self.solenoid, GPIO.OUT)

        print "GPIO initialization complete"

    
def main():
    HOST, PORT = "192.168.2.1", 9999

    # Create the server, binding to localhost on port 9999
    server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)

    # Activate the server; this will keep running until you
    # interrupt the program with Ctrl-C
    server.serve_forever()
    




if __name__ == "__main__":
    main()
