text: # Copyright (c) 2014 Adafruit Industries
  # Author: Tony DiCola
  # Based on Adafruit_I2C.py created by Kevin Townsend.
  #
  # Permission is hereby granted, free of charge, to any person obtaining a copy
  # of this software and associated documentation files (the "Software"), to deal
  # in the Software without restriction, including without limitation the rights
  # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  # copies of the Software, and to permit persons to whom the Software is
  # furnished to do so, subject to the following conditions:
  #
  # The above copyright notice and this permission notice shall be included in
  # all copies or substantial portions of the Software.
  #
  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  # THE SOFTWARE.
  import logging
  import subprocess
  
  import Platform
  
  
  def reverseByteOrder(data):
      """DEPRECATED: See https://github.com/adafruit/Adafruit_Python_GPIO/issues/48"""
      # # Courtesy Vishal Sapre
      # byteCount = len(hex(data)[2:].replace('L','')[::2])
      # val       = 0
      # for i in range(byteCount):
      #     val    = (val << 8) | (data & 0xff)
      #     data >>= 8
      # return val
      raise RuntimeError('reverseByteOrder is deprecated! See: https://github.com/adafruit/Adafruit_Python_GPIO/issues/48')
  
  def get_default_bus():
      """Return the default bus number based on the device platform.  For a
      Raspberry Pi either bus 0 or 1 (based on the Pi revision) will be returned.
      For a Beaglebone Black the first user accessible bus, 1, will be returned.
      """
      plat = Platform.platform_detect()
  
      if plat == Platform.RASPBERRY_PI:
          if Platform.pi_revision() == 1:
              # Revision 1 Pi uses I2C bus 0.
              return 0
          else:
              # Revision 2 Pi uses I2C bus 1.
              return 1
      elif plat == Platform.BEAGLEBONE_BLACK:
          # Beaglebone Black has multiple I2C buses, default to 1 (P9_19 and P9_20).
          return 1
      else:
          raise RuntimeError('Could not determine default I2C bus for platform.')
  
  def get_i2c_device(address, busnum=None, i2c_interface=None, **kwargs):
      """Return an I2C device for the specified address and on the specified bus.
      If busnum isn't specified, the default I2C bus for the platform will attempt
      to be detected.
      """
      if busnum is None:
          busnum = get_default_bus()
      return Device(address, busnum, i2c_interface, **kwargs)
  
  def require_repeated_start():
      """Enable repeated start conditions for I2C register reads.  This is the
      normal behavior for I2C, however on some platforms like the Raspberry Pi
      there are bugs which disable repeated starts unless explicitly enabled with
      this function.  See this thread for more details:
        http://www.raspberrypi.org/forums/viewtopic.php?f=44&t=15840
      """
      plat = Platform.platform_detect()
      if plat == Platform.RASPBERRY_PI:
          # On the Raspberry Pi there is a bug where register reads don't send a
          # repeated start condition like the kernel smbus I2C driver functions
          # define.  As a workaround this bit in the BCM2708 driver sysfs tree can
          # be changed to enable I2C repeated starts.
          subprocess.check_call('chmod 666 /sys/module/i2c_bcm2708/parameters/combined', shell=True)
          subprocess.check_call('echo -n 1 > /sys/module/i2c_bcm2708/parameters/combined', shell=True)
      # Other platforms are a no-op because they (presumably) have the correct
      # behavior and send repeated starts.
  
  
  class Device(object):
      """Class for communicating with an I2C device using the adafruit-pureio pure
      python smbus library, or other smbus compatible I2C interface. Allows reading
      and writing 8-bit, 16-bit, and byte array values to registers
      on the device."""
      def __init__(self, address, busnum, i2c_interface=None):
          """Create an instance of the I2C device at the specified address on the
          specified I2C bus number."""
          self._address = address
          if i2c_interface is None:
              # Use pure python I2C interface if none is specified.
              import smbus
              self._bus = smbus.SMBus(busnum)
          else:
              # Otherwise use the provided class to create an smbus interface.
              self._bus = i2c_interface(busnum)
          self._logger = logging.getLogger('Adafruit_I2C.Device.Bus.{0}.Address.{1:#0X}' \
                                  .format(busnum, address))
  
      def writeRaw8(self, value):
          """Write an 8-bit value on the bus (without register)."""
          value = value & 0xFF
          self._bus.write_byte(self._address, value)
          self._logger.debug("Wrote 0x%02X",
                       value)
  
      def write8(self, register, value):
          """Write an 8-bit value to the specified register."""
          value = value & 0xFF
          self._bus.write_byte_data(self._address, register, value)
          self._logger.debug("Wrote 0x%02X to register 0x%02X",
                       value, register)
  
      def write16(self, register, value):
          """Write a 16-bit value to the specified register."""
          value = value & 0xFFFF
          self._bus.write_word_data(self._address, register, value)
          self._logger.debug("Wrote 0x%04X to register pair 0x%02X, 0x%02X",
                       value, register, register+1)
  
      def writeList(self, register, data):
          """Write bytes to the specified register."""
          self._bus.write_i2c_block_data(self._address, register, data)
          self._logger.debug("Wrote to register 0x%02X: %s",
                       register, data)
  
      def readList(self, register, length):
          """Read a length number of bytes from the specified register.  Results
          will be returned as a bytearray."""
          results = self._bus.read_i2c_block_data(self._address, register, length)
          self._logger.debug("Read the following from register 0x%02X: %s",
                       register, results)
          return results
  
      def readRaw8(self):
          """Read an 8-bit value on the bus (without register)."""
          result = self._bus.read_byte(self._address) & 0xFF
          self._logger.debug("Read 0x%02X",
                      result)
          return result
  
      def readU8(self, register):
          """Read an unsigned byte from the specified register."""
          result = self._bus.read_byte_data(self._address, register) & 0xFF
          self._logger.debug("Read 0x%02X from register 0x%02X",
                       result, register)
          return result
  
      def readS8(self, register):
          """Read a signed byte from the specified register."""
          result = self.readU8(register)
          if result > 127:
              result -= 256
          return result
  
      def readU16(self, register, little_endian=True):
          """Read an unsigned 16-bit value from the specified register, with the
          specified endianness (default little endian, or least significant byte
          first)."""
          result = self._bus.read_word_data(self._address,register) & 0xFFFF
          self._logger.debug("Read 0x%04X from register pair 0x%02X, 0x%02X",
                             result, register, register+1)
          # Swap bytes if using big endian because read_word_data assumes little
          # endian on ARM (little endian) systems.
          if not little_endian:
              result = ((result << 8) & 0xFF00) + (result >> 8)
          return result
  
      def readS16(self, register, little_endian=True):
          """Read a signed 16-bit value from the specified register, with the
          specified endianness (default little endian, or least significant byte
          first)."""
          result = self.readU16(register, little_endian)
          if result > 32767:
              result -= 65536
          return result
  
      def readU16LE(self, register):
          """Read an unsigned 16-bit value from the specified register, in little
          endian byte order."""
          return self.readU16(register, little_endian=True)
  
      def readU16BE(self, register):
          """Read an unsigned 16-bit value from the specified register, in big
          endian byte order."""
          return self.readU16(register, little_endian=False)
  
      def readS16LE(self, register):
          """Read a signed 16-bit value from the specified register, in little
          endian byte order."""
          return self.readS16(register, little_endian=True)
  
      def readS16BE(self, register):
          """Read a signed 16-bit value from the specified register, in big
          endian byte order."""
          return self.readS16(register, little_endian=False)
  