Home | History | Annotate | Download | only in common_lib
      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 
      7 Dependency
      8  - This library depends on a new C shared library called "libsmogcheck.so".
      9 """
     10 
     11 import ctypes, logging
     12 
     13 
     14 # I2C constants
     15 I2C_BUS = 2
     16 
     17 # Path of shared library.
     18 SMOGCHECK_C_LIB = "/usr/local/lib/libsmogcheck.so.0"
     19 
     20 
     21 class I2cError(Exception):
     22     """Base class for all errors in this module."""
     23 
     24 
     25 class 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