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}