001package com.pi4j.io.spi.impl; 002 003/* 004 * #%L 005 * ********************************************************************** 006 * ORGANIZATION : Pi4J 007 * PROJECT : Pi4J :: Java Library (Core) 008 * FILENAME : SpiDeviceImpl.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 032 033import com.pi4j.io.spi.SpiChannel; 034import com.pi4j.io.spi.SpiDevice; 035import com.pi4j.io.spi.SpiMode; 036import com.pi4j.wiringpi.Spi; 037 038import java.io.IOException; 039import java.io.InputStream; 040import java.io.OutputStream; 041import java.nio.ByteBuffer; 042import java.nio.charset.Charset; 043 044public class SpiDeviceImpl implements SpiDevice { 045 046 protected final SpiChannel channel; 047 protected final SpiMode mode; 048 049 /** 050 * Creates the SPI Device at the given spi and input channel 051 * 052 * @param channel 053 * spi channel to use 054 * @param speed 055 * spi speed/rate (in Hertz) for channel to communicate at 056 * (range is 500kHz - 32MHz) 057 * @param mode 058 * spi mode (see http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus#Mode_numbers) 059 * 060 */ 061 public SpiDeviceImpl(SpiChannel channel, int speed, SpiMode mode) throws IOException { 062 this.channel = channel; 063 this.mode = mode; 064 try { 065 int fd = Spi.wiringPiSPISetupMode(channel.getChannel(), speed, mode.getMode()); 066 if (fd <= -1) { 067 throw new IOException("SPI port setup failed, wiringPiSPISetupMode returned " + fd); 068 } 069 } catch (UnsatisfiedLinkError e) { 070 throw new IOException("SPI port setup failed, no SPI available.", e); 071 } 072 } 073 074 /** 075 * Creates the SPI Device at the given spi and input channel 076 * 077 * @param channel 078 * spi channel to use 079 * @param speed 080 * spi speed/rate (in Hertz) for channel to communicate at 081 * (range is 500kHz - 32MHz) 082 */ 083 public SpiDeviceImpl(SpiChannel channel, int speed) throws IOException { 084 this(channel, speed, DEFAULT_SPI_MODE); 085 } 086 087 /** 088 * Creates the SPI Device at the given SPI and input channel 089 * (A default speed of 1 MHz will be used) 090 * 091 * @param channel 092 * spi channel to use 093 * @param mode 094 * spi mode (see http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus#Mode_numbers) 095 */ 096 public SpiDeviceImpl(SpiChannel channel, SpiMode mode) throws IOException { 097 this(channel, DEFAULT_SPI_SPEED, mode); 098 } 099 100 /** 101 * Creates the SPI Device at the given SPI and input channel 102 * (A default speed of 1 MHz will be used) 103 * 104 * @param channel 105 * spi channel to use 106 */ 107 public SpiDeviceImpl(SpiChannel channel) throws IOException { 108 this(channel, DEFAULT_SPI_SPEED); 109 } 110 111 @Override 112 public String write(String data, String charset) throws IOException { 113 byte[] buffer = data.getBytes(charset); 114 return new String(write(buffer), charset); 115 } 116 117 @Override 118 public String write(String data, Charset charset) throws IOException { 119 byte[] buffer = data.getBytes(charset); 120 return new String(write(buffer), charset); 121 } 122 123 @Override 124 public ByteBuffer write(ByteBuffer data) throws IOException { 125 return ByteBuffer.wrap(write(data.array())); 126 } 127 128 @Override 129 public byte[] write(InputStream input) throws IOException { 130 131 // ensure bytes are available 132 if(input.available() <= 0){ 133 throw new IOException("No available bytes in input stream to write to SPI channel: " + channel.getChannel()); 134 } 135 else if(input.available() > MAX_SUPPORTED_BYTES){ 136 throw new IOException("Number of bytes in stream exceed the maximum bytes allowed to write SPI channel in a single call"); 137 } 138 139 // create a temporary buffer to store read bytes from stream 140 byte[] buffer = new byte[MAX_SUPPORTED_BYTES]; 141 142 // read maximum number of supported bytes 143 int length = input.read(buffer, 0 , MAX_SUPPORTED_BYTES); 144 145 // write bytes to SPI channel 146 return write(buffer, 0, length); 147 } 148 149 @Override 150 public int write(InputStream input, OutputStream output) throws IOException { 151 // write stream data to SPI device 152 byte[] buffer = write(input); 153 154 //write resulting byte array to output stream 155 output.write(buffer); 156 157 // return data length 158 return buffer.length; 159 } 160 161 @Override 162 public byte[] write(byte... data) throws IOException { 163 return write(data, 0, data.length); 164 } 165 166 @Override 167 public short[] write(short... data) throws IOException { 168 return write(data, 0, data.length); 169 } 170 171 @Override 172 public byte[] write(byte[] data, int start, int length) throws IOException { 173 174 // ensure the length does not exceed the data array 175 length = Math.min(data.length - start, length); 176 177 // validate max length allowed 178 if (length > MAX_SUPPORTED_BYTES) { 179 throw new IOException("Number of bytes in data to write exceed the maximum bytes allowed to write SPI channel in a single call"); 180 } 181 182 // we make a copy of the data argument because we don't want to modify the original source data 183 byte[] buffer = new byte[length]; 184 System.arraycopy(data, start, buffer, 0, length); 185 186 synchronized (channel) { 187 // write the bytes from the temporary buffer to the SPI channel 188 if (Spi.wiringPiSPIDataRW(channel.getChannel(), buffer) <= 0) { 189 throw new IOException("Failed to write data to SPI channel: " + channel.getChannel()); 190 } 191 } 192 // return the updated byte buffer as the SPI read results 193 return buffer; 194 } 195 196 @Override 197 public short[] write(short[] data, int start, int length) throws IOException { 198 199 // ensure the length does not exceed the data array 200 length = Math.min(data.length - start, length); 201 202 // validate max length allowed 203 if (length > MAX_SUPPORTED_BYTES) { 204 throw new IOException("Number of bytes in data to write exceed the maximum bytes allowed to write SPI channel in a single call"); 205 } 206 207 // we make a copy of the data argument because we don't want to modify the original source data 208 short[] buffer = new short[length]; 209 System.arraycopy(data, start, buffer, 0, length); 210 211 synchronized (channel) { 212 // write the bytes from the temporary buffer to the SPI channel 213 if (Spi.wiringPiSPIDataRW(channel.getChannel(), buffer) <= 0) { 214 throw new IOException("Failed to write data to SPI channel: " + channel.getChannel()); 215 } 216 217 // return the updated byte buffer as the SPI read results 218 return buffer; 219 } 220 } 221 222}