You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
208 lines
6.6 KiB
208 lines
6.6 KiB
# Lint as: python2, python3
|
|
# Copyright (c) 2011 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.
|
|
|
|
"""A base class to interact with I2C node device.
|
|
|
|
Dependency
|
|
- This library depends on a new C shared library called "libsmogcheck.so".
|
|
"""
|
|
|
|
import ctypes, logging
|
|
|
|
|
|
# I2C constants
|
|
I2C_BUS = 2
|
|
|
|
# Path of shared library.
|
|
SMOGCHECK_C_LIB = "/usr/local/lib/libsmogcheck.so.0"
|
|
|
|
|
|
class I2cError(Exception):
|
|
"""Base class for all errors in this module."""
|
|
|
|
|
|
class I2cNode(object):
|
|
"""A generic I2C node object that supports basic I2C bus input/output."""
|
|
|
|
def __init__(self, adapter_nr=None, load_lib=None):
|
|
"""Constructor.
|
|
|
|
Mandatory params:
|
|
adapter_nr: adapter's number address. Default: I2C_BUS.
|
|
fd: file descriptor to communicate with I2C bus.
|
|
lib_obj: ctypes library object to interface with SMOGCHECK_C_LIB.
|
|
load_lib: a string, name of C shared library object to load.
|
|
node_addr: node address to set. Default: None.
|
|
|
|
Args:
|
|
lib: a string, name of C shared library object to load.
|
|
"""
|
|
self.node_addr = None
|
|
|
|
if adapter_nr is None:
|
|
adapter_nr = I2C_BUS
|
|
self.adapter_nr = adapter_nr
|
|
|
|
if load_lib is None:
|
|
load_lib = SMOGCHECK_C_LIB
|
|
self.load_lib = load_lib
|
|
|
|
# Load shared library object.
|
|
self.lib_obj = self._loadSharedLibrary()
|
|
self.fd = self._getDeviceFile()
|
|
|
|
def _loadSharedLibrary(self):
|
|
"""Loads C shared library .so file.
|
|
|
|
Returns:
|
|
a new instance of the shared (C) library.
|
|
|
|
Raises:
|
|
I2cError: if error loading the shared library.
|
|
"""
|
|
logging.info('Attempt to load shared library %s', self.load_lib)
|
|
try:
|
|
return ctypes.cdll.LoadLibrary(self.load_lib)
|
|
except OSError as e:
|
|
raise I2cError('Error loading C library %s: %s' %
|
|
(self.load_lib, e))
|
|
logging.info('Successfully loaded shared library %s', self.load_lib)
|
|
|
|
def _getDeviceFile(self):
|
|
"""Gets a file descriptor of a device file.
|
|
|
|
Returns:
|
|
fd: an integer, file descriptor to communicate with I2C bus.
|
|
|
|
Raises:
|
|
I2cError: if error getting device file.
|
|
"""
|
|
logging.info('Attempt to get device file for adapter %s',
|
|
self.adapter_nr)
|
|
fd = self.lib_obj.GetDeviceFile(self.adapter_nr)
|
|
if fd < 0:
|
|
raise I2cError('Error getting device file for adapter %s' %
|
|
self.adapter_nr)
|
|
|
|
logging.info('Got device file for adapter %s', self.adapter_nr)
|
|
return fd
|
|
|
|
def setNodeAddress(self, addr):
|
|
"""Sets node address on I2C bus to be communicated with.
|
|
|
|
TODO(tgao): add retry loop and raise error if all retries fail.
|
|
(so that caller does not have to check self.err for status)
|
|
|
|
We use 7-bit address space for I2C, which has 128 addresses total.
|
|
Besides 16 reserved addresses, the total usable address space is 112.
|
|
See - http://www.i2c-bus.org/addressing/
|
|
|
|
Args:
|
|
addr: a (positive) integer, 7-bit I2C node address.
|
|
|
|
Raises:
|
|
I2cError: if node address is invalid or can't be set.
|
|
"""
|
|
if self.node_addr == addr:
|
|
logging.info('Node address already set, noop: %s', addr)
|
|
return
|
|
|
|
if addr < 0x8 or addr > 0x77:
|
|
raise I2cError('Error: invalid I2C node address %s', addr)
|
|
|
|
logging.info('Attempt to set node address: %s', addr)
|
|
if not self.fd:
|
|
self.fd = self._getDeviceFile()
|
|
|
|
ret = self.lib_obj.setNodeAddress(self.fd, addr)
|
|
if ret < 0:
|
|
raise I2cError('Error communicating to node address %s' % addr)
|
|
|
|
self.node_addr = addr
|
|
logging.info('node address set to: %s', addr)
|
|
|
|
def writeByte(self, reg, byte):
|
|
"""Writes a byte to a specific register.
|
|
|
|
TODO(tgao): add retry loop and raise error if all retries fail.
|
|
|
|
Args:
|
|
reg: a (positive) integer, register number.
|
|
byte: a char (8-bit byte), value to write.
|
|
|
|
Raises:
|
|
I2cError: if error writing byte to I2C bus.
|
|
"""
|
|
logging.info('Attempt to write byte %r to reg %r', byte, reg)
|
|
if self.lib_obj.WriteByte(self.fd, reg, byte) < 0:
|
|
raise I2cError('Error writing byte 0x%x to reg %r' % (byte, reg))
|
|
|
|
logging.info('Successfully wrote byte 0x%x to reg %r', byte, reg)
|
|
|
|
def readByte(self, reg):
|
|
"""Reads a byte from a specific register.
|
|
|
|
TODO(tgao): add retry loop and raise error if all retries fail.
|
|
|
|
Args:
|
|
reg: a (positive) integer, register number.
|
|
|
|
Returns:
|
|
byte_read: a char (8-bit byte), value read from register.
|
|
|
|
Raises:
|
|
I2cError: if error reading byte from I2C bus.
|
|
"""
|
|
logging.info('Attempt to read byte from register %r', reg)
|
|
byte_read = self.lib_obj.ReadByte(self.fd, reg)
|
|
if byte_read < 0:
|
|
raise I2cError('Error reading byte from reg %r' % reg)
|
|
|
|
logging.info('Successfully read byte 0x%x from reg %r',
|
|
byte_read, reg)
|
|
return byte_read
|
|
|
|
def writeWord(self, reg, word):
|
|
"""Writes a word to a specific register.
|
|
|
|
TODO(tgao): add retry loop and raise error if all retries fail.
|
|
|
|
Args:
|
|
reg: a (positive) integer, register number.
|
|
word: a 16-bit unsigned integer, value to write.
|
|
|
|
Raises:
|
|
I2cError: if error writing word to I2C bus.
|
|
"""
|
|
logging.info('Attempt to write word %r to reg %r', word, reg)
|
|
if self.lib_obj.WriteWord(self.fd, reg, ctypes.c_uint16(word)) < 0:
|
|
raise I2cError('Error writing word 0x%x to reg %r' % (word, reg))
|
|
|
|
logging.info('Successfully wrote word 0x%x to reg %r',
|
|
word, reg)
|
|
|
|
def readWord(self, reg):
|
|
"""Reads a word from a specific register.
|
|
|
|
TODO(tgao): add retry loop and raise error if all retries fail.
|
|
|
|
Args:
|
|
reg: a (positive) integer, register number.
|
|
|
|
Returns:
|
|
a 16-bit unsigned integer, value read from register.
|
|
|
|
Raises:
|
|
I2cError: if error reading word from I2C bus.
|
|
"""
|
|
logging.info('Attempt to read word from register %r', reg)
|
|
word_read = self.lib_obj.ReadWord(self.fd, reg)
|
|
if word_read < 0:
|
|
raise I2cError('Error reading word from reg %r' % reg)
|
|
|
|
logging.info('Successfully read word 0x%x from reg %r',
|
|
word_read, reg)
|
|
return word_read
|