001// Copyright (c) FIRST and other WPILib contributors.
002// Open Source Software; you can modify and/or share it under the terms of
003// the WPILib BSD license file in the root directory of this project.
004
005package edu.wpi.first.wpilibj;
006
007import edu.wpi.first.hal.CANAPIJNI;
008import edu.wpi.first.hal.CANAPITypes;
009import edu.wpi.first.hal.HAL;
010import edu.wpi.first.hal.can.CANReceiveMessage;
011import java.io.Closeable;
012
013/**
014 * High level class for interfacing with CAN devices conforming to the standard CAN spec.
015 *
016 * <p>No packets that can be sent gets blocked by the RoboRIO, so all methods work identically in
017 * all robot modes.
018 *
019 * <p>All methods are thread safe, however the CANData object passed into the read methods and the
020 * byte[] passed into the write methods need to not be modified for the duration of their respective
021 * calls.
022 */
023public class CAN implements Closeable {
024  /** Team manufacturer. */
025  public static final int kTeamManufacturer = CANAPITypes.CANManufacturer.kTeamUse.id;
026
027  /** Team device type. */
028  public static final int kTeamDeviceType = CANAPITypes.CANDeviceType.kMiscellaneous.id;
029
030  private final int m_handle;
031
032  /**
033   * Create a new CAN communication interface with the specific device ID. This uses the team
034   * manufacturer and device types. The device ID is 6 bits (0-63).
035   *
036   * @param busId The bus ID
037   * @param deviceId The device id
038   */
039  public CAN(int busId, int deviceId) {
040    this(busId, deviceId, kTeamManufacturer, kTeamDeviceType);
041  }
042
043  /**
044   * Create a new CAN communication interface with a specific device ID, manufacturer and device
045   * type. The device ID is 6 bits, the manufacturer is 8 bits, and the device type is 5 bits.
046   *
047   * @param busId The bus ID
048   * @param deviceId The device ID
049   * @param deviceManufacturer The device manufacturer
050   * @param deviceType The device type
051   */
052  public CAN(int busId, int deviceId, int deviceManufacturer, int deviceType) {
053    m_handle = CANAPIJNI.initializeCAN(busId, deviceManufacturer, deviceId, deviceType);
054    HAL.reportUsage("CAN[" + deviceType + "][" + deviceManufacturer + "][" + deviceId + "]", "");
055  }
056
057  /** Closes the CAN communication. */
058  @Override
059  public void close() {
060    if (m_handle != 0) {
061      CANAPIJNI.cleanCAN(m_handle);
062    }
063  }
064
065  /**
066   * Write a packet to the CAN device with a specific ID. This ID is 10 bits.
067   *
068   * @param apiId The API ID to write.
069   * @param data The data to write
070   * @param dataLength The data length
071   * @param flags The flags
072   */
073  public void writePacket(int apiId, byte[] data, int dataLength, int flags) {
074    CANAPIJNI.writeCANPacket(m_handle, apiId, data, dataLength, flags);
075  }
076
077  /**
078   * Write a repeating packet to the CAN device with a specific ID. This ID is 10 bits. The RoboRIO
079   * will automatically repeat the packet at the specified interval
080   *
081   * @param apiId The API ID to write.
082   * @param data The data to write
083   * @param dataLength The data length
084   * @param flags The flags
085   * @param repeatMs The period to repeat the packet at.
086   */
087  public void writePacketRepeating(
088      int apiId, byte[] data, int dataLength, int flags, int repeatMs) {
089    CANAPIJNI.writeCANPacketRepeating(m_handle, apiId, data, dataLength, flags, repeatMs);
090  }
091
092  /**
093   * Write an RTR frame to the CAN device with a specific ID. This ID is 10 bits. The length by spec
094   * must match what is returned by the responding device
095   *
096   * @param apiId The API ID to write.
097   * @param data The data to write
098   * @param dataLength The data length
099   * @param flags The flags
100   */
101  public void writeRTRFrame(int apiId, byte[] data, int dataLength, int flags) {
102    CANAPIJNI.writeCANRTRFrame(m_handle, apiId, data, dataLength, flags);
103  }
104
105  /**
106   * Write a packet to the CAN device with a specific ID. This ID is 10 bits.
107   *
108   * @param apiId The API ID to write.
109   * @param data The data to write
110   * @param dataLength The data length
111   * @param flags The flags
112   * @return TODO
113   */
114  public int writePacketNoThrow(int apiId, byte[] data, int dataLength, int flags) {
115    return CANAPIJNI.writeCANPacketNoThrow(m_handle, apiId, data, dataLength, flags);
116  }
117
118  /**
119   * Write a repeating packet to the CAN device with a specific ID. This ID is 10 bits. The RoboRIO
120   * will automatically repeat the packet at the specified interval
121   *
122   * @param apiId The API ID to write.
123   * @param data The data to write
124   * @param dataLength The data length
125   * @param flags The flags
126   * @param repeatMs The period to repeat the packet at.
127   * @return TODO
128   */
129  public int writePacketRepeatingNoThrow(
130      int apiId, byte[] data, int dataLength, int flags, int repeatMs) {
131    return CANAPIJNI.writeCANPacketRepeatingNoThrow(
132        m_handle, apiId, data, dataLength, flags, repeatMs);
133  }
134
135  /**
136   * Write an RTR frame to the CAN device with a specific ID. This ID is 10 bits. The length by spec
137   * must match what is returned by the responding device
138   *
139   * @param apiId The API ID to write.
140   * @param data The data to write
141   * @param dataLength The data length
142   * @param flags The flags
143   * @return TODO
144   */
145  public int writeRTRFrameNoThrow(int apiId, byte[] data, int dataLength, int flags) {
146    return CANAPIJNI.writeCANRTRFrameNoThrow(m_handle, apiId, data, dataLength, flags);
147  }
148
149  /**
150   * Stop a repeating packet with a specific ID. This ID is 10 bits.
151   *
152   * @param apiId The API ID to stop repeating
153   */
154  public void stopPacketRepeating(int apiId) {
155    CANAPIJNI.stopCANPacketRepeating(m_handle, apiId);
156  }
157
158  /**
159   * Read a new CAN packet. This will only return properly once per packet received. Multiple calls
160   * without receiving another packet will return false.
161   *
162   * @param apiId The API ID to read.
163   * @param data Storage for the received data.
164   * @return True if the data is valid, otherwise false.
165   */
166  public boolean readPacketNew(int apiId, CANReceiveMessage data) {
167    return CANAPIJNI.readCANPacketNew(m_handle, apiId, data);
168  }
169
170  /**
171   * Read a CAN packet. This will continuously return the last packet received, without accounting
172   * for packet age.
173   *
174   * @param apiId The API ID to read.
175   * @param data Storage for the received data.
176   * @return True if the data is valid, otherwise false.
177   */
178  public boolean readPacketLatest(int apiId, CANReceiveMessage data) {
179    return CANAPIJNI.readCANPacketLatest(m_handle, apiId, data);
180  }
181
182  /**
183   * Read a CAN packet. This will return the last packet received until the packet is older than the
184   * requested timeout. Then it will return false.
185   *
186   * @param apiId The API ID to read.
187   * @param timeoutMs The timeout time for the packet
188   * @param data Storage for the received data.
189   * @return True if the data is valid, otherwise false.
190   */
191  public boolean readPacketTimeout(int apiId, CANReceiveMessage data, int timeoutMs) {
192    return CANAPIJNI.readCANPacketTimeout(m_handle, apiId, data, timeoutMs);
193  }
194}