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