blob: d8541717f63f388e74b65aec39d59bdbdf320d7a [file] [log] [blame]
Tan Gao3768ffe2011-08-30 11:12:20 -07001# 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