001package com.pi4j.io.i2c.impl;
002
003/*
004 * #%L
005 * **********************************************************************
006 * ORGANIZATION  :  Pi4J
007 * PROJECT       :  Pi4J :: Java Library (Core)
008 * FILENAME      :  I2CBusImpl.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 - 2015 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 com.pi4j.io.i2c.I2CBus;
033import com.pi4j.io.i2c.I2CDevice;
034import com.pi4j.jni.I2C;
035
036import java.io.IOException;
037import java.util.concurrent.locks.Lock;
038import java.util.concurrent.locks.ReentrantLock;
039
040/**
041 * This is implementation of i2c bus. This class keeps underlying linux file descriptor of
042 * particular bus. As all reads and writes from/to i2c bus are blocked I/Os current implementation uses only 
043 * one file per bus for all devices. Device implementations use this class file handle.
044 * 
045 * @author Daniel Sendula
046 *
047 */
048public class I2CBusImpl implements I2CBus {
049
050    /** Singleton instance of bus 0 */
051    private static I2CBus bus0 = null;
052
053    /** Singleton instance of bus 1 */
054    private static I2CBus bus1 = null;
055    
056    /** to lock the creation/destruction of the bus singletons */
057    private final static Lock lock = new ReentrantLock( true );
058
059    /** 
060     * Factory method that returns bus implementation.
061     * 
062     * @param busNumber bus number
063     * @return appropriate bus implementation
064     * @throws IOException thrown in case there is a problem opening bus file or bus number is not 0 or 1.
065     */
066    public static I2CBus getBus(int busNumber) throws IOException {
067        I2CBus bus;
068        lock.lock();
069        if (busNumber == 0) {
070            bus = bus0;
071            if (bus == null) {
072                bus = new I2CBusImpl("/dev/i2c-0");
073                bus0 = bus;
074            }
075        } else if (busNumber == 1) {
076            bus = bus1;
077            if (bus == null) {
078                bus = new I2CBusImpl("/dev/i2c-1");
079                bus1 = bus;
080            }
081        } else {
082            throw new IOException("Unknown bus number " + busNumber);
083        }
084        lock.unlock();
085        return bus;
086    }
087
088    /** File handle for this i2c bus */
089    protected int fd;
090    
091    /** File name of this i2c bus */
092    protected String filename;
093    
094    /**
095     * Constructor of i2c bus implementation.
096     * 
097     * @param filename file name of device to be opened.
098     * 
099     * @throws IOException thrown in case that file cannot be opened
100     */
101    public I2CBusImpl(String filename) throws IOException {
102        this.filename = filename;
103        fd = I2C.i2cOpen(filename);
104        if (fd < 0) {
105            throw new IOException("Cannot open file handle for " + filename + " got " + fd + " back.");
106        }
107    }
108
109    /**
110     * Returns i2c device implementation ({@link I2CDeviceImpl}).
111     * 
112     * @param address address of i2c device
113     * 
114     * @return implementation of i2c device with given address
115     * 
116     * @throws IOException never in this implementation
117     */
118    @Override
119    public I2CDevice getDevice(int address) throws IOException {
120        return new I2CDeviceImpl(this, address);
121    }
122
123    /**
124     * Closes this i2c bus
125     * 
126     * @throws IOException never in this implementation
127     */
128    @Override
129    public void close() throws IOException {
130        lock.lock();
131        I2C.i2cClose(fd);
132        /* after closing the fd, we must "forget" the singleton bus instance, otherwise further request to this bus will
133         * always fail
134         */
135        if (this == bus0) {
136            bus0 = null;
137        } else if (this == bus1) {
138            bus1 = null;
139        }
140        lock.unlock();
141    }
142
143        @Override
144        public String getFileName()
145        {
146                return filename;
147        }
148
149        @Override
150        public int getFileDescriptor()
151        {
152                return fd;
153        }
154}