
import serial, os, time
import argparse
import struct

LIN_SYNC = 0x55
LIN_SPEED = 19200

class LinProtocol( object ):
	def __init__(self):
		self.states = {
			"start": self.state_start, 
			"sync": self.state_sync,
			"id": self.state_id,
			"data": self.state_data,
			"crc": self.state_crc
			}
		self.state = "start"

	def next(self, inp):
		self.state = self.states[self.state](inp)
		#print self.state

	def state_start( self, inp ):
		print ("in:{0:X}".format(inp))
		if inp == LIN_SYNC:
			return "sync"
		else:
			return "start"

	def state_sync(self, inp):
		return "id" 

	def state_id(self, inp):
		return "data"

	def state_data(self, inp):
		return "crc" 

	def state_crc(self, inp):
		return "start" 

def IdConvert(Id):
	return 22

class LinCommand():
	def __init__(self):
		self.lin = LinProtocol()

	def read(self, args):
		pass

	def write(self, args):
		with serial.Serial(args.port, LIN_SPEED/2, timeout=1) as ser:
			# Send break
			ser.write(struct.pack('>B',0x80))
		time.sleep(0.05) # wake-up
		with serial.Serial(args.port, LIN_SPEED, timeout=1) as ser:
			# sync
			ser.write(struct.pack('>BB', LIN_SYNC, IdConvert(args.id)))
			ser.write(struct.pack('>BB',22, 33))

	def sleep(self, args):
		pass

	def slave(self, args):
		try:
			with serial.Serial(args.port, LIN_SPEED, timeout=1) as ser:
				while(True):
					if (ser.in_waiting > 0):
						b = ser.read()
						print b
						self.lin.next(ord(b))
					else:
						time.sleep(1)
		except KeyboardInterrupt:
			return


def get_parser():
	prog = os.path.basename(__file__)
	parser = argparse.ArgumentParser(
        description="Send LIN commands",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog=('{0} COMxx write <filename>\n'
                '{0} read\n'
                '{0} sleep\n'
                .format(prog))
    )

	parser.add_argument('port')

	subparsers = parser.add_subparsers(help='Available commands')
	command = LinCommand()

	write = subparsers.add_parser('write', help='Write LIN frame')
	write.add_argument('id', type=int, nargs='+',help='slave id')
	write.set_defaults(func=command.write)

	read = subparsers.add_parser('read', help='Read frame from device')
	read.set_defaults(func=command.read)

	slave = subparsers.add_parser('slave', help='Emulating slave device')
	slave.set_defaults(func=command.slave)

	sleep = subparsers.add_parser('sleep', help='Send sleep command')
	sleep.set_defaults(func=command.sleep)
	
	return parser
	
def main():
	args = get_parser().parse_args()
	result = args.func(args)
	return result

if __name__ == '__main__':
	main()
