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