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 - 2013 Pi4J
015 * %%
016 * Licensed under the Apache License, Version 2.0 (the "License");
017 * you may not use this file except in compliance with the License.
018 * You may obtain a copy of the License at
019 * 
020 *      http://www.apache.org/licenses/LICENSE-2.0
021 * 
022 * Unless required by applicable law or agreed to in writing, software
023 * distributed under the License is distributed on an "AS IS" BASIS,
024 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
025 * See the License for the specific language governing permissions and
026 * limitations under the License.
027 * #L%
028 */
029
030import java.io.IOException;
031
032import com.pi4j.io.i2c.I2CDevice;
033import com.pi4j.jni.I2C;
034
035/**
036 * Implementation of i2c device. This class only holds reference to i2c bus (so it can use its handle) and
037 * device address.
038 * 
039 * @author Daniel Sendula
040 *
041 */
042public class I2CDeviceImpl implements I2CDevice {
043
044    /** Reference to i2c bus */
045    private I2CBusImpl bus;
046    
047    /** I2c device address */
048    private int deviceAddress;
049    
050    /**
051     * Constructor.
052     * 
053     * @param bus i2c bus
054     * @param address i2c device address
055     */
056    public I2CDeviceImpl(I2CBusImpl bus, int address) {
057        this.bus = bus;
058        this.deviceAddress = address;
059    }
060
061    /**
062     * This method writes one byte to i2c device. 
063     * 
064     * @param b byte to be written
065     * 
066     * @throws IOException thrown in case byte cannot be written to the i2c device or i2c bus
067     */
068    @Override
069    public void write(byte data) throws IOException {
070        int ret = I2C.i2cWriteByteDirect(bus.fd, deviceAddress, data);
071        if (ret < 0) {
072            throw new IOException("Error writing to " + makeDescription() + ". Got " + ret + ".");
073        }
074    }
075
076    /**
077     * This method writes several bytes to the i2c device from given buffer at given offset.
078     * 
079     * @param buffer buffer of data to be written to the i2c device in one go
080     * @param offset offset in buffer 
081     * @param size number of bytes to be written 
082     * 
083     * @throws IOException thrown in case byte cannot be written to the i2c device or i2c bus
084     */
085    @Override
086    public void write(byte[] buffer, int offset, int size) throws IOException {
087        
088        int ret = I2C.i2cWriteBytesDirect(bus.fd, deviceAddress, size, offset, buffer);
089        if (ret < 0) {
090            throw new IOException("Error writing to " + makeDescription() + ". Got " + ret + ".");
091        }
092    }
093
094    /**
095     * This method writes one byte to i2c device. 
096     * 
097     * @param address local address in the i2c device
098     * @param b byte to be written
099     * 
100     * @throws IOException thrown in case byte cannot be written to the i2c device or i2c bus
101     */
102    @Override
103    public void write(int address, byte data) throws IOException {
104        int ret = I2C.i2cWriteByte(bus.fd, deviceAddress, address, data);
105        if (ret < 0) {
106            throw new IOException("Error writing to " + makeDescription(address) + ". Got " + ret + ".");
107        }
108    }
109
110    /**
111     * This method writes several bytes to the i2c device from given buffer at given offset.
112     * 
113     * @param address local address in the i2c device
114     * @param buffer buffer of data to be written to the i2c device in one go
115     * @param offset offset in buffer 
116     * @param size number of bytes to be written 
117     * 
118     * @throws IOException thrown in case byte cannot be written to the i2c device or i2c bus
119     */
120    @Override
121    public void write(int address, byte[] buffer, int offset, int size) throws IOException {
122        
123        int ret = I2C.i2cWriteBytes(bus.fd, deviceAddress, address, size, offset, buffer);
124        if (ret < 0) {
125            throw new IOException("Error writing to " + makeDescription(address) + ". Got " + ret + ".");
126        }
127    }
128
129    /**
130     * This method reads one byte from the i2c device. Result is between -128 and 127.
131     * 
132     * @return
133     * 
134     * @throws IOException thrown in case byte cannot be read from the i2c device or i2c bus
135     */
136    @Override
137    public int read() throws IOException {
138        int ret = I2C.i2cReadByteDirect(bus.fd, deviceAddress);
139        if (ret < 0) {
140            throw new IOException("Error reading from " + makeDescription() + ". Got " + ret + ".");
141        }
142        return ret;
143    }
144
145    /**
146     * <p>This method reads bytes from the i2c device to given buffer at asked offset. </p>
147     * 
148     * <p>Note: Current implementation calls {@link #read(int)}. That means for each read byte 
149     * i2c bus will send (next) address to i2c device.
150     * </p>
151     * 
152     * @param buffer buffer of data to be read from the i2c device in one go
153     * @param offset offset in buffer 
154     * @param size number of bytes to be read 
155     * 
156     * @return number of bytes read
157     * 
158     * @throws IOException thrown in case byte cannot be read from the i2c device or i2c bus
159     */
160    @Override
161    public int read(byte[] buffer, int offset, int size) throws IOException {
162        // It doesn't work for some reason. 
163        int ret = I2C.i2cReadBytesDirect(bus.fd, deviceAddress, size, offset, buffer);
164        if (ret < 0) {
165            throw new IOException("Error reading from " + makeDescription() + ". Got " + ret + ".");
166        }
167        return ret;
168    }
169
170    /**
171     * This method reads one byte from the i2c device. Result is between -128 and 127.
172     * 
173     * @param address local address in the i2c device
174     * @return
175     * 
176     * @throws IOException thrown in case byte cannot be read from the i2c device or i2c bus
177     */
178    @Override
179    public int read(int address) throws IOException {
180        int ret = I2C.i2cReadByte(bus.fd, deviceAddress, address);
181        if (ret < 0) {
182            throw new IOException("Error reading from " + makeDescription(address) + ". Got " + ret + ".");
183        }
184        return ret;
185    }
186
187    /**
188     * <p>This method reads bytes from the i2c device to given buffer at asked offset. </p>
189     * 
190     * <p>Note: Current implementation calls {@link #read(int)}. That means for each read byte 
191     * i2c bus will send (next) address to i2c device.
192     * </p>
193     * 
194     * @param address local address in the i2c device
195     * @param buffer buffer of data to be read from the i2c device in one go
196     * @param offset offset in buffer 
197     * @param size number of bytes to be read 
198     * 
199     * @return number of bytes read
200     * 
201     * @throws IOException thrown in case byte cannot be read from the i2c device or i2c bus
202     */
203    @Override
204    public int read(int address, byte[] buffer, int offset, int size) throws IOException {
205        // It doesn't work for some reason. 
206        int ret = I2C.i2cReadBytes(bus.fd, deviceAddress, address, size, offset, buffer);
207        if (ret < 0) {
208            throw new IOException("Error reading from " + makeDescription(address) + ". Got " + ret + ".");
209        }
210        return ret;
211    }
212    
213    /**
214     * This helper method creates a string describing bus file name and device address (in hex).
215     * 
216     * @return string with all details
217     */
218    protected String makeDescription() {
219        return bus.filename + " at address 0x" + Integer.toHexString(deviceAddress);
220    }
221    
222    /**
223     * This helper method creates a string describing bus file name, device address (in hex)
224     * and local i2c address.
225     * 
226     * @param address local address in i2c device
227     * @return string with all details
228     */
229    protected String makeDescription(int address) {
230        return bus.filename + " at address 0x" + Integer.toHexString(deviceAddress) 
231                + " to address 0x" + Integer.toHexString(address);
232    }
233    
234}