[hal, wpilib] Rewrite CAN APIs (#7798)

This commit is contained in:
Thad House
2025-02-25 19:07:01 -08:00
committed by GitHub
parent b39744b562
commit baa20fa239
107 changed files with 1447 additions and 1379 deletions

View File

@@ -6,8 +6,8 @@ package edu.wpi.first.wpilibj;
import edu.wpi.first.hal.CANAPIJNI;
import edu.wpi.first.hal.CANAPITypes;
import edu.wpi.first.hal.CANData;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.hal.can.CANReceiveMessage;
import java.io.Closeable;
/**
@@ -33,22 +33,24 @@ public class CAN implements Closeable {
* Create a new CAN communication interface with the specific device ID. This uses the team
* manufacturer and device types. The device ID is 6 bits (0-63).
*
* @param busId The bus ID
* @param deviceId The device id
*/
public CAN(int deviceId) {
this(kTeamManufacturer, deviceId, kTeamDeviceType);
public CAN(int busId, int deviceId) {
this(busId, deviceId, kTeamManufacturer, kTeamDeviceType);
}
/**
* Create a new CAN communication interface with a specific device ID, manufacturer and device
* type. The device ID is 6 bits, the manufacturer is 8 bits, and the device type is 5 bits.
*
* @param busId The bus ID
* @param deviceId The device ID
* @param deviceManufacturer The device manufacturer
* @param deviceType The device type
*/
public CAN(int deviceId, int deviceManufacturer, int deviceType) {
m_handle = CANAPIJNI.initializeCAN(deviceManufacturer, deviceId, deviceType);
public CAN(int busId, int deviceId, int deviceManufacturer, int deviceType) {
m_handle = CANAPIJNI.initializeCAN(busId, deviceManufacturer, deviceId, deviceType);
HAL.reportUsage("CAN[" + deviceType + "][" + deviceManufacturer + "][" + deviceId + "]", "");
}
@@ -63,70 +65,85 @@ public class CAN implements Closeable {
/**
* Write a packet to the CAN device with a specific ID. This ID is 10 bits.
*
* @param data The data to write (8 bytes max)
* @param apiId The API ID to write.
* @param data The data to write
* @param dataLength The data length
* @param flags The flags
*/
public void writePacket(byte[] data, int apiId) {
CANAPIJNI.writeCANPacket(m_handle, data, apiId);
public void writePacket(int apiId, byte[] data, int dataLength, int flags) {
CANAPIJNI.writeCANPacket(m_handle, apiId, data, dataLength, flags);
}
/**
* Write a repeating packet to the CAN device with a specific ID. This ID is 10 bits. The RoboRIO
* will automatically repeat the packet at the specified interval
*
* @param data The data to write (8 bytes max)
* @param apiId The API ID to write.
* @param data The data to write
* @param dataLength The data length
* @param flags The flags
* @param repeatMs The period to repeat the packet at.
*/
public void writePacketRepeating(byte[] data, int apiId, int repeatMs) {
CANAPIJNI.writeCANPacketRepeating(m_handle, data, apiId, repeatMs);
public void writePacketRepeating(
int apiId, byte[] data, int dataLength, int flags, int repeatMs) {
CANAPIJNI.writeCANPacketRepeating(m_handle, apiId, data, dataLength, flags, repeatMs);
}
/**
* Write an RTR frame to the CAN device with a specific ID. This ID is 10 bits. The length by spec
* must match what is returned by the responding device
*
* @param length The length to request (0 to 8)
* @param apiId The API ID to write.
* @param data The data to write
* @param dataLength The data length
* @param flags The flags
*/
public void writeRTRFrame(int length, int apiId) {
CANAPIJNI.writeCANRTRFrame(m_handle, length, apiId);
public void writeRTRFrame(int apiId, byte[] data, int dataLength, int flags) {
CANAPIJNI.writeCANRTRFrame(m_handle, apiId, data, dataLength, flags);
}
/**
* Write a packet to the CAN device with a specific ID. This ID is 10 bits.
*
* @param data The data to write (8 bytes max)
* @param apiId The API ID to write.
* @param data The data to write
* @param dataLength The data length
* @param flags The flags
* @return TODO
*/
public int writePacketNoThrow(byte[] data, int apiId) {
return CANAPIJNI.writeCANPacketNoThrow(m_handle, data, apiId);
public int writePacketNoThrow(int apiId, byte[] data, int dataLength, int flags) {
return CANAPIJNI.writeCANPacketNoThrow(m_handle, apiId, data, dataLength, flags);
}
/**
* Write a repeating packet to the CAN device with a specific ID. This ID is 10 bits. The RoboRIO
* will automatically repeat the packet at the specified interval
*
* @param data The data to write (8 bytes max)
* @param apiId The API ID to write.
* @param data The data to write
* @param dataLength The data length
* @param flags The flags
* @param repeatMs The period to repeat the packet at.
* @return TODO
*/
public int writePacketRepeatingNoThrow(byte[] data, int apiId, int repeatMs) {
return CANAPIJNI.writeCANPacketRepeatingNoThrow(m_handle, data, apiId, repeatMs);
public int writePacketRepeatingNoThrow(
int apiId, byte[] data, int dataLength, int flags, int repeatMs) {
return CANAPIJNI.writeCANPacketRepeatingNoThrow(
m_handle, apiId, data, dataLength, flags, repeatMs);
}
/**
* Write an RTR frame to the CAN device with a specific ID. This ID is 10 bits. The length by spec
* must match what is returned by the responding device
*
* @param length The length to request (0 to 8)
* @param apiId The API ID to write.
* @param data The data to write
* @param dataLength The data length
* @param flags The flags
* @return TODO
*/
public int writeRTRFrameNoThrow(int length, int apiId) {
return CANAPIJNI.writeCANRTRFrameNoThrow(m_handle, length, apiId);
public int writeRTRFrameNoThrow(int apiId, byte[] data, int dataLength, int flags) {
return CANAPIJNI.writeCANRTRFrameNoThrow(m_handle, apiId, data, dataLength, flags);
}
/**
@@ -146,7 +163,7 @@ public class CAN implements Closeable {
* @param data Storage for the received data.
* @return True if the data is valid, otherwise false.
*/
public boolean readPacketNew(int apiId, CANData data) {
public boolean readPacketNew(int apiId, CANReceiveMessage data) {
return CANAPIJNI.readCANPacketNew(m_handle, apiId, data);
}
@@ -158,7 +175,7 @@ public class CAN implements Closeable {
* @param data Storage for the received data.
* @return True if the data is valid, otherwise false.
*/
public boolean readPacketLatest(int apiId, CANData data) {
public boolean readPacketLatest(int apiId, CANReceiveMessage data) {
return CANAPIJNI.readCANPacketLatest(m_handle, apiId, data);
}
@@ -171,18 +188,7 @@ public class CAN implements Closeable {
* @param data Storage for the received data.
* @return True if the data is valid, otherwise false.
*/
public boolean readPacketTimeout(int apiId, int timeoutMs, CANData data) {
return CANAPIJNI.readCANPacketTimeout(m_handle, apiId, timeoutMs, data);
}
/**
* Reads the current value of the millisecond-resolution timer that {@link CANData} timestamps are
* based on.
*
* @return Current value of timer used as a base time for {@link CANData} timestamps in
* milliseconds
*/
public static long getTimestampBaseTime() {
return CANAPIJNI.getCANPacketBaseTime();
public boolean readPacketTimeout(int apiId, CANReceiveMessage data, int timeoutMs) {
return CANAPIJNI.readCANPacketTimeout(m_handle, apiId, data, timeoutMs);
}
}

View File

@@ -27,12 +27,13 @@ public class Compressor implements Sendable, AutoCloseable {
/**
* Constructs a compressor for a specified module and type.
*
* @param busId The bus ID
* @param module The module ID to use.
* @param moduleType The module type to use.
*/
@SuppressWarnings("this-escape")
public Compressor(int module, PneumaticsModuleType moduleType) {
m_module = PneumaticsBase.getForType(module, moduleType);
public Compressor(int busId, int module, PneumaticsModuleType moduleType) {
m_module = PneumaticsBase.getForType(busId, module, moduleType);
m_moduleType = moduleType;
if (!m_module.reserveCompressor()) {
@@ -49,10 +50,11 @@ public class Compressor implements Sendable, AutoCloseable {
/**
* Constructs a compressor for a default module and specified type.
*
* @param busId The bus ID
* @param moduleType The module type to use.
*/
public Compressor(PneumaticsModuleType moduleType) {
this(PneumaticsBase.getDefaultForType(moduleType), moduleType);
public Compressor(int busId, PneumaticsModuleType moduleType) {
this(busId, PneumaticsBase.getDefaultForType(moduleType), moduleType);
}
@Override

View File

@@ -37,18 +37,28 @@ public class DoubleSolenoid implements Sendable, AutoCloseable {
/**
* Constructs a double solenoid for a default module of a specific module type.
*
* @param busId The bus ID
* @param moduleType The module type to use.
* @param forwardChannel The forward channel on the module to control.
* @param reverseChannel The reverse channel on the module to control.
*/
public DoubleSolenoid(
final PneumaticsModuleType moduleType, final int forwardChannel, final int reverseChannel) {
this(PneumaticsBase.getDefaultForType(moduleType), moduleType, forwardChannel, reverseChannel);
final int busId,
final PneumaticsModuleType moduleType,
final int forwardChannel,
final int reverseChannel) {
this(
busId,
PneumaticsBase.getDefaultForType(moduleType),
moduleType,
forwardChannel,
reverseChannel);
}
/**
* Constructs a double solenoid for a specified module of a specific module type.
*
* @param busId The bus ID
* @param module The module of the solenoid module to use.
* @param moduleType The module type to use.
* @param forwardChannel The forward channel on the module to control.
@@ -56,11 +66,12 @@ public class DoubleSolenoid implements Sendable, AutoCloseable {
*/
@SuppressWarnings({"PMD.UseTryWithResources", "this-escape"})
public DoubleSolenoid(
final int busId,
final int module,
final PneumaticsModuleType moduleType,
final int forwardChannel,
final int reverseChannel) {
m_module = PneumaticsBase.getForType(module, moduleType);
m_module = PneumaticsBase.getForType(busId, module, moduleType);
boolean allocatedSolenoids = false;
boolean successfulCompletion = false;

View File

@@ -23,16 +23,18 @@ public class PneumaticHub implements PneumaticsBase {
private static class DataStore implements AutoCloseable {
public final int m_module;
public final int m_handle;
private final int m_busId;
private int m_refCount;
private int m_reservedMask;
private boolean m_compressorReserved;
public final int[] m_oneShotDurMs = new int[PortsJNI.getNumREVPHChannels()];
private final Object m_reserveLock = new Object();
DataStore(int module) {
m_handle = REVPHJNI.initialize(module);
DataStore(int busId, int module) {
m_handle = REVPHJNI.initialize(busId, module);
m_module = module;
m_handleMap.put(module, this);
m_busId = busId;
m_handleMaps[busId].put(module, this);
final REVPHVersion version = REVPHJNI.getVersion(m_handle);
final String fwVersion =
@@ -77,7 +79,7 @@ public class PneumaticHub implements PneumaticsBase {
@Override
public void close() {
REVPHJNI.free(m_handle);
m_handleMap.remove(m_module);
m_handleMaps[m_busId].remove(m_module);
}
public void addRef() {
@@ -92,14 +94,23 @@ public class PneumaticHub implements PneumaticsBase {
}
}
private static final Map<Integer, DataStore> m_handleMap = new HashMap<>();
@SuppressWarnings({"unchecked", "rawtypes"})
private static final Map<Integer, DataStore>[] m_handleMaps =
(Map<Integer, DataStore>[]) new Map[PortsJNI.getNumCanBuses()];
private static final Object m_handleLock = new Object();
private static DataStore getForModule(int module) {
private static DataStore getForModule(int busId, int module) {
synchronized (m_handleLock) {
DataStore pcm = m_handleMap.get(module);
Map<Integer, DataStore> handleMap = m_handleMaps[busId];
if (handleMap == null) {
handleMap = new HashMap<>();
m_handleMaps[busId] = handleMap;
}
DataStore pcm = handleMap.get(module);
if (pcm == null) {
pcm = new DataStore(module);
pcm = new DataStore(busId, module);
}
pcm.addRef();
return pcm;
@@ -125,18 +136,23 @@ public class PneumaticHub implements PneumaticsBase {
private final DataStore m_dataStore;
private final int m_handle;
/** Constructs a PneumaticHub with the default ID (1). */
public PneumaticHub() {
this(SensorUtil.getDefaultREVPHModule());
/**
* Constructs a PneumaticHub with the default ID (1).
*
* @param busId The bus ID
*/
public PneumaticHub(int busId) {
this(busId, SensorUtil.getDefaultREVPHModule());
}
/**
* Constructs a PneumaticHub.
*
* @param busId The bus ID
* @param module module number to construct
*/
public PneumaticHub(int module) {
m_dataStore = getForModule(module);
public PneumaticHub(int busId, int module) {
m_dataStore = getForModule(busId, module);
m_handle = m_dataStore.m_handle;
}

View File

@@ -9,14 +9,15 @@ public interface PneumaticsBase extends AutoCloseable {
/**
* For internal use to get a module for a specific type.
*
* @param busId The bus ID
* @param module module number
* @param type module type
* @return module
*/
static PneumaticsBase getForType(int module, PneumaticsModuleType type) {
static PneumaticsBase getForType(int busId, int module, PneumaticsModuleType type) {
return switch (type) {
case CTREPCM -> new PneumaticsControlModule(module);
case REVPH -> new PneumaticHub(module);
case CTREPCM -> new PneumaticsControlModule(busId, module);
case REVPH -> new PneumaticHub(busId, module);
};
}

View File

@@ -6,6 +6,7 @@ package edu.wpi.first.wpilibj;
import edu.wpi.first.hal.CTREPCMJNI;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.hal.PortsJNI;
import java.util.HashMap;
import java.util.Map;
@@ -14,21 +15,23 @@ public class PneumaticsControlModule implements PneumaticsBase {
private static class DataStore implements AutoCloseable {
public final int m_module;
public final int m_handle;
private final int m_busId;
private int m_refCount;
private int m_reservedMask;
private boolean m_compressorReserved;
private final Object m_reserveLock = new Object();
DataStore(int module) {
m_handle = CTREPCMJNI.initialize(module);
DataStore(int busId, int module) {
m_handle = CTREPCMJNI.initialize(busId, module);
m_module = module;
m_handleMap.put(module, this);
m_busId = busId;
m_handleMaps[busId].put(module, this);
}
@Override
public void close() {
CTREPCMJNI.free(m_handle);
m_handleMap.remove(m_module);
m_handleMaps[m_busId].remove(m_module);
}
public void addRef() {
@@ -43,14 +46,23 @@ public class PneumaticsControlModule implements PneumaticsBase {
}
}
private static final Map<Integer, DataStore> m_handleMap = new HashMap<>();
@SuppressWarnings({"unchecked", "rawtypes"})
private static final Map<Integer, DataStore>[] m_handleMaps =
(Map<Integer, DataStore>[]) new Map[PortsJNI.getNumCanBuses()];
private static final Object m_handleLock = new Object();
private static DataStore getForModule(int module) {
private static DataStore getForModule(int busId, int module) {
synchronized (m_handleLock) {
DataStore pcm = m_handleMap.get(module);
Map<Integer, DataStore> handleMap = m_handleMaps[busId];
if (handleMap == null) {
handleMap = new HashMap<>();
m_handleMaps[busId] = handleMap;
}
DataStore pcm = handleMap.get(module);
if (pcm == null) {
pcm = new DataStore(module);
pcm = new DataStore(busId, module);
}
pcm.addRef();
return pcm;
@@ -66,18 +78,23 @@ public class PneumaticsControlModule implements PneumaticsBase {
private final DataStore m_dataStore;
private final int m_handle;
/** Constructs a PneumaticsControlModule with the default ID (0). */
public PneumaticsControlModule() {
this(SensorUtil.getDefaultCTREPCMModule());
/**
* Constructs a PneumaticsControlModule with the default ID (0).
*
* @param busId The bus ID
*/
public PneumaticsControlModule(int busId) {
this(busId, SensorUtil.getDefaultCTREPCMModule());
}
/**
* Constructs a PneumaticsControlModule.
*
* @param busId The bus ID
* @param module module number to construct
*/
public PneumaticsControlModule(int module) {
m_dataStore = getForModule(module);
public PneumaticsControlModule(int busId, int module) {
m_dataStore = getForModule(busId, module);
m_handle = m_dataStore.m_handle;
}

View File

@@ -42,12 +42,13 @@ public class PowerDistribution implements Sendable, AutoCloseable {
/**
* Constructs a PowerDistribution object.
*
* @param busId The bus ID
* @param module The CAN ID of the PDP/PDH.
* @param moduleType Module type (CTRE or REV).
*/
@SuppressWarnings("this-escape")
public PowerDistribution(int module, ModuleType moduleType) {
m_handle = PowerDistributionJNI.initialize(module, moduleType.value);
public PowerDistribution(int busId, int module, ModuleType moduleType) {
m_handle = PowerDistributionJNI.initialize(busId, module, moduleType.value);
m_module = PowerDistributionJNI.getModuleNumber(m_handle);
if (moduleType == ModuleType.kCTRE) {
@@ -62,10 +63,13 @@ public class PowerDistribution implements Sendable, AutoCloseable {
* Constructs a PowerDistribution object.
*
* <p>Detects the connected PDP/PDH using the default CAN ID (0 for CTRE and 1 for REV).
*
* @param busId The bus ID
*/
@SuppressWarnings("this-escape")
public PowerDistribution() {
m_handle = PowerDistributionJNI.initialize(kDefaultModule, PowerDistributionJNI.AUTOMATIC_TYPE);
public PowerDistribution(int busId) {
m_handle =
PowerDistributionJNI.initialize(busId, kDefaultModule, PowerDistributionJNI.AUTOMATIC_TYPE);
m_module = PowerDistributionJNI.getModuleNumber(m_handle);
if (PowerDistributionJNI.getType(m_handle) == PowerDistributionJNI.CTRE_TYPE) {

View File

@@ -556,11 +556,12 @@ public final class RobotController {
/**
* Get the current status of the CAN bus.
*
* @param busId The bus ID
* @return The status of the CAN bus
*/
public static CANStatus getCANStatus() {
public static CANStatus getCANStatus(int busId) {
CANStatus status = new CANStatus();
CANJNI.getCANStatus(status);
CANJNI.getCANStatus(busId, status);
return status;
}
}

View File

@@ -23,23 +23,26 @@ public class Solenoid implements Sendable, AutoCloseable {
/**
* Constructs a solenoid for a default module and specified type.
*
* @param busId The bus ID
* @param moduleType The module type to use.
* @param channel The channel the solenoid is on.
*/
public Solenoid(final PneumaticsModuleType moduleType, final int channel) {
this(PneumaticsBase.getDefaultForType(moduleType), moduleType, channel);
public Solenoid(final int busId, final PneumaticsModuleType moduleType, final int channel) {
this(busId, PneumaticsBase.getDefaultForType(moduleType), moduleType, channel);
}
/**
* Constructs a solenoid for a specified module and type.
*
* @param busId The bus ID
* @param module The module ID to use.
* @param moduleType The module type to use.
* @param channel The channel the solenoid is on.
*/
@SuppressWarnings("this-escape")
public Solenoid(final int module, final PneumaticsModuleType moduleType, final int channel) {
m_module = PneumaticsBase.getForType(module, moduleType);
public Solenoid(
final int busId, final int module, final PneumaticsModuleType moduleType, final int channel) {
m_module = PneumaticsBase.getForType(busId, module, moduleType);
m_mask = 1 << channel;
m_channel = channel;