#!/usr/bin/env python3

# from following url:
# http://www.eeweb.com/project/mohd_kashif/controlling-of-stepper-motors-using-raspberry-pi

# sudo apt-get install python3-rpi.gpio

# https://sourceforge.net/p/raspberry-gpio-python/wiki/Examples/
# https://sourceforge.net/p/raspberry-gpio-python/wiki/Home/  # Documentation
# http://elinux.org/RPi_GPIO_Code_Samples#RPi.GPIO
# https://www.google.com/?gws_rd=ssl#q=raspberry+pi+python+import+RPi.GPIO+as+GPIO&start=10


import RPi.GPIO as GPIO
import time

#s Proc Print Sequence
def prtseq(seqName, seq):
	#s Print the sequence name
    print(seqName)
    #s Print each sequence item
    for i in range(0,len(seq)):
        print("seq[",i,"]=",seq[i])
#s endproc

#s Proc Rotate To
def rotateTo(direction, loc):
	global lastPosition
	global stepCount
	rotate_direction=direction
	#s While not at desired position
	while lastPosition!=loc:
		#s Increment/Decrement to next position
		stepCount+=rotate_direction
		if stepCount<0:
			stepCount=len(seq)-1
		elif stepCount>=len(seq):
			stepCount=0
		lastPosition+=rotate_direction
		if lastPosition>200:
			lastPosition=1
		elif lastPosition<1:
			lastPosition=200
		#s Set output pins to correct value for step
		GPIO.output(PiPins,seq[stepCount])
		time.sleep(waitTime)
		#s endWhile
#s endproc



#s MainProc
# ============  main starts here ====================

#s Initialize
print("GPIO.VERSION=", GPIO.VERSION)
mydebug=False
waitTime=0.003
waitTime=0.003

lastPosition=1

#s define possible sequences for movement
seq0 = [0,1,2,3]
seq0[0]=[1,1,1,1]
seq0[1]=[0,0,0,0]
seq0[2]=[1,1,1,1]
seq0[3]=[0,0,0,0]
prtseq ("seq0", seq0)

seq1 = [0,1,2,3]
seq1[0]=[1,0,0,0]
seq1[1]=[0,1,0,0]
seq1[2]=[0,0,1,0]
seq1[3]=[0,0,0,1]
prtseq ("seq1", seq1)

seq2 = [0,1,2,3]
seq2[0]=[1,0,1,0]
seq2[1]=[0,1,1,0]
seq2[2]=[0,1,0,1]
seq2[3]=[1,0,0,1]
prtseq ("seq2", seq2)

seq3 = [0,1,2,3,4,5,6,7]
seq3[0]=[1,0,0,0]
seq3[1]=[1,1,0,0]
seq3[2]=[0,1,0,0]
seq3[3]=[0,1,1,0]
seq3[4]=[0,0,1,0]
seq3[5]=[0,0,1,1]
seq3[6]=[0,0,0,1]
seq3[7]=[1,0,0,1]
prtseq ("seq3", seq3)

seq4 = [0,1,2,3]
seq4[0]=[1,1,0,0]
seq4[1]=[0,1,1,0]
seq4[2]=[0,0,1,1]
seq4[3]=[1,0,0,1]
prtseq ("seq4", seq4)

#s Choose Raspberry Pi P1 pins to use (board values)
#PiPins = [7,12,11,15]
#PiPins = [11,15,16,18]
#PiPins = [7,12,10,8]
PiPins = [3,5,10,8]
#PiPins = [11,13,10,8]
print("PiPins=",PiPins)

#s determine if input need to be inverted (using transistors)
invertIn=input("Invert inpUts (I,i - default) or Non-invert (N,n)")
invert=True
if invertIn in ["N","n"]:
	invert=False
if invert:
	invertTrue=False
	invertFalse=True
else:
	invertTrue=True
	invertFalse=False


#s Initialize GPIO Package
GPIO.setwarnings(False)
GPIO.cleanup()
GPIO.setmode(GPIO.BOARD)  # vs GPIO.BCM values
for pin in PiPins:
	if mydebug:
		print("setting up pi pin: ", pin)
	print("setting up pi pin: ", pin)
	GPIO.setup(pin, GPIO.OUT)
GPIO.setwarnings(True)

#s  Test output pins/lights	
# set all pins for output and turn on
for pin in PiPins:
	GPIO.output(pin, invertTrue)
if mydebug:
	input("Ready?  (all lights on)")
time.sleep(0.5)
# set all pins for output and turn off
for pin in PiPins:
	GPIO.output(pin, invertFalse)
if mydebug:
	input("Ready?  (all lights off)")
time.sleep(0.5)

#s While User wants to do another test
goAgain=True
stepCount=0
while goAgain:
	
#s Ask user for which sequence to use
#s (currently fixed as sequence #2)	
	seqSelect=2
	#seqSelect=input("Enter sequence number to use (0-4): ")


#s Case Chosen Selection
	if seqSelect=="":
		seqSelect="0"

#s Select Sequence 0
	if int(seqSelect)==0:
		seq=seq0
		seqName="seq0"
#s Select Sequence 1
	elif int(seqSelect)==1:
		seq=seq1
		seqName="seq1"
#s Select Sequence 2
	elif int(seqSelect)==2:
		seq=seq2
		seqName="seq2"
#s Select Sequence 3
	elif int(seqSelect)==3:
		seq=seq3
		seqName="seq3"
#s Select Sequence 4
	else:
		seq=seq4
		seqName="seq4"
#s Endcase
	
	print( "Using : ",seqName)

#s Ask user for steps or time (in negative seconds)	
	moveCount=0
	movesIn=input("How many moves (for timing, use neg. number of secs - default=4 steps)? ")
	if movesIn=="":
		movesIn="4"
	maxMoves=int(movesIn)

	timeRun=False
	if maxMoves<0:
		timeRun=True
		maxTime=-maxMoves
		maxMoves=10

#s Ask user for which direction to rotate (which way to setep sequence)	
	inDir=input("Rotation Direction [F=forward (default) or R=reverse]: ")
	if inDir in ["R","r"]:
		rotate_direction=-1
	else:
		rotate_direction=+1

	manual=input("Enter Y or y to manually step after each move: ")
	waitUser=False
	if manual=="Y":
		waitUser=True
	if manual=="y":
		waitUser = True
	
#	stepCount=0
	
#s While steping remains to be done
	#print("move #1 ====")
	try:
		initTime=time.time()
		while True:
			# Increment/Decrement to next position
			#print("Before Incr= moveCount:",moveCount,"  stepCount:",stepCount)
			stepCount+=rotate_direction
			if stepCount<0:
				stepCount=len(seq)-1
			elif stepCount>=len(seq):
				stepCount=0
			lastPosition+=rotate_direction
			if lastPosition>200:
				lastPosition=1
			elif lastPosition<1:
				lastPosition=200
			moveCount+=1
			#print("After Incr= moveCount:",moveCount,"  stepCount:",stepCount)
			#s Set output pins to correct value for step
			if waitUser:
				print (seq[stepCount])
			GPIO.output(PiPins,seq[stepCount])
			#for pinSelect in range(0,4):
				#pin=PiPins[pinSelect]
				#if mydebug:
					#time.sleep(0.05)
				#if seq[stepCount][pinSelect]==1:
					#setVal=invertTrue
				#else:
					#setVal=invertFalse
				#GPIO.output(pin, setVal)
				#if mydebug:
					#time.sleep(0.05)
				#if mydebug:
					#print("pin=",pin, ", output set to:",setVal)
#s          Wait for user or automatically step
			# wait before sending next step
			time.sleep(waitTime)
			curTime=time.time()
			if timeRun:
				if (curTime-initTime)>=maxTime:
					break
			else:
				if moveCount>=maxMoves:
					break
			#print("move #",(moveCount+1)," ====")
			if waitUser:
				input("Press enter to continue")
#s endwhile
		print ("moveCount: ", moveCount,", time elapsed: ",(curTime-initTime))
		
	except IOError as err:
		print("Exception: ", err)
		print("Error number: ",err.errno)
	#finally:
		#print("Finally")
	
#s Ask user if he wants to do another test
	anotherRound=input("Enter S to stop: ")
	goAgain=not (anotherRound in ["S","s"])
	#print (goAgain)
#s endwhile

input("Press enter when ready to cleanup?")
rotateTo(1,1)

#s Move back and forth and move to original position using rotateTo
time.sleep(2.0)
rotateTo(1,50)
time.sleep(2.0)
rotateTo(-1,150)
time.sleep(2.0)
rotateTo(1,1)

#s Turn off all power to motor
if mydebug:
	input("Press enter when ready to turn off all?")
for pin in PiPins:
	GPIO.output(pin, invertFalse)

#GPIO.setwarnings(False)
#GPIO.cleanup()
#GPIO.setwarnings(True)
#s endmain
exit()
