001package com.pi4j.io.i2c.impl;
002
003/*
004 * #%L
005 * **********************************************************************
006 * ORGANIZATION  :  Pi4J
007 * PROJECT       :  Pi4J :: Java Library (Core)
008 * FILENAME      :  I2CDeviceImpl.java
009 *
010 * This file is part of the Pi4J project. More information about
011 * this project can be found here:  http://www.pi4j.com/
012 * **********************************************************************
013 * %%
014 * Copyright (C) 2012 - 2016 Pi4J
015 * %%
016 * This program is free software: you can redistribute it and/or modify
017 * it under the terms of the GNU Lesser General Public License as
018 * published by the Free Software Foundation, either version 3 of the
019 * License, or (at your option) any later version.
020 *
021 * This program is distributed in the hope that it will be useful,
022 * but WITHOUT ANY WARRANTY; without even the implied warranty of
023 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
024 * GNU General Lesser Public License for more details.
025 *
026 * You should have received a copy of the GNU General Lesser Public
027 * License along with this program.  If not, see
028 * <http://www.gnu.org/licenses/lgpl-3.0.html>.
029 * #L%
030 */
031
032import java.io.IOException;
033
034import com.pi4j.io.i2c.I2CDevice;
035
036/**
037 * Implementation of i2c device. This class only holds reference to i2c bus (so it can use its handle) and device address.
038 *
039 * @author Daniel Sendula, refactored by <a href="http://raspelikan.blogspot.co.at">RasPelikan</a>
040 *
041 */
042public class I2CDeviceImpl implements I2CDevice {
043
044    /**
045     * Reference to i2c bus
046     */
047    private I2CBusImpl bus;
048
049    /**
050     * I2c device address
051     */
052    private int deviceAddress;
053
054    /**
055     * @return The address for which this instance is constructed for.
056     */
057    @Override
058    public int getAddress() {
059        return deviceAddress;
060    }
061
062    /**
063     * Constructor.
064     *
065     * @param bus i2c bus
066     * @param address i2c device address
067     */
068    public I2CDeviceImpl(I2CBusImpl bus, int address) {
069        this.bus = bus;
070        this.deviceAddress = address;
071    }
072
073    /**
074     * Used by WriteRunnables and ReadRunnables.
075     *
076     * @return The bus associated with this I2CDeviceImpl instance.
077     */
078    I2CBusImpl getBus() {
079        return bus;
080    }
081
082    /**
083     * This method writes one byte to i2c device.
084     *
085     * @param data byte to be written
086     *
087     * @throws IOException thrown in case byte cannot be written to the i2c device or i2c bus
088     */
089    @Override
090    public void write(final byte data) throws IOException {
091        int ret = getBus().writeByteDirect(this, data);
092        if (ret < 0) {
093            throw new IOException("Error writing to " + makeDescription() + ". Got '" + ret + "'.");
094
095        }
096    }
097
098    /**
099     * This method writes several bytes to the i2c device from given buffer at given offset.
100     *
101     * @param data buffer of data to be written to the i2c device in one go
102     * @param offset offset in buffer
103     * @param size number of bytes to be written
104     *
105     * @throws IOException thrown in case byte cannot be written to the i2c device or i2c bus
106     */
107    @Override
108    public void write(final byte[] data, final int offset, final int size) throws IOException {
109        int ret = getBus().writeBytesDirect(this, size, offset, data);
110        if (ret < 0) {
111            throw new IOException("Error writing to " + makeDescription() + ". Got '" + ret + "'.");
112        }
113    }
114
115    /**
116     * This method writes all bytes included in the given buffer directly to the i2c device.
117     *
118     * @param buffer buffer of data to be written to the i2c device in one go
119     *
120     * @throws IOException thrown in case byte cannot be written to the i2c device or i2c bus
121     */
122    @Override
123    public void write(byte[] buffer) throws IOException {
124        write(buffer, 0, buffer.length);
125    }
126
127    /**
128     * This method writes one byte to i2c device.
129     *
130     * @param address local address in the i2c device
131     * @param data byte to be written
132     *
133     * @throws IOException thrown in case byte cannot be written to the i2c device or i2c bus
134     */
135    @Override
136    public void write(final int address, final byte data) throws IOException {
137        int ret = getBus().writeByte(this, address, data);
138        if (ret < 0) {
139            throw new IOException("Error writing to " + makeDescription(address) + ". Got '" + ret + "'.");
140        }
141    }
142
143    /**
144     * This method writes several bytes to the i2c device from given buffer at given offset.
145     *
146     * @param address local address in the i2c device
147     * @param data buffer of data to be written to the i2c device in one go
148     * @param offset offset in buffer
149     * @param size number of bytes to be written
150     *
151     * @throws IOException thrown in case byte cannot be written to the i2c device or i2c bus
152     */
153    @Override
154    public void write(final int address, final byte[] data, final int offset, final int size) throws IOException {
155        int ret = getBus().writeBytes(this, address, size, offset, data);
156        if (ret < 0) {
157            throw new IOException("Error writing to " + makeDescription(address) + ". Got '" + ret + "'.");
158        }
159    }
160
161    /**
162     * This method writes all bytes included in the given buffer directoy to the register address on the i2c device
163     *
164     * @param address local address in the i2c device
165     * @param buffer buffer of data to be written to the i2c device in one go
166     *
167     * @throws IOException thrown in case byte cannot be written to the i2c device or i2c bus
168     */
169    public void write(int address, byte[] buffer) throws IOException {
170        write(address, buffer, 0, buffer.length);
171    }
172
173    /**
174     * This method reads one byte from the i2c device. Result is between 0 and 255 if read operation was successful, else a negative number for an error.
175     *
176     * @return byte value read: positive number (or zero) to 255 if read was successful. Negative number if reading failed.
177     *
178     * @throws IOException thrown in case byte cannot be read from the i2c device or i2c bus
179     */
180    @Override
181    public int read() throws IOException {
182        int ret = getBus().readByteDirect(this);
183        if (ret < 0) {
184            throw new IOException("Error reading from " + makeDescription() + ". Got '" + ret + "'.");
185        }
186        return ret;
187    }
188
189    /**
190     * <p>
191     * This method reads bytes from the i2c device to given buffer at asked offset.
192     * </p>
193     *
194     * <p>
195     * Note: Current implementation calls {@link #read(int)}. That means for each read byte i2c bus will send (next) address to i2c device.
196     * </p>
197     *
198     * @param data buffer of data to be read from the i2c device in one go
199     * @param offset offset in buffer
200     * @param size number of bytes to be read
201     *
202     * @return number of bytes read
203     *
204     * @throws IOException thrown in case byte cannot be read from the i2c device or i2c bus
205     */
206    @Override
207    public int read(final byte[] data, final int offset, final int size) throws IOException {
208        int ret = getBus().readBytesDirect(this, size, offset, data);
209        if (ret < 0) {
210            throw new IOException("Error reading from " + makeDescription() + ". Got '" + ret + "'.");
211        }
212        return ret;
213    }
214
215    /**
216     * This method reads one byte from the i2c device. Result is between 0 and 255 if read operation was successful, else a negative number for an error.
217     *
218     * @param address local address in the i2c device
219     * @return byte value read: positive number (or zero) to 255 if read was successful. Negative number if reading failed.
220     *
221     * @throws IOException thrown in case byte cannot be read from the i2c device or i2c bus
222     */
223    @Override
224    public int read(final int address) throws IOException {
225        int ret = getBus().readByte(this, address);
226        if (ret < 0) {
227            throw new IOException("Error reading from " + makeDescription(address) + ". Got '" + ret + "'.");
228        }
229        return ret;
230    }
231
232    /**
233     * <p>
234     * This method reads bytes from the i2c device to given buffer at asked offset.
235     * </p>
236     *
237     * <p>
238     * Note: Current implementation calls {@link #read(int)}. That means for each read byte i2c bus will send (next) address to i2c device.
239     * </p>
240     *
241     * @param address local address in the i2c device
242     * @param data buffer of data to be read from the i2c device in one go
243     * @param offset offset in buffer
244     * @param size number of bytes to be read
245     *
246     * @return number of bytes read
247     *
248     * @throws IOException thrown in case byte cannot be read from the i2c device or i2c bus
249     */
250    @Override
251    public int read(final int address, final byte[] data, final int offset, final int size) throws IOException {
252        int ret = getBus().readBytes(this, address, size, offset, data);
253        if (ret < 0) {
254            throw new IOException("Error reading from " + makeDescription(address) + ". Got '" + ret + "'.");
255        }
256        return ret;
257    }
258
259    /**
260     * This method writes and reads bytes to/from the i2c device in a single method call
261     *
262     * @param writeData buffer of data to be written to the i2c device in one go
263     * @param writeOffset offset in write buffer
264     * @param writeSize number of bytes to be written from buffer
265     * @param readData buffer of data to be read from the i2c device in one go
266     * @param readOffset offset in read buffer
267     * @param readSize number of bytes to be read
268     *
269     * @return number of bytes read
270     *
271     * @throws IOException thrown in case byte cannot be read from the i2c device or i2c bus
272     */
273    @Override
274    public int read(final byte[] writeData, final int writeOffset, final int writeSize, final byte[] readData, final int readOffset, final int readSize) throws IOException {
275        int ret = getBus().writeAndReadBytesDirect(this, writeSize, writeOffset, writeData, readSize, readOffset, readData);
276        if (ret < 0) {
277            throw new IOException("Error reading from " + makeDescription() + ". Got '" + ret + "'.");
278        }
279        return ret;
280    }
281
282    /**
283     * This helper method creates a string describing bus file name and device address (in hex).
284     *
285     * @return string with all details
286     */
287    protected String makeDescription() {
288        return "I2CDevice on " + bus + " at address 0x" + Integer.toHexString(deviceAddress);
289    }
290
291    /**
292     * This helper method creates a string describing bus file name, device address (in hex) and local i2c address.
293     *
294     * @param address local address in i2c device
295     * @return string with all details
296     */
297    protected String makeDescription(int address) {
298        return "I2CDevice on " + bus + " at address 0x" + Integer.toHexString(deviceAddress) + " to address 0x" + Integer.toHexString(address);
299    }
300}