#!/usr/bin/env python

import serial
import time

__author__ = "Duane Odom"
__date__ = "Tue May 17 10:33:49 CDT 2005"
__version__ = "1.0"


class pyrman:
	"""Provides access to the irman device (http://evation.com/irman/index.html).
	Allows you to use most infrared remotes to control your pc via a serial port."""

	__port = serial.Serial()
	__last_read_time = 0
	__last_read_value = ""
	__duplicate_threshold = 0.4
	



#################################################
# Constructor
#################################################
	def __init__(self, device = "", timeout = 1.0):
		"""Initializes the serial port, sends the initialization string to the
		device and reads back the string indicating successful initialization
		of the device. "device" is the device identifier for the serial port
		that your irman is connected to.  Look at the python serial documentation
		to see how device ids are specified.  The default device is your first
		serial port (/dev/ttyS0, com1, etc..)  "timeout" is the maximum amount
		of time this call will block if no data is read from the device."""

		if(len(device) == 0):
			self.__port.port = 0
		else:
			self.__port.port = device

		self.__port.baudrate = 9600
		self.__port.bytesize = serial.EIGHTBITS
		self.__port.parity = serial.PARITY_NONE
		self.__port.stopbits = serial.STOPBITS_ONE

		# we need some reasonable value for timeout, because
		# when we initialize the device we need to use the
		# readline function to clear the initial trash from 
		# the serial buffer and the readline function needs
		# a timeout to work correctly
		if(timeout == None):
			timeout = 0.1

		self.__port.timeout = timeout
		self.__port.xonxoff = 0
		self.__port.rtscts = 0
		self.__port.open()

		if(self.__port.isOpen()):
			print "initializing irman.."

			time.sleep(0.5)
			# some trash will be sitting in the buffer upon opening
			# the port (usually the char "X" on my system)
			trash = self.__port.readline()
			print "trash = %s" % trash

			# write the init string to the device
			self.__port.write("I")
			time.sleep(0.5)
			self.__port.write("R")
			time.sleep(0.5)

			# read back the status to make sure the device was initialized
			status = self.__port.readline()
			print "status = %s" % status

			if(status.find("OK") == -1):
				print "problem initializing irman device!"
				self.__port.close()
			else:
				print "irman initialized!"
		else:
			print "problem opening serial port!"






#################################################
# Is Initialized?
#################################################
	def is_initialized(self):
		"""Returns boolean indicating whether or not the device is initialized."""

		return self.__port.isOpen()






#################################################
# Destructor
#################################################
	def __del__(self):
		"""Closes the serial port.  The device requires no shutdown procedure."""

		self.__port.close()

	




#################################################
# Read
#################################################
	def read(self):
		"""Returns a 12 character string representing the hex values of the six bytes
		read from the device.  This call will block for the amount of time specified
		in the timeout parameter passed to the object constructor unless data arrives
		at the port before the timeout has elapsed."""

		if(self.__port.isOpen()):
			# read six bytes from the device
			code = self.__port.read(6)
			# convert the char bytes into hex value strings
			retval = self.__convert_code_to_string(code)

			# if we actually got some data we want to see if the data
			# is the same that we got last time and if it is within the
			# duplicate_threshold that we define at the top of the file.
			# if it is, then we want to append "(dup)" to the returned hex
			# value string.
			if(len(retval) > 0):
				if((time.time() - self.__last_read_time) <= self.__duplicate_threshold):
					if(retval == self.__last_read_value):
						retval += "(dup)"
				self.__last_read_time = time.time()
				self.__last_read_value = retval

			return retval
		else:
			return ""
		





#################################################
# Convert Code To String
#################################################
	def __convert_code_to_string(self, code):
		"""Converts the 6 character string into a 12 character string representing the
		hex values stored in the original 6 chars."""

		# convert this string of chars to a string of hex value
		# representations of the original char values

		if(len(code) > 0):
			values = []
			# get the ordinal value of this char
			values.append(ord(code[0:1]))
			values.append(ord(code[1:2]))
			values.append(ord(code[2:3]))
			values.append(ord(code[3:4]))
			values.append(ord(code[4:5]))
			values.append(ord(code[5:6]))

			retval = ""
			
			# convert this value to a hex string and strip off the "0x"
			for value in values:
				hexval = hex(value)[2:]

				# buffer the value "0" out to 2 chars to keep uniformity
				if(hexval == "0"):
					hexval += "0"

				retval += hexval

			return retval
		else:
			return ""
		
		




#################################################
# Test Procedure
#################################################
if(__name__ == "__main__"):

	#remote = pyrman("/dev/ttyS0", 0.5)
	remote = pyrman()

	try:
		while(1):
			code = remote.read()

			if(len(code) > 0):
				print code
	except KeyboardInterrupt:
		print "exiting.."
