1# Copyright (c) 2011 The Chromium OS Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5"""A base class to interact with I2C slave device. 6 7Dependency 8 - This library depends on a new C shared library called "libsmogcheck.so". 9""" 10 11import ctypes, logging 12 13 14# I2C constants 15I2C_BUS = 2 16 17# Path of shared library. 18SMOGCHECK_C_LIB = "/usr/local/lib/libsmogcheck.so.0" 19 20 21class I2cError(Exception): 22 """Base class for all errors in this module.""" 23 24 25class I2cSlave(object): 26 """A generic I2C slave object that supports basic I2C bus input/output.""" 27 28 def __init__(self, adapter_nr=None, load_lib=None): 29 """Constructor. 30 31 Mandatory params: 32 adapter_nr: adapter's number address. Default: I2C_BUS. 33 fd: file descriptor to communicate with I2C bus. 34 lib_obj: ctypes library object to interface with SMOGCHECK_C_LIB. 35 load_lib: a string, name of C shared library object to load. 36 slave_addr: slave address to set. Default: None. 37 38 Args: 39 lib: a string, name of C shared library object to load. 40 """ 41 self.slave_addr = None 42 43 if adapter_nr is None: 44 adapter_nr = I2C_BUS 45 self.adapter_nr = adapter_nr 46 47 if load_lib is None: 48 load_lib = SMOGCHECK_C_LIB 49 self.load_lib = load_lib 50 51 # Load shared library object. 52 self.lib_obj = self._loadSharedLibrary() 53 self.fd = self._getDeviceFile() 54 55 def _loadSharedLibrary(self): 56 """Loads C shared library .so file. 57 58 Returns: 59 a new instance of the shared (C) library. 60 61 Raises: 62 I2cError: if error loading the shared library. 63 """ 64 logging.info('Attempt to load shared library %s', self.load_lib) 65 try: 66 return ctypes.cdll.LoadLibrary(self.load_lib) 67 except OSError, e: 68 raise I2cError('Error loading C library %s: %s' % 69 (self.load_lib, e)) 70 logging.info('Successfully loaded shared library %s', self.load_lib) 71 72 def _getDeviceFile(self): 73 """Gets a file descriptor of a device file. 74 75 Returns: 76 fd: an integer, file descriptor to communicate with I2C bus. 77 78 Raises: 79 I2cError: if error getting device file. 80 """ 81 logging.info('Attempt to get device file for adapter %s', 82 self.adapter_nr) 83 fd = self.lib_obj.GetDeviceFile(self.adapter_nr) 84 if fd < 0: 85 raise I2cError('Error getting device file for adapter %s' % 86 self.adapter_nr) 87 88 logging.info('Got device file for adapter %s', self.adapter_nr) 89 return fd 90 91 def setSlaveAddress(self, addr): 92 """Sets slave address on I2C bus to be communicated with. 93 94 TODO(tgao): add retry loop and raise error if all retries fail. 95 (so that caller does not have to check self.err for status) 96 97 We use 7-bit address space for I2C, which has 128 addresses total. 98 Besides 16 reserved addresses, the total usable address space is 112. 99 See - http://www.i2c-bus.org/addressing/ 100 101 Args: 102 addr: a (positive) integer, 7-bit I2C slave address. 103 104 Raises: 105 I2cError: if slave address is invalid or can't be set. 106 """ 107 if self.slave_addr == addr: 108 logging.info('Slave address already set, noop: %s', addr) 109 return 110 111 if addr < 0x8 or addr > 0x77: 112 raise I2cError('Error: invalid I2C slave address %s', addr) 113 114 logging.info('Attempt to set slave address: %s', addr) 115 if not self.fd: 116 self.fd = self._getDeviceFile() 117 118 ret = self.lib_obj.SetSlaveAddress(self.fd, addr) 119 if ret < 0: 120 raise I2cError('Error communicating to slave address %s' % addr) 121 122 self.slave_addr = addr 123 logging.info('Slave address set to: %s', addr) 124 125 def writeByte(self, reg, byte): 126 """Writes a byte to a specific register. 127 128 TODO(tgao): add retry loop and raise error if all retries fail. 129 130 Args: 131 reg: a (positive) integer, register number. 132 byte: a char (8-bit byte), value to write. 133 134 Raises: 135 I2cError: if error writing byte to I2C bus. 136 """ 137 logging.info('Attempt to write byte %r to reg %r', byte, reg) 138 if self.lib_obj.WriteByte(self.fd, reg, byte) < 0: 139 raise I2cError('Error writing byte 0x%x to reg %r' % (byte, reg)) 140 141 logging.info('Successfully wrote byte 0x%x to reg %r', byte, reg) 142 143 def readByte(self, reg): 144 """Reads a byte from a specific register. 145 146 TODO(tgao): add retry loop and raise error if all retries fail. 147 148 Args: 149 reg: a (positive) integer, register number. 150 151 Returns: 152 byte_read: a char (8-bit byte), value read from register. 153 154 Raises: 155 I2cError: if error reading byte from I2C bus. 156 """ 157 logging.info('Attempt to read byte from register %r', reg) 158 byte_read = self.lib_obj.ReadByte(self.fd, reg) 159 if byte_read < 0: 160 raise I2cError('Error reading byte from reg %r' % reg) 161 162 logging.info('Successfully read byte 0x%x from reg %r', 163 byte_read, reg) 164 return byte_read 165 166 def writeWord(self, reg, word): 167 """Writes a word to a specific register. 168 169 TODO(tgao): add retry loop and raise error if all retries fail. 170 171 Args: 172 reg: a (positive) integer, register number. 173 word: a 16-bit unsigned integer, value to write. 174 175 Raises: 176 I2cError: if error writing word to I2C bus. 177 """ 178 logging.info('Attempt to write word %r to reg %r', word, reg) 179 if self.lib_obj.WriteWord(self.fd, reg, ctypes.c_uint16(word)) < 0: 180 raise I2cError('Error writing word 0x%x to reg %r' % (word, reg)) 181 182 logging.info('Successfully wrote word 0x%x to reg %r', 183 word, reg) 184 185 def readWord(self, reg): 186 """Reads a word from a specific register. 187 188 TODO(tgao): add retry loop and raise error if all retries fail. 189 190 Args: 191 reg: a (positive) integer, register number. 192 193 Returns: 194 a 16-bit unsigned integer, value read from register. 195 196 Raises: 197 I2cError: if error reading word from I2C bus. 198 """ 199 logging.info('Attempt to read word from register %r', reg) 200 word_read = self.lib_obj.ReadWord(self.fd, reg) 201 if word_read < 0: 202 raise I2cError('Error reading word from reg %r' % reg) 203 204 logging.info('Successfully read word 0x%x from reg %r', 205 word_read, reg) 206 return word_read 207