"""
Python module presenting an API to an ELM327 serial interface
(C) 2015 Jamie Fraser <fwaggle@fwaggle.org>
h
ttp://github.com/fwaggle/pyELM327

Please see License.txt and Readme.md.
"""

# Pretty much taken from https://en.wikipedia.org/wiki/OBD-II_PIDs
__pids ={
		0x01: {
			# TODO: ignori
ng fuel system #2 atm
			0x03: {
				'Name': 'Fuel system status',
				'Units': '',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) [A-Z0-9]{2} $',
				'Value': lambda m: decode_0x03(int(m.group(1),16))},
			0x04: {
				'Name': 'Calculated engine load value',
				'Units': '%',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) $',
				'Value': lambda m: int(m.group(1),16) * 100.0 / 255 },
			0x05: {
				'Name': 'Engine coolant temperature',
				'Units': '*C',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) $',
				'Value': lambda m: int(m.group(1),16) - 40 },
			0x06: {
				'Name': 'Short term fuel % trim - Bank 1',
				'Units': '%',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) $',
				'Value': lambda m: (int(m.group(1),16)-128) * 100.0 / 128 },
			0x07: {
				'Name': 'Long term fuel % trim - Bank 1',
				'Units': '%',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) $',
				'Value': lambda m: (int(m.group(1),16)-128) * 100.0 / 128 },
			0x08: {
				'Name': 'Short term fuel % trim - Bank 2',
				'Units': '%',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) $',
				'Value': lambda m: (int(m.group(1),16)-128) * 100.0 / 128 },
			0x09: {
				'Name': 'Long term fuel % trim - Bank 2',
				'Units': '%',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) $',
				'Value': lambda m: (int(m.group(1),16)-128) * 100.0 / 128 },
			0x0A: {
				'Name': 'Fuel pressure',
				'Units': 'kPa (gauge)',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) $',
				'Value': lambda m: int(m.group(1),16) * 3 },
			0x0B: {
				'Name': 'Intake manifold absolute pressure',
				'Units': 'kPa (absolute)',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) $',
				'Value': lambda m: int(m.group(1),16) },
			0x0C: {
				'Name': 'Engine RPM',
				'Units': 'RPM',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) ([A-Z0-9]{2}) $',
				'Value': lambda m: ((int(m.group(1),16) * 256) + int(m.group(2), 16))/4.0},
			0x0D: {
				'Name': 'Vehicle speed',
				'Units': 'km/h',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) $',
				'Value': lambda m: int(m.group(1),16) },
			0x0E: {
				'Name': 'Timing advance',
				'Units': '* rel #1 cylinder',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) $',
				'Value': lambda m: (int(m.group(1),16) - 128) / 2.0 },
			0x0F: {
				'Name': 'Intake air temperature',
				'Units': '*C',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) $',
				'Value': lambda m: int(m.group(1),16) - 40 },
			0x10: {
				'Name': 'MAF Sensor air flow rate',
				'Units': 'grams/sec',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) ([A-Z0-9]{2}) $',
				'Value': lambda m: ((int(m.group(1),16) * 256) + int(m.group(2), 16))/100.0},
			0x11: {
				'Name': 'Throttle position',
				'Units': '%',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) $',
				'Value': lambda m: (int(m.group(1),16) * 100.0) / 255 },
			0x12: {
				'Name': 'Commanded secondary air status',
				'Units': 'Bit-encoded',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) $',
				'Value': lambda m: int(m.group(1),16) },
			0x13: {
				'Name': 'Oxygen sensors present',
				'Units': 'Bit-encoded',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) $',
				'Value': lambda m: int(m.group(1),16) },

			# NOTE: We currently throw away the fuel trim readings for these PIDs
			0x14: {
				'Name': 'Bank 1, Sensor 1: Oxygen sensor voltage',
				'Units': 'V',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) [A-Z0-9]{2} $',
				'Value': lambda m: ((int(m.group(1),16) / 200))},
			0x15: {
				'Name': 'Bank 1, Sensor 2: Oxygen sensor voltage',
				'Units': 'V',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) [A-Z0-9]{2} $',
				'Value': lambda m: ((int(m.group(1),16) / 200))},
			0x16: {
				'Name': 'Bank 1, Sensor 3: Oxygen sensor voltage',
				'Units': 'V',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) [A-Z0-9]{2} $',
				'Value': lambda m: ((int(m.group(1),16) / 200))},
			0x17: {
				'Name': 'Bank 1, Sensor 4 Oxygen sensor voltage',
				'Units': 'V',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) [A-Z0-9]{2} $',
				'Value': lambda m: ((int(m.group(1),16) / 200))},
			0x18: {
				'Name': 'Bank 2, Sensor 1: Oxygen sensor voltage',
				'Units': 'V',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) [A-Z0-9]{2} $',
				'Value': lambda m: ((int(m.group(1),16) / 200))},
			0x19: {
				'Name': 'Bank 2, Sensor 2: Oxygen sensor voltage',
				'Units': 'V',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) [A-Z0-9]{2} $',
				'Value': lambda m: ((int(m.group(1),16) / 200))},
			0x1A: {
				'Name': 'Bank 2, Sensor 3: Oxygen sensor voltage',
				'Units': 'V',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) [A-Z0-9]{2} $',
				'Value': lambda m: ((int(m.group(1),16) / 200))},
			0x1B: {
				'Name': 'Bank 2, Sensor 4 Oxygen sensor voltage',
				'Units': 'V',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) [A-Z0-9]{2} $',
				'Value': lambda m: ((int(m.group(1),16) / 200))},

			0x1C: {
				'Name': 'OBD standards this vehicle conforms to',
				'Units': '',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) $',
				'Value': lambda m: decode_0x1c(int(m.group(1),16)) },
			0x1F: {
				'Name': 'Run time since engine start',
				'Units': 's',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) ([A-Z0-9]{2}) $',
				'Value': lambda m: (int(m.group(1),16) * 256) + int(m.group(2), 16)},
			0x21: {
				'Name': 'Distance traveled with malfuction indicator lamp on',
				'Units': 'km',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) ([A-Z0-9]{2}) $',
				'Value': lambda m: (int(m.group(1),16) * 256) + int(m.group(2), 16)},
			0x22: {
				'Name': 'Fuel Rail Pressure (relative to manifold vacuum)',
				'Units': 'kPa',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) ([A-Z0-9]{2}) $',
				'Value': lambda m: (int(m.group(1),16) * 256) + int(m.group(2), 16) * 0.079},
			0x23: {
				'Name': 'Fuel Rail Pressure (diesel, or gasoline direct injection)',
				'Units': 'kPa',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) ([A-Z0-9]{2}) $',
				'Value': lambda m: (int(m.group(1),16) * 256) + int(m.group(2), 16) * 10},
			0x2C: {
				'Name': 'Commanded EGR',
				'Units': '%',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) $',
				'Value': lambda m: (int(m.group(1),16) * 100.0) / 255 },
			0x2D: {
				'Name': 'EGR Error',
				'Units': '%',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) $',
				'Value': lambda m: ((int(m.group(1),16) - 128) * 100.0) / 128 },
			0x2E: {
				'Name': 'Commanded evaporative purge',
				'Units': '%',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) $',
				'Value': lambda m: (int(m.group(1),16) * 100.0) / 255 },
			0x2F: {
				'Name': 'Fuel level input',
				'Units': '%',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) $',
				'Value': lambda m: (int(m.group(1),16) * 100.0) / 255 },
			0x30: {
				'Name': '# of warm-ups since codes cleared',
				'Units': '%',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) $',
				'Value': lambda m: int(m.group(1),16) },
			0x31: {
				'Name': 'Distance traveled since codes cleared',
				'Units': 'km',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) ([A-Z0-9]{2}) $',
				'Value': lambda m: (int(m.group(1),16) * 256) + int(m.group(2), 16)},
			0x33: {
				'Name': 'Barometric pressure',
				'Units': 'kPa (absolute)',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) $',
				'Value': lambda m: int(m.group(1),16) },
			0x42: {
				'Name': 'Control module voltage',
				'Units': 'V',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) ([A-Z0-9]{2}) $',
				'Value': lambda m: (int(m.group(1),16) * 256) + int(m.group(2), 16) / 1000.0},
			0x43: {
				'Name': 'Absolute load value',
				'Units': '%',
				'Pattern': '^[A-Z0-9]{2} [A-Z0-9]{2} ([A-Z0-9]{2}) ([A-Z0-9]{2}) $',
				'V