text: # Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
  # Use of this source code is governed by a BSD-style license that can be
  # found in the LICENSE file.
  """Allows creation of i2c interface for beaglebone devices."""
  import logging
  import subprocess
  
  import bbmux_controller
  
  
  class BBi2cError(Exception):
    """Class for exceptions of BBi2c."""
    def __init__(self, msg, value=0):
      """BBi2cError constructor.
  
      Args:
        msg: string, message describing error in detail
        value: integer, value of error when non-zero status returned.  Default=0
      """
      super(BBi2cError, self).__init__(msg, value)
      self.msg = msg
      self.value = value
  
  class BBi2c(object):
    """Provide interface to i2c through beaglebone"""
  
    def __init__(self, interface):
      self._logger = logging.getLogger("BBi2c")
      self._interface = interface
      self._bus_num = interface['bus_num']
      # Older kernels utilizing the omap mux starts counting from 1
      if bbmux_controller.use_omapmux():
        self._bus_num += 1
  
    def open(self):
      """Opens access to FTDI interface as a i2c (MPSSE mode) interface.
  
      Raises:
        BBi2cError: If open fails
      """
      pass
  
    def close(self):
      """Close connection to i2c through beaglebone and cleanup.
  
      Raises:
        BBi2cError: If close fails
      """
      pass
  
    def setclock(self, speed=100000):
      """Sets i2c clock speed.
  
      Args:
        speed: clock speed in hertz.  Default is 100kHz
      """
      pass
  
    def _write(self, slv, address, wlist):
      """Preform a single i2cset write command.
  
      Args:
        slv: 7-bit address of the slave device.
        address: data address we are writing to. Will be written to the i2c bus.
        wlist: list of bytes to write to the slave. List length must be between
            0-2 bytes.
  
      Raises:
        BBi2cError: If wlist has more than 3 bytes or the i2cset call fails.
      """
      # i2cset can write up to 3 bytes to an i2c device in the format of:
      # [1-byte address][0-2 bytes of data]
      args = ['i2cset', '-y', str(self._bus_num), '0x%02x' % slv,
              address]
      if len(wlist) > 2:
        raise BBi2cError('Can only write up to 3 bytes (1-byte register address '
                         'and 2-byte word) per i2cset command. '
                         'wlist: %s' % wlist)
      # Form the data argument and reverse the bytes due to endianness.
      if wlist:
        data = '0x' + ''.join('%02x' % wbyte for wbyte in reversed(wlist))
        args.append(data)
        if len(wlist) == 2:
          # Put the command in word mode.
          args.append('w')
      try:
        logging.debug(' '.join(args))
        subprocess.check_call(args)
      except subprocess.CalledProcessError:
        raise BBi2cError('Failed i2c write to slave address: %s data: %s' % (slv,
                         wlist))
  
    def _read(self, slv, address, rcnt):
      """Read from a slave i2c device.
  
      Args:
        slv: 7-bit address of the slave device.
        address: data address to read.
        rcnt: number of bytes (0-2) to read from the device.
  
      Returns:
        list of bytes read from i2c device.
  
      Raises:
        BBi2cError: If read (i2cget call) fails or if rcnt > 2.
      """
      if not rcnt:
        return []
  
      if rcnt > 2:
        raise BBi2cError('Can only read up to 2 bytes per i2cget command.')
  
      if rcnt == 2:
        return self._read_two_bytes(slv, address)
  
      return self._read_one_byte(slv)
  
    def _read_one_byte(self, slv):
      """Read one byte from a slave i2c device.
  
      Args:
        slv: 7-bit address of the slave device.
  
      Returns:
        list of bytes read from i2c device.
  
      Raises:
        BBi2cError: If read (i2cget call) fails.
      """
      read_bytes = []
      args = ['i2cget', '-y', str(self._bus_num), '0x%x' % slv]
      try:
        logging.debug(' '.join(args))
        read_value = subprocess.check_output(args)
      except subprocess.CalledProcessError:
        raise BBi2cError('Failed i2c read of 1 byte from slave address: %s' %
                         slv)
      read_value_int = int(read_value, 0)
      read_bytes.append(read_value_int)
      return read_bytes
  
    def _read_two_bytes(self, slv, address):
      """Read two byte from a slave i2c device.
  
      Args:
        slv: 7-bit address of the slave device.
        address: data address to read.
  
      Returns:
        list of bytes read from i2c device.
  
      Raises:
        BBi2cError: If read (i2cget call) fails.
      """
      read_bytes = []
      args = ['i2cget', '-y', str(self._bus_num), '0x%x' % slv, address, 'w']
      try:
        logging.debug(' '.join(args))
        read_value = subprocess.check_output(args)
      except subprocess.CalledProcessError:
        raise BBi2cError('Failed i2c read of 2 bytes from slave address: %s, '
                         'data address: %s.' % (slv, address))
      read_value_int = int(read_value, 0)
      # Grab the second byte first (converting little endian to big).
      read_bytes.append(read_value_int & 0xff)
      # Grab the first byte.
      read_bytes.append(read_value_int >> 8)
      return read_bytes
  
    def wr_rd(self, slv, wlist, rcnt):
      """Write and/or read a slave i2c device.
  
      Args:
        slv: 7-bit address of the slave device
        wlist: list of bytes to write to the slave.  If list length is zero its
            just a read.
        rcnt: number of bytes (0-2) to read from the device. If zero, its just a
            write.
  
      Returns:
        list of bytes read from i2c device.
      """
      self._logger.debug('wr_rd. slv: 0x%x, wlist: %s, rcnt: %s', slv, wlist,
                         rcnt)
      address = '0x%02x' % wlist[0]
      if wlist:
        self._write(slv, address, wlist[1:])
  
      return self._read(slv, address, rcnt)
  
  
  def test():
    """Test code. (forked from ftdii2c.py)"""
    loglevel=logging.INFO
    logging.basicConfig(level=loglevel,
                        format='%(asctime)s - %(name)s - ' +
                        '%(levelname)s - %(message)s')
    i2c = BBi2c(3)
  
    wbuf = [0]
    slv = 0x21
    rbuf = i2c.wr_rd(slv, wbuf, 1)
    logging.info('first: i2c read of slv=0x%02x reg=0x%02x == 0x%02x' %
                 (slv, wbuf[0], rbuf[0]))
    errcnt = 0
    for cnt in xrange(1000):
      try:
        rbuf = i2c.wr_rd(slv, [], 1)
      except:
        errcnt += 1
        logging.error('errs = %d cnt = %d' % (errcnt, cnt))
  
    logging.info('last: i2c read of slv=0x%02x reg=0x%02x == 0x%02x' %
                 (slv, wbuf[0], rbuf[0]))
  
  if __name__ == '__main__':
    test()
  