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.CANData;
009import edu.wpi.first.hal.FRCNetComm.tResourceType;
010import edu.wpi.first.hal.HAL;
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  public static final int kTeamManufacturer = 8;
025  public static final int kTeamDeviceType = 10;
026
027  private final int m_handle;
028
029  /**
030   * Create a new CAN communication interface with the specific device ID. This uses the team
031   * manufacturer and device types. The device ID is 6 bits (0-63).
032   *
033   * @param deviceId The device id
034   */
035  public CAN(int deviceId) {
036    m_handle = CANAPIJNI.initializeCAN(kTeamManufacturer, deviceId, kTeamDeviceType);
037    HAL.report(tResourceType.kResourceType_CAN, deviceId + 1);
038  }
039
040  /**
041   * Create a new CAN communication interface with a specific device ID, manufacturer and device
042   * type. The device ID is 6 bits, the manufacturer is 8 bits, and the device type is 5 bits.
043   *
044   * @param deviceId The device ID
045   * @param deviceManufacturer The device manufacturer
046   * @param deviceType The device type
047   */
048  public CAN(int deviceId, int deviceManufacturer, int deviceType) {
049    m_handle = CANAPIJNI.initializeCAN(deviceManufacturer, deviceId, deviceType);
050    HAL.report(tResourceType.kResourceType_CAN, deviceId + 1);
051  }
052
053  /** Closes the CAN communication. */
054  @Override
055  public void close() {
056    if (m_handle != 0) {
057      CANAPIJNI.cleanCAN(m_handle);
058    }
059  }
060
061  /**
062   * Write a packet to the CAN device with a specific ID. This ID is 10 bits.
063   *
064   * @param data The data to write (8 bytes max)
065   * @param apiId The API ID to write.
066   */
067  public void writePacket(byte[] data, int apiId) {
068    CANAPIJNI.writeCANPacket(m_handle, data, apiId);
069  }
070
071  /**
072   * Write a repeating packet to the CAN device with a specific ID. This ID is 10 bits. The RoboRIO
073   * will automatically repeat the packet at the specified interval
074   *
075   * @param data The data to write (8 bytes max)
076   * @param apiId The API ID to write.
077   * @param repeatMs The period to repeat the packet at.
078   */
079  public void writePacketRepeating(byte[] data, int apiId, int repeatMs) {
080    CANAPIJNI.writeCANPacketRepeating(m_handle, data, apiId, repeatMs);
081  }
082
083  /**
084   * Write an RTR frame to the CAN device with a specific ID. This ID is 10 bits. The length by spec
085   * must match what is returned by the responding device
086   *
087   * @param length The length to request (0 to 8)
088   * @param apiId The API ID to write.
089   */
090  public void writeRTRFrame(int length, int apiId) {
091    CANAPIJNI.writeCANRTRFrame(m_handle, length, apiId);
092  }
093
094  /**
095   * Write a packet to the CAN device with a specific ID. This ID is 10 bits.
096   *
097   * @param data The data to write (8 bytes max)
098   * @param apiId The API ID to write.
099   * @return TODO
100   */
101  public int writePacketNoThrow(byte[] data, int apiId) {
102    return CANAPIJNI.writeCANPacketNoThrow(m_handle, data, apiId);
103  }
104
105  /**
106   * Write a repeating packet to the CAN device with a specific ID. This ID is 10 bits. The RoboRIO
107   * will automatically repeat the packet at the specified interval
108   *
109   * @param data The data to write (8 bytes max)
110   * @param apiId The API ID to write.
111   * @param repeatMs The period to repeat the packet at.
112   * @return TODO
113   */
114  public int writePacketRepeatingNoThrow(byte[] data, int apiId, int repeatMs) {
115    return CANAPIJNI.writeCANPacketRepeatingNoThrow(m_handle, data, apiId, repeatMs);
116  }
117
118  /**
119   * Write an RTR frame to the CAN device with a specific ID. This ID is 10 bits. The length by spec
120   * must match what is returned by the responding device
121   *
122   * @param length The length to request (0 to 8)
123   * @param apiId The API ID to write.
124   * @return TODO
125   */
126  public int writeRTRFrameNoThrow(int length, int apiId) {
127    return CANAPIJNI.writeCANRTRFrameNoThrow(m_handle, length, apiId);
128  }
129
130  /**
131   * Stop a repeating packet with a specific ID. This ID is 10 bits.
132   *
133   * @param apiId The API ID to stop repeating
134   */
135  public void stopPacketRepeating(int apiId) {
136    CANAPIJNI.stopCANPacketRepeating(m_handle, apiId);
137  }
138
139  /**
140   * Read a new CAN packet. This will only return properly once per packet received. Multiple calls
141   * without receiving another packet will return false.
142   *
143   * @param apiId The API ID to read.
144   * @param data Storage for the received data.
145   * @return True if the data is valid, otherwise false.
146   */
147  public boolean readPacketNew(int apiId, CANData data) {
148    return CANAPIJNI.readCANPacketNew(m_handle, apiId, data);
149  }
150
151  /**
152   * Read a CAN packet. This will continuously return the last packet received, without accounting
153   * for packet age.
154   *
155   * @param apiId The API ID to read.
156   * @param data Storage for the received data.
157   * @return True if the data is valid, otherwise false.
158   */
159  public boolean readPacketLatest(int apiId, CANData data) {
160    return CANAPIJNI.readCANPacketLatest(m_handle, apiId, data);
161  }
162
163  /**
164   * Read a CAN packet. This will return the last packet received until the packet is older than the
165   * requested timeout. Then it will return false.
166   *
167   * @param apiId The API ID to read.
168   * @param timeoutMs The timeout time for the packet
169   * @param data Storage for the received data.
170   * @return True if the data is valid, otherwise false.
171   */
172  public boolean readPacketTimeout(int apiId, int timeoutMs, CANData data) {
173    return CANAPIJNI.readCANPacketTimeout(m_handle, apiId, timeoutMs, data);
174  }
175
176  /**
177   * Reads the current value of the millisecond-resolution timer that {@link CANData} timestamps are
178   * based on.
179   *
180   * @return Current value of timer used as a base time for {@link CANData} timestamps in
181   *     milliseconds
182   */
183  public static long getTimestampBaseTime() {
184    return CANAPIJNI.getCANPacketBaseTime();
185  }
186}