mirror of
https://github.com/processing/processing4.git
synced 2026-06-08 16:40:46 +02:00
273 lines
7.9 KiB
Java
273 lines
7.9 KiB
Java
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
|
|
|
/*
|
|
Copyright (c) The Processing Foundation 2015
|
|
Hardware I/O library developed by Gottfried Haider as part of GSoC 2015
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General
|
|
Public License along with this library; if not, write to the
|
|
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
|
Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
package processing.io;
|
|
|
|
import processing.io.NativeInterface;
|
|
|
|
import java.io.File;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.HashMap;
|
|
import java.util.Map;
|
|
|
|
|
|
/**
|
|
* Opens an SPI interface as master<br/>
|
|
* </br>
|
|
* Serial Peripheral Interface (SPI) is a serial bus, commonly used to
|
|
* communicate with sensors and memory devices. It uses four pins: MOSI (Master
|
|
* Out Slave In), MISO (Master In Slave Out), and SCLK (clock signal) - those
|
|
* three are shared among all devices on the bus - as well as one or more SS
|
|
* (Slave Select) pins, that are used for the master to signal to the slave
|
|
* device that it is the desired respondent for the transmission.<br/>
|
|
* <br/>
|
|
* The "master" device initiates a transfer by pulling the SS pin of the "slave"
|
|
* low, and begins outputting a clock signal. In SPI, both the "master" as well
|
|
* as the "slave" device output data at the same time. It is hence not possible
|
|
* to read data without writing some (even if it means outputting zeros or other
|
|
* dummy data).</br>
|
|
* </br>
|
|
* There are multiple possible configuration settings for SPI, see
|
|
* <a href="SPI_settings_.html">settings()</a> for details.</br>
|
|
* <br/>
|
|
* This library supports multiple SPI objects making use of the same SPI
|
|
* interface.
|
|
*
|
|
* @webref
|
|
* @webBrief Opens an SPI interface as master
|
|
*/
|
|
public class SPI {
|
|
|
|
/**
|
|
* CPOL=0, CPHA=0, most common
|
|
*/
|
|
public static final int MODE0 = 0;
|
|
/**
|
|
* CPOL=0, CPHA=1
|
|
*/
|
|
public static final int MODE1 = 1;
|
|
/**
|
|
* CPOL=1, CPHA=0
|
|
*/
|
|
public static final int MODE2 = 2;
|
|
/**
|
|
* CPOL=1, CPHA=1
|
|
*/
|
|
public static final int MODE3 = 3;
|
|
/**
|
|
* most significant bit first, most common
|
|
*/
|
|
public static final int MSBFIRST = 0;
|
|
/**
|
|
* least significant bit first
|
|
*/
|
|
public static final int LSBFIRST = 1;
|
|
|
|
protected int dataOrder = 0;
|
|
protected String dev;
|
|
protected int handle;
|
|
protected int maxSpeed = 500000;
|
|
protected int mode = 0;
|
|
protected static Map<String, String> settings = new HashMap<String, String>();
|
|
|
|
|
|
/**
|
|
* Opens an SPI interface as master
|
|
* @param dev device name
|
|
* @see list
|
|
* @webref
|
|
* @webBrief Opens an SPI interface as master
|
|
*/
|
|
public SPI(String dev) {
|
|
NativeInterface.loadLibrary();
|
|
this.dev = dev;
|
|
|
|
if (NativeInterface.isSimulated()) {
|
|
return;
|
|
}
|
|
|
|
handle = NativeInterface.openDevice("/dev/" + dev);
|
|
if (handle < 0) {
|
|
throw new RuntimeException(NativeInterface.getError(handle));
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Closes the SPI interface</br>
|
|
* </br>
|
|
* It is normally not necessary to explicitly close SPI interfaces, as they are
|
|
* closed automatically by the operating system when the sketch exits.</br>
|
|
* </br>
|
|
* Note: It is possible to have two or more objects using the same interface at
|
|
* a time.
|
|
*
|
|
* @webref
|
|
* @webBrief Closes the SPI interface
|
|
*/
|
|
public void close() {
|
|
if (NativeInterface.isSimulated()) {
|
|
return;
|
|
}
|
|
|
|
NativeInterface.closeDevice(handle);
|
|
handle = 0;
|
|
}
|
|
|
|
|
|
protected void finalize() throws Throwable {
|
|
try {
|
|
close();
|
|
} finally {
|
|
super.finalize();
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Lists all available SPI interfaces
|
|
* @return String array
|
|
* @webref
|
|
* @webBrief Lists all available SPI interfaces
|
|
*/
|
|
public static String[] list() {
|
|
if (NativeInterface.isSimulated()) {
|
|
// as on the Raspberry Pi
|
|
return new String[]{ "spidev0.0", "spidev0.1" };
|
|
}
|
|
|
|
ArrayList<String> devs = new ArrayList<String>();
|
|
File dir = new File("/dev");
|
|
File[] files = dir.listFiles();
|
|
if (files != null) {
|
|
for (File file : files) {
|
|
if (file.getName().startsWith("spidev")) {
|
|
devs.add(file.getName());
|
|
}
|
|
}
|
|
}
|
|
// listFiles() does not guarantee ordering
|
|
String[] tmp = devs.toArray(new String[devs.size()]);
|
|
Arrays.sort(tmp);
|
|
return tmp;
|
|
}
|
|
|
|
|
|
/**
|
|
* Configures the SPI interface<br/>
|
|
* <br/>
|
|
* The default setting is: 500000, SPI.MSBFIRST, SPI.MODE0
|
|
*
|
|
* @param maxSpeed maximum transmission rate in Hz, 500000 (500 kHz) is a
|
|
* resonable default
|
|
* @param dataOrder whether data is send with the first- or least-significant
|
|
* bit first (SPI.MSBFIRST or SPI.LSBFIRST, the former is more
|
|
* common)
|
|
* @param mode <a href=
|
|
* "https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus#Clock_polarity_and_phase">SPI.MODE0
|
|
* to SPI.MODE3</a>
|
|
* @webref
|
|
* @webBrief Configures the SPI interface
|
|
*/
|
|
public void settings(int maxSpeed, int dataOrder, int mode) {
|
|
this.maxSpeed = maxSpeed;
|
|
this.dataOrder = dataOrder;
|
|
this.mode = mode;
|
|
}
|
|
|
|
|
|
/**
|
|
* Transfers data over the SPI bus<br/>
|
|
* <br/>
|
|
* With SPI, data is simultaneously being exchanged between the master device
|
|
* and the slave device. For every byte that is being sent out, there's also one
|
|
* byte being read in.
|
|
*
|
|
* @param out bytes to send
|
|
* @return bytes read in (array is the same length as out)
|
|
* @webref Transfers data over the SPI bus
|
|
*/
|
|
public byte[] transfer(byte[] out) {
|
|
if (NativeInterface.isSimulated()) {
|
|
return new byte[out.length];
|
|
}
|
|
|
|
// track the current setting per device across multiple instances
|
|
String curSettings = maxSpeed + "-" + dataOrder + "-" + mode;
|
|
if (!curSettings.equals(settings.get(dev))) {
|
|
int ret = NativeInterface.setSpiSettings(handle, maxSpeed, dataOrder, mode);
|
|
if (ret < 0) {
|
|
System.err.println(NativeInterface.getError(handle));
|
|
throw new RuntimeException("Error updating device configuration");
|
|
}
|
|
settings.put(dev, curSettings);
|
|
}
|
|
|
|
byte[] in = new byte[out.length];
|
|
int transferred = NativeInterface.transferSpi(handle, out, in);
|
|
if (transferred < 0) {
|
|
throw new RuntimeException(NativeInterface.getError(transferred));
|
|
} else if (transferred < out.length) {
|
|
throw new RuntimeException("Fewer bytes transferred than requested: " + transferred);
|
|
}
|
|
return in;
|
|
}
|
|
|
|
|
|
/**
|
|
* Transfers data over the SPI bus
|
|
* @param out string to send
|
|
* @return bytes read in (array is the same length as out)
|
|
*/
|
|
public byte[] transfer(String out) {
|
|
return transfer(out.getBytes());
|
|
}
|
|
|
|
|
|
/**
|
|
* Transfers data over the SPI bus
|
|
* @param out single byte to send, e.g. numeric literal (0 to 255, or -128 to 127)
|
|
* @return bytes read in (array is the same length as out)
|
|
*/
|
|
public byte[] transfer(int out) {
|
|
if (out < -128 || 255 < out) {
|
|
System.err.println("The transfer function can only operate on a single byte at a time. Call it with a value from 0 to 255, or -128 to 127.");
|
|
throw new RuntimeException("Argument does not fit into a single byte");
|
|
}
|
|
byte[] tmp = new byte[1];
|
|
tmp[0] = (byte)out;
|
|
return transfer(tmp);
|
|
}
|
|
|
|
|
|
/**
|
|
* Transfers data over the SPI bus
|
|
* @param out single byte to send
|
|
* @return bytes read in (array is the same length as out)
|
|
*/
|
|
public byte[] transfer(byte out) {
|
|
// cast to (unsigned) int
|
|
return transfer(out & 0xff);
|
|
}
|
|
}
|