001package edu.wpi.first.wpilibj; 002 003import java.nio.ByteOrder; 004import java.nio.IntBuffer; 005import java.nio.ByteBuffer; 006 007import edu.wpi.first.wpilibj.communication.FRCNetworkCommunicationsLibrary.tResourceType; 008import edu.wpi.first.wpilibj.communication.UsageReporting; 009import edu.wpi.first.wpilibj.hal.HALLibrary; 010import edu.wpi.first.wpilibj.hal.HALUtil; 011import edu.wpi.first.wpilibj.hal.SPIJNI; 012 013/** 014 * 015 * Represents a SPI bus port 016 017 * @author koconnor 018 */ 019public class SPI extends SensorBase { 020 021 public enum Port { 022 kOnboardCS0(0), 023 kOnboardCS1(1), 024 kOnboardCS2(2), 025 kOnboardCS3(3), 026 kMXP(4); 027 028 private int value; 029 030 private Port(int value){ 031 this.value = value; 032 } 033 034 public int getValue(){ 035 return this.value; 036 } 037 }; 038 039 private static int devices = 0; 040 041 private byte m_port; 042 private int bitOrder; 043 private int clockPolarity; 044 private int dataOnTrailing; 045 046 /** 047 * Constructor 048 * 049 * @param port the physical SPI port 050 */ 051 public SPI(Port port) { 052 ByteBuffer status = ByteBuffer.allocateDirect(4); 053 status.order(ByteOrder.LITTLE_ENDIAN); 054 055 m_port = (byte)port.getValue(); 056 devices++; 057 058 SPIJNI.spiInitialize(m_port, status.asIntBuffer()); 059 HALUtil.checkStatus(status.asIntBuffer()); 060 061 UsageReporting.report(tResourceType.kResourceType_SPI, devices); 062 } 063 064 /** 065 * Free the resources used by this object 066 */ 067 public void free(){ 068 SPIJNI.spiClose(m_port); 069 } 070 071 /** 072 * Configure the rate of the generated clock signal. 073 * The default value is 500,000 Hz. 074 * The maximum value is 4,000,000 Hz. 075 * 076 * @param hz The clock rate in Hertz. 077 */ 078 public final void setClockRate(int hz) { 079 SPIJNI.spiSetSpeed(m_port, hz); 080 } 081 082 /** 083 * Configure the order that bits are sent and received on the wire 084 * to be most significant bit first. 085 */ 086 public final void setMSBFirst() { 087 this.bitOrder = 1; 088 SPIJNI.spiSetOpts(m_port, this.bitOrder, this.dataOnTrailing, this.clockPolarity); 089 } 090 091 /** 092 * Configure the order that bits are sent and received on the wire 093 * to be least significant bit first. 094 */ 095 public final void setLSBFirst() { 096 this.bitOrder = 0; 097 SPIJNI.spiSetOpts(m_port, this.bitOrder, this.dataOnTrailing, this.clockPolarity); 098 } 099 100 /** 101 * Configure the clock output line to be active low. 102 * This is sometimes called clock polarity high or clock idle high. 103 */ 104 public final void setClockActiveLow() { 105 this.clockPolarity = 1; 106 SPIJNI.spiSetOpts(m_port, this.bitOrder, this.dataOnTrailing, this.clockPolarity); 107 } 108 109 /** 110 * Configure the clock output line to be active high. 111 * This is sometimes called clock polarity low or clock idle low. 112 */ 113 public final void setClockActiveHigh() { 114 this.clockPolarity = 0; 115 SPIJNI.spiSetOpts(m_port, this.bitOrder, this.dataOnTrailing, this.clockPolarity); 116 } 117 118 /** 119 * Configure that the data is stable on the falling edge and the data 120 * changes on the rising edge. 121 */ 122 public final void setSampleDataOnFalling() { 123 this.dataOnTrailing = 1; 124 SPIJNI.spiSetOpts(m_port, this.bitOrder, this.dataOnTrailing, this.clockPolarity); 125 } 126 127 /** 128 * Configure that the data is stable on the rising edge and the data 129 * changes on the falling edge. 130 */ 131 public final void setSampleDataOnRising() { 132 this.dataOnTrailing = 0; 133 SPIJNI.spiSetOpts(m_port, this.bitOrder, this.dataOnTrailing, this.clockPolarity); 134 } 135 136 /** 137 * Configure the chip select line to be active high. 138 */ 139 public final void setChipSelectActiveHigh() { 140 ByteBuffer status = ByteBuffer.allocateDirect(4); 141 status.order(ByteOrder.LITTLE_ENDIAN); 142 143 SPIJNI.spiSetChipSelectActiveHigh(m_port, status.asIntBuffer()); 144 145 HALUtil.checkStatus(status.asIntBuffer()); 146 } 147 148 /** 149 * Configure the chip select line to be active low. 150 */ 151 public final void setChipSelectActiveLow() { 152 ByteBuffer status = ByteBuffer.allocateDirect(4); 153 status.order(ByteOrder.LITTLE_ENDIAN); 154 155 SPIJNI.spiSetChipSelectActiveLow(m_port, status.asIntBuffer()); 156 157 HALUtil.checkStatus(status.asIntBuffer()); 158 } 159 160 /** 161 * Write data to the slave device. Blocks until there is space in the 162 * output FIFO. 163 * 164 * If not running in output only mode, also saves the data received 165 * on the MISO input during the transfer into the receive FIFO. 166 */ 167 public int write(byte[] dataToSend, int size) { 168 int retVal = 0; 169 ByteBuffer dataToSendBuffer = ByteBuffer.allocateDirect(size); 170 dataToSendBuffer.put(dataToSend); 171 retVal = SPIJNI.spiWrite(m_port, dataToSendBuffer, (byte) size); 172 return retVal; 173 } 174 175 /** 176 * Read a word from the receive FIFO. 177 * 178 * Waits for the current transfer to complete if the receive FIFO is empty. 179 * 180 * If the receive FIFO is empty, there is no active transfer, and initiate 181 * is false, errors. 182 * 183 * @param initiate If true, this function pushes "0" into the 184 * transmit buffer and initiates a transfer. 185 * If false, this function assumes that data is 186 * already in the receive FIFO from a previous write. 187 */ 188 public int read(boolean initiate, byte[] dataReceived, int size) { 189 int retVal = 0; 190 ByteBuffer dataReceivedBuffer = ByteBuffer.allocateDirect(size); 191 ByteBuffer dataToSendBuffer = ByteBuffer.allocateDirect(size); 192 if(initiate) 193 retVal = SPIJNI.spiTransaction(m_port, dataToSendBuffer, dataReceivedBuffer, (byte) size); 194 else 195 retVal = SPIJNI.spiRead(m_port, dataReceivedBuffer, (byte) size); 196 dataReceivedBuffer.get(dataReceived); 197 return retVal; 198 } 199 200 /** 201 * Perform a simultaneous read/write transaction with the device 202 * 203 * @param dataToSend The data to be written out to the device 204 * @param dataReceived Buffer to receive data from the device 205 * @param size The length of the transaction, in bytes 206 */ 207 public int transaction(byte[] dataToSend, byte[] dataReceived, int size) { 208 int retVal = 0; 209 ByteBuffer dataToSendBuffer = ByteBuffer.allocateDirect(size); 210 dataToSendBuffer.put(dataToSend); 211 ByteBuffer dataReceivedBuffer = ByteBuffer.allocateDirect(size); 212 retVal = SPIJNI.spiTransaction(m_port, dataToSendBuffer, dataReceivedBuffer, (byte) size); 213 dataReceivedBuffer.get(dataReceived); 214 return retVal; 215 } 216}