[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

@@ -4,34 +4,28 @@
package edu.wpi.first.hal;
import edu.wpi.first.hal.can.CANReceiveMessage;
/**
* CAN API HAL JNI Functions.
*
* @see "hal/CANAPI.h"
*/
public class CANAPIJNI extends JNIWrapper {
/**
* Reads the current value of the millisecond-resolution timer that the CAN API functions use as a
* time base.
*
* @return Current value of timer used as a base time by the CAN API in milliseconds.
* @see "HAL_GetCANPacketBaseTime"
*/
public static native long getCANPacketBaseTime();
/**
* Initializes a CAN device.
*
* <p>These follow the FIRST standard CAN layout.
* https://docs.wpilib.org/en/stable/docs/software/can-devices/can-addressing.html
*
* @param busId the bus ID
* @param manufacturer the can manufacturer
* @param deviceId the device ID (0-63)
* @param deviceType the device type
* @return the created CAN handle
* @see "HAL_InitializeCAN"
*/
public static native int initializeCAN(int manufacturer, int deviceId, int deviceType);
public static native int initializeCAN(int busId, int manufacturer, int deviceId, int deviceType);
/**
* Frees a CAN device.
@@ -47,11 +41,14 @@ public class CANAPIJNI extends JNIWrapper {
* <p>This ID is 10 bits.
*
* @param handle the CAN handle
* @param data the data to write (0-8 bytes)
* @param apiId the ID to write (0-1023 bits)
* @param data the data to send.
* @param dataLength the length of data to send
* @param flags the message flags
* @see "HAL_WriteCANPacket"
*/
public static native void writeCANPacket(int handle, byte[] data, int apiId);
public static native void writeCANPacket(
int handle, int apiId, byte[] data, int dataLength, int flags);
/**
* Writes a repeating packet to the CAN device with a specific ID.
@@ -61,13 +58,15 @@ public class CANAPIJNI extends JNIWrapper {
* <p>The RoboRIO will automatically repeat the packet at the specified interval
*
* @param handle the CAN handle
* @param data the data to write (0-8 bytes)
* @param apiId the ID to write (0-1023)
* @param data the data to send.
* @param dataLength the length of data to send
* @param flags the message flags
* @param repeatMs the period to repeat in ms
* @see "HAL_WriteCANPacketRepeating"
*/
public static native void writeCANPacketRepeating(
int handle, byte[] data, int apiId, int repeatMs);
int handle, int apiId, byte[] data, int dataLength, int flags, int repeatMs);
/**
* Writes an RTR frame of the specified length to the CAN device with the specific ID.
@@ -76,11 +75,14 @@ public class CANAPIJNI extends JNIWrapper {
* is unspecified.
*
* @param handle the CAN handle
* @param length the length of data to request (0-8)
* @param apiId the ID to write (0-1023)
* @param data the data to send.
* @param dataLength the length of data to send
* @param flags the message flags
* @see "HAL_WriteCANRTRFrame"
*/
public static native void writeCANRTRFrame(int handle, int length, int apiId);
public static native void writeCANRTRFrame(
int handle, int apiId, byte[] data, int dataLength, int flags);
/**
* Writes a packet to the CAN device with a specific ID without throwing on error.
@@ -88,12 +90,15 @@ public class CANAPIJNI extends JNIWrapper {
* <p>This ID is 10 bits.
*
* @param handle the CAN handle
* @param data the data to write (0-8 bytes)
* @param apiId the ID to write (0-1023 bits)
* @param data the data to send.
* @param dataLength the length of data to send
* @param flags the message flags
* @return Error status variable. 0 on success.
* @see "HAL_WriteCANPacket"
*/
public static native int writeCANPacketNoThrow(int handle, byte[] data, int apiId);
public static native int writeCANPacketNoThrow(
int handle, int apiId, byte[] data, int dataLength, int flags);
/**
* Writes a repeating packet to the CAN device with a specific ID without throwing on error.
@@ -103,14 +108,16 @@ public class CANAPIJNI extends JNIWrapper {
* <p>The RoboRIO will automatically repeat the packet at the specified interval
*
* @param handle the CAN handle
* @param data the data to write (0-8 bytes)
* @param apiId the ID to write (0-1023)
* @param data the data to send.
* @param dataLength the length of data to send
* @param flags the message flags
* @param repeatMs the period to repeat in ms
* @return Error status variable. 0 on success.
* @see "HAL_WriteCANPacketRepeating"
*/
public static native int writeCANPacketRepeatingNoThrow(
int handle, byte[] data, int apiId, int repeatMs);
int handle, int apiId, byte[] data, int dataLength, int flags, int repeatMs);
/**
* Writes an RTR frame of the specified length to the CAN device with the specific ID without
@@ -119,13 +126,16 @@ public class CANAPIJNI extends JNIWrapper {
* <p>By spec, the length must be equal to the length sent by the other device, otherwise behavior
* is unspecified.
*
* @param handle the CAN handle
* @param length the length of data to request (0-8)
* @param handle the CAN handlee
* @param apiId the ID to write (0-1023)
* @param data the data to send.
* @param dataLength the length of data to send
* @param flags the message flags
* @return Error status variable. 0 on success.
* @see "HAL_WriteCANRTRFrame"
*/
public static native int writeCANRTRFrameNoThrow(int handle, int length, int apiId);
public static native int writeCANRTRFrameNoThrow(
int handle, int apiId, byte[] data, int dataLength, int flags);
/**
* Stops a repeating packet with a specific ID.
@@ -146,11 +156,11 @@ public class CANAPIJNI extends JNIWrapper {
*
* @param handle the CAN handle
* @param apiId the ID to read (0-1023)
* @param data the packet data (8 bytes)
* @param data the received message
* @return true on success, false on error
* @see "HAL_ReadCANPacketNew"
*/
public static native boolean readCANPacketNew(int handle, int apiId, CANData data);
public static native boolean readCANPacketNew(int handle, int apiId, CANReceiveMessage data);
/**
* Reads a CAN packet. The will continuously return the last packet received, without accounting
@@ -158,11 +168,11 @@ public class CANAPIJNI extends JNIWrapper {
*
* @param handle the CAN handle
* @param apiId the ID to read (0-1023)
* @param data the packet data (8 bytes)
* @param data the received message
* @return true on success, false on error
* @see "HAL_ReadCANPacketLatest"
*/
public static native boolean readCANPacketLatest(int handle, int apiId, CANData data);
public static native boolean readCANPacketLatest(int handle, int apiId, CANReceiveMessage data);
/**
* Reads a CAN packet. The will return the last packet received until the packet is older then the
@@ -170,13 +180,13 @@ public class CANAPIJNI extends JNIWrapper {
*
* @param handle the CAN handle
* @param apiId the ID to read (0-1023)
* @param data the received message
* @param timeoutMs the timeout time for the packet
* @param data the packet data (8 bytes)
* @return true on success, false on error
* @see "HAL_ReadCANPacketTimeout"
*/
public static native boolean readCANPacketTimeout(
int handle, int apiId, int timeoutMs, CANData data);
int handle, int apiId, CANReceiveMessage data, int timeoutMs);
/** Utility class. */
private CANAPIJNI() {}

View File

@@ -1,35 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.hal;
/** Represents a received CAN message. */
@SuppressWarnings("MemberName")
public class CANData {
/** Contents of the CAN frame. */
public final byte[] data = new byte[8];
/** Length of the frame in bytes. */
public int length;
/** CAN frame timestamp in milliseconds. */
public long timestamp;
/** Default constructor. */
public CANData() {}
/**
* API used from JNI to set the data.
*
* @param length Length of packet in bytes.
* @param timestamp CAN frame timestamp in milliseconds.
* @return Buffer to place CAN frame data in.
*/
@SuppressWarnings("PMD.MethodReturnsInternalArray")
public byte[] setData(int length, long timestamp) {
this.length = length;
this.timestamp = timestamp;
return data;
}
}

View File

@@ -13,11 +13,12 @@ public class CTREPCMJNI extends JNIWrapper {
/**
* Initializes a PCM.
*
* @param busId the bus id
* @param module the CAN ID to initialize
* @return the created PH handle
* @see "HAL_InitializeCTREPCM"
*/
public static native int initialize(int module);
public static native int initialize(int busId, int module);
/**
* Frees a PCM handle.

View File

@@ -10,6 +10,14 @@ package edu.wpi.first.hal;
* @see "hal/Ports.h"
*/
public class PortsJNI extends JNIWrapper {
/**
* Gets the number of can buses in the current system.
*
* @return the number of can buses
* @see "HAL_GetNumCanBuses"
*/
public static native int getNumCanBuses();
/**
* Gets the number of analog inputs in the current system.
*

View File

@@ -25,12 +25,13 @@ public class PowerDistributionJNI extends JNIWrapper {
/**
* Initializes a Power Distribution Panel.
*
* @param busId the bus id
* @param module the module number to initialize
* @param type the type of module to initialize
* @return the created PowerDistribution handle
* @see "HAL_InitializePowerDistribution"
*/
public static native int initialize(int module, int type);
public static native int initialize(int busId, int module, int type);
/**
* Cleans a PowerDistribution module.

View File

@@ -25,11 +25,12 @@ public class REVPHJNI extends JNIWrapper {
/**
* Initializes a PH.
*
* @param busId the bus id
* @param module the CAN ID to initialize
* @return the created PH handle
* @see "HAL_InitializeREVPH"
*/
public static native int initialize(int module);
public static native int initialize(int busId, int module);
/**
* Frees a PH handle.

View File

@@ -1,49 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.hal.can;
import edu.wpi.first.hal.communication.NIRioStatus;
import edu.wpi.first.hal.util.UncleanStatusException;
/**
* Checks the status of a CAN message and throws an exception of the appropriate type if necessary.
*/
public final class CANExceptionFactory {
// FRC Error codes
static final int ERR_CANSessionMux_InvalidBuffer = -44086;
static final int ERR_CANSessionMux_MessageNotFound = -44087;
static final int ERR_CANSessionMux_NotAllowed = -44088;
static final int ERR_CANSessionMux_NotInitialized = -44089;
/**
* Checks the status of a CAN message with the given message ID.
*
* @param status The CAN status.
* @param messageID The CAN message ID.
* @throws CANInvalidBufferException if the buffer is invalid.
* @throws CANMessageNotAllowedException if the message isn't allowed.
* @throws CANNotInitializedException if the CAN bus isn't initialized.
* @throws UncleanStatusException if the status code passed in reports an error.
*/
public static void checkStatus(int status, int messageID) {
switch (status) {
case NIRioStatus.kRioStatusSuccess -> {
// Everything is ok... don't throw.
}
case ERR_CANSessionMux_InvalidBuffer,
NIRioStatus.kRIOStatusBufferInvalidSize -> throw new CANInvalidBufferException();
case ERR_CANSessionMux_MessageNotFound,
NIRioStatus.kRIOStatusOperationTimedOut -> throw new CANMessageNotFoundException();
case ERR_CANSessionMux_NotAllowed,
NIRioStatus.kRIOStatusFeatureNotSupported -> throw new CANMessageNotAllowedException(
"MessageID = " + messageID);
case ERR_CANSessionMux_NotInitialized,
NIRioStatus.kRIOStatusResourceNotInitialized -> throw new CANNotInitializedException();
default -> throw new UncleanStatusException("Fatal status code detected: " + status);
}
}
private CANExceptionFactory() {}
}

View File

@@ -1,27 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.hal.can;
/**
* Exception indicating that a CAN driver library entry-point was passed an invalid buffer.
* Typically, this is due to a buffer being too small to include the needed safety token.
*/
public class CANInvalidBufferException extends RuntimeException {
private static final long serialVersionUID = -7993785672956997939L;
/** Constructs a new CANInvalidBufferException with no message. */
public CANInvalidBufferException() {
super();
}
/**
* Constructs a new CANInvalidBufferException with {@code msg} as its detail message.
*
* @param msg the message
*/
public CANInvalidBufferException(String msg) {
super(msg);
}
}

View File

@@ -4,10 +4,7 @@
package edu.wpi.first.hal.can;
import edu.wpi.first.hal.CANStreamMessage;
import edu.wpi.first.hal.JNIWrapper;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
/**
* CAN API HAL JNI Functions.
@@ -34,47 +31,52 @@ public class CANJNI extends JNIWrapper {
/**
* Sends a CAN message.
*
* @param messageID The ID of the CAN message.
* @param data The data bytes to be sent.
* @param busId The bus ID.
* @param messageId The ID of the CAN message.
* @param data the data to send.
* @param dataLength the length of data to send
* @param flags the message flags
* @param periodMs The period in milliseconds at which to send the message, use {@link
* #CAN_SEND_PERIOD_NO_REPEAT} for a single send.
* @return send status, 0 on success.
*/
public static native void FRCNetCommCANSessionMuxSendMessage(
int messageID, byte[] data, int periodMs);
public static native int sendMessage(
int busId, int messageId, byte[] data, int dataLength, int flags, int periodMs);
/**
* Receives a CAN message.
*
* @param messageID store for the received message ID (output parameter).
* @param messageIDMask the message ID mask to look for
* @param timeStamp the packet received timestamp (based off of CLOCK_MONOTONIC) (output
* parameter).
* @return The data bytes of the received message.
* @param busId The bus ID.
* @param messageId message id to look for.
* @param message The message.
* @return receive status, 0 on success.
*/
public static native byte[] FRCNetCommCANSessionMuxReceiveMessage(
IntBuffer messageID, int messageIDMask, ByteBuffer timeStamp);
public static native int receiveMessage(int busId, int messageId, CANReceiveMessage message);
/**
* Retrieves the current status of the CAN bus.
*
* @param busId The bus ID.
* @param status The CANStatus object to hold the retrieved status.
*/
public static native void getCANStatus(CANStatus status);
public static native void getCANStatus(int busId, CANStatus status);
/**
* Opens a new CAN stream session for receiving CAN messages with specified filters.
*
* @param messageID The CAN messageID to match against. The bits of the messageID are bitwise
* @param busId The bus ID.
* @param messageId The CAN messageId to match against. The bits of the messageId are bitwise
* ANDed with the messageIDMask.
* @param messageIDMask The CAN messageIDMask is a bit-wise mask of bits in the messageID to match
* against. This allows matching against multiple frames. For example, providing an messageID
* @param messageIDMask The CAN messageIDMask is a bit-wise mask of bits in the messageId to match
* against. This allows matching against multiple frames. For example, providing an messageId
* of 0x2050001 and a mask of 0x1FFF003F would match all REV motor controller frames for a
* device with CAN ID 1. Providing a mask of 0x1FFFFFFF means that only the exact messageID
* device with CAN ID 1. Providing a mask of 0x1FFFFFFF means that only the exact messageId
* will be matched. Providing a mask of 0 would match any frame of any type.
* @param maxMessages The maximum number of messages that can be buffered in the session.
* @return The handle to the opened CAN stream session.
*/
public static native int openCANStreamSession(int messageID, int messageIDMask, int maxMessages);
public static native int openCANStreamSession(
int busId, int messageId, int messageIDMask, int maxMessages);
/**
* Closes a CAN stream session.

View File

@@ -1,22 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.hal.can;
/**
* Exception indicating that the Jaguar CAN Driver layer refused to send a restricted message ID to
* the CAN bus.
*/
public class CANMessageNotAllowedException extends RuntimeException {
private static final long serialVersionUID = -638450112427013494L;
/**
* Constructs a new CANMessageNotAllowedException with {@code msg} as its detail message.
*
* @param msg the message
*/
public CANMessageNotAllowedException(String msg) {
super(msg);
}
}

View File

@@ -1,27 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.hal.can;
/**
* Exception indicating that a can message is not available from Network Communications. This
* usually just means we already have the most recent value cached locally.
*/
public class CANMessageNotFoundException extends RuntimeException {
private static final long serialVersionUID = 8249780881928189975L;
/** Constructs a new CANMessageNotFoundException with no message. */
public CANMessageNotFoundException() {
super();
}
/**
* Constructs a new CANMessageNotFoundException with {@code msg} as its detail message.
*
* @param msg the message
*/
public CANMessageNotFoundException(String msg) {
super(msg);
}
}

View File

@@ -1,27 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.hal.can;
/**
* Exception indicating that the CAN driver layer has not been initialized. This happens when an
* entry-point is called before a CAN driver plugin has been installed.
*/
public class CANNotInitializedException extends RuntimeException {
private static final long serialVersionUID = -5982895147092686594L;
/** Constructs a new CANNotInitializedException with no message. */
public CANNotInitializedException() {
super();
}
/**
* Constructs a new CANNotInitializedException with {@code msg} as its detail message.
*
* @param msg the message
*/
public CANNotInitializedException(String msg) {
super(msg);
}
}

View File

@@ -0,0 +1,43 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.hal.can;
/** Represents a CAN message read from a stream. */
public class CANReceiveMessage {
/** The message data. */
@SuppressWarnings("MemberName")
public final byte[] data = new byte[64];
/** The length of the data received (0-8 bytes). */
@SuppressWarnings("MemberName")
public int length;
/** The flags of the message. */
@SuppressWarnings("MemberName")
public int flags;
/** Timestamp message was received, in microseconds (wpi time). */
@SuppressWarnings("MemberName")
public long timestamp;
/** Default constructor. */
public CANReceiveMessage() {}
/**
* API used from JNI to set the data.
*
* @param length Length of packet in bytes.
* @param flags Message flags.
* @param timestamp CAN frame timestamp in microseconds.
* @return Buffer containing CAN frame.
*/
@SuppressWarnings("PMD.MethodReturnsInternalArray")
public byte[] setReceiveData(int length, int flags, long timestamp) {
this.flags = flags;
this.length = length;
this.timestamp = timestamp;
return data;
}
}

View File

@@ -2,7 +2,7 @@
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.hal;
package edu.wpi.first.hal.can;
/** Represents a CAN message read from a stream. */
public class CANStreamMessage {
@@ -14,13 +14,17 @@ public class CANStreamMessage {
@SuppressWarnings("MemberName")
public int length;
/** The flags of the message. */
@SuppressWarnings("MemberName")
public int flags;
/** Timestamp message was received, in milliseconds (based off of CLOCK_MONOTONIC). */
@SuppressWarnings("MemberName")
public long timestamp;
/** The message ID. */
@SuppressWarnings("MemberName")
public int messageID;
public int messageId;
/** Default constructor. */
public CANStreamMessage() {}
@@ -29,13 +33,15 @@ public class CANStreamMessage {
* API used from JNI to set the data.
*
* @param length Length of packet in bytes.
* @param messageID CAN message ID of the message.
* @param messageId CAN message ID of the message.
* @param flags Message flags.
* @param timestamp CAN frame timestamp in microseconds.
* @return Buffer containing CAN frame.
*/
@SuppressWarnings("PMD.MethodReturnsInternalArray")
public byte[] setStreamData(int length, int messageID, long timestamp) {
this.messageID = messageID;
public byte[] setStreamData(int length, int flags, int messageId, long timestamp) {
this.messageId = messageId;
this.flags = flags;
this.length = length;
this.timestamp = timestamp;
return data;

View File

@@ -4,7 +4,6 @@
package edu.wpi.first.hal.can;
import edu.wpi.first.hal.CANStreamMessage;
import java.io.IOException;
/**

View File

@@ -19,29 +19,20 @@ using namespace wpi::java;
extern "C" {
/*
* Class: edu_wpi_first_hal_CANAPIJNI
* Method: getCANPacketBaseTime
* Signature: ()J
*/
JNIEXPORT jlong JNICALL
Java_edu_wpi_first_hal_CANAPIJNI_getCANPacketBaseTime
(JNIEnv*, jclass)
{
return HAL_GetCANPacketBaseTime();
}
/*
* Class: edu_wpi_first_hal_CANAPIJNI
* Method: initializeCAN
* Signature: (III)I
* Signature: (IIII)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_CANAPIJNI_initializeCAN
(JNIEnv* env, jclass, jint manufacturer, jint deviceId, jint deviceType)
(JNIEnv* env, jclass, jint busId, jint manufacturer, jint deviceId,
jint deviceType)
{
int32_t status = 0;
auto handle =
HAL_InitializeCAN(static_cast<HAL_CANManufacturer>(manufacturer),
HAL_InitializeCAN(static_cast<int32_t>(busId),
static_cast<HAL_CANManufacturer>(manufacturer),
static_cast<int32_t>(deviceId),
static_cast<HAL_CANDeviceType>(deviceType), &status);
@@ -63,105 +54,189 @@ Java_edu_wpi_first_hal_CANAPIJNI_cleanCAN
}
}
static bool PackCANMessage(JNIEnv* env, jbyteArray data, jint dataLength,
jint flags, HAL_CANMessage* message) {
if (data == nullptr) {
ThrowNullPointerException(env, "data array cannot be null");
return false;
}
auto arrLen = env->GetArrayLength(data);
if (arrLen < dataLength) {
ThrowIllegalArgumentException(env, "array length less than data length");
return false;
}
if ((flags & HAL_CAN_FD_DATALENGTH) && dataLength > 64) {
ThrowIllegalArgumentException(env, "FD frame has max length of 64 bytes");
return false;
} else if (!(flags & HAL_CAN_FD_DATALENGTH) && dataLength > 8) {
ThrowIllegalArgumentException(env,
"Non FD frame has max length of 8 bytes");
return false;
}
std::memset(message, 0, sizeof(*message));
message->dataSize = dataLength;
message->flags = flags;
JSpan<const jbyte> arr{env, data, static_cast<size_t>(dataLength)};
std::memcpy(message->data, arr.data(), dataLength);
return true;
}
/*
* Class: edu_wpi_first_hal_CANAPIJNI
* Method: writeCANPacket
* Signature: (I[BI)V
* Signature: (II[BII)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_CANAPIJNI_writeCANPacket
(JNIEnv* env, jclass, jint handle, jbyteArray data, jint apiId)
(JNIEnv* env, jclass, jint handle, jint apiId, jbyteArray data,
jint dataLength, jint flags)
{
auto halHandle = static_cast<HAL_CANHandle>(handle);
JSpan<const jbyte> arr{env, data};
HAL_CANMessage message;
if (!PackCANMessage(env, data, dataLength, flags, &message)) {
return;
}
int32_t status = 0;
HAL_WriteCANPacket(halHandle, reinterpret_cast<const uint8_t*>(arr.data()),
arr.size(), apiId, &status);
HAL_WriteCANPacket(static_cast<HAL_CANHandle>(handle), apiId, &message,
&status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_CANAPIJNI
* Method: writeCANPacketRepeating
* Signature: (I[BII)V
* Signature: (II[BIII)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_CANAPIJNI_writeCANPacketRepeating
(JNIEnv* env, jclass, jint handle, jbyteArray data, jint apiId,
jint timeoutMs)
(JNIEnv* env, jclass, jint handle, jint apiId, jbyteArray data,
jint dataLength, jint flags, jint repeatMs)
{
auto halHandle = static_cast<HAL_CANHandle>(handle);
JSpan<const jbyte> arr{env, data};
HAL_CANMessage message;
if (!PackCANMessage(env, data, dataLength, flags, &message)) {
return;
}
int32_t status = 0;
HAL_WriteCANPacketRepeating(halHandle,
reinterpret_cast<const uint8_t*>(arr.data()),
arr.size(), apiId, timeoutMs, &status);
HAL_WriteCANPacketRepeating(static_cast<HAL_CANHandle>(handle), apiId,
&message, repeatMs, &status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_CANAPIJNI
* Method: writeCANRTRFrame
* Signature: (III)V
* Signature: (II[BII)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_CANAPIJNI_writeCANRTRFrame
(JNIEnv* env, jclass, jint handle, jint length, jint apiId)
(JNIEnv* env, jclass, jint handle, jint apiId, jbyteArray data,
jint dataLength, jint flags)
{
auto halHandle = static_cast<HAL_CANHandle>(handle);
HAL_CANMessage message;
if (data == nullptr) {
// We will allow RTR frames to have a null data array
if ((flags & HAL_CAN_FD_DATALENGTH) && dataLength > 64) {
ThrowIllegalArgumentException(env, "FD frame has max length of 64 bytes");
return;
} else if (!(flags & HAL_CAN_FD_DATALENGTH) && dataLength > 8) {
ThrowIllegalArgumentException(env,
"Non FD frame has max length of 8 bytes");
return;
}
std::memset(&message, 0, sizeof(message));
message.flags = flags;
message.dataSize = dataLength;
} else if (!PackCANMessage(env, data, dataLength, flags, &message)) {
return;
}
int32_t status = 0;
HAL_WriteCANRTRFrame(halHandle, static_cast<int32_t>(length), apiId, &status);
HAL_WriteCANRTRFrame(static_cast<HAL_CANHandle>(handle), apiId, &message,
&status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_CANAPIJNI
* Method: writeCANPacketNoThrow
* Signature: (I[BI)I
* Signature: (II[BII)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_CANAPIJNI_writeCANPacketNoThrow
(JNIEnv* env, jclass, jint handle, jbyteArray data, jint apiId)
(JNIEnv* env, jclass, jint handle, jint apiId, jbyteArray data,
jint dataLength, jint flags)
{
auto halHandle = static_cast<HAL_CANHandle>(handle);
JSpan<const jbyte> arr{env, data};
HAL_CANMessage message;
if (!PackCANMessage(env, data, dataLength, flags, &message)) {
return PARAMETER_OUT_OF_RANGE;
}
int32_t status = 0;
HAL_WriteCANPacket(halHandle, reinterpret_cast<const uint8_t*>(arr.data()),
arr.size(), apiId, &status);
HAL_WriteCANPacket(static_cast<HAL_CANHandle>(handle), apiId, &message,
&status);
return status;
}
/*
* Class: edu_wpi_first_hal_CANAPIJNI
* Method: writeCANPacketRepeatingNoThrow
* Signature: (I[BII)I
* Signature: (II[BIII)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_CANAPIJNI_writeCANPacketRepeatingNoThrow
(JNIEnv* env, jclass, jint handle, jbyteArray data, jint apiId,
jint timeoutMs)
(JNIEnv* env, jclass, jint handle, jint apiId, jbyteArray data,
jint dataLength, jint flags, jint repeatMs)
{
auto halHandle = static_cast<HAL_CANHandle>(handle);
JSpan<const jbyte> arr{env, data};
HAL_CANMessage message;
if (!PackCANMessage(env, data, dataLength, flags, &message)) {
return PARAMETER_OUT_OF_RANGE;
}
int32_t status = 0;
HAL_WriteCANPacketRepeating(halHandle,
reinterpret_cast<const uint8_t*>(arr.data()),
arr.size(), apiId, timeoutMs, &status);
HAL_WriteCANPacketRepeating(static_cast<HAL_CANHandle>(handle), apiId,
&message, repeatMs, &status);
return status;
}
/*
* Class: edu_wpi_first_hal_CANAPIJNI
* Method: writeCANRTRFrameNoThrow
* Signature: (III)I
* Signature: (II[BII)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_CANAPIJNI_writeCANRTRFrameNoThrow
(JNIEnv* env, jclass, jint handle, jint length, jint apiId)
(JNIEnv* env, jclass, jint handle, jint apiId, jbyteArray data,
jint dataLength, jint flags)
{
auto halHandle = static_cast<HAL_CANHandle>(handle);
HAL_CANMessage message;
if (data == nullptr) {
// We will allow RTR frames to have a null data array
if ((flags & HAL_CAN_FD_DATALENGTH) && dataLength > 64) {
ThrowIllegalArgumentException(env, "FD frame has max length of 64 bytes");
return PARAMETER_OUT_OF_RANGE;
} else if (!(flags & HAL_CAN_FD_DATALENGTH) && dataLength > 8) {
ThrowIllegalArgumentException(env,
"Non FD frame has max length of 8 bytes");
return PARAMETER_OUT_OF_RANGE;
}
std::memset(&message, 0, sizeof(message));
message.flags = flags;
message.dataSize = dataLength;
} else if (!PackCANMessage(env, data, dataLength, flags, &message)) {
return PARAMETER_OUT_OF_RANGE;
}
int32_t status = 0;
HAL_WriteCANRTRFrame(halHandle, static_cast<int32_t>(length), apiId, &status);
HAL_WriteCANRTRFrame(static_cast<HAL_CANHandle>(handle), apiId, &message,
&status);
return status;
}
@@ -190,29 +265,28 @@ Java_edu_wpi_first_hal_CANAPIJNI_readCANPacketNew
(JNIEnv* env, jclass, jint handle, jint apiId, jobject data)
{
auto halHandle = static_cast<HAL_CANHandle>(handle);
uint8_t dataTemp[8];
int32_t dataLength = 0;
uint64_t timestamp = 0;
HAL_CANReceiveMessage message;
std::memset(&message, 0, sizeof(message));
int32_t status = 0;
HAL_ReadCANPacketNew(halHandle, apiId, dataTemp, &dataLength, &timestamp,
&status);
HAL_ReadCANPacketNew(halHandle, apiId, &message, &status);
if (status == HAL_ERR_CANSessionMux_MessageNotFound) {
return false;
}
if (!CheckStatus(env, status)) {
return false;
}
if (dataLength > 8) {
dataLength = 8;
}
jbyteArray toSetArray = SetCANDataObject(env, data, dataLength, timestamp);
jbyteArray toSetArray =
SetCANReceiveMessageObject(env, data, message.message.dataSize,
message.message.flags, message.timeStamp);
auto javaLen = env->GetArrayLength(toSetArray);
if (javaLen < dataLength) {
dataLength = javaLen;
if (javaLen < message.message.dataSize) {
ThrowIllegalArgumentException(env,
"Message buffer not long enough for message");
return false;
}
env->SetByteArrayRegion(toSetArray, 0, dataLength,
reinterpret_cast<jbyte*>(dataTemp));
env->SetByteArrayRegion(toSetArray, 0, message.message.dataSize,
reinterpret_cast<jbyte*>(message.message.data));
return true;
}
@@ -226,48 +300,45 @@ Java_edu_wpi_first_hal_CANAPIJNI_readCANPacketLatest
(JNIEnv* env, jclass, jint handle, jint apiId, jobject data)
{
auto halHandle = static_cast<HAL_CANHandle>(handle);
uint8_t dataTemp[8];
int32_t dataLength = 0;
uint64_t timestamp = 0;
HAL_CANReceiveMessage message;
std::memset(&message, 0, sizeof(message));
int32_t status = 0;
HAL_ReadCANPacketLatest(halHandle, apiId, dataTemp, &dataLength, &timestamp,
&status);
HAL_ReadCANPacketLatest(halHandle, apiId, &message, &status);
if (status == HAL_ERR_CANSessionMux_MessageNotFound) {
return false;
}
if (!CheckStatus(env, status)) {
return false;
}
if (dataLength > 8) {
dataLength = 8;
}
jbyteArray toSetArray = SetCANDataObject(env, data, dataLength, timestamp);
jbyteArray toSetArray =
SetCANReceiveMessageObject(env, data, message.message.dataSize,
message.message.flags, message.timeStamp);
auto javaLen = env->GetArrayLength(toSetArray);
if (javaLen < dataLength) {
dataLength = javaLen;
if (javaLen < message.message.dataSize) {
ThrowIllegalArgumentException(env,
"Message buffer not long enough for message");
return false;
}
env->SetByteArrayRegion(toSetArray, 0, dataLength,
reinterpret_cast<jbyte*>(dataTemp));
env->SetByteArrayRegion(toSetArray, 0, message.message.dataSize,
reinterpret_cast<jbyte*>(message.message.data));
return true;
}
/*
* Class: edu_wpi_first_hal_CANAPIJNI
* Method: readCANPacketTimeout
* Signature: (IIILjava/lang/Object;)Z
* Signature: (IILjava/lang/Object;I)Z
*/
JNIEXPORT jboolean JNICALL
Java_edu_wpi_first_hal_CANAPIJNI_readCANPacketTimeout
(JNIEnv* env, jclass, jint handle, jint apiId, jint timeoutMs, jobject data)
(JNIEnv* env, jclass, jint handle, jint apiId, jobject data, jint timeoutMs)
{
auto halHandle = static_cast<HAL_CANHandle>(handle);
uint8_t dataTemp[8];
int32_t dataLength = 0;
uint64_t timestamp = 0;
HAL_CANReceiveMessage message;
std::memset(&message, 0, sizeof(message));
int32_t status = 0;
HAL_ReadCANPacketTimeout(halHandle, apiId, dataTemp, &dataLength, &timestamp,
timeoutMs, &status);
HAL_ReadCANPacketTimeout(halHandle, apiId, &message, timeoutMs, &status);
if (status == HAL_CAN_TIMEOUT ||
status == HAL_ERR_CANSessionMux_MessageNotFound) {
return false;
@@ -275,17 +346,18 @@ Java_edu_wpi_first_hal_CANAPIJNI_readCANPacketTimeout
if (!CheckStatus(env, status)) {
return false;
}
if (dataLength > 8) {
dataLength = 8;
}
jbyteArray toSetArray = SetCANDataObject(env, data, dataLength, timestamp);
jbyteArray toSetArray =
SetCANReceiveMessageObject(env, data, message.message.dataSize,
message.message.flags, message.timeStamp);
auto javaLen = env->GetArrayLength(toSetArray);
if (javaLen < dataLength) {
dataLength = javaLen;
if (javaLen < message.message.dataSize) {
ThrowIllegalArgumentException(env,
"Message buffer not long enough for message");
return false;
}
env->SetByteArrayRegion(toSetArray, 0, dataLength,
reinterpret_cast<jbyte*>(dataTemp));
env->SetByteArrayRegion(toSetArray, 0, message.message.dataSize,
reinterpret_cast<jbyte*>(message.message.data));
return true;
}
} // extern "C"

View File

@@ -11,68 +11,98 @@
#include "HALUtil.h"
#include "edu_wpi_first_hal_can_CANJNI.h"
#include "hal/CAN.h"
#include "hal/Errors.h"
using namespace hal;
using namespace wpi::java;
extern "C" {
/*
* Class: edu_wpi_first_hal_can_CANJNI
* Method: FRCNetCommCANSessionMuxSendMessage
* Signature: (I[BI)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_can_CANJNI_FRCNetCommCANSessionMuxSendMessage
(JNIEnv* env, jclass, jint messageID, jbyteArray data, jint periodMs)
{
JSpan<const jbyte> dataArray{env, data};
static bool PackCANMessage(JNIEnv* env, jbyteArray data, jint dataLength,
jint flags, HAL_CANMessage* message) {
if (data == nullptr) {
ThrowNullPointerException(env, "data array cannot be null");
return false;
}
const uint8_t* dataBuffer =
reinterpret_cast<const uint8_t*>(dataArray.data());
uint8_t dataSize = dataArray.size();
auto arrLen = env->GetArrayLength(data);
if (arrLen < dataLength) {
ThrowIllegalArgumentException(env, "array length less than data length");
return false;
}
int32_t status = 0;
HAL_CAN_SendMessage(messageID, dataBuffer, dataSize, periodMs, &status);
CheckCANStatus(env, status, messageID);
if ((flags & HAL_CAN_FD_DATALENGTH) && dataLength > 64) {
ThrowIllegalArgumentException(env, "FD frame has max length of 64 bytes");
return false;
} else if (!(flags & HAL_CAN_FD_DATALENGTH) && dataLength > 8) {
ThrowIllegalArgumentException(env,
"Non FD frame has max length of 8 bytes");
return false;
}
std::memset(message, 0, sizeof(*message));
message->dataSize = dataLength;
message->flags = flags;
JSpan<const jbyte> arr{env, data, static_cast<size_t>(dataLength)};
std::memcpy(message->data, arr.data(), dataLength);
return true;
}
/*
* Class: edu_wpi_first_hal_can_CANJNI
* Method: FRCNetCommCANSessionMuxReceiveMessage
* Signature: (Ljava/lang/Object;ILjava/lang/Object;)[B
* Method: sendMessage
* Signature: (II[BIII)I
*/
JNIEXPORT jbyteArray JNICALL
Java_edu_wpi_first_hal_can_CANJNI_FRCNetCommCANSessionMuxReceiveMessage
(JNIEnv* env, jclass, jobject messageID, jint messageIDMask,
jobject timeStamp)
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_can_CANJNI_sendMessage
(JNIEnv* env, jclass, jint busId, jint messageId, jbyteArray data,
jint dataLength, jint flags, jint periodMs)
{
uint32_t* messageIDPtr =
reinterpret_cast<uint32_t*>(env->GetDirectBufferAddress(messageID));
uint32_t* timeStampPtr =
reinterpret_cast<uint32_t*>(env->GetDirectBufferAddress(timeStamp));
uint8_t dataSize = 0;
uint8_t buffer[8];
HAL_CANMessage message;
if (!PackCANMessage(env, data, dataLength, flags, &message)) {
return PARAMETER_OUT_OF_RANGE;
}
int32_t status = 0;
HAL_CAN_ReceiveMessage(messageIDPtr, messageIDMask, buffer, &dataSize,
timeStampPtr, &status);
HAL_CAN_SendMessage(busId, messageId, &message, periodMs, &status);
return status;
}
if (!CheckCANStatus(env, status, *messageIDPtr)) {
return nullptr;
/*
* Class: edu_wpi_first_hal_can_CANJNI
* Method: receiveMessage
* Signature: (IILjava/lang/Object;)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_can_CANJNI_receiveMessage
(JNIEnv* env, jclass, jint busId, jint messageId, jobject data)
{
HAL_CANReceiveMessage message;
std::memset(&message, 0, sizeof(message));
int32_t status = 0;
HAL_CAN_ReceiveMessage(busId, messageId, &message, &status);
jbyteArray toSetArray =
SetCANReceiveMessageObject(env, data, message.message.dataSize,
message.message.flags, message.timeStamp);
auto javaLen = env->GetArrayLength(toSetArray);
if (javaLen < message.message.dataSize) {
ThrowIllegalArgumentException(env,
"Message buffer not long enough for message");
return status;
}
return MakeJByteArray(env, {buffer, static_cast<size_t>(dataSize)});
env->SetByteArrayRegion(toSetArray, 0, message.message.dataSize,
reinterpret_cast<jbyte*>(message.message.data));
return status;
}
/*
* Class: edu_wpi_first_hal_can_CANJNI
* Method: getCANStatus
* Signature: (Ljava/lang/Object;)V
* Signature: (ILjava/lang/Object;)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_can_CANJNI_getCANStatus
(JNIEnv* env, jclass, jobject canStatus)
(JNIEnv* env, jclass, jint busId, jobject canStatus)
{
float percentBusUtilization = 0;
uint32_t busOffCount = 0;
@@ -80,8 +110,9 @@ Java_edu_wpi_first_hal_can_CANJNI_getCANStatus
uint32_t receiveErrorCount = 0;
uint32_t transmitErrorCount = 0;
int32_t status = 0;
HAL_CAN_GetCANStatus(&percentBusUtilization, &busOffCount, &txFullCount,
&receiveErrorCount, &transmitErrorCount, &status);
HAL_CAN_GetCANStatus(busId, &percentBusUtilization, &busOffCount,
&txFullCount, &receiveErrorCount, &transmitErrorCount,
&status);
if (!CheckStatus(env, status)) {
return;
@@ -94,17 +125,18 @@ Java_edu_wpi_first_hal_can_CANJNI_getCANStatus
/*
* Class: edu_wpi_first_hal_can_CANJNI
* Method: openCANStreamSession
* Signature: (III)I
* Signature: (IIII)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_can_CANJNI_openCANStreamSession
(JNIEnv* env, jclass, jint messageID, jint messageIDMask, jint maxMessages)
(JNIEnv* env, jclass, jint busId, jint messageId, jint messageIDMask,
jint maxMessages)
{
uint32_t handle = 0;
int32_t status = 0;
HAL_CAN_OpenStreamSession(&handle, static_cast<uint32_t>(messageID),
static_cast<uint32_t>(messageIDMask),
static_cast<uint32_t>(maxMessages), &status);
HAL_CANStreamHandle handle =
HAL_CAN_OpenStreamSession(busId, static_cast<uint32_t>(messageId),
static_cast<uint32_t>(messageIDMask),
static_cast<uint32_t>(maxMessages), &status);
if (!CheckStatus(env, status)) {
return static_cast<jint>(0);
@@ -182,14 +214,17 @@ Java_edu_wpi_first_hal_can_CANJNI_readCANStreamSession
}
}
JLocal<jbyteArray> toSetArray{
env, SetCANStreamObject(env, elem, msg->dataSize, msg->messageID,
msg->timeStamp)};
env, SetCANStreamObject(env, elem, msg->message.message.dataSize,
msg->messageId, msg->message.timeStamp)};
auto javaLen = env->GetArrayLength(toSetArray);
if (javaLen < msg->dataSize) {
msg->dataSize = javaLen;
if (javaLen < msg->message.message.dataSize) {
ThrowIllegalArgumentException(
env, "Message buffer not long enough for message");
return PARAMETER_OUT_OF_RANGE;
}
env->SetByteArrayRegion(toSetArray, 0, msg->dataSize,
reinterpret_cast<jbyte*>(msg->data));
env->SetByteArrayRegion(
toSetArray, 0, msg->message.message.dataSize,
reinterpret_cast<jbyte*>(msg->message.message.data));
}
if (status == HAL_ERR_CANSessionMux_SessionOverrun) {

View File

@@ -19,15 +19,15 @@ extern "C" {
/*
* Class: edu_wpi_first_hal_CTREPCMJNI
* Method: initialize
* Signature: (I)I
* Signature: (II)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_CTREPCMJNI_initialize
(JNIEnv* env, jclass, jint module)
(JNIEnv* env, jclass, jint busId, jint module)
{
int32_t status = 0;
auto stack = wpi::java::GetJavaStackTrace(env, "edu.wpi.first");
auto handle = HAL_InitializeCTREPCM(module, stack.c_str(), &status);
auto handle = HAL_InitializeCTREPCM(busId, module, stack.c_str(), &status);
CheckStatusForceThrow(env, status);
return handle;
}

View File

@@ -41,17 +41,13 @@ static JException illegalArgExCls;
static JException boundaryExCls;
static JException allocationExCls;
static JException halHandleExCls;
static JException canInvalidBufferExCls;
static JException canMessageNotFoundExCls;
static JException canMessageNotAllowedExCls;
static JException canNotInitializedExCls;
static JException uncleanStatusExCls;
static JException nullPointerEx;
static JClass powerDistributionVersionCls;
static JClass pwmConfigDataResultCls;
static JClass canStatusCls;
static JClass matchInfoDataCls;
static JClass canDataCls;
static JClass canReceiveMessageCls;
static JClass canStreamMessageCls;
static JClass halValueCls;
static JClass revPHVersionCls;
@@ -63,8 +59,8 @@ static const JClassInit classes[] = {
{"edu/wpi/first/hal/PWMConfigDataResult", &pwmConfigDataResultCls},
{"edu/wpi/first/hal/can/CANStatus", &canStatusCls},
{"edu/wpi/first/hal/MatchInfoData", &matchInfoDataCls},
{"edu/wpi/first/hal/CANData", &canDataCls},
{"edu/wpi/first/hal/CANStreamMessage", &canStreamMessageCls},
{"edu/wpi/first/hal/can/CANReceiveMessage", &canReceiveMessageCls},
{"edu/wpi/first/hal/can/CANStreamMessage", &canStreamMessageCls},
{"edu/wpi/first/hal/HALValue", &halValueCls},
{"edu/wpi/first/hal/REVPHVersion", &revPHVersionCls},
{"edu/wpi/first/hal/can/CANStreamOverflowException",
@@ -75,13 +71,6 @@ static const JExceptionInit exceptions[] = {
{"edu/wpi/first/hal/util/BoundaryException", &boundaryExCls},
{"edu/wpi/first/hal/util/AllocationException", &allocationExCls},
{"edu/wpi/first/hal/util/HalHandleException", &halHandleExCls},
{"edu/wpi/first/hal/can/CANInvalidBufferException", &canInvalidBufferExCls},
{"edu/wpi/first/hal/can/CANMessageNotFoundException",
&canMessageNotFoundExCls},
{"edu/wpi/first/hal/can/CANMessageNotAllowedException",
&canMessageNotAllowedExCls},
{"edu/wpi/first/hal/can/CANNotInitializedException",
&canNotInitializedExCls},
{"edu/wpi/first/hal/util/UncleanStatusException", &uncleanStatusExCls},
{"java/lang/NullPointerException", &nullPointerEx}};
@@ -152,64 +141,6 @@ void ThrowError(JNIEnv* env, int32_t status, int32_t minRange, int32_t maxRange,
env, fmt::format(" Code: {}. {}", status, lastError).c_str(), status);
}
void ReportCANError(JNIEnv* env, int32_t status, int message_id) {
if (status >= 0) {
return;
}
switch (status) {
case kRioStatusSuccess:
// Everything is ok... don't throw.
break;
case HAL_ERR_CANSessionMux_InvalidBuffer:
case kRIOStatusBufferInvalidSize: {
static jmethodID invalidBufConstruct = nullptr;
if (!invalidBufConstruct) {
invalidBufConstruct =
env->GetMethodID(canInvalidBufferExCls, "<init>", "()V");
}
jobject exception =
env->NewObject(canInvalidBufferExCls, invalidBufConstruct);
env->Throw(static_cast<jthrowable>(exception));
break;
}
case HAL_ERR_CANSessionMux_MessageNotFound:
case kRIOStatusOperationTimedOut: {
static jmethodID messageNotFoundConstruct = nullptr;
if (!messageNotFoundConstruct) {
messageNotFoundConstruct =
env->GetMethodID(canMessageNotFoundExCls, "<init>", "()V");
}
jobject exception =
env->NewObject(canMessageNotFoundExCls, messageNotFoundConstruct);
env->Throw(static_cast<jthrowable>(exception));
break;
}
case HAL_ERR_CANSessionMux_NotAllowed:
case kRIOStatusFeatureNotSupported: {
canMessageNotAllowedExCls.Throw(
env, fmt::format("MessageID = {}", message_id).c_str());
break;
}
case HAL_ERR_CANSessionMux_NotInitialized:
case kRIOStatusResourceNotInitialized: {
static jmethodID notInitConstruct = nullptr;
if (!notInitConstruct) {
notInitConstruct =
env->GetMethodID(canNotInitializedExCls, "<init>", "()V");
}
jobject exception =
env->NewObject(canNotInitializedExCls, notInitConstruct);
env->Throw(static_cast<jthrowable>(exception));
break;
}
default: {
uncleanStatusExCls.Throw(
env, fmt::format("Fatal status code detected: {}", status).c_str());
break;
}
}
}
void ThrowNullPointerException(JNIEnv* env, std::string_view msg) {
nullPointerEx.Throw(env, msg);
}
@@ -302,24 +233,27 @@ void SetMatchInfoObject(JNIEnv* env, jobject matchStatus,
static_cast<jint>(matchInfo.matchType));
}
jbyteArray SetCANDataObject(JNIEnv* env, jobject canData, int32_t length,
uint64_t timestamp) {
static jmethodID func = env->GetMethodID(canDataCls, "setData", "(IJ)[B");
jbyteArray SetCANReceiveMessageObject(JNIEnv* env, jobject canData,
int32_t length, int32_t flags,
uint64_t timestamp) {
static jmethodID func =
env->GetMethodID(canReceiveMessageCls, "setReceiveData", "(IIJ)[B");
jbyteArray retVal = static_cast<jbyteArray>(env->CallObjectMethod(
canData, func, static_cast<jint>(length), static_cast<jlong>(timestamp)));
canData, func, static_cast<jint>(length), static_cast<jint>(flags),
static_cast<jlong>(timestamp)));
return retVal;
}
jbyteArray SetCANStreamObject(JNIEnv* env, jobject canStreamData,
int32_t length, uint32_t messageID,
int32_t length, uint32_t messageId,
uint64_t timestamp) {
static jmethodID func =
env->GetMethodID(canStreamMessageCls, "setStreamData", "(IIJ)[B");
jbyteArray retVal = static_cast<jbyteArray>(env->CallObjectMethod(
canStreamData, func, static_cast<jint>(length),
static_cast<jint>(messageID), static_cast<jlong>(timestamp)));
static_cast<jint>(messageId), static_cast<jlong>(timestamp)));
return retVal;
}

View File

@@ -42,15 +42,6 @@ inline bool CheckStatusForceThrow(JNIEnv* env, int32_t status) {
return status == 0;
}
void ReportCANError(JNIEnv* env, int32_t status, int32_t message_id);
inline bool CheckCANStatus(JNIEnv* env, int32_t status, int32_t message_id) {
if (status != 0) {
ReportCANError(env, status, message_id);
}
return status == 0;
}
void ThrowNullPointerException(JNIEnv* env, std::string_view msg);
void ThrowCANStreamOverflowException(JNIEnv* env, jobjectArray messages,
jint length);
@@ -75,11 +66,12 @@ void SetCanStatusObject(JNIEnv* env, jobject canStatus,
void SetMatchInfoObject(JNIEnv* env, jobject matchStatus,
const HAL_MatchInfo& matchInfo);
jbyteArray SetCANDataObject(JNIEnv* env, jobject canData, int32_t length,
uint64_t timestamp);
jbyteArray SetCANReceiveMessageObject(JNIEnv* env, jobject canData,
int32_t length, int32_t flags,
uint64_t timestamp);
jbyteArray SetCANStreamObject(JNIEnv* env, jobject canStreamData,
int32_t length, uint32_t messageID,
int32_t length, uint32_t messageId,
uint64_t timestamp);
jobject CreateHALValue(JNIEnv* env, const HAL_Value& value);

View File

@@ -13,6 +13,19 @@
using namespace hal;
extern "C" {
/*
* Class: edu_wpi_first_hal_PortsJNI
* Method: getNumCanBuses
* Signature: ()I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_PortsJNI_getNumCanBuses
(JNIEnv*, jclass)
{
jint value = HAL_GetNumCanBuses();
return value;
}
/*
* Class: edu_wpi_first_hal_PortsJNI
* Method: getNumAnalogInputs

View File

@@ -27,17 +27,17 @@ extern "C" {
/*
* Class: edu_wpi_first_hal_PowerDistributionJNI
* Method: initialize
* Signature: (II)I
* Signature: (III)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_PowerDistributionJNI_initialize
(JNIEnv* env, jclass, jint module, jint type)
(JNIEnv* env, jclass, jint busId, jint module, jint type)
{
int32_t status = 0;
auto stack = wpi::java::GetJavaStackTrace(env, "edu.wpi.first");
auto handle = HAL_InitializePowerDistribution(
module, static_cast<HAL_PowerDistributionType>(type), stack.c_str(),
&status);
busId, module, static_cast<HAL_PowerDistributionType>(type),
stack.c_str(), &status);
CheckStatusForceThrow(env, status);
return static_cast<jint>(handle);
}

View File

@@ -32,15 +32,15 @@ extern "C" {
/*
* Class: edu_wpi_first_hal_REVPHJNI
* Method: initialize
* Signature: (I)I
* Signature: (II)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_REVPHJNI_initialize
(JNIEnv* env, jclass, jint module)
(JNIEnv* env, jclass, jint busId, jint module)
{
int32_t status = 0;
auto stack = wpi::java::GetJavaStackTrace(env, "edu.wpi.first");
auto handle = HAL_InitializeREVPH(module, stack.c_str(), &status);
auto handle = HAL_InitializeREVPH(busId, module, stack.c_str(), &status);
CheckStatusForceThrow(env, status);
return handle;
}

View File

@@ -4,6 +4,8 @@
#pragma once
#include <hal/CANAPITypes.h>
#include <hal/Types.h>
#include <stdint.h>
/**
@@ -13,26 +15,7 @@
*/
// These are copies of defines located in CANSessionMux.h prepended with HAL_
/**
* Flag for sending a CAN message once.
*/
#define HAL_CAN_SEND_PERIOD_NO_REPEAT 0
/**
* Flag for stopping periodic CAN message sends.
*/
#define HAL_CAN_SEND_PERIOD_STOP_REPEATING -1
/**
* Mask for "is frame remote" in message ID.
*/
#define HAL_CAN_IS_FRAME_REMOTE 0x40000000
/**
* Mask for "is frame 11 bits" in message ID.
*/
#define HAL_CAN_IS_FRAME_11BIT 0x80000000
#define HAL_ERR_CANSessionMux_BufferTooLong -44085
#define HAL_ERR_CANSessionMux_InvalidBuffer -44086
#define HAL_ERR_CANSessionMux_MessageNotFound -44087
#define HAL_WARN_CANSessionMux_NoToken 44087
@@ -46,19 +29,17 @@
* @ingroup hal_capi
* @{
*/
/**
* Storage for CAN Stream Messages.
*/
struct HAL_CANStreamMessage {
/** The message ID */
uint32_t messageID;
/** The packet received timestamp (based off of CLOCK_MONOTONIC) */
uint32_t timeStamp;
/** The message data */
uint8_t data[8];
/** The size of the data received (0-8 bytes) */
uint8_t dataSize;
uint32_t messageId;
/** The message */
struct HAL_CANReceiveMessage message;
};
/** @} */
#ifdef __cplusplus
extern "C" {
@@ -70,33 +51,31 @@ extern "C" {
/**
* Sends a CAN message.
*
* @param[in] messageID the CAN ID to send
* @param[in] data the data to send (0-8 bytes)
* @param[in] dataSize the size of the data to send (0-8 bytes)
* @param[in] periodMs the period to repeat the packet at. Use
* HAL_CAN_SEND_PERIOD_NO_REPEAT to not repeat.
* @param[out] status Error status variable. 0 on success.
* @param[in] busId the CAN bus number
* @param[in] messageId the message id
* @param[in] message the CAN message
* @param[in] periodMs the repeat period
* @param[out] status Error status variable. 0 on success.
*/
void HAL_CAN_SendMessage(uint32_t messageID, const uint8_t* data,
uint8_t dataSize, int32_t periodMs, int32_t* status);
void HAL_CAN_SendMessage(int32_t busId, uint32_t messageId,
const struct HAL_CANMessage* message, int32_t periodMs,
int32_t* status);
/**
* Receives a CAN message.
*
* @param[out] messageID store for the received message ID
* @param[in] messageIDMask the message ID mask to look for
* @param[out] data data output (8 bytes)
* @param[out] dataSize data length (0-8 bytes)
* @param[out] timeStamp the packet received timestamp (based off of
* CLOCK_MONOTONIC)
* @param[out] status Error status variable. 0 on success.
* @param[in] busId The CAN bus number
* @param[in] messageId the message id
* @param[out] message The CAN message
* @param[out] status Error status variable. 0 on success.
*/
void HAL_CAN_ReceiveMessage(uint32_t* messageID, uint32_t messageIDMask,
uint8_t* data, uint8_t* dataSize,
uint32_t* timeStamp, int32_t* status);
void HAL_CAN_ReceiveMessage(int32_t busId, uint32_t messageId,
struct HAL_CANReceiveMessage* message,
int32_t* status);
/**
* Gets CAN status information.
*
* @param[in] busId the bus number
* @param[out] percentBusUtilization the bus utilization
* @param[out] busOffCount the number of bus off errors
* @param[out] txFullCount the number of tx full errors
@@ -104,8 +83,9 @@ void HAL_CAN_ReceiveMessage(uint32_t* messageID, uint32_t messageIDMask,
* @param[out] transmitErrorCount the number of transmit errors
* @param[out] status Error status variable. 0 on success.
*/
void HAL_CAN_GetCANStatus(float* percentBusUtilization, uint32_t* busOffCount,
uint32_t* txFullCount, uint32_t* receiveErrorCount,
void HAL_CAN_GetCANStatus(int32_t busId, float* percentBusUtilization,
uint32_t* busOffCount, uint32_t* txFullCount,
uint32_t* receiveErrorCount,
uint32_t* transmitErrorCount, int32_t* status);
/** @} */
/**
@@ -115,22 +95,24 @@ void HAL_CAN_GetCANStatus(float* percentBusUtilization, uint32_t* busOffCount,
/**
* Opens a CAN stream.
*
* @param[out] sessionHandle output for the session handle
* @param[in] messageID the message ID to read
* @param[in] busId the bus number
* @param[in] messageId the message ID to read
* @param[in] messageIDMask the message ID mask
* @param[in] maxMessages the maximum number of messages to stream
* @param[out] status Error status variable. 0 on success.
* @return the stream handle
*/
void HAL_CAN_OpenStreamSession(uint32_t* sessionHandle, uint32_t messageID,
uint32_t messageIDMask, uint32_t maxMessages,
int32_t* status);
HAL_CANStreamHandle HAL_CAN_OpenStreamSession(int32_t busId, uint32_t messageId,
uint32_t messageIDMask,
uint32_t maxMessages,
int32_t* status);
/**
* Closes a CAN stream.
*
* @param sessionHandle the session to close
*/
void HAL_CAN_CloseStreamSession(uint32_t sessionHandle);
void HAL_CAN_CloseStreamSession(HAL_CANStreamHandle sessionHandle);
/**
* Reads a CAN stream message.
@@ -141,7 +123,7 @@ void HAL_CAN_CloseStreamSession(uint32_t sessionHandle);
* @param[out] messagesRead the number of messages actually read
* @param[out] status Error status variable. 0 on success.
*/
void HAL_CAN_ReadStreamSession(uint32_t sessionHandle,
void HAL_CAN_ReadStreamSession(HAL_CANStreamHandle sessionHandle,
struct HAL_CANStreamMessage* messages,
uint32_t messagesToRead, uint32_t* messagesRead,
int32_t* status);

View File

@@ -6,6 +6,7 @@
#include <stdint.h>
#include "hal/CAN.h"
#include "hal/CANAPITypes.h"
#include "hal/Types.h"
@@ -19,28 +20,20 @@
extern "C" {
#endif
/**
* Reads the current value of the millisecond-resolution timer that the CAN API
* functions use as a time base.
*
* @return Current value of timer used as a base time by the CAN API in
* milliseconds.
*/
uint32_t HAL_GetCANPacketBaseTime(void);
/**
* Initializes a CAN device.
*
* These follow the FIRST standard CAN layout.
* https://docs.wpilib.org/en/stable/docs/software/can-devices/can-addressing.html
*
* @param[in] busId the bus id
* @param[in] manufacturer the can manufacturer
* @param[in] deviceId the device ID (0-63)
* @param[in] deviceType the device type
* @param[out] status Error status variable. 0 on success.
* @return the created CAN handle
*/
HAL_CANHandle HAL_InitializeCAN(HAL_CANManufacturer manufacturer,
HAL_CANHandle HAL_InitializeCAN(int32_t busId, HAL_CANManufacturer manufacturer,
int32_t deviceId, HAL_CANDeviceType deviceType,
int32_t* status);
@@ -57,30 +50,28 @@ void HAL_CleanCAN(HAL_CANHandle handle);
* This ID is 10 bits.
*
* @param[in] handle the CAN handle
* @param[in] data the data to write (0-8 bytes)
* @param[in] length the length of data (0-8)
* @param[in] apiId the ID to write (0-1023 bits)
* @param[in] apiId the ID to write (0-1023)
* @param[in] message the message
* @param[out] status Error status variable. 0 on success.
*/
void HAL_WriteCANPacket(HAL_CANHandle handle, const uint8_t* data,
int32_t length, int32_t apiId, int32_t* status);
void HAL_WriteCANPacket(HAL_CANHandle handle, int32_t apiId,
const struct HAL_CANMessage* message, int32_t* status);
/**
* Writes 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
* The device will automatically repeat the packet at the specified interval
*
* @param[in] handle the CAN handle
* @param[in] data the data to write (0-8 bytes)
* @param[in] length the length of data (0-8)
* @param[in] apiId the ID to write (0-1023)
* @param[in] message the message
* @param[in] repeatMs the period to repeat in ms
* @param[out] status Error status variable. 0 on success.
*/
void HAL_WriteCANPacketRepeating(HAL_CANHandle handle, const uint8_t* data,
int32_t length, int32_t apiId,
void HAL_WriteCANPacketRepeating(HAL_CANHandle handle, int32_t apiId,
const struct HAL_CANMessage* message,
int32_t repeatMs, int32_t* status);
/**
@@ -91,11 +82,12 @@ void HAL_WriteCANPacketRepeating(HAL_CANHandle handle, const uint8_t* data,
* otherwise behavior is unspecified.
*
* @param[in] handle the CAN handle
* @param[in] length the length of data to request (0-8)
* @param[in] apiId the ID to write (0-1023)
* @param[in] message the message
* @param[out] status Error status variable. 0 on success.
*/
void HAL_WriteCANRTRFrame(HAL_CANHandle handle, int32_t length, int32_t apiId,
void HAL_WriteCANRTRFrame(HAL_CANHandle handle, int32_t apiId,
const struct HAL_CANMessage* message,
int32_t* status);
/**
@@ -116,32 +108,26 @@ void HAL_StopCANPacketRepeating(HAL_CANHandle handle, int32_t apiId,
* This will only return properly once per packet received. Multiple calls
* without receiving another packet will return an error code.
*
* @param[in] handle the CAN handle
* @param[in] apiId the ID to read (0-1023)
* @param[out] data the packet data (8 bytes)
* @param[out] length the received length (0-8 bytes)
* @param[out] receivedTimestamp the packet received timestamp in ms (based off
* of CLOCK_MONOTONIC)
* @param[out] status Error status variable. 0 on success.
* @param[in] handle the CAN handle
* @param[in] apiId the ID to read (0-1023)
* @param[out] message the message received.
* @param[out] status Error status variable. 0 on success.
*/
void HAL_ReadCANPacketNew(HAL_CANHandle handle, int32_t apiId, uint8_t* data,
int32_t* length, uint64_t* receivedTimestamp,
void HAL_ReadCANPacketNew(HAL_CANHandle handle, int32_t apiId,
struct HAL_CANReceiveMessage* message,
int32_t* status);
/**
* Reads a CAN packet. The will continuously return the last packet received,
* without accounting for packet age.
*
* @param[in] handle the CAN handle
* @param[in] apiId the ID to read (0-1023)
* @param[out] data the packet data (8 bytes)
* @param[out] length the received length (0-8 bytes)
* @param[out] receivedTimestamp the packet received timestamp in ms (based off
* of CLOCK_MONOTONIC)
* @param[out] status Error status variable. 0 on success.
* @param[in] handle the CAN handle
* @param[in] apiId the ID to read (0-1023)
* @param[out] message the message received.
* @param[out] status Error status variable. 0 on success.
*/
void HAL_ReadCANPacketLatest(HAL_CANHandle handle, int32_t apiId, uint8_t* data,
int32_t* length, uint64_t* receivedTimestamp,
void HAL_ReadCANPacketLatest(HAL_CANHandle handle, int32_t apiId,
struct HAL_CANReceiveMessage* message,
int32_t* status);
/**
@@ -149,19 +135,15 @@ void HAL_ReadCANPacketLatest(HAL_CANHandle handle, int32_t apiId, uint8_t* data,
* packet is older then the requested timeout. Then it will return an error
* code.
*
* @param[in] handle the CAN handle
* @param[in] apiId the ID to read (0-1023)
* @param[out] data the packet data (8 bytes)
* @param[out] length the received length (0-8 bytes)
* @param[out] receivedTimestamp the packet received timestamp in ms (based off
* of CLOCK_MONOTONIC)
* @param[out] timeoutMs the timeout time for the packet
* @param[out] status Error status variable. 0 on success.
* @param[in] handle the CAN handle
* @param[in] apiId the ID to read (0-1023)
* @param[out] message the message received.
* @param[out] timeoutMs the timeout time for the packet
* @param[out] status Error status variable. 0 on success.
*/
void HAL_ReadCANPacketTimeout(HAL_CANHandle handle, int32_t apiId,
uint8_t* data, int32_t* length,
uint64_t* receivedTimestamp, int32_t timeoutMs,
int32_t* status);
struct HAL_CANReceiveMessage* message,
int32_t timeoutMs, int32_t* status);
#ifdef __cplusplus
} // extern "C"

View File

@@ -91,4 +91,54 @@ HAL_ENUM(HAL_CANManufacturer) {
/// Vivid-Hosting.
HAL_CAN_Man_kVividHosting = 16
};
/**
* Flag for sending a CAN message once.
*/
#define HAL_CAN_SEND_PERIOD_NO_REPEAT 0
/**
* Flag for stopping periodic CAN message sends.
*/
#define HAL_CAN_SEND_PERIOD_STOP_REPEATING -1
/**
* Mask for "is frame remote" in message ID.
*/
#define HAL_CAN_IS_FRAME_REMOTE 0x40000000
/**
* Mask for "is frame 11 bits" in message ID.
*/
#define HAL_CAN_IS_FRAME_11BIT 0x80000000
HAL_ENUM(HAL_CANFlags) {
/** Placeholder for no flags */
HAL_CAN_NO_FLAGS = 0x0,
/**
* Mask for if frame will do FD bit rate switching.
* Only matters to send.
*/
HAL_CAN_FD_BITRATESWITCH = 0x1,
/**
* Mask for is frame will contain an FD length.
*/
HAL_CAN_FD_DATALENGTH = 0x2,
};
struct HAL_CANMessage {
/** Flags for the message (HAL_CANFlags) */
int32_t flags;
/** The size of the data received (0-64 bytes) */
uint8_t dataSize;
/** The message data */
uint8_t data[64];
};
struct HAL_CANReceiveMessage {
/** Receive timestamp (wpi time) */
uint64_t timeStamp;
/** The received message */
struct HAL_CANMessage message;
};
/** @} */

View File

@@ -21,13 +21,14 @@ extern "C" {
/**
* Initializes a PCM.
*
* @param[in] busId the CAN bus ID
* @param[in] module the CAN ID to initialize
* @param[in] allocationLocation the location where the allocation is occurring
* (can be null)
* @param[out] status Error status variable. 0 on success.
* @return the created PH handle
*/
HAL_CTREPCMHandle HAL_InitializeCTREPCM(int32_t module,
HAL_CTREPCMHandle HAL_InitializeCTREPCM(int32_t busId, int32_t module,
const char* allocationLocation,
int32_t* status);

View File

@@ -16,6 +16,13 @@
extern "C" {
#endif
/**
* Gets the number of can buses in the current system.
*
* @return the number of can buses
*/
int32_t HAL_GetNumCanBuses(void);
/**
* Gets the number of analog inputs in the current system.
*

View File

@@ -37,6 +37,7 @@ extern "C" {
/**
* Initializes a Power Distribution Panel.
*
* @param[in] busId the bus id
* @param[in] moduleNumber the module number to initialize
* @param[in] type the type of module to initialize
* @param[in] allocationLocation the location where the allocation is occurring
@@ -44,7 +45,7 @@ extern "C" {
* @return the created PowerDistribution handle
*/
HAL_PowerDistributionHandle HAL_InitializePowerDistribution(
int32_t moduleNumber, HAL_PowerDistributionType type,
int32_t busId, int32_t moduleNumber, HAL_PowerDistributionType type,
const char* allocationLocation, int32_t* status);
/**
@@ -412,7 +413,7 @@ void HAL_StartPowerDistributionStream(HAL_PowerDistributionHandle handle,
typedef struct HAL_PowerDistributionChannelData {
float current;
int32_t channel;
uint32_t timestamp;
uint64_t timestamp;
} HAL_PowerDistributionChannelData;
HAL_PowerDistributionChannelData* HAL_GetPowerDistributionStreamData(

View File

@@ -137,13 +137,14 @@ extern "C" {
/**
* Initializes a PH.
*
* @param[in] busId the bus id
* @param[in] module the CAN ID to initialize
* @param[in] allocationLocation the location where the allocation is occurring
* (can be null)
* @param[out] status Error status variable. 0 on success.
* @return the created PH handle
*/
HAL_REVPHHandle HAL_InitializeREVPH(int32_t module,
HAL_REVPHHandle HAL_InitializeREVPH(int32_t busId, int32_t module,
const char* allocationLocation,
int32_t* status);

View File

@@ -68,6 +68,8 @@ typedef HAL_Handle HAL_REVPDHHandle;
typedef HAL_Handle HAL_REVPHHandle;
typedef HAL_Handle HAL_CANStreamHandle;
typedef int32_t HAL_Bool;
#ifdef __cplusplus

View File

@@ -8,31 +8,29 @@
#include "hal/Value.h"
#include "hal/simulation/NotifyListener.h"
typedef void (*HAL_CAN_SendMessageCallback)(const char* name, void* param,
uint32_t messageID,
const uint8_t* data,
uint8_t dataSize, int32_t periodMs,
int32_t* status);
typedef void (*HAL_CAN_SendMessageCallback)(
const char* name, void* param, int32_t busId, uint32_t messageId,
const struct HAL_CANMessage* message, int32_t periodMs, int32_t* status);
typedef void (*HAL_CAN_ReceiveMessageCallback)(
const char* name, void* param, uint32_t* messageID, uint32_t messageIDMask,
uint8_t* data, uint8_t* dataSize, uint32_t* timeStamp, int32_t* status);
const char* name, void* param, int32_t busId, uint32_t messageId,
struct HAL_CANReceiveMessage* message, int32_t* status);
typedef void (*HAL_CAN_OpenStreamSessionCallback)(
const char* name, void* param, uint32_t* sessionHandle, uint32_t messageID,
uint32_t messageIDMask, uint32_t maxMessages, int32_t* status);
const char* name, void* param, HAL_CANStreamHandle* streamHandle,
int32_t busId, uint32_t messageId, uint32_t messageIDMask,
uint32_t maxMessages, int32_t* status);
typedef void (*HAL_CAN_CloseStreamSessionCallback)(const char* name,
void* param,
uint32_t sessionHandle);
typedef void (*HAL_CAN_CloseStreamSessionCallback)(
const char* name, void* param, HAL_CANStreamHandle sessionHandle);
typedef void (*HAL_CAN_ReadStreamSessionCallback)(
const char* name, void* param, uint32_t sessionHandle,
const char* name, void* param, HAL_CANStreamHandle sessionHandle,
struct HAL_CANStreamMessage* messages, uint32_t messagesToRead,
uint32_t* messagesRead, int32_t* status);
typedef void (*HAL_CAN_GetCANStatusCallback)(
const char* name, void* param, float* percentBusUtilization,
const char* name, void* param, int32_t busId, float* percentBusUtilization,
uint32_t* busOffCount, uint32_t* txFullCount, uint32_t* receiveErrorCount,
uint32_t* transmitErrorCount, int32_t* status);

View File

@@ -14,45 +14,50 @@ void InitializeCAN() {}
extern "C" {
void HAL_CAN_SendMessage(uint32_t messageID, const uint8_t* data,
uint8_t dataSize, int32_t periodMs, int32_t* status) {
SimCanData->sendMessage(messageID, data, dataSize, periodMs, status);
void HAL_CAN_SendMessage(int32_t busId, uint32_t messageId,
const struct HAL_CANMessage* message, int32_t periodMs,
int32_t* status) {
SimCanData->sendMessage(busId, messageId, message, periodMs, status);
}
void HAL_CAN_ReceiveMessage(uint32_t* messageID, uint32_t messageIDMask,
uint8_t* data, uint8_t* dataSize,
uint32_t* timeStamp, int32_t* status) {
// Use a data size of 42 as call check. Difficult to add check to invoke
void HAL_CAN_ReceiveMessage(int32_t busId, uint32_t messageId,
struct HAL_CANReceiveMessage* message,
int32_t* status) {
// Use a data size of 100 as call check. Difficult to add check to invoke
// handler
*dataSize = 42;
message->message.dataSize = 100;
auto tmpStatus = *status;
SimCanData->receiveMessage(messageID, messageIDMask, data, dataSize,
timeStamp, status);
SimCanData->receiveMessage(busId, messageId, message, status);
// If no handler invoked, return message not found
if (*dataSize == 42 && *status == tmpStatus) {
if (message->message.dataSize == 100 && *status == tmpStatus) {
*status = HAL_ERR_CANSessionMux_MessageNotFound;
}
}
void HAL_CAN_OpenStreamSession(uint32_t* sessionHandle, uint32_t messageID,
uint32_t messageIDMask, uint32_t maxMessages,
int32_t* status) {
SimCanData->openStreamSession(sessionHandle, messageID, messageIDMask,
HAL_CANStreamHandle HAL_CAN_OpenStreamSession(int32_t busId, uint32_t messageId,
uint32_t messageIDMask,
uint32_t maxMessages,
int32_t* status) {
HAL_CANStreamHandle handle = 0;
SimCanData->openStreamSession(&handle, busId, messageId, messageIDMask,
maxMessages, status);
return handle;
}
void HAL_CAN_CloseStreamSession(uint32_t sessionHandle) {
void HAL_CAN_CloseStreamSession(HAL_CANStreamHandle sessionHandle) {
SimCanData->closeStreamSession(sessionHandle);
}
void HAL_CAN_ReadStreamSession(uint32_t sessionHandle,
void HAL_CAN_ReadStreamSession(HAL_CANStreamHandle sessionHandle,
struct HAL_CANStreamMessage* messages,
uint32_t messagesToRead, uint32_t* messagesRead,
int32_t* status) {
SimCanData->readStreamSession(sessionHandle, messages, messagesToRead,
messagesRead, status);
}
void HAL_CAN_GetCANStatus(float* percentBusUtilization, uint32_t* busOffCount,
uint32_t* txFullCount, uint32_t* receiveErrorCount,
void HAL_CAN_GetCANStatus(int32_t busId, float* percentBusUtilization,
uint32_t* busOffCount, uint32_t* txFullCount,
uint32_t* receiveErrorCount,
uint32_t* transmitErrorCount, int32_t* status) {
SimCanData->getCANStatus(percentBusUtilization, busOffCount, txFullCount,
receiveErrorCount, transmitErrorCount, status);
SimCanData->getCANStatus(busId, percentBusUtilization, busOffCount,
txFullCount, receiveErrorCount, transmitErrorCount,
status);
}
} // extern "C"

View File

@@ -4,34 +4,31 @@
#include "hal/CANAPI.h"
#include <ctime>
#include <memory>
#include <wpi/DenseMap.h>
#include <wpi/mutex.h>
#include <wpi/timestamp.h>
#include "CANAPIInternal.h"
#include "HALInitializer.h"
#include "PortsInternal.h"
#include "hal/CAN.h"
#include "hal/Errors.h"
#include "hal/HALBase.h"
#include "hal/handles/UnlimitedHandleResource.h"
using namespace hal;
namespace {
struct Receives {
uint64_t lastTimeStamp;
uint8_t data[8];
uint8_t length;
};
struct CANStorage {
HAL_CANManufacturer manufacturer;
HAL_CANDeviceType deviceType;
int32_t busId;
uint8_t deviceId;
wpi::mutex periodicSendsMutex;
wpi::SmallDenseMap<int32_t, int32_t> periodicSends;
wpi::mutex receivesMutex;
wpi::SmallDenseMap<int32_t, Receives> receives;
wpi::SmallDenseMap<int32_t, HAL_CANReceiveMessage> receives;
};
} // namespace
@@ -66,18 +63,19 @@ static int32_t CreateCANId(CANStorage* storage, int32_t apiId) {
createdId |= (storage->deviceId & 0x3F);
return createdId;
}
extern "C" {
uint32_t HAL_GetCANPacketBaseTime(void) {
int status = 0;
auto basetime = HAL_GetFPGATime(&status);
// us to ms
return (basetime / 1000ull) & 0xFFFFFFFF;
}
HAL_CANHandle HAL_InitializeCAN(HAL_CANManufacturer manufacturer,
extern "C" {
HAL_CANHandle HAL_InitializeCAN(int32_t busId, HAL_CANManufacturer manufacturer,
int32_t deviceId, HAL_CANDeviceType deviceType,
int32_t* status) {
hal::init::CheckInit();
if (busId < 0 || busId > hal::kNumCanBuses) {
*status = PARAMETER_OUT_OF_RANGE;
return HAL_kInvalidHandle;
}
auto can = std::make_shared<CANStorage>();
auto handle = canHandles->Allocate(can);
@@ -87,6 +85,7 @@ HAL_CANHandle HAL_InitializeCAN(HAL_CANManufacturer manufacturer,
return HAL_kInvalidHandle;
}
can->busId = busId;
can->deviceId = deviceId;
can->deviceType = deviceType;
can->manufacturer = manufacturer;
@@ -105,13 +104,16 @@ void HAL_CleanCAN(HAL_CANHandle handle) {
for (auto&& i : data->periodicSends) {
int32_t s = 0;
auto id = CreateCANId(data.get(), i.first);
HAL_CAN_SendMessage(id, nullptr, 0, HAL_CAN_SEND_PERIOD_STOP_REPEATING, &s);
HAL_CANMessage message;
std::memset(&message, 0, sizeof(message));
HAL_CAN_SendMessage(data->busId, id, &message,
HAL_CAN_SEND_PERIOD_STOP_REPEATING, &s);
i.second = -1;
}
}
void HAL_WriteCANPacket(HAL_CANHandle handle, const uint8_t* data,
int32_t length, int32_t apiId, int32_t* status) {
void HAL_WriteCANPacket(HAL_CANHandle handle, int32_t apiId,
const struct HAL_CANMessage* message, int32_t* status) {
auto can = canHandles->Get(handle);
if (!can) {
*status = HAL_HANDLE_ERROR;
@@ -120,12 +122,13 @@ void HAL_WriteCANPacket(HAL_CANHandle handle, const uint8_t* data,
auto id = CreateCANId(can.get(), apiId);
std::scoped_lock lock(can->periodicSendsMutex);
HAL_CAN_SendMessage(id, data, length, HAL_CAN_SEND_PERIOD_NO_REPEAT, status);
HAL_CAN_SendMessage(can->busId, id, message, HAL_CAN_SEND_PERIOD_NO_REPEAT,
status);
can->periodicSends[apiId] = -1;
}
void HAL_WriteCANPacketRepeating(HAL_CANHandle handle, const uint8_t* data,
int32_t length, int32_t apiId,
void HAL_WriteCANPacketRepeating(HAL_CANHandle handle, int32_t apiId,
const struct HAL_CANMessage* message,
int32_t repeatMs, int32_t* status) {
auto can = canHandles->Get(handle);
if (!can) {
@@ -135,11 +138,12 @@ void HAL_WriteCANPacketRepeating(HAL_CANHandle handle, const uint8_t* data,
auto id = CreateCANId(can.get(), apiId);
std::scoped_lock lock(can->periodicSendsMutex);
HAL_CAN_SendMessage(id, data, length, repeatMs, status);
HAL_CAN_SendMessage(can->busId, id, message, repeatMs, status);
can->periodicSends[apiId] = repeatMs;
}
void HAL_WriteCANRTRFrame(HAL_CANHandle handle, int32_t length, int32_t apiId,
void HAL_WriteCANRTRFrame(HAL_CANHandle handle, int32_t apiId,
const struct HAL_CANMessage* message,
int32_t* status) {
auto can = canHandles->Get(handle);
if (!can) {
@@ -148,11 +152,10 @@ void HAL_WriteCANRTRFrame(HAL_CANHandle handle, int32_t length, int32_t apiId,
}
auto id = CreateCANId(can.get(), apiId);
id |= HAL_CAN_IS_FRAME_REMOTE;
uint8_t data[8];
std::memset(data, 0, sizeof(data));
std::scoped_lock lock(can->periodicSendsMutex);
HAL_CAN_SendMessage(id, data, length, HAL_CAN_SEND_PERIOD_NO_REPEAT, status);
HAL_CAN_SendMessage(can->busId, id, message, HAL_CAN_SEND_PERIOD_NO_REPEAT,
status);
can->periodicSends[apiId] = -1;
}
@@ -165,14 +168,17 @@ void HAL_StopCANPacketRepeating(HAL_CANHandle handle, int32_t apiId,
}
auto id = CreateCANId(can.get(), apiId);
HAL_CANMessage message;
std::memset(&message, 0, sizeof(message));
std::scoped_lock lock(can->periodicSendsMutex);
HAL_CAN_SendMessage(id, nullptr, 0, HAL_CAN_SEND_PERIOD_STOP_REPEATING,
status);
HAL_CAN_SendMessage(can->busId, id, &message,
HAL_CAN_SEND_PERIOD_STOP_REPEATING, status);
can->periodicSends[apiId] = -1;
}
void HAL_ReadCANPacketNew(HAL_CANHandle handle, int32_t apiId, uint8_t* data,
int32_t* length, uint64_t* receivedTimestamp,
void HAL_ReadCANPacketNew(HAL_CANHandle handle, int32_t apiId,
struct HAL_CANReceiveMessage* message,
int32_t* status) {
auto can = canHandles->Get(handle);
if (!can) {
@@ -181,24 +187,17 @@ void HAL_ReadCANPacketNew(HAL_CANHandle handle, int32_t apiId, uint8_t* data,
}
uint32_t messageId = CreateCANId(can.get(), apiId);
uint8_t dataSize = 0;
uint32_t ts = 0;
HAL_CAN_ReceiveMessage(&messageId, 0x1FFFFFFF, data, &dataSize, &ts, status);
HAL_CAN_ReceiveMessage(can->busId, messageId, message, status);
if (*status == 0) {
std::scoped_lock lock(can->receivesMutex);
auto& msg = can->receives[messageId];
msg.length = dataSize;
msg.lastTimeStamp = ts;
// The NetComm call placed in data, copy into the msg
std::memcpy(msg.data, data, dataSize);
can->receives[messageId] = *message;
}
*length = dataSize;
*receivedTimestamp = ts;
}
void HAL_ReadCANPacketLatest(HAL_CANHandle handle, int32_t apiId, uint8_t* data,
int32_t* length, uint64_t* receivedTimestamp,
void HAL_ReadCANPacketLatest(HAL_CANHandle handle, int32_t apiId,
struct HAL_CANReceiveMessage* message,
int32_t* status) {
auto can = canHandles->Get(handle);
if (!can) {
@@ -207,36 +206,26 @@ void HAL_ReadCANPacketLatest(HAL_CANHandle handle, int32_t apiId, uint8_t* data,
}
uint32_t messageId = CreateCANId(can.get(), apiId);
uint8_t dataSize = 0;
uint32_t ts = 0;
HAL_CAN_ReceiveMessage(&messageId, 0x1FFFFFFF, data, &dataSize, &ts, status);
HAL_CAN_ReceiveMessage(can->busId, messageId, message, status);
std::scoped_lock lock(can->receivesMutex);
if (*status == 0) {
// fresh update
auto& msg = can->receives[messageId];
msg.length = dataSize;
*length = dataSize;
msg.lastTimeStamp = ts;
*receivedTimestamp = ts;
// The NetComm call placed in data, copy into the msg
std::memcpy(msg.data, data, dataSize);
can->receives[messageId] = *message;
} else {
auto i = can->receives.find(messageId);
if (i != can->receives.end()) {
// Read the data from the stored message into the output
std::memcpy(data, i->second.data, i->second.length);
*length = i->second.length;
*receivedTimestamp = i->second.lastTimeStamp;
*message = i->second;
*status = 0;
}
}
}
void HAL_ReadCANPacketTimeout(HAL_CANHandle handle, int32_t apiId,
uint8_t* data, int32_t* length,
uint64_t* receivedTimestamp, int32_t timeoutMs,
int32_t* status) {
struct HAL_CANReceiveMessage* message,
int32_t timeoutMs, int32_t* status) {
auto can = canHandles->Get(handle);
if (!can) {
*status = HAL_HANDLE_ERROR;
@@ -244,36 +233,43 @@ void HAL_ReadCANPacketTimeout(HAL_CANHandle handle, int32_t apiId,
}
uint32_t messageId = CreateCANId(can.get(), apiId);
uint8_t dataSize = 0;
uint32_t ts = 0;
HAL_CAN_ReceiveMessage(&messageId, 0x1FFFFFFF, data, &dataSize, &ts, status);
HAL_CAN_ReceiveMessage(can->busId, messageId, message, status);
std::scoped_lock lock(can->receivesMutex);
if (*status == 0) {
// fresh update
auto& msg = can->receives[messageId];
msg.length = dataSize;
*length = dataSize;
msg.lastTimeStamp = ts;
*receivedTimestamp = ts;
// The NetComm call placed in data, copy into the msg
std::memcpy(msg.data, data, dataSize);
can->receives[messageId] = *message;
} else {
auto i = can->receives.find(messageId);
if (i != can->receives.end()) {
// Found, check if new enough
uint32_t now = HAL_GetCANPacketBaseTime();
if (now - i->second.lastTimeStamp > static_cast<uint32_t>(timeoutMs)) {
uint64_t now = wpi::Now();
if (now - i->second.timeStamp >
(static_cast<uint64_t>(timeoutMs) * 1000)) {
// Timeout, return bad status
*status = HAL_CAN_TIMEOUT;
return;
}
// Read the data from the stored message into the output
std::memcpy(data, i->second.data, i->second.length);
*length = i->second.length;
*receivedTimestamp = i->second.lastTimeStamp;
*message = i->second;
*status = 0;
}
}
}
uint32_t HAL_StartCANStream(HAL_CANHandle handle, int32_t apiId, int32_t depth,
int32_t* status) {
auto can = canHandles->Get(handle);
if (!can) {
*status = HAL_HANDLE_ERROR;
return 0;
}
uint32_t messageId = CreateCANId(can.get(), apiId);
uint32_t session = HAL_CAN_OpenStreamSession(can->busId, messageId,
0x1FFFFFFF, depth, status);
return session;
}
} // extern "C"

View File

@@ -35,7 +35,7 @@ void InitializeCTREPCM() {
}
} // namespace hal::init
HAL_CTREPCMHandle HAL_InitializeCTREPCM(int32_t module,
HAL_CTREPCMHandle HAL_InitializeCTREPCM(int32_t busId, int32_t module,
const char* allocationLocation,
int32_t* status) {
hal::init::CheckInit();

View File

@@ -13,6 +13,9 @@ void InitializePorts() {}
} // namespace hal::init
extern "C" {
int32_t HAL_GetNumCanBuses(void) {
return kNumCanBuses;
}
int32_t HAL_GetNumAnalogInputs(void) {
return kNumAnalogInputs;
}

View File

@@ -7,6 +7,7 @@
#include <stdint.h>
namespace hal {
constexpr int32_t kNumCanBuses = 2;
constexpr int32_t kAccelerometers = 1;
constexpr int32_t kNumAccumulators = 2;
constexpr int32_t kNumAnalogInputs = 8;

View File

@@ -28,7 +28,7 @@ void InitializePowerDistribution() {}
extern "C" {
HAL_PowerDistributionHandle HAL_InitializePowerDistribution(
int32_t module, HAL_PowerDistributionType type,
int32_t busId, int32_t module, HAL_PowerDistributionType type,
const char* allocationLocation, int32_t* status) {
if (type == HAL_PowerDistributionType_kAutomatic) {
if (module != HAL_DEFAULT_POWER_DISTRIBUTION_MODULE) {
@@ -56,7 +56,8 @@ HAL_PowerDistributionHandle HAL_InitializePowerDistribution(
}
hal::init::CheckInit();
SimPowerDistributionData[module].initialized = true;
auto handle = HAL_InitializeCAN(manufacturer, module, deviceType, status);
auto handle =
HAL_InitializeCAN(busId, manufacturer, module, deviceType, status);
if (*status != 0) {
HAL_CleanCAN(handle);

View File

@@ -35,7 +35,7 @@ void InitializeREVPH() {
}
} // namespace hal::init
HAL_REVPHHandle HAL_InitializeREVPH(int32_t module,
HAL_REVPHHandle HAL_InitializeREVPH(int32_t busId, int32_t module,
const char* allocationLocation,
int32_t* status) {
hal::init::CheckInit();

View File

@@ -21,14 +21,13 @@
#include <wpi/mutex.h>
#include <wpi/timestamp.h>
#include "PortsInternal.h"
#include "hal/Errors.h"
#include "hal/Threads.h"
#include "wpinet/EventLoopRunner.h"
#include "wpinet/uv/Poll.h"
#include "wpinet/uv/Timer.h"
#define NUM_CAN_BUSES 1
namespace {
static constexpr uint32_t MatchingBitMask = CAN_EFF_MASK | CAN_RTR_FLAG;
@@ -68,20 +67,21 @@ struct FrameStore {
struct SocketCanState {
wpi::EventLoopRunner readLoopRunner;
wpi::EventLoopRunner writeLoopRunner;
wpi::mutex writeMutex[NUM_CAN_BUSES];
int socketHandle[NUM_CAN_BUSES];
wpi::mutex writeMutex[hal::kNumCanBuses];
int socketHandle[hal::kNumCanBuses];
// ms to count/timer map
wpi::DenseMap<uint16_t, std::pair<size_t, std::weak_ptr<wpi::uv::Timer>>>
timers;
// ms to bus mask/packet
wpi::DenseMap<uint16_t, std::array<std::optional<canfd_frame>, NUM_CAN_BUSES>>
wpi::DenseMap<uint16_t,
std::array<std::optional<canfd_frame>, hal::kNumCanBuses>>
timedFrames;
// packet to time
wpi::DenseMap<uint32_t, std::array<uint16_t, NUM_CAN_BUSES>> packetToTime;
wpi::DenseMap<uint32_t, std::array<uint16_t, hal::kNumCanBuses>> packetToTime;
wpi::mutex readMutex[NUM_CAN_BUSES];
wpi::mutex readMutex[hal::kNumCanBuses];
// TODO(thadhouse) we need a MUCH better way of doing this masking
wpi::DenseMap<uint32_t, FrameStore> readFrames[NUM_CAN_BUSES];
wpi::DenseMap<uint32_t, FrameStore> readFrames[hal::kNumCanBuses];
bool InitializeBuses();
@@ -111,7 +111,7 @@ bool SocketCanState::InitializeBuses() {
std::printf("Failed to set CAN thread priority\n");
}
for (int i = 0; i < NUM_CAN_BUSES; i++) {
for (int i = 0; i < hal::kNumCanBuses; i++) {
std::scoped_lock lock{writeMutex[i]};
socketHandle[i] = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if (socketHandle[i] == -1) {
@@ -240,23 +240,21 @@ namespace {} // namespace
extern "C" {
void HAL_CAN_SendMessage(uint32_t messageID, const uint8_t* data,
uint8_t dataSize, int32_t periodMs, int32_t* status) {
// TODO(thadhouse) this will become a parameter
// isFd will also be a part of this parameter
uint8_t busId = 0;
if (busId >= NUM_CAN_BUSES) {
void HAL_CAN_SendMessage(int32_t busId, uint32_t messageId,
const struct HAL_CANMessage* message, int32_t periodMs,
int32_t* status) {
if (busId < 0 || busId >= hal::kNumCanBuses) {
*status = PARAMETER_OUT_OF_RANGE;
return;
}
bool isFd = false;
messageID = MapMessageIdToSocketCan(messageID);
messageId = MapMessageIdToSocketCan(messageId);
// TODO determine on the real roborio is a non periodic send removes any
// periodic send.
if (periodMs == HAL_CAN_SEND_PERIOD_STOP_REPEATING) {
canState->writeLoopRunner.ExecSync([messageID, busId](wpi::uv::Loop&) {
canState->RemovePeriodic(busId, messageID);
canState->writeLoopRunner.ExecSync([messageId, busId](wpi::uv::Loop&) {
canState->RemovePeriodic(busId, messageId);
});
*status = 0;
@@ -265,15 +263,20 @@ void HAL_CAN_SendMessage(uint32_t messageID, const uint8_t* data,
canfd_frame frame;
std::memset(&frame, 0, sizeof(frame));
frame.can_id = messageID;
frame.flags = isFd ? CANFD_FDF | CANFD_BRS : 0;
if (dataSize) {
auto size = (std::min)(dataSize, static_cast<uint8_t>(sizeof(frame.data)));
std::memcpy(frame.data, data, size);
frame.can_id = messageId;
frame.flags |=
(message->flags & HAL_CANFlags::HAL_CAN_FD_DATALENGTH) ? CANFD_FDF : 0;
frame.flags |=
(message->flags & HAL_CANFlags::HAL_CAN_FD_BITRATESWITCH) ? CANFD_BRS : 0;
if (message->dataSize) {
auto size =
(std::min)(message->dataSize, static_cast<uint8_t>(sizeof(frame.data)));
std::memcpy(frame.data, message->data, size);
frame.len = size;
}
int mtu = isFd ? CANFD_MTU : CAN_MTU;
int mtu = (message->flags & HAL_CANFlags::HAL_CAN_FD_DATALENGTH) ? CANFD_MTU
: CAN_MTU;
{
std::scoped_lock lock{canState->writeMutex[busId]};
int result = send(canState->socketHandle[busId], &frame, mtu, 0);
@@ -291,70 +294,62 @@ void HAL_CAN_SendMessage(uint32_t messageID, const uint8_t* data,
});
}
}
void HAL_CAN_ReceiveMessage(uint32_t* messageID, uint32_t messageIDMask,
uint8_t* data, uint8_t* dataSize,
uint32_t* timeStamp, int32_t* status) {
uint8_t busId = 0;
if (busId >= NUM_CAN_BUSES) {
void HAL_CAN_ReceiveMessage(int32_t busId, uint32_t messageId,
struct HAL_CANReceiveMessage* message,
int32_t* status) {
if (busId < 0 || busId >= hal::kNumCanBuses) {
message->message.dataSize = 0;
message->timeStamp = 0;
*status = PARAMETER_OUT_OF_RANGE;
return;
}
std::scoped_lock lock{canState->readMutex[busId]};
// TODO(thadhouse) this is going to be wrong, but we're going to assume that
// any lookup without the 11 bit mask set wants to look for a 29 bit frame.
// Also, only do fast lookups for 29 bit frames
// Fast case is the following.
// Mask doesn't include 11 bit flag
// Mask doesn't include RTR flag
// Mask is full
if (messageIDMask == CAN_EFF_MASK) {
// We're doing a fast lookup
auto& msg = canState->readFrames[busId][*messageID];
if (msg.timestamp == 0) {
*status = HAL_ERR_CANSessionMux_MessageNotFound;
return;
}
if ((msg.frame.flags & CANFD_FDF) || msg.frame.len > 8) {
std::printf("FD frames not supported for read right now\n");
*status = HAL_ERR_CANSessionMux_InvalidBuffer;
return;
}
// TODO(thadhouse) this time needs to be fixed up.
*timeStamp = msg.timestamp / 1000;
std::memcpy(data, msg.frame.data, msg.frame.len);
*dataSize = msg.frame.len;
*status = 0;
msg.timestamp = 0;
auto& msg = canState->readFrames[busId][messageId];
if (msg.timestamp == 0) {
message->message.dataSize = 0;
message->timeStamp = 0;
*status = HAL_ERR_CANSessionMux_MessageNotFound;
return;
}
std::printf("Slow lookup not supported yet\n");
message->message.flags = HAL_CANFlags::HAL_CAN_NO_FLAGS;
message->message.flags |= (msg.frame.flags & CANFD_FDF)
? HAL_CANFlags::HAL_CAN_FD_DATALENGTH
: HAL_CANFlags::HAL_CAN_NO_FLAGS;
message->message.flags |= (msg.frame.flags & CANFD_BRS)
? HAL_CANFlags::HAL_CAN_FD_BITRATESWITCH
: HAL_CANFlags::HAL_CAN_NO_FLAGS;
// Add support for slow lookup later
*status = HAL_ERR_CANSessionMux_NotAllowed;
message->message.dataSize = msg.frame.len;
if (msg.frame.len > 0) {
std::memcpy(message->message.data, msg.frame.data, msg.frame.len);
}
message->timeStamp = msg.timestamp;
*status = 0;
msg.timestamp = 0;
return;
}
void HAL_CAN_OpenStreamSession(uint32_t* sessionHandle, uint32_t messageID,
uint32_t messageIDMask, uint32_t maxMessages,
int32_t* status) {
*sessionHandle = 0;
HAL_CANStreamHandle HAL_CAN_OpenStreamSession(int32_t busId, uint32_t messageId,
uint32_t messageIDMask,
uint32_t maxMessages,
int32_t* status) {
*status = HAL_HANDLE_ERROR;
return;
return 0;
}
void HAL_CAN_CloseStreamSession(uint32_t sessionHandle) {}
void HAL_CAN_ReadStreamSession(uint32_t sessionHandle,
void HAL_CAN_CloseStreamSession(HAL_CANStreamHandle sessionHandle) {}
void HAL_CAN_ReadStreamSession(HAL_CANStreamHandle sessionHandle,
struct HAL_CANStreamMessage* messages,
uint32_t messagesToRead, uint32_t* messagesRead,
int32_t* status) {
*status = HAL_HANDLE_ERROR;
return;
}
void HAL_CAN_GetCANStatus(float* percentBusUtilization, uint32_t* busOffCount,
uint32_t* txFullCount, uint32_t* receiveErrorCount,
void HAL_CAN_GetCANStatus(int32_t busId, float* percentBusUtilization,
uint32_t* busOffCount, uint32_t* txFullCount,
uint32_t* receiveErrorCount,
uint32_t* transmitErrorCount, int32_t* status) {
*status = HAL_HANDLE_ERROR;
return;

View File

@@ -12,6 +12,7 @@
#include <wpi/timestamp.h>
#include "HALInitializer.h"
#include "PortsInternal.h"
#include "hal/CAN.h"
#include "hal/Errors.h"
#include "hal/handles/UnlimitedHandleResource.h"
@@ -19,20 +20,15 @@
using namespace hal;
namespace {
struct Receives {
uint32_t lastTimeStamp;
uint8_t data[8];
uint8_t length;
};
struct CANStorage {
HAL_CANManufacturer manufacturer;
HAL_CANDeviceType deviceType;
int32_t busId;
uint8_t deviceId;
wpi::mutex periodicSendsMutex;
wpi::SmallDenseMap<int32_t, int32_t> periodicSends;
wpi::mutex receivesMutex;
wpi::SmallDenseMap<int32_t, Receives> receives;
wpi::SmallDenseMap<int32_t, HAL_CANReceiveMessage> receives;
};
} // namespace
@@ -58,14 +54,16 @@ static int32_t CreateCANId(CANStorage* storage, int32_t apiId) {
extern "C" {
uint32_t HAL_GetCANPacketBaseTime(void) {
return wpi::Now() / 1000;
}
HAL_CANHandle HAL_InitializeCAN(HAL_CANManufacturer manufacturer,
HAL_CANHandle HAL_InitializeCAN(int32_t busId, HAL_CANManufacturer manufacturer,
int32_t deviceId, HAL_CANDeviceType deviceType,
int32_t* status) {
hal::init::CheckInit();
if (busId < 0 || busId > hal::kNumCanBuses) {
*status = PARAMETER_OUT_OF_RANGE;
return HAL_kInvalidHandle;
}
auto can = std::make_shared<CANStorage>();
auto handle = canHandles->Allocate(can);
@@ -75,6 +73,7 @@ HAL_CANHandle HAL_InitializeCAN(HAL_CANManufacturer manufacturer,
return HAL_kInvalidHandle;
}
can->busId = busId;
can->deviceId = deviceId;
can->deviceType = deviceType;
can->manufacturer = manufacturer;
@@ -93,13 +92,16 @@ void HAL_CleanCAN(HAL_CANHandle handle) {
for (auto&& i : data->periodicSends) {
int32_t s = 0;
auto id = CreateCANId(data.get(), i.first);
HAL_CAN_SendMessage(id, nullptr, 0, HAL_CAN_SEND_PERIOD_STOP_REPEATING, &s);
HAL_CANMessage message;
std::memset(&message, 0, sizeof(message));
HAL_CAN_SendMessage(data->busId, id, &message,
HAL_CAN_SEND_PERIOD_STOP_REPEATING, &s);
i.second = -1;
}
}
void HAL_WriteCANPacket(HAL_CANHandle handle, const uint8_t* data,
int32_t length, int32_t apiId, int32_t* status) {
void HAL_WriteCANPacket(HAL_CANHandle handle, int32_t apiId,
const struct HAL_CANMessage* message, int32_t* status) {
auto can = canHandles->Get(handle);
if (!can) {
*status = HAL_HANDLE_ERROR;
@@ -108,12 +110,13 @@ void HAL_WriteCANPacket(HAL_CANHandle handle, const uint8_t* data,
auto id = CreateCANId(can.get(), apiId);
std::scoped_lock lock(can->periodicSendsMutex);
HAL_CAN_SendMessage(id, data, length, HAL_CAN_SEND_PERIOD_NO_REPEAT, status);
HAL_CAN_SendMessage(can->busId, id, message, HAL_CAN_SEND_PERIOD_NO_REPEAT,
status);
can->periodicSends[apiId] = -1;
}
void HAL_WriteCANPacketRepeating(HAL_CANHandle handle, const uint8_t* data,
int32_t length, int32_t apiId,
void HAL_WriteCANPacketRepeating(HAL_CANHandle handle, int32_t apiId,
const struct HAL_CANMessage* message,
int32_t repeatMs, int32_t* status) {
auto can = canHandles->Get(handle);
if (!can) {
@@ -123,11 +126,12 @@ void HAL_WriteCANPacketRepeating(HAL_CANHandle handle, const uint8_t* data,
auto id = CreateCANId(can.get(), apiId);
std::scoped_lock lock(can->periodicSendsMutex);
HAL_CAN_SendMessage(id, data, length, repeatMs, status);
HAL_CAN_SendMessage(can->busId, id, message, repeatMs, status);
can->periodicSends[apiId] = repeatMs;
}
void HAL_WriteCANRTRFrame(HAL_CANHandle handle, int32_t length, int32_t apiId,
void HAL_WriteCANRTRFrame(HAL_CANHandle handle, int32_t apiId,
const struct HAL_CANMessage* message,
int32_t* status) {
auto can = canHandles->Get(handle);
if (!can) {
@@ -136,11 +140,10 @@ void HAL_WriteCANRTRFrame(HAL_CANHandle handle, int32_t length, int32_t apiId,
}
auto id = CreateCANId(can.get(), apiId);
id |= HAL_CAN_IS_FRAME_REMOTE;
uint8_t data[8];
std::memset(data, 0, sizeof(data));
std::scoped_lock lock(can->periodicSendsMutex);
HAL_CAN_SendMessage(id, data, length, HAL_CAN_SEND_PERIOD_NO_REPEAT, status);
HAL_CAN_SendMessage(can->busId, id, message, HAL_CAN_SEND_PERIOD_NO_REPEAT,
status);
can->periodicSends[apiId] = -1;
}
@@ -153,14 +156,17 @@ void HAL_StopCANPacketRepeating(HAL_CANHandle handle, int32_t apiId,
}
auto id = CreateCANId(can.get(), apiId);
HAL_CANMessage message;
std::memset(&message, 0, sizeof(message));
std::scoped_lock lock(can->periodicSendsMutex);
HAL_CAN_SendMessage(id, nullptr, 0, HAL_CAN_SEND_PERIOD_STOP_REPEATING,
status);
HAL_CAN_SendMessage(can->busId, id, &message,
HAL_CAN_SEND_PERIOD_STOP_REPEATING, status);
can->periodicSends[apiId] = -1;
}
void HAL_ReadCANPacketNew(HAL_CANHandle handle, int32_t apiId, uint8_t* data,
int32_t* length, uint64_t* receivedTimestamp,
void HAL_ReadCANPacketNew(HAL_CANHandle handle, int32_t apiId,
struct HAL_CANReceiveMessage* message,
int32_t* status) {
auto can = canHandles->Get(handle);
if (!can) {
@@ -169,24 +175,17 @@ void HAL_ReadCANPacketNew(HAL_CANHandle handle, int32_t apiId, uint8_t* data,
}
uint32_t messageId = CreateCANId(can.get(), apiId);
uint8_t dataSize = 0;
uint32_t ts = 0;
HAL_CAN_ReceiveMessage(&messageId, 0x1FFFFFFF, data, &dataSize, &ts, status);
HAL_CAN_ReceiveMessage(can->busId, messageId, message, status);
if (*status == 0) {
std::scoped_lock lock(can->receivesMutex);
auto& msg = can->receives[messageId];
msg.length = dataSize;
msg.lastTimeStamp = ts;
// The NetComm call placed in data, copy into the msg
std::memcpy(msg.data, data, dataSize);
can->receives[messageId] = *message;
}
*length = dataSize;
*receivedTimestamp = ts;
}
void HAL_ReadCANPacketLatest(HAL_CANHandle handle, int32_t apiId, uint8_t* data,
int32_t* length, uint64_t* receivedTimestamp,
void HAL_ReadCANPacketLatest(HAL_CANHandle handle, int32_t apiId,
struct HAL_CANReceiveMessage* message,
int32_t* status) {
auto can = canHandles->Get(handle);
if (!can) {
@@ -195,36 +194,26 @@ void HAL_ReadCANPacketLatest(HAL_CANHandle handle, int32_t apiId, uint8_t* data,
}
uint32_t messageId = CreateCANId(can.get(), apiId);
uint8_t dataSize = 0;
uint32_t ts = 0;
HAL_CAN_ReceiveMessage(&messageId, 0x1FFFFFFF, data, &dataSize, &ts, status);
HAL_CAN_ReceiveMessage(can->busId, messageId, message, status);
std::scoped_lock lock(can->receivesMutex);
if (*status == 0) {
// fresh update
auto& msg = can->receives[messageId];
msg.length = dataSize;
*length = dataSize;
msg.lastTimeStamp = ts;
*receivedTimestamp = ts;
// The NetComm call placed in data, copy into the msg
std::memcpy(msg.data, data, dataSize);
can->receives[messageId] = *message;
} else {
auto i = can->receives.find(messageId);
if (i != can->receives.end()) {
// Read the data from the stored message into the output
std::memcpy(data, i->second.data, i->second.length);
*length = i->second.length;
*receivedTimestamp = i->second.lastTimeStamp;
*message = i->second;
*status = 0;
}
}
}
void HAL_ReadCANPacketTimeout(HAL_CANHandle handle, int32_t apiId,
uint8_t* data, int32_t* length,
uint64_t* receivedTimestamp, int32_t timeoutMs,
int32_t* status) {
struct HAL_CANReceiveMessage* message,
int32_t timeoutMs, int32_t* status) {
auto can = canHandles->Get(handle);
if (!can) {
*status = HAL_HANDLE_ERROR;
@@ -232,34 +221,26 @@ void HAL_ReadCANPacketTimeout(HAL_CANHandle handle, int32_t apiId,
}
uint32_t messageId = CreateCANId(can.get(), apiId);
uint8_t dataSize = 0;
uint32_t ts = 0;
HAL_CAN_ReceiveMessage(&messageId, 0x1FFFFFFF, data, &dataSize, &ts, status);
HAL_CAN_ReceiveMessage(can->busId, messageId, message, status);
std::scoped_lock lock(can->receivesMutex);
if (*status == 0) {
// fresh update
auto& msg = can->receives[messageId];
msg.length = dataSize;
*length = dataSize;
msg.lastTimeStamp = ts;
*receivedTimestamp = ts;
// The NetComm call placed in data, copy into the msg
std::memcpy(msg.data, data, dataSize);
can->receives[messageId] = *message;
} else {
auto i = can->receives.find(messageId);
if (i != can->receives.end()) {
// Found, check if new enough
uint32_t now = HAL_GetCANPacketBaseTime();
if (now - i->second.lastTimeStamp > static_cast<uint32_t>(timeoutMs)) {
uint64_t now = wpi::Now();
if (now - i->second.timeStamp >
(static_cast<uint64_t>(timeoutMs) * 1000)) {
// Timeout, return bad status
*status = HAL_CAN_TIMEOUT;
return;
}
// Read the data from the stored message into the output
std::memcpy(data, i->second.data, i->second.length);
*length = i->second.length;
*receivedTimestamp = i->second.lastTimeStamp;
*message = i->second;
*status = 0;
}
}
@@ -275,8 +256,8 @@ uint32_t HAL_StartCANStream(HAL_CANHandle handle, int32_t apiId, int32_t depth,
uint32_t messageId = CreateCANId(can.get(), apiId);
uint32_t session = 0;
HAL_CAN_OpenStreamSession(&session, messageId, 0x1FFFFFFF, depth, status);
uint32_t session = HAL_CAN_OpenStreamSession(can->busId, messageId,
0x1FFFFFFF, depth, status);
return session;
}
} // extern "C"

View File

@@ -145,33 +145,37 @@ void InitializeCTREPCM() {
}
} // namespace hal::init
#define READ_PACKET(type, frame, failureValue) \
auto pcm = pcmHandles->Get(handle); \
if (pcm == nullptr) { \
*status = HAL_HANDLE_ERROR; \
return failureValue; \
} \
type pcmStatus; \
int32_t length = 0; \
uint64_t receivedTimestamp = 0; \
HAL_ReadCANPacketTimeout(pcm->canHandle, frame, pcmStatus.data, &length, \
&receivedTimestamp, TimeoutMs, status); \
if (*status != 0) { \
return failureValue; \
}
#define READ_PACKET(type, frame, failureValue) \
auto pcm = pcmHandles->Get(handle); \
if (pcm == nullptr) { \
*status = HAL_HANDLE_ERROR; \
return failureValue; \
} \
HAL_CANReceiveMessage message; \
type pcmStatus; \
HAL_ReadCANPacketTimeout(pcm->canHandle, frame, &message, TimeoutMs, \
status); \
if (*status != 0) { \
return failureValue; \
} \
std::memcpy(pcmStatus.data, message.message.data, sizeof(pcmStatus.data));
#define READ_STATUS(failureValue) READ_PACKET(PcmStatus, Status1, failureValue)
#define READ_SOL_FAULTS(failureValue) \
READ_PACKET(PcmStatusFault, StatusSolFaults, failureValue)
static void SendControl(PCM* pcm, int32_t* status) {
HAL_WriteCANPacketRepeating(pcm->canHandle, pcm->control.data, 8, Control1,
SendPeriod, status);
HAL_CANMessage message;
std::memset(&message, 0, sizeof(message));
message.dataSize = 8;
std::memcpy(message.data, pcm->control.data, 8);
HAL_WriteCANPacketRepeating(pcm->canHandle, Control1, &message, SendPeriod,
status);
}
extern "C" {
HAL_CTREPCMHandle HAL_InitializeCTREPCM(int32_t module,
HAL_CTREPCMHandle HAL_InitializeCTREPCM(int32_t busId, int32_t module,
const char* allocationLocation,
int32_t* status) {
hal::init::CheckInit();
@@ -190,7 +194,8 @@ HAL_CTREPCMHandle HAL_InitializeCTREPCM(int32_t module,
return HAL_kInvalidHandle; // failed to allocate. Pass error back.
}
pcm->canHandle = HAL_InitializeCAN(manufacturer, module, deviceType, status);
pcm->canHandle =
HAL_InitializeCAN(busId, manufacturer, module, deviceType, status);
if (*status != 0) {
pcmHandles->Free(handle);
return HAL_kInvalidHandle;
@@ -344,9 +349,11 @@ void HAL_ClearAllCTREPCMStickyFaults(HAL_CTREPCMHandle handle,
*status = HAL_HANDLE_ERROR;
return;
}
uint8_t controlData[] = {0, 0, 0, 0x80};
HAL_WriteCANPacket(pcm->canHandle, controlData, sizeof(controlData), Control2,
status);
HAL_CANMessage message;
std::memset(&message, 0, sizeof(message));
message.dataSize = 4;
message.data[3] = 0x80;
HAL_WriteCANPacket(pcm->canHandle, Control2, &message, status);
}
void HAL_FireCTREPCMOneShot(HAL_CTREPCMHandle handle, int32_t index,
@@ -397,11 +404,16 @@ void HAL_SetCTREPCMOneShotDuration(HAL_CTREPCMHandle handle, int32_t index,
return;
}
HAL_CANMessage message;
std::memset(&message, 0, sizeof(message));
message.dataSize = 8;
std::scoped_lock lock{pcm->lock};
pcm->oneShot.sol10MsPerUnit[index] = (std::min)(
static_cast<uint32_t>(durMs) / 10, static_cast<uint32_t>(0xFF));
HAL_WriteCANPacketRepeating(pcm->canHandle, pcm->oneShot.sol10MsPerUnit, 8,
Control3, SendPeriod, status);
std::memcpy(message.data, pcm->oneShot.sol10MsPerUnit, 8);
HAL_WriteCANPacketRepeating(pcm->canHandle, Control3, &message, SendPeriod,
status);
}
} // extern "C"

View File

@@ -129,7 +129,8 @@ void InitializeCTREPDP() {
extern "C" {
HAL_PDPHandle HAL_InitializePDP(int32_t module, const char* allocationLocation,
HAL_PDPHandle HAL_InitializePDP(int32_t busId, int32_t module,
const char* allocationLocation,
int32_t* status) {
hal::init::CheckInit();
if (!HAL_CheckPDPModule(module)) {
@@ -153,7 +154,8 @@ HAL_PDPHandle HAL_InitializePDP(int32_t module, const char* allocationLocation,
return HAL_kInvalidHandle; // failed to allocate. Pass error back.
}
pdp->canHandle = HAL_InitializeCAN(manufacturer, module, deviceType, status);
pdp->canHandle =
HAL_InitializeCAN(busId, manufacturer, module, deviceType, status);
if (*status != 0) {
pdpHandles->Free(handle);
return HAL_kInvalidHandle;
@@ -191,16 +193,16 @@ double HAL_GetPDPTemperature(HAL_PDPHandle handle, int32_t* status) {
return 0;
}
HAL_CANReceiveMessage message;
PdpStatus3 pdpStatus;
int32_t length = 0;
uint64_t receivedTimestamp = 0;
HAL_ReadCANPacketTimeout(pdp->canHandle, Status3, pdpStatus.data, &length,
&receivedTimestamp, TimeoutMs, status);
HAL_ReadCANPacketTimeout(pdp->canHandle, Status3, &message, TimeoutMs,
status);
if (*status != 0) {
return 0;
} else {
std::memcpy(pdpStatus.data, message.message.data, sizeof(pdpStatus.data));
return pdpStatus.bits.temp * 1.03250836957542 - 67.8564500484966;
}
}
@@ -212,16 +214,16 @@ double HAL_GetPDPVoltage(HAL_PDPHandle handle, int32_t* status) {
return 0;
}
HAL_CANReceiveMessage message;
PdpStatus3 pdpStatus;
int32_t length = 0;
uint64_t receivedTimestamp = 0;
HAL_ReadCANPacketTimeout(pdp->canHandle, Status3, pdpStatus.data, &length,
&receivedTimestamp, TimeoutMs, status);
HAL_ReadCANPacketTimeout(pdp->canHandle, Status3, &message, TimeoutMs,
status);
if (*status != 0) {
return 0;
} else {
std::memcpy(pdpStatus.data, message.message.data, sizeof(pdpStatus.data));
return pdpStatus.bits.busVoltage * 0.05 + 4.0; /* 50mV per unit plus 4V. */
}
}
@@ -240,18 +242,18 @@ double HAL_GetPDPChannelCurrent(HAL_PDPHandle handle, int32_t channel,
return 0;
}
int32_t length = 0;
uint64_t receivedTimestamp = 0;
HAL_CANReceiveMessage message;
double raw = 0;
if (channel <= 5) {
PdpStatus1 pdpStatus;
HAL_ReadCANPacketTimeout(pdp->canHandle, Status1, pdpStatus.data, &length,
&receivedTimestamp, TimeoutMs, status);
HAL_ReadCANPacketTimeout(pdp->canHandle, Status1, &message, TimeoutMs,
status);
if (*status != 0) {
return 0;
}
std::memcpy(pdpStatus.data, message.message.data, sizeof(pdpStatus.data));
switch (channel) {
case 0:
raw = (static_cast<uint32_t>(pdpStatus.bits.chan1_h8) << 2) |
@@ -280,11 +282,12 @@ double HAL_GetPDPChannelCurrent(HAL_PDPHandle handle, int32_t channel,
}
} else if (channel <= 11) {
PdpStatus2 pdpStatus;
HAL_ReadCANPacketTimeout(pdp->canHandle, Status2, pdpStatus.data, &length,
&receivedTimestamp, TimeoutMs, status);
HAL_ReadCANPacketTimeout(pdp->canHandle, Status2, &message, TimeoutMs,
status);
if (*status != 0) {
return 0;
}
std::memcpy(pdpStatus.data, message.message.data, sizeof(pdpStatus.data));
switch (channel) {
case 6:
raw = (static_cast<uint32_t>(pdpStatus.bits.chan7_h8) << 2) |
@@ -313,11 +316,12 @@ double HAL_GetPDPChannelCurrent(HAL_PDPHandle handle, int32_t channel,
}
} else {
PdpStatus3 pdpStatus;
HAL_ReadCANPacketTimeout(pdp->canHandle, Status3, pdpStatus.data, &length,
&receivedTimestamp, TimeoutMs, status);
HAL_ReadCANPacketTimeout(pdp->canHandle, Status3, &message, TimeoutMs,
status);
if (*status != 0) {
return 0;
}
std::memcpy(pdpStatus.data, message.message.data, sizeof(pdpStatus.data));
switch (channel) {
case 12:
raw = (static_cast<uint32_t>(pdpStatus.bits.chan13_h8) << 2) |
@@ -350,26 +354,28 @@ void HAL_GetPDPAllChannelCurrents(HAL_PDPHandle handle, double* currents,
return;
}
int32_t length = 0;
uint64_t receivedTimestamp = 0;
HAL_CANReceiveMessage message;
PdpStatus1 pdpStatus;
HAL_ReadCANPacketTimeout(pdp->canHandle, Status1, pdpStatus.data, &length,
&receivedTimestamp, TimeoutMs, status);
HAL_ReadCANPacketTimeout(pdp->canHandle, Status1, &message, TimeoutMs,
status);
if (*status != 0) {
return;
}
std::memcpy(pdpStatus.data, message.message.data, sizeof(pdpStatus.data));
PdpStatus2 pdpStatus2;
HAL_ReadCANPacketTimeout(pdp->canHandle, Status2, pdpStatus2.data, &length,
&receivedTimestamp, TimeoutMs, status);
HAL_ReadCANPacketTimeout(pdp->canHandle, Status2, &message, TimeoutMs,
status);
if (*status != 0) {
return;
}
std::memcpy(pdpStatus2.data, message.message.data, sizeof(pdpStatus2.data));
PdpStatus3 pdpStatus3;
HAL_ReadCANPacketTimeout(pdp->canHandle, Status3, pdpStatus3.data, &length,
&receivedTimestamp, TimeoutMs, status);
HAL_ReadCANPacketTimeout(pdp->canHandle, Status3, &message, TimeoutMs,
status);
if (*status != 0) {
return;
}
std::memcpy(pdpStatus3.data, message.message.data, sizeof(pdpStatus3.data));
currents[0] = ((static_cast<uint32_t>(pdpStatus.bits.chan1_h8) << 2) |
pdpStatus.bits.chan1_l2) *
@@ -430,15 +436,15 @@ double HAL_GetPDPTotalCurrent(HAL_PDPHandle handle, int32_t* status) {
return 0;
}
HAL_CANReceiveMessage message;
PdpStatusEnergy pdpStatus;
int32_t length = 0;
uint64_t receivedTimestamp = 0;
HAL_ReadCANPacketTimeout(pdp->canHandle, StatusEnergy, pdpStatus.data,
&length, &receivedTimestamp, TimeoutMs, status);
HAL_ReadCANPacketTimeout(pdp->canHandle, StatusEnergy, &message, TimeoutMs,
status);
if (*status != 0) {
return 0;
}
std::memcpy(pdpStatus.data, message.message.data, sizeof(pdpStatus.data));
uint32_t raw;
raw = pdpStatus.bits.TotalCurrent_125mAperunit_h8;
@@ -454,15 +460,15 @@ double HAL_GetPDPTotalPower(HAL_PDPHandle handle, int32_t* status) {
return 0;
}
HAL_CANReceiveMessage message;
PdpStatusEnergy pdpStatus;
int32_t length = 0;
uint64_t receivedTimestamp = 0;
HAL_ReadCANPacketTimeout(pdp->canHandle, StatusEnergy, pdpStatus.data,
&length, &receivedTimestamp, TimeoutMs, status);
HAL_ReadCANPacketTimeout(pdp->canHandle, StatusEnergy, &message, TimeoutMs,
status);
if (*status != 0) {
return 0;
}
std::memcpy(pdpStatus.data, message.message.data, sizeof(pdpStatus.data));
uint32_t raw;
raw = pdpStatus.bits.Power_125mWperunit_h4;
@@ -480,15 +486,15 @@ double HAL_GetPDPTotalEnergy(HAL_PDPHandle handle, int32_t* status) {
return 0;
}
HAL_CANReceiveMessage message;
PdpStatusEnergy pdpStatus;
int32_t length = 0;
uint64_t receivedTimestamp = 0;
HAL_ReadCANPacketTimeout(pdp->canHandle, StatusEnergy, pdpStatus.data,
&length, &receivedTimestamp, TimeoutMs, status);
HAL_ReadCANPacketTimeout(pdp->canHandle, StatusEnergy, &message, TimeoutMs,
status);
if (*status != 0) {
return 0;
}
std::memcpy(pdpStatus.data, message.message.data, sizeof(pdpStatus.data));
uint32_t raw;
raw = pdpStatus.bits.Energy_125mWPerUnitXTmeas_h4;
@@ -514,8 +520,12 @@ void HAL_ResetPDPTotalEnergy(HAL_PDPHandle handle, int32_t* status) {
return;
}
uint8_t pdpControl[] = {0x40}; /* only bit set is ResetEnergy */
HAL_WriteCANPacket(pdp->canHandle, pdpControl, 1, Control1, status);
HAL_CANMessage message;
std::memset(&message, 0, sizeof(message));
message.dataSize = 1;
message.data[0] = 0x40; /* only bit set is ResetEnergy */
HAL_WriteCANPacket(pdp->canHandle, Control1, &message, status);
}
void HAL_ClearPDPStickyFaults(HAL_PDPHandle handle, int32_t* status) {
@@ -525,8 +535,12 @@ void HAL_ClearPDPStickyFaults(HAL_PDPHandle handle, int32_t* status) {
return;
}
uint8_t pdpControl[] = {0x80}; /* only bit set is ClearStickyFaults */
HAL_WriteCANPacket(pdp->canHandle, pdpControl, 1, Control1, status);
HAL_CANMessage message;
std::memset(&message, 0, sizeof(message));
message.dataSize = 1;
message.data[0] = 0x80; /* only bit set is ClearStickyFaults */
HAL_WriteCANPacket(pdp->canHandle, Control1, &message, status);
}
uint32_t HAL_StartCANStream(HAL_CANHandle handle, int32_t apiId, int32_t depth,
@@ -594,8 +608,9 @@ HAL_PowerDistributionChannelData* HAL_GetPDPStreamData(HAL_PDPHandle handle,
for (uint32_t i = 0; i < messagesRead; i++) {
PdpStatus1 pdpStatus;
std::memcpy(pdpStatus.data, messages[i].data, sizeof(messages[i].data));
uint32_t timestamp = messages[i].timeStamp;
std::memcpy(pdpStatus.data, messages[i].message.message.data,
sizeof(pdpStatus));
uint64_t timestamp = messages[i].message.timeStamp;
retData[*count].current =
((static_cast<uint32_t>(pdpStatus.bits.chan1_h8) << 2) |
@@ -650,8 +665,9 @@ HAL_PowerDistributionChannelData* HAL_GetPDPStreamData(HAL_PDPHandle handle,
for (uint32_t i = 0; i < messagesRead; i++) {
PdpStatus2 pdpStatus;
std::memcpy(pdpStatus.data, messages[i].data, sizeof(messages[i].data));
uint32_t timestamp = messages[i].timeStamp;
std::memcpy(pdpStatus.data, messages[i].message.message.data,
sizeof(pdpStatus));
uint64_t timestamp = messages[i].message.timeStamp;
retData[*count].current =
((static_cast<uint32_t>(pdpStatus.bits.chan7_h8) << 2) |
@@ -706,8 +722,9 @@ HAL_PowerDistributionChannelData* HAL_GetPDPStreamData(HAL_PDPHandle handle,
for (uint32_t i = 0; i < messagesRead; i++) {
PdpStatus3 pdpStatus;
std::memcpy(pdpStatus.data, messages[i].data, sizeof(messages[i].data));
uint32_t timestamp = messages[i].timeStamp;
std::memcpy(pdpStatus.data, messages[i].message.message.data,
sizeof(pdpStatus));
uint64_t timestamp = messages[i].message.timeStamp;
retData[*count].current =
((static_cast<uint32_t>(pdpStatus.bits.chan13_h8) << 2) |

View File

@@ -23,10 +23,12 @@ extern "C" {
/**
* Initializes a Power Distribution Panel.
*
* @param busID the can bus id
* @param module the module number to initialize
* @return the created PDP
*/
HAL_PDPHandle HAL_InitializePDP(int32_t module, const char* allocationLocation,
HAL_PDPHandle HAL_InitializePDP(int32_t busId, int32_t module,
const char* allocationLocation,
int32_t* status);
/**

View File

@@ -13,6 +13,9 @@ void InitializePorts() {}
} // namespace hal::init
extern "C" {
int32_t HAL_GetNumCanBuses(void) {
return kNumCanBuses;
}
int32_t HAL_GetNumAnalogInputs(void) {
return kNumAnalogInputs;
}

View File

@@ -8,6 +8,7 @@
namespace hal {
constexpr int32_t kNumCanBuses = 2;
constexpr int32_t kNumSmartIo = 5;
constexpr int32_t kNumAccumulators = 0;
constexpr int32_t kNumAnalogInputs = 8;

View File

@@ -20,7 +20,7 @@ using namespace hal;
extern "C" {
HAL_PowerDistributionHandle HAL_InitializePowerDistribution(
int32_t moduleNumber, HAL_PowerDistributionType type,
int32_t busId, int32_t moduleNumber, HAL_PowerDistributionType type,
const char* allocationLocation, int32_t* status) {
if (type == HAL_PowerDistributionType::HAL_PowerDistributionType_kAutomatic) {
if (moduleNumber != HAL_DEFAULT_POWER_DISTRIBUTION_MODULE) {
@@ -46,7 +46,7 @@ HAL_PowerDistributionHandle HAL_InitializePowerDistribution(
} while (true);
// Try PDP first
auto pdpHandle = HAL_InitializePDP(0, allocationLocation, status);
auto pdpHandle = HAL_InitializePDP(busId, 0, allocationLocation, status);
if (pdpHandle != HAL_kInvalidHandle) {
*status = 0;
HAL_GetPDPVoltage(pdpHandle, status);
@@ -56,7 +56,7 @@ HAL_PowerDistributionHandle HAL_InitializePowerDistribution(
HAL_CleanPDP(pdpHandle);
}
*status = 0;
auto pdhHandle = HAL_InitializeREVPDH(1, allocationLocation, status);
auto pdhHandle = HAL_InitializeREVPDH(busId, 1, allocationLocation, status);
return static_cast<HAL_PowerDistributionHandle>(pdhHandle);
}
@@ -65,13 +65,13 @@ HAL_PowerDistributionHandle HAL_InitializePowerDistribution(
moduleNumber = 0;
}
return static_cast<HAL_PowerDistributionHandle>(
HAL_InitializePDP(moduleNumber, allocationLocation, status));
HAL_InitializePDP(busId, moduleNumber, allocationLocation, status));
} else {
if (moduleNumber == HAL_DEFAULT_POWER_DISTRIBUTION_MODULE) {
moduleNumber = 1;
}
return static_cast<HAL_PowerDistributionHandle>(
HAL_InitializeREVPDH(moduleNumber, allocationLocation, status));
HAL_InitializeREVPDH(busId, moduleNumber, allocationLocation, status));
}
}

View File

@@ -91,95 +91,85 @@ extern "C" {
static PDH_status_0_t HAL_ReadREVPDHStatus0(HAL_CANHandle hcan,
int32_t* status) {
uint8_t packedData[8] = {0};
int32_t length = 0;
uint64_t timestamp = 0;
HAL_CANReceiveMessage message;
PDH_status_0_t result = {};
HAL_ReadCANPacketTimeout(hcan, PDH_STATUS_0_FRAME_API, packedData, &length,
&timestamp, kPDHFrameStatus0Timeout * 2, status);
HAL_ReadCANPacketTimeout(hcan, PDH_STATUS_0_FRAME_API, &message,
kPDHFrameStatus0Timeout * 2, status);
if (*status != 0) {
return result;
}
PDH_status_0_unpack(&result, packedData, PDH_STATUS_0_LENGTH);
PDH_status_0_unpack(&result, message.message.data, PDH_STATUS_0_LENGTH);
return result;
}
static PDH_status_1_t HAL_ReadREVPDHStatus1(HAL_CANHandle hcan,
int32_t* status) {
uint8_t packedData[8] = {0};
int32_t length = 0;
uint64_t timestamp = 0;
HAL_CANReceiveMessage message;
PDH_status_1_t result = {};
HAL_ReadCANPacketTimeout(hcan, PDH_STATUS_1_FRAME_API, packedData, &length,
&timestamp, kPDHFrameStatus1Timeout * 2, status);
HAL_ReadCANPacketTimeout(hcan, PDH_STATUS_1_FRAME_API, &message,
kPDHFrameStatus1Timeout * 2, status);
if (*status != 0) {
return result;
}
PDH_status_1_unpack(&result, packedData, PDH_STATUS_1_LENGTH);
PDH_status_1_unpack(&result, message.message.data, PDH_STATUS_1_LENGTH);
return result;
}
static PDH_status_2_t HAL_ReadREVPDHStatus2(HAL_CANHandle hcan,
int32_t* status) {
uint8_t packedData[8] = {0};
int32_t length = 0;
uint64_t timestamp = 0;
HAL_CANReceiveMessage message;
PDH_status_2_t result = {};
HAL_ReadCANPacketTimeout(hcan, PDH_STATUS_2_FRAME_API, packedData, &length,
&timestamp, kPDHFrameStatus2Timeout * 2, status);
HAL_ReadCANPacketTimeout(hcan, PDH_STATUS_2_FRAME_API, &message,
kPDHFrameStatus2Timeout * 2, status);
if (*status != 0) {
return result;
}
PDH_status_2_unpack(&result, packedData, PDH_STATUS_2_LENGTH);
PDH_status_2_unpack(&result, message.message.data, PDH_STATUS_2_LENGTH);
return result;
}
static PDH_status_3_t HAL_ReadREVPDHStatus3(HAL_CANHandle hcan,
int32_t* status) {
uint8_t packedData[8] = {0};
int32_t length = 0;
uint64_t timestamp = 0;
HAL_CANReceiveMessage message;
PDH_status_3_t result = {};
HAL_ReadCANPacketTimeout(hcan, PDH_STATUS_3_FRAME_API, packedData, &length,
&timestamp, kPDHFrameStatus3Timeout * 2, status);
HAL_ReadCANPacketTimeout(hcan, PDH_STATUS_3_FRAME_API, &message,
kPDHFrameStatus3Timeout * 2, status);
if (*status != 0) {
return result;
}
PDH_status_3_unpack(&result, packedData, PDH_STATUS_3_LENGTH);
PDH_status_3_unpack(&result, message.message.data, PDH_STATUS_3_LENGTH);
return result;
}
static PDH_status_4_t HAL_ReadREVPDHStatus4(HAL_CANHandle hcan,
int32_t* status) {
uint8_t packedData[8] = {0};
int32_t length = 0;
uint64_t timestamp = 0;
HAL_CANReceiveMessage message;
PDH_status_4_t result = {};
HAL_ReadCANPacketTimeout(hcan, PDH_STATUS_4_FRAME_API, packedData, &length,
&timestamp, kPDHFrameStatus4Timeout * 2, status);
HAL_ReadCANPacketTimeout(hcan, PDH_STATUS_4_FRAME_API, &message,
kPDHFrameStatus4Timeout * 2, status);
if (*status != 0) {
return result;
}
PDH_status_4_unpack(&result, packedData, PDH_STATUS_4_LENGTH);
PDH_status_4_unpack(&result, message.message.data, PDH_STATUS_4_LENGTH);
return result;
}
@@ -199,7 +189,7 @@ PDH_status_4_t HAL_GetREVPDHStatus4(HAL_REVPDHHandle handle, int32_t* status) {
return statusFrame;
}
HAL_REVPDHHandle HAL_InitializeREVPDH(int32_t module,
HAL_REVPDHHandle HAL_InitializeREVPDH(int32_t busId, int32_t module,
const char* allocationLocation,
int32_t* status) {
hal::init::CheckInit();
@@ -225,7 +215,7 @@ HAL_REVPDHHandle HAL_InitializeREVPDH(int32_t module,
}
HAL_CANHandle hcan =
HAL_InitializeCAN(manufacturer, module, deviceType, status);
HAL_InitializeCAN(busId, manufacturer, module, deviceType, status);
if (*status != 0) {
REVPDHHandles->Free(handle);
@@ -454,14 +444,16 @@ void HAL_SetREVPDHSwitchableChannel(HAL_REVPDHHandle handle, HAL_Bool enabled,
return;
}
uint8_t packedData[8] = {0};
HAL_CANMessage message;
std::memset(&message, 0, sizeof(message));
PDH_set_switch_channel_t frame;
frame.output_set_value = enabled;
PDH_set_switch_channel_pack(packedData, &frame,
PDH_set_switch_channel_pack(message.data, &frame,
PDH_SET_SWITCH_CHANNEL_LENGTH);
message.dataSize = PDH_SET_SWITCH_CHANNEL_LENGTH;
HAL_WriteCANPacket(hpdh->hcan, packedData, PDH_SET_SWITCH_CHANNEL_LENGTH,
PDH_SET_SWITCH_CHANNEL_FRAME_API, status);
HAL_WriteCANPacket(hpdh->hcan, PDH_SET_SWITCH_CHANNEL_FRAME_API, &message,
status);
}
HAL_Bool HAL_GetREVPDHSwitchableChannelState(HAL_REVPDHHandle handle,
@@ -490,9 +482,6 @@ void HAL_GetREVPDHVersion(HAL_REVPDHHandle handle,
HAL_PowerDistributionVersion* version,
int32_t* status) {
std::memset(version, 0, sizeof(*version));
uint8_t packedData[8] = {0};
int32_t length = 0;
uint64_t timestamp = 0;
PDH_version_t result = {};
auto hpdh = REVPDHHandles->Get(handle);
if (hpdh == nullptr) {
@@ -512,17 +501,20 @@ void HAL_GetREVPDHVersion(HAL_REVPDHHandle handle,
return;
}
HAL_WriteCANRTRFrame(hpdh->hcan, PDH_VERSION_LENGTH, PDH_VERSION_FRAME_API,
status);
HAL_CANMessage rtrmessage;
std::memset(&rtrmessage, 0, sizeof(rtrmessage));
rtrmessage.dataSize = PDH_VERSION_LENGTH;
HAL_WriteCANRTRFrame(hpdh->hcan, PDH_VERSION_FRAME_API, &rtrmessage, status);
if (*status != 0) {
return;
}
uint32_t timeoutMs = 100;
HAL_CANReceiveMessage message;
for (uint32_t i = 0; i <= timeoutMs; i++) {
HAL_ReadCANPacketNew(hpdh->hcan, PDH_VERSION_FRAME_API, packedData, &length,
&timestamp, status);
HAL_ReadCANPacketNew(hpdh->hcan, PDH_VERSION_FRAME_API, &message, status);
if (*status == 0) {
break;
}
@@ -533,7 +525,7 @@ void HAL_GetREVPDHVersion(HAL_REVPDHHandle handle,
return;
}
PDH_version_unpack(&result, packedData, PDH_VERSION_LENGTH);
PDH_version_unpack(&result, message.message.data, PDH_VERSION_LENGTH);
version->firmwareMajor = result.firmware_year;
version->firmwareMinor = result.firmware_minor;
@@ -640,9 +632,11 @@ void HAL_ClearREVPDHStickyFaults(HAL_REVPDHHandle handle, int32_t* status) {
return;
}
uint8_t packedData[8] = {0};
HAL_WriteCANPacket(hpdh->hcan, packedData, PDH_CLEAR_FAULTS_LENGTH,
PDH_CLEAR_FAULTS_FRAME_API, status);
HAL_CANMessage message;
std::memset(&message, 0, sizeof(message));
message.dataSize = PDH_CLEAR_FAULTS_LENGTH;
HAL_WriteCANPacket(hpdh->hcan, PDH_CLEAR_FAULTS_FRAME_API, &message, status);
}
uint32_t HAL_StartCANStream(HAL_CANHandle handle, int32_t apiId, int32_t depth,
@@ -717,8 +711,9 @@ HAL_PowerDistributionChannelData* HAL_GetREVPDHStreamData(
for (uint32_t i = 0; i < messagesRead; i++) {
PDH_status_0_t statusFrame0;
PDH_status_0_unpack(&statusFrame0, messages[i].data, PDH_STATUS_0_LENGTH);
uint32_t timestamp = messages[i].timeStamp;
PDH_status_0_unpack(&statusFrame0, messages[i].message.message.data,
PDH_STATUS_0_LENGTH);
uint32_t timestamp = messages[i].message.timeStamp;
retData[*count].current =
PDH_status_0_channel_0_current_decode(statusFrame0.channel_0_current);
@@ -761,8 +756,9 @@ HAL_PowerDistributionChannelData* HAL_GetREVPDHStreamData(
for (uint32_t i = 0; i < messagesRead; i++) {
PDH_status_1_t statusFrame1;
PDH_status_1_unpack(&statusFrame1, messages[i].data, PDH_STATUS_1_LENGTH);
uint32_t timestamp = messages[i].timeStamp;
PDH_status_1_unpack(&statusFrame1, messages[i].message.message.data,
PDH_STATUS_1_LENGTH);
uint32_t timestamp = messages[i].message.timeStamp;
retData[*count].current =
PDH_status_1_channel_6_current_decode(statusFrame1.channel_6_current);
@@ -805,8 +801,9 @@ HAL_PowerDistributionChannelData* HAL_GetREVPDHStreamData(
for (uint32_t i = 0; i < messagesRead; i++) {
PDH_status_2_t statusFrame2;
PDH_status_2_unpack(&statusFrame2, messages[i].data, PDH_STATUS_2_LENGTH);
uint32_t timestamp = messages[i].timeStamp;
PDH_status_2_unpack(&statusFrame2, messages[i].message.message.data,
PDH_STATUS_2_LENGTH);
uint32_t timestamp = messages[i].message.timeStamp;
retData[*count].current =
PDH_status_2_channel_12_current_decode(statusFrame2.channel_12_current);
@@ -849,8 +846,9 @@ HAL_PowerDistributionChannelData* HAL_GetREVPDHStreamData(
for (uint32_t i = 0; i < messagesRead; i++) {
PDH_status_3_t statusFrame3;
PDH_status_3_unpack(&statusFrame3, messages[i].data, PDH_STATUS_3_LENGTH);
uint32_t timestamp = messages[i].timeStamp;
PDH_status_3_unpack(&statusFrame3, messages[i].message.message.data,
PDH_STATUS_3_LENGTH);
uint32_t timestamp = messages[i].message.timeStamp;
retData[*count].current =
PDH_status_3_channel_18_current_decode(statusFrame3.channel_18_current);

View File

@@ -25,7 +25,7 @@ extern "C" {
* @param module the device CAN ID (1 .. 63)
* @return the created PDH handle
*/
HAL_REVPDHHandle HAL_InitializeREVPDH(int32_t module,
HAL_REVPDHHandle HAL_InitializeREVPDH(int32_t busId, int32_t module,
const char* allocationLocation,
int32_t* status);

View File

@@ -84,37 +84,33 @@ void InitializeREVPH() {
} // namespace hal::init
static PH_status_0_t HAL_ReadREVPHStatus0(HAL_CANHandle hcan, int32_t* status) {
uint8_t packedData[8] = {0};
int32_t length = 0;
uint64_t timestamp = 0;
HAL_CANReceiveMessage message;
PH_status_0_t result = {};
HAL_ReadCANPacketTimeout(hcan, PH_STATUS_0_FRAME_API, packedData, &length,
&timestamp, kPHFrameStatus0Timeout * 2, status);
HAL_ReadCANPacketTimeout(hcan, PH_STATUS_0_FRAME_API, &message,
kPHFrameStatus0Timeout * 2, status);
if (*status != 0) {
return result;
}
PH_status_0_unpack(&result, packedData, PH_STATUS_0_LENGTH);
PH_status_0_unpack(&result, message.message.data, PH_STATUS_0_LENGTH);
return result;
}
static PH_status_1_t HAL_ReadREVPHStatus1(HAL_CANHandle hcan, int32_t* status) {
uint8_t packedData[8] = {0};
int32_t length = 0;
uint64_t timestamp = 0;
HAL_CANReceiveMessage message;
PH_status_1_t result = {};
HAL_ReadCANPacketTimeout(hcan, PH_STATUS_1_FRAME_API, packedData, &length,
&timestamp, kPHFrameStatus1Timeout * 2, status);
HAL_ReadCANPacketTimeout(hcan, PH_STATUS_1_FRAME_API, &message,
kPHFrameStatus1Timeout * 2, status);
if (*status != 0) {
return result;
}
PH_status_1_unpack(&result, packedData, PH_STATUS_1_LENGTH);
PH_status_1_unpack(&result, message.message.data, PH_STATUS_1_LENGTH);
return result;
}
@@ -181,17 +177,21 @@ static void HAL_UpdateDesiredREVPHSolenoidState(REV_PHObj* hph,
}
static void HAL_SendREVPHSolenoidsState(REV_PHObj* hph, int32_t* status) {
uint8_t packedData[PH_SET_ALL_LENGTH] = {0};
PH_set_all_pack(packedData, &(hph->desiredSolenoidsState), PH_SET_ALL_LENGTH);
HAL_WriteCANPacketRepeating(hph->hcan, packedData, PH_SET_ALL_LENGTH,
PH_SET_ALL_FRAME_API, hph->controlPeriod, status);
HAL_CANMessage message;
std::memset(&message, 0, sizeof(message));
message.dataSize = PH_SET_ALL_LENGTH;
PH_set_all_pack(message.data, &(hph->desiredSolenoidsState),
PH_SET_ALL_LENGTH);
HAL_WriteCANPacketRepeating(hph->hcan, PH_SET_ALL_FRAME_API, &message,
hph->controlPeriod, status);
}
static HAL_Bool HAL_CheckREVPHPulseTime(int32_t time) {
return ((time > 0) && (time <= HAL_REVPH_MAX_PULSE_TIME)) ? 1 : 0;
}
HAL_REVPHHandle HAL_InitializeREVPH(int32_t module,
HAL_REVPHHandle HAL_InitializeREVPH(int32_t busId, int32_t module,
const char* allocationLocation,
int32_t* status) {
hal::init::CheckInit();
@@ -217,7 +217,7 @@ HAL_REVPHHandle HAL_InitializeREVPH(int32_t module,
}
HAL_CANHandle hcan =
HAL_InitializeCAN(manufacturer, module, deviceType, status);
HAL_InitializeCAN(busId, manufacturer, module, deviceType, status);
if (*status != 0) {
REVPHHandles->Free(handle);
@@ -291,11 +291,13 @@ void HAL_SetREVPHCompressorConfig(HAL_REVPHHandle handle,
frameData.force_disable = config->forceDisable;
frameData.use_digital = config->useDigital;
uint8_t packedData[PH_COMPRESSOR_CONFIG_LENGTH] = {0};
PH_compressor_config_pack(packedData, &frameData,
HAL_CANMessage message;
std::memset(&message, 0, sizeof(message));
message.dataSize = PH_COMPRESSOR_CONFIG_LENGTH;
PH_compressor_config_pack(message.data, &frameData,
PH_COMPRESSOR_CONFIG_LENGTH);
HAL_WriteCANPacket(ph->hcan, packedData, PH_COMPRESSOR_CONFIG_LENGTH,
PH_COMPRESSOR_CONFIG_API, status);
HAL_WriteCANPacket(ph->hcan, PH_COMPRESSOR_CONFIG_API, &message, status);
}
void HAL_SetREVPHClosedLoopControlDisabled(HAL_REVPHHandle handle,
@@ -480,9 +482,6 @@ double HAL_GetREVPHSolenoidVoltage(HAL_REVPHHandle handle, int32_t* status) {
void HAL_GetREVPHVersion(HAL_REVPHHandle handle, HAL_REVPHVersion* version,
int32_t* status) {
std::memset(version, 0, sizeof(*version));
uint8_t packedData[8] = {0};
int32_t length = 0;
uint64_t timestamp = 0;
PH_version_t result = {};
auto ph = REVPHHandles->Get(handle);
if (ph == nullptr) {
@@ -502,17 +501,20 @@ void HAL_GetREVPHVersion(HAL_REVPHHandle handle, HAL_REVPHVersion* version,
return;
}
HAL_WriteCANRTRFrame(ph->hcan, PH_VERSION_LENGTH, PH_VERSION_FRAME_API,
status);
HAL_CANMessage rtrmessage;
std::memset(&rtrmessage, 0, sizeof(rtrmessage));
rtrmessage.dataSize = PH_VERSION_LENGTH;
HAL_WriteCANRTRFrame(ph->hcan, PH_VERSION_FRAME_API, &rtrmessage, status);
if (*status != 0) {
return;
}
uint32_t timeoutMs = 100;
HAL_CANReceiveMessage message;
for (uint32_t i = 0; i <= timeoutMs; i++) {
HAL_ReadCANPacketNew(ph->hcan, PH_VERSION_FRAME_API, packedData, &length,
&timestamp, status);
HAL_ReadCANPacketNew(ph->hcan, PH_VERSION_FRAME_API, &message, status);
if (*status == 0) {
break;
}
@@ -523,7 +525,7 @@ void HAL_GetREVPHVersion(HAL_REVPHHandle handle, HAL_REVPHVersion* version,
return;
}
PH_version_unpack(&result, packedData, PH_VERSION_LENGTH);
PH_version_unpack(&result, message.message.data, PH_VERSION_LENGTH);
version->firmwareMajor = result.firmware_year;
version->firmwareMinor = result.firmware_minor;
@@ -683,10 +685,11 @@ void HAL_FireREVPHOneShot(HAL_REVPHHandle handle, int32_t index, int32_t durMs,
}
// Send pulse command
uint8_t packedData[PH_PULSE_ONCE_LENGTH] = {0};
PH_pulse_once_pack(packedData, &pulse, PH_PULSE_ONCE_LENGTH);
HAL_WriteCANPacket(ph->hcan, packedData, PH_PULSE_ONCE_LENGTH,
PH_PULSE_ONCE_FRAME_API, status);
HAL_CANMessage message;
std::memset(&message, 0, sizeof(message));
message.dataSize = PH_PULSE_ONCE_LENGTH;
PH_pulse_once_pack(message.data, &pulse, PH_PULSE_ONCE_LENGTH);
HAL_WriteCANPacket(ph->hcan, PH_PULSE_ONCE_FRAME_API, &message, status);
}
void HAL_GetREVPHFaults(HAL_REVPHHandle handle, HAL_REVPHFaults* faults,
@@ -752,9 +755,11 @@ void HAL_ClearREVPHStickyFaults(HAL_REVPHHandle handle, int32_t* status) {
return;
}
uint8_t packedData[8] = {0};
HAL_WriteCANPacket(ph->hcan, packedData, PH_CLEAR_FAULTS_LENGTH,
PH_CLEAR_FAULTS_FRAME_API, status);
HAL_CANMessage message;
std::memset(&message, 0, sizeof(message));
message.dataSize = PH_CLEAR_FAULTS_LENGTH;
HAL_WriteCANPacket(ph->hcan, PH_CLEAR_FAULTS_FRAME_API, &message, status);
}
int32_t HAL_GetREVPHSolenoidDisabledList(HAL_REVPHHandle handle,

View File

@@ -2,6 +2,7 @@
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include <cstring>
#include <utility>
#include <gtest/gtest.h>
@@ -11,10 +12,10 @@
namespace hal {
struct CANTestStore {
CANTestStore(int32_t deviceId, int32_t* status) {
CANTestStore(int32_t busId, int32_t deviceId, int32_t* status) {
this->deviceId = deviceId;
handle = HAL_InitializeCAN(
HAL_CANManufacturer::HAL_CAN_Man_kTeamUse, deviceId,
busId, HAL_CANManufacturer::HAL_CAN_Man_kTeamUse, deviceId,
HAL_CANDeviceType::HAL_CAN_Dev_kMiscellaneous, status);
}
@@ -43,28 +44,31 @@ struct CANSendCallbackStore {
TEST(CANTest, CanIdPacking) {
int32_t status = 0;
int32_t deviceId = 12;
CANTestStore testStore(deviceId, &status);
CANTestStore testStore(0, deviceId, &status);
ASSERT_EQ(0, status);
std::pair<int32_t, bool> storePair;
storePair.second = false;
auto cbHandle = HALSIM_RegisterCanSendMessageCallback(
[](const char* name, void* param, uint32_t messageID, const uint8_t* data,
uint8_t dataSize, int32_t periodMs, int32_t* status) {
[](const char* name, void* param, int32_t busId, uint32_t messageId,
const struct HAL_CANMessage* message, int32_t periodMs,
int32_t* status) {
std::pair<int32_t, bool>* paramI =
reinterpret_cast<std::pair<int32_t, bool>*>(param);
paramI->first = messageID;
paramI->first = messageId;
paramI->second = true;
},
&storePair);
CANSendCallbackStore cbStore(cbHandle);
uint8_t data[8];
HAL_CANMessage message;
std::memset(&message, 0, sizeof(message));
message.dataSize = 8;
int32_t apiId = 42;
HAL_WriteCANPacket(testStore.handle, data, 8, 42, &status);
HAL_WriteCANPacket(testStore.handle, apiId, &message, &status);
ASSERT_EQ(0, status);

View File

@@ -38,7 +38,7 @@ TEST(PCMDataTest, PCMInitialization) {
// Use out of range index
module = 8000;
gTestSolenoidCallbackName = "Unset";
pcmHandle = HAL_InitializeCTREPCM(module, nullptr, &status);
pcmHandle = HAL_InitializeCTREPCM(0, module, nullptr, &status);
EXPECT_EQ(HAL_kInvalidHandle, pcmHandle);
EXPECT_EQ(HAL_USE_LAST_ERROR, status);
HAL_GetLastError(&status);
@@ -49,7 +49,7 @@ TEST(PCMDataTest, PCMInitialization) {
status = 0;
module = MODULE_TO_TEST;
gTestSolenoidCallbackName = "Unset";
pcmHandle = HAL_InitializeCTREPCM(module, nullptr, &status);
pcmHandle = HAL_InitializeCTREPCM(0, module, nullptr, &status);
EXPECT_TRUE(HAL_kInvalidHandle != pcmHandle);
EXPECT_EQ(0, status);
EXPECT_STREQ("Initialized", gTestSolenoidCallbackName.c_str());
@@ -58,7 +58,7 @@ TEST(PCMDataTest, PCMInitialization) {
status = 0;
module = MODULE_TO_TEST;
gTestSolenoidCallbackName = "Unset";
pcmHandle = HAL_InitializeCTREPCM(module, nullptr, &status);
pcmHandle = HAL_InitializeCTREPCM(0, module, nullptr, &status);
EXPECT_EQ(HAL_kInvalidHandle, pcmHandle);
EXPECT_EQ(HAL_USE_LAST_ERROR, status);
HAL_GetLastError(&status);
@@ -76,7 +76,7 @@ TEST(PCMDataTest, PCMInitialization) {
status = 0;
module = MODULE_TO_TEST;
gTestSolenoidCallbackName = "Unset";
pcmHandle = HAL_InitializeCTREPCM(module, nullptr, &status);
pcmHandle = HAL_InitializeCTREPCM(0, module, nullptr, &status);
EXPECT_TRUE(HAL_kInvalidHandle != pcmHandle);
EXPECT_EQ(0, status);
EXPECT_STREQ("Initialized", gTestSolenoidCallbackName.c_str());

View File

@@ -33,7 +33,7 @@ TEST(PdpSimTest, PdpInitialization) {
// Use out of range index
gTestPdpCallbackName = "Unset";
HAL_InitializePowerDistribution(
INDEX_TO_TEST, HAL_PowerDistributionType_kCTRE, nullptr, &status);
0, INDEX_TO_TEST, HAL_PowerDistributionType_kCTRE, nullptr, &status);
EXPECT_EQ(0, status);
EXPECT_STREQ("Initialized", gTestPdpCallbackName.c_str());
}

View File

@@ -15,12 +15,13 @@
using namespace frc;
CAN::CAN(int deviceId) : CAN{kTeamManufacturer, deviceId, kTeamDeviceType} {}
CAN::CAN(int busId, int deviceId)
: CAN{busId, deviceId, kTeamManufacturer, kTeamDeviceType} {}
CAN::CAN(int deviceId, int deviceManufacturer, int deviceType) {
CAN::CAN(int busId, int deviceId, int deviceManufacturer, int deviceType) {
int32_t status = 0;
m_handle = HAL_InitializeCAN(
static_cast<HAL_CANManufacturer>(deviceManufacturer), deviceId,
busId, static_cast<HAL_CANManufacturer>(deviceManufacturer), deviceId,
static_cast<HAL_CANDeviceType>(deviceType), &status);
FRC_CheckErrorStatus(status, "device id {} mfg {} type {}", deviceId,
deviceManufacturer, deviceType);
@@ -30,41 +31,41 @@ CAN::CAN(int deviceId, int deviceManufacturer, int deviceType) {
"");
}
void CAN::WritePacket(const uint8_t* data, int length, int apiId) {
void CAN::WritePacket(int apiId, const HAL_CANMessage& message) {
int32_t status = 0;
HAL_WriteCANPacket(m_handle, data, length, apiId, &status);
HAL_WriteCANPacket(m_handle, apiId, &message, &status);
FRC_CheckErrorStatus(status, "WritePacket");
}
void CAN::WritePacketRepeating(const uint8_t* data, int length, int apiId,
void CAN::WritePacketRepeating(int apiId, const HAL_CANMessage& message,
int repeatMs) {
int32_t status = 0;
HAL_WriteCANPacketRepeating(m_handle, data, length, apiId, repeatMs, &status);
HAL_WriteCANPacketRepeating(m_handle, apiId, &message, repeatMs, &status);
FRC_CheckErrorStatus(status, "WritePacketRepeating");
}
void CAN::WriteRTRFrame(int length, int apiId) {
void CAN::WriteRTRFrame(int apiId, const HAL_CANMessage& message) {
int32_t status = 0;
HAL_WriteCANRTRFrame(m_handle, length, apiId, &status);
HAL_WriteCANRTRFrame(m_handle, apiId, &message, &status);
FRC_CheckErrorStatus(status, "WriteRTRFrame");
}
int CAN::WritePacketNoError(const uint8_t* data, int length, int apiId) {
int CAN::WritePacketNoError(int apiId, const HAL_CANMessage& message) {
int32_t status = 0;
HAL_WriteCANPacket(m_handle, data, length, apiId, &status);
HAL_WriteCANPacket(m_handle, apiId, &message, &status);
return status;
}
int CAN::WritePacketRepeatingNoError(const uint8_t* data, int length, int apiId,
int CAN::WritePacketRepeatingNoError(int apiId, const HAL_CANMessage& message,
int repeatMs) {
int32_t status = 0;
HAL_WriteCANPacketRepeating(m_handle, data, length, apiId, repeatMs, &status);
HAL_WriteCANPacketRepeating(m_handle, apiId, &message, repeatMs, &status);
return status;
}
int CAN::WriteRTRFrameNoError(int length, int apiId) {
int CAN::WriteRTRFrameNoError(int apiId, const HAL_CANMessage& message) {
int32_t status = 0;
HAL_WriteCANRTRFrame(m_handle, length, apiId, &status);
HAL_WriteCANRTRFrame(m_handle, apiId, &message, &status);
return status;
}
@@ -74,10 +75,9 @@ void CAN::StopPacketRepeating(int apiId) {
FRC_CheckErrorStatus(status, "StopPacketRepeating");
}
bool CAN::ReadPacketNew(int apiId, CANData* data) {
bool CAN::ReadPacketNew(int apiId, HAL_CANReceiveMessage* data) {
int32_t status = 0;
HAL_ReadCANPacketNew(m_handle, apiId, data->data, &data->length,
&data->timestamp, &status);
HAL_ReadCANPacketNew(m_handle, apiId, data, &status);
if (status == HAL_ERR_CANSessionMux_MessageNotFound) {
return false;
}
@@ -89,10 +89,9 @@ bool CAN::ReadPacketNew(int apiId, CANData* data) {
}
}
bool CAN::ReadPacketLatest(int apiId, CANData* data) {
bool CAN::ReadPacketLatest(int apiId, HAL_CANReceiveMessage* data) {
int32_t status = 0;
HAL_ReadCANPacketLatest(m_handle, apiId, data->data, &data->length,
&data->timestamp, &status);
HAL_ReadCANPacketLatest(m_handle, apiId, data, &status);
if (status == HAL_ERR_CANSessionMux_MessageNotFound) {
return false;
}
@@ -104,10 +103,10 @@ bool CAN::ReadPacketLatest(int apiId, CANData* data) {
}
}
bool CAN::ReadPacketTimeout(int apiId, int timeoutMs, CANData* data) {
bool CAN::ReadPacketTimeout(int apiId, int timeoutMs,
HAL_CANReceiveMessage* data) {
int32_t status = 0;
HAL_ReadCANPacketTimeout(m_handle, apiId, data->data, &data->length,
&data->timestamp, timeoutMs, &status);
HAL_ReadCANPacketTimeout(m_handle, apiId, data, timeoutMs, &status);
if (status == HAL_CAN_TIMEOUT ||
status == HAL_ERR_CANSessionMux_MessageNotFound) {
return false;
@@ -119,7 +118,3 @@ bool CAN::ReadPacketTimeout(int apiId, int timeoutMs, CANData* data) {
return true;
}
}
uint64_t CAN::GetTimestampBaseTime() {
return HAL_GetCANPacketBaseTime();
}

View File

@@ -14,8 +14,8 @@
using namespace frc;
Compressor::Compressor(int module, PneumaticsModuleType moduleType)
: m_module{PneumaticsBase::GetForType(module, moduleType)},
Compressor::Compressor(int busId, int module, PneumaticsModuleType moduleType)
: m_module{PneumaticsBase::GetForType(busId, module, moduleType)},
m_moduleType{moduleType} {
if (!m_module->ReserveCompressor()) {
throw FRC_MakeError(err::ResourceAlreadyAllocated, "{}", module);
@@ -27,8 +27,9 @@ Compressor::Compressor(int module, PneumaticsModuleType moduleType)
wpi::SendableRegistry::Add(this, "Compressor", module);
}
Compressor::Compressor(PneumaticsModuleType moduleType)
: Compressor{PneumaticsBase::GetDefaultForType(moduleType), moduleType} {}
Compressor::Compressor(int busId, PneumaticsModuleType moduleType)
: Compressor{busId, PneumaticsBase::GetDefaultForType(moduleType),
moduleType} {}
Compressor::~Compressor() {
if (m_module) {

View File

@@ -16,9 +16,10 @@
using namespace frc;
DoubleSolenoid::DoubleSolenoid(int module, PneumaticsModuleType moduleType,
DoubleSolenoid::DoubleSolenoid(int busId, int module,
PneumaticsModuleType moduleType,
int forwardChannel, int reverseChannel)
: m_module{PneumaticsBase::GetForType(module, moduleType)},
: m_module{PneumaticsBase::GetForType(busId, module, moduleType)},
m_forwardChannel{forwardChannel},
m_reverseChannel{reverseChannel} {
if (!m_module->CheckSolenoidChannel(m_forwardChannel)) {
@@ -56,10 +57,10 @@ DoubleSolenoid::DoubleSolenoid(int module, PneumaticsModuleType moduleType,
m_module->GetModuleNumber(), m_forwardChannel);
}
DoubleSolenoid::DoubleSolenoid(PneumaticsModuleType moduleType,
DoubleSolenoid::DoubleSolenoid(int busId, PneumaticsModuleType moduleType,
int forwardChannel, int reverseChannel)
: DoubleSolenoid{PneumaticsBase::GetDefaultForType(moduleType), moduleType,
forwardChannel, reverseChannel} {}
: DoubleSolenoid{busId, PneumaticsBase::GetDefaultForType(moduleType),
moduleType, forwardChannel, reverseChannel} {}
DoubleSolenoid::~DoubleSolenoid() {
if (m_module) {

View File

@@ -10,6 +10,7 @@
#include <string>
#include <fmt/format.h>
#include <hal/Ports.h>
#include <hal/REVPH.h>
#include <hal/UsageReporting.h>
#include <wpi/NullDeleter.h>
@@ -39,26 +40,31 @@ units::volt_t PSIToVolts(units::pounds_per_square_inch_t pressure,
}
wpi::mutex PneumaticHub::m_handleLock;
std::unique_ptr<wpi::DenseMap<int, std::weak_ptr<PneumaticHub::DataStore>>>
PneumaticHub::m_handleMap = nullptr;
std::unique_ptr<wpi::DenseMap<int, std::weak_ptr<PneumaticHub::DataStore>>[]>
PneumaticHub::m_handleMaps = nullptr;
// Always called under lock, so we can avoid the double lock from the magic
// static
std::weak_ptr<PneumaticHub::DataStore>& PneumaticHub::GetDataStore(int module) {
if (!m_handleMap) {
m_handleMap = std::make_unique<
wpi::DenseMap<int, std::weak_ptr<PneumaticHub::DataStore>>>();
std::weak_ptr<PneumaticHub::DataStore>& PneumaticHub::GetDataStore(int busId,
int module) {
int32_t numBuses = HAL_GetNumCanBuses();
FRC_AssertMessage(busId >= 0 && busId < numBuses,
"Bus {} out of range. Must be [0-{}).", busId, numBuses);
if (!m_handleMaps) {
m_handleMaps = std::make_unique<
wpi::DenseMap<int, std::weak_ptr<PneumaticHub::DataStore>>[]>(numBuses);
}
return (*m_handleMap)[module];
return m_handleMaps[busId][module];
}
class PneumaticHub::DataStore {
public:
explicit DataStore(int module, const char* stackTrace) {
explicit DataStore(int busId, int module, const char* stackTrace) {
int32_t status = 0;
HAL_REVPHHandle handle = HAL_InitializeREVPH(module, stackTrace, &status);
HAL_REVPHHandle handle =
HAL_InitializeREVPH(busId, module, stackTrace, &status);
FRC_CheckErrorStatus(status, "Module {}", module);
m_moduleObject = PneumaticHub{handle, module};
m_moduleObject = PneumaticHub{busId, handle, module};
m_moduleObject.m_dataStore =
std::shared_ptr<DataStore>{this, wpi::NullDeleter<DataStore>()};
@@ -105,27 +111,28 @@ class PneumaticHub::DataStore {
uint32_t m_reservedMask{0};
bool m_compressorReserved{false};
wpi::mutex m_reservedLock;
PneumaticHub m_moduleObject{HAL_kInvalidHandle, 0};
PneumaticHub m_moduleObject{0, HAL_kInvalidHandle, 0};
std::array<units::millisecond_t, 16> m_oneShotDurMs{0_ms};
};
PneumaticHub::PneumaticHub()
: PneumaticHub{SensorUtil::GetDefaultREVPHModule()} {}
PneumaticHub::PneumaticHub(int busId)
: PneumaticHub{busId, SensorUtil::GetDefaultREVPHModule()} {}
PneumaticHub::PneumaticHub(int module) {
PneumaticHub::PneumaticHub(int busId, int module) {
std::string stackTrace = wpi::GetStackTrace(1);
std::scoped_lock lock(m_handleLock);
auto& res = GetDataStore(module);
auto& res = GetDataStore(busId, module);
m_dataStore = res.lock();
if (!m_dataStore) {
m_dataStore = std::make_shared<DataStore>(module, stackTrace.c_str());
m_dataStore =
std::make_shared<DataStore>(busId, module, stackTrace.c_str());
res = m_dataStore;
}
m_handle = m_dataStore->m_moduleObject.m_handle;
m_module = module;
}
PneumaticHub::PneumaticHub(HAL_REVPHHandle handle, int module)
PneumaticHub::PneumaticHub(int /* busId */, HAL_REVPHHandle handle, int module)
: m_handle{handle}, m_module{module} {}
bool PneumaticHub::GetCompressor() const {
@@ -446,13 +453,14 @@ void PneumaticHub::ReportUsage(std::string_view device, std::string_view data) {
HAL_ReportUsage(fmt::format("PH[{}]/{}", m_module, device), data);
}
std::shared_ptr<PneumaticsBase> PneumaticHub::GetForModule(int module) {
std::shared_ptr<PneumaticsBase> PneumaticHub::GetForModule(int busId,
int module) {
std::string stackTrace = wpi::GetStackTrace(1);
std::scoped_lock lock(m_handleLock);
auto& res = GetDataStore(module);
auto& res = GetDataStore(busId, module);
std::shared_ptr<DataStore> dataStore = res.lock();
if (!dataStore) {
dataStore = std::make_shared<DataStore>(module, stackTrace.c_str());
dataStore = std::make_shared<DataStore>(busId, module, stackTrace.c_str());
res = dataStore;
}

View File

@@ -29,11 +29,11 @@ static_assert(
HAL_REVPHCompressorConfigType::HAL_REVPHCompressorConfigType_kHybrid);
std::shared_ptr<PneumaticsBase> PneumaticsBase::GetForType(
int module, PneumaticsModuleType moduleType) {
int busId, int module, PneumaticsModuleType moduleType) {
if (moduleType == PneumaticsModuleType::CTREPCM) {
return PneumaticsControlModule::GetForModule(module);
return PneumaticsControlModule::GetForModule(busId, module);
} else if (moduleType == PneumaticsModuleType::REVPH) {
return PneumaticHub::GetForModule(module);
return PneumaticHub::GetForModule(busId, module);
}
throw FRC_MakeError(err::InvalidParameter, "{}",
static_cast<int>(moduleType));

View File

@@ -9,6 +9,7 @@
#include <fmt/format.h>
#include <hal/CTREPCM.h>
#include <hal/Ports.h>
#include <hal/UsageReporting.h>
#include <wpi/NullDeleter.h>
#include <wpi/StackTrace.h>
@@ -23,28 +24,32 @@ using namespace frc;
wpi::mutex PneumaticsControlModule::m_handleLock;
std::unique_ptr<
wpi::DenseMap<int, std::weak_ptr<PneumaticsControlModule::DataStore>>>
PneumaticsControlModule::m_handleMap = nullptr;
wpi::DenseMap<int, std::weak_ptr<PneumaticsControlModule::DataStore>>[]>
PneumaticsControlModule::m_handleMaps = nullptr;
// Always called under lock, so we can avoid the double lock from the magic
// static
std::weak_ptr<PneumaticsControlModule::DataStore>&
PneumaticsControlModule::GetDataStore(int module) {
if (!m_handleMap) {
m_handleMap = std::make_unique<wpi::DenseMap<
int, std::weak_ptr<PneumaticsControlModule::DataStore>>>();
PneumaticsControlModule::GetDataStore(int busId, int module) {
int32_t numBuses = HAL_GetNumCanBuses();
FRC_AssertMessage(busId >= 0 && busId < numBuses,
"Bus {} out of range. Must be [0-{}).", busId, numBuses);
if (!m_handleMaps) {
m_handleMaps = std::make_unique<wpi::DenseMap<
int, std::weak_ptr<PneumaticsControlModule::DataStore>>[]>(numBuses);
}
return (*m_handleMap)[module];
return m_handleMaps[busId][module];
}
class PneumaticsControlModule::DataStore {
public:
explicit DataStore(int module, const char* stackTrace) {
explicit DataStore(int busId, int module, const char* stackTrace) {
int32_t status = 0;
HAL_CTREPCMHandle handle =
HAL_InitializeCTREPCM(module, stackTrace, &status);
HAL_InitializeCTREPCM(busId, module, stackTrace, &status);
FRC_CheckErrorStatus(status, "Module {}", module);
m_moduleObject = PneumaticsControlModule{handle, module};
m_moduleObject = PneumaticsControlModule{busId, handle, module};
m_moduleObject.m_dataStore =
std::shared_ptr<DataStore>{this, wpi::NullDeleter<DataStore>()};
}
@@ -59,26 +64,28 @@ class PneumaticsControlModule::DataStore {
uint32_t m_reservedMask{0};
bool m_compressorReserved{false};
wpi::mutex m_reservedLock;
PneumaticsControlModule m_moduleObject{HAL_kInvalidHandle, 0};
PneumaticsControlModule m_moduleObject{0, HAL_kInvalidHandle, 0};
};
PneumaticsControlModule::PneumaticsControlModule()
: PneumaticsControlModule{SensorUtil::GetDefaultCTREPCMModule()} {}
PneumaticsControlModule::PneumaticsControlModule(int busId)
: PneumaticsControlModule{busId, SensorUtil::GetDefaultCTREPCMModule()} {}
PneumaticsControlModule::PneumaticsControlModule(int module) {
PneumaticsControlModule::PneumaticsControlModule(int busId, int module) {
std::string stackTrace = wpi::GetStackTrace(1);
std::scoped_lock lock(m_handleLock);
auto& res = GetDataStore(module);
auto& res = GetDataStore(busId, module);
m_dataStore = res.lock();
if (!m_dataStore) {
m_dataStore = std::make_shared<DataStore>(module, stackTrace.c_str());
m_dataStore =
std::make_shared<DataStore>(busId, module, stackTrace.c_str());
res = m_dataStore;
}
m_handle = m_dataStore->m_moduleObject.m_handle;
m_module = module;
}
PneumaticsControlModule::PneumaticsControlModule(HAL_CTREPCMHandle handle,
PneumaticsControlModule::PneumaticsControlModule(int /* busId */,
HAL_CTREPCMHandle handle,
int module)
: m_handle{handle}, m_module{module} {}
@@ -297,13 +304,13 @@ void PneumaticsControlModule::ReportUsage(std::string_view device,
}
std::shared_ptr<PneumaticsBase> PneumaticsControlModule::GetForModule(
int module) {
int busId, int module) {
std::string stackTrace = wpi::GetStackTrace(1);
std::scoped_lock lock(m_handleLock);
auto& res = GetDataStore(module);
auto& res = GetDataStore(busId, module);
std::shared_ptr<DataStore> dataStore = res.lock();
if (!dataStore) {
dataStore = std::make_shared<DataStore>(module, stackTrace.c_str());
dataStore = std::make_shared<DataStore>(busId, module, stackTrace.c_str());
res = dataStore;
}

View File

@@ -27,12 +27,12 @@ static_assert(frc::PowerDistribution::kDefaultModule ==
using namespace frc;
PowerDistribution::PowerDistribution() {
PowerDistribution::PowerDistribution(int busId) {
auto stack = wpi::GetStackTrace(1);
int32_t status = 0;
m_handle = HAL_InitializePowerDistribution(
kDefaultModule,
busId, kDefaultModule,
HAL_PowerDistributionType::HAL_PowerDistributionType_kAutomatic,
stack.c_str(), &status);
FRC_CheckErrorStatus(status, "Module {}", kDefaultModule);
@@ -48,13 +48,14 @@ PowerDistribution::PowerDistribution() {
wpi::SendableRegistry::Add(this, "PowerDistribution", m_module);
}
PowerDistribution::PowerDistribution(int module, ModuleType moduleType) {
PowerDistribution::PowerDistribution(int busId, int module,
ModuleType moduleType) {
auto stack = wpi::GetStackTrace(1);
int32_t status = 0;
m_handle = HAL_InitializePowerDistribution(
module, static_cast<HAL_PowerDistributionType>(moduleType), stack.c_str(),
&status);
busId, module, static_cast<HAL_PowerDistributionType>(moduleType),
stack.c_str(), &status);
FRC_CheckErrorStatus(status, "Module {}", module);
m_module = HAL_GetPowerDistributionModuleNumber(m_handle, &status);
FRC_ReportError(status, "Module {}", module);

View File

@@ -284,15 +284,16 @@ RadioLEDState RobotController::GetRadioLEDState() {
return retVal;
}
CANStatus RobotController::GetCANStatus() {
CANStatus RobotController::GetCANStatus(int busId) {
int32_t status = 0;
float percentBusUtilization = 0;
uint32_t busOffCount = 0;
uint32_t txFullCount = 0;
uint32_t receiveErrorCount = 0;
uint32_t transmitErrorCount = 0;
HAL_CAN_GetCANStatus(&percentBusUtilization, &busOffCount, &txFullCount,
&receiveErrorCount, &transmitErrorCount, &status);
HAL_CAN_GetCANStatus(busId, &percentBusUtilization, &busOffCount,
&txFullCount, &receiveErrorCount, &transmitErrorCount,
&status);
FRC_CheckErrorStatus(status, "GetCANStatus");
return {percentBusUtilization, static_cast<int>(busOffCount),
static_cast<int>(txFullCount), static_cast<int>(receiveErrorCount),

View File

@@ -15,8 +15,9 @@
using namespace frc;
Solenoid::Solenoid(int module, PneumaticsModuleType moduleType, int channel)
: m_module{PneumaticsBase::GetForType(module, moduleType)},
Solenoid::Solenoid(int busId, int module, PneumaticsModuleType moduleType,
int channel)
: m_module{PneumaticsBase::GetForType(busId, module, moduleType)},
m_channel{channel} {
if (!m_module->CheckSolenoidChannel(m_channel)) {
throw FRC_MakeError(err::ChannelIndexOutOfRange, "Channel {}", m_channel);
@@ -32,8 +33,8 @@ Solenoid::Solenoid(int module, PneumaticsModuleType moduleType, int channel)
m_channel);
}
Solenoid::Solenoid(PneumaticsModuleType moduleType, int channel)
: Solenoid{PneumaticsBase::GetDefaultForType(moduleType), moduleType,
Solenoid::Solenoid(int busId, PneumaticsModuleType moduleType, int channel)
: Solenoid{busId, PneumaticsBase::GetDefaultForType(moduleType), moduleType,
channel} {}
Solenoid::~Solenoid() {

View File

@@ -9,14 +9,6 @@
#include <hal/CANAPI.h>
namespace frc {
struct CANData {
/** Contents of the CAN packet. */
uint8_t data[8];
/** Length of packet in bytes. */
int32_t length;
/** CAN frame timestamp in milliseconds. */
uint64_t timestamp;
};
/**
* High level class for interfacing with CAN devices conforming to
@@ -35,20 +27,22 @@ class CAN {
* 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
*/
explicit CAN(int deviceId);
CAN(int busId, int deviceId);
/**
* 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
*/
CAN(int deviceId, int deviceManufacturer, int deviceType);
CAN(int busId, int deviceId, int deviceManufacturer, int deviceType);
CAN(CAN&&) = default;
CAN& operator=(CAN&&) = default;
@@ -56,23 +50,21 @@ class CAN {
/**
* 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 length The data length to write
* @param apiId The API ID to write.
* @param message the CAN message.
*/
void WritePacket(const uint8_t* data, int length, int apiId);
void WritePacket(int apiId, const HAL_CANMessage& message);
/**
* 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 length The data length to write
* @param apiId The API ID to write.
* @param message the CAN message.
* @param repeatMs The period to repeat the packet at.
*/
void WritePacketRepeating(const uint8_t* data, int length, int apiId,
void WritePacketRepeating(int apiId, const HAL_CANMessage& message,
int repeatMs);
/**
@@ -80,31 +72,29 @@ class CAN {
* 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 message the CAN message.
*/
void WriteRTRFrame(int length, int apiId);
void WriteRTRFrame(int apiId, const HAL_CANMessage& message);
/**
* 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 length The data length to write
* @param apiId The API ID to write.
* @param message the CAN message.
*/
int WritePacketNoError(const uint8_t* data, int length, int apiId);
int WritePacketNoError(int apiId, const HAL_CANMessage& message);
/**
* 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 length The data length to write
* @param apiId The API ID to write.
* @param message the CAN message.
* @param repeatMs The period to repeat the packet at.
*/
int WritePacketRepeatingNoError(const uint8_t* data, int length, int apiId,
int WritePacketRepeatingNoError(int apiId, const HAL_CANMessage& message,
int repeatMs);
/**
@@ -112,10 +102,10 @@ class CAN {
* 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 message the CAN message.
*/
int WriteRTRFrameNoError(int length, int apiId);
int WriteRTRFrameNoError(int apiId, const HAL_CANMessage& message);
/**
* Stop a repeating packet with a specific ID. This ID is 10 bits.
@@ -133,7 +123,7 @@ class CAN {
* @param data Storage for the received data.
* @return True if the data is valid, otherwise false.
*/
bool ReadPacketNew(int apiId, CANData* data);
bool ReadPacketNew(int apiId, HAL_CANReceiveMessage* data);
/**
* Read a CAN packet. The will continuously return the last packet received,
@@ -143,7 +133,7 @@ class CAN {
* @param data Storage for the received data.
* @return True if the data is valid, otherwise false.
*/
bool ReadPacketLatest(int apiId, CANData* data);
bool ReadPacketLatest(int apiId, HAL_CANReceiveMessage* data);
/**
* Read a CAN packet. The will return the last packet received until the
@@ -154,16 +144,7 @@ class CAN {
* @param data Storage for the received data.
* @return True if the data is valid, otherwise false.
*/
bool ReadPacketTimeout(int apiId, int timeoutMs, CANData* data);
/**
* Reads the current value of the millisecond-resolution timer that CANData
* timestamps are based on
*
* @return Current value of timer used as a base time for CANData timestamps
* in milliseconds
*/
static uint64_t GetTimestampBaseTime();
bool ReadPacketTimeout(int apiId, int timeoutMs, HAL_CANReceiveMessage* data);
/// Team manufacturer.
static constexpr HAL_CANManufacturer kTeamManufacturer = HAL_CAN_Man_kTeamUse;

View File

@@ -37,17 +37,19 @@ class Compressor : public wpi::Sendable,
/**
* 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.
*/
Compressor(int module, PneumaticsModuleType moduleType);
Compressor(int busId, int module, PneumaticsModuleType moduleType);
/**
* Constructs a compressor for a default module and specified type.
*
* @param busId The bus ID.
* @param moduleType The module type to use.
*/
explicit Compressor(PneumaticsModuleType moduleType);
Compressor(int busId, PneumaticsModuleType moduleType);
~Compressor() override;

View File

@@ -41,23 +41,25 @@ class DoubleSolenoid : public wpi::Sendable,
* 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.
* @param reverseChannel The reverse channel on the module to control.
*/
DoubleSolenoid(int module, PneumaticsModuleType moduleType,
DoubleSolenoid(int busId, int module, PneumaticsModuleType moduleType,
int forwardChannel, int reverseChannel);
/**
* 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.
*/
DoubleSolenoid(PneumaticsModuleType moduleType, int forwardChannel,
DoubleSolenoid(int busId, PneumaticsModuleType moduleType, int forwardChannel,
int reverseChannel);
~DoubleSolenoid() override;

View File

@@ -17,15 +17,20 @@ namespace frc {
/** Module class for controlling a REV Robotics Pneumatic Hub. */
class PneumaticHub : public PneumaticsBase {
public:
/** Constructs a PneumaticHub with the default ID (1). */
PneumaticHub();
/**
* Constructs a PneumaticHub with the default ID (1).
*
* @param busId The bus ID.
*/
explicit PneumaticHub(int busId);
/**
* Constructs a PneumaticHub.
*
* @param busId The bus ID.
* @param module module number to construct
*/
explicit PneumaticHub(int module);
PneumaticHub(int busId, int module);
~PneumaticHub() override = default;
@@ -296,17 +301,17 @@ class PneumaticHub : public PneumaticsBase {
class DataStore;
friend class DataStore;
friend class PneumaticsBase;
PneumaticHub(HAL_REVPHHandle handle, int module);
PneumaticHub(int busId, HAL_REVPHHandle handle, int module);
static std::shared_ptr<PneumaticsBase> GetForModule(int module);
static std::shared_ptr<PneumaticsBase> GetForModule(int busId, int module);
std::shared_ptr<DataStore> m_dataStore;
HAL_REVPHHandle m_handle;
int m_module;
static wpi::mutex m_handleLock;
static std::unique_ptr<wpi::DenseMap<int, std::weak_ptr<DataStore>>>
m_handleMap;
static std::weak_ptr<DataStore>& GetDataStore(int module);
static std::unique_ptr<wpi::DenseMap<int, std::weak_ptr<DataStore>>[]>
m_handleMaps;
static std::weak_ptr<DataStore>& GetDataStore(int busId, int module);
};
} // namespace frc

View File

@@ -267,12 +267,13 @@ class PneumaticsBase {
/**
* For internal use to get a module for a specific type.
*
* @param busId The bus ID.
* @param module module number
* @param moduleType module type
* @return module
*/
static std::shared_ptr<PneumaticsBase> GetForType(
int module, PneumaticsModuleType moduleType);
int busId, int module, PneumaticsModuleType moduleType);
/**
* For internal use to get the default for a specific type.

View File

@@ -17,15 +17,20 @@ namespace frc {
* Module. */
class PneumaticsControlModule : public PneumaticsBase {
public:
/** Constructs a PneumaticsControlModule with the default ID (0). */
PneumaticsControlModule();
/**
* Constructs a PneumaticsControlModule with the default ID (0).
*
* @param busId The bus ID.
*/
explicit PneumaticsControlModule(int busId);
/**
* Constructs a PneumaticsControlModule.
*
* @param busId The bus ID.
* @param module module number to construct
*/
explicit PneumaticsControlModule(int module);
PneumaticsControlModule(int busId, int module);
~PneumaticsControlModule() override = default;
@@ -196,17 +201,17 @@ class PneumaticsControlModule : public PneumaticsBase {
class DataStore;
friend class DataStore;
friend class PneumaticsBase;
PneumaticsControlModule(HAL_CTREPCMHandle handle, int module);
PneumaticsControlModule(int busId, HAL_CTREPCMHandle handle, int module);
static std::shared_ptr<PneumaticsBase> GetForModule(int module);
static std::shared_ptr<PneumaticsBase> GetForModule(int busId, int module);
std::shared_ptr<DataStore> m_dataStore;
HAL_CTREPCMHandle m_handle;
int m_module;
static wpi::mutex m_handleLock;
static std::unique_ptr<wpi::DenseMap<int, std::weak_ptr<DataStore>>>
m_handleMap;
static std::weak_ptr<DataStore>& GetDataStore(int module);
static std::unique_ptr<wpi::DenseMap<int, std::weak_ptr<DataStore>>[]>
m_handleMaps;
static std::weak_ptr<DataStore>& GetDataStore(int busId, int module);
};
} // namespace frc

View File

@@ -38,16 +38,19 @@ class PowerDistribution : public wpi::Sendable,
*
* Detects the connected PDP/PDH using the default CAN ID (0 for CTRE and 1
* for REV).
*
* @param busId The bus ID.
*/
PowerDistribution();
explicit PowerDistribution(int busId);
/**
* Constructs a PowerDistribution object.
*
* @param busId The bus ID.
* @param module The CAN ID of the PDP/PDH
* @param moduleType The type of module
*/
PowerDistribution(int module, ModuleType moduleType);
PowerDistribution(int busId, int module, ModuleType moduleType);
PowerDistribution(PowerDistribution&&) = default;
PowerDistribution& operator=(PowerDistribution&&) = default;

View File

@@ -336,9 +336,10 @@ class RobotController {
/**
* Get the current status of the CAN bus.
*
* @param busId The bus ID.
* @return The status of the CAN bus
*/
static CANStatus GetCANStatus();
static CANStatus GetCANStatus(int busId);
private:
static std::function<uint64_t()> m_timeSource;

View File

@@ -28,19 +28,21 @@ class Solenoid : public wpi::Sendable, public wpi::SendableHelper<Solenoid> {
/**
* 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.
*/
Solenoid(int module, PneumaticsModuleType moduleType, int channel);
Solenoid(int busId, int module, PneumaticsModuleType moduleType, int channel);
/**
* 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.
*/
Solenoid(PneumaticsModuleType moduleType, int channel);
Solenoid(int busId, PneumaticsModuleType moduleType, int channel);
~Solenoid() override;

View File

@@ -12,7 +12,7 @@
namespace frc {
TEST(DoubleSolenoidCTRETest, ValidInitialization) {
DoubleSolenoid solenoid{3, frc::PneumaticsModuleType::CTREPCM, 2, 3};
DoubleSolenoid solenoid{0, 3, frc::PneumaticsModuleType::CTREPCM, 2, 3};
solenoid.Set(DoubleSolenoid::kReverse);
EXPECT_EQ(DoubleSolenoid::kReverse, solenoid.Get());
@@ -25,29 +25,29 @@ TEST(DoubleSolenoidCTRETest, ValidInitialization) {
TEST(DoubleSolenoidCTRETest, ThrowForwardPortAlreadyInitialized) {
// Single solenoid that is reused for forward port
Solenoid solenoid{5, frc::PneumaticsModuleType::CTREPCM, 2};
EXPECT_THROW(DoubleSolenoid(5, frc::PneumaticsModuleType::CTREPCM, 2, 3),
Solenoid solenoid{0, 5, frc::PneumaticsModuleType::CTREPCM, 2};
EXPECT_THROW(DoubleSolenoid(0, 5, frc::PneumaticsModuleType::CTREPCM, 2, 3),
std::runtime_error);
}
TEST(DoubleSolenoidCTRETest, ThrowReversePortAlreadyInitialized) {
// Single solenoid that is reused for forward port
Solenoid solenoid{6, frc::PneumaticsModuleType::CTREPCM, 3};
Solenoid solenoid{0, 6, frc::PneumaticsModuleType::CTREPCM, 3};
EXPECT_THROW(DoubleSolenoid(6, frc::PneumaticsModuleType::CTREPCM, 2, 3),
std::runtime_error);
}
TEST(DoubleSolenoidCTRETest, ThrowBothPortsAlreadyInitialized) {
PneumaticsControlModule pcm{6};
PneumaticsControlModule pcm{0, 6};
// Single solenoid that is reused for forward port
Solenoid solenoid0(6, frc::PneumaticsModuleType::CTREPCM, 2);
Solenoid solenoid1(6, frc::PneumaticsModuleType::CTREPCM, 3);
Solenoid solenoid0(0, 6, frc::PneumaticsModuleType::CTREPCM, 2);
Solenoid solenoid1(0, 6, frc::PneumaticsModuleType::CTREPCM, 3);
EXPECT_THROW(DoubleSolenoid(6, frc::PneumaticsModuleType::CTREPCM, 2, 3),
std::runtime_error);
}
TEST(DoubleSolenoidCTRETest, Toggle) {
DoubleSolenoid solenoid{4, frc::PneumaticsModuleType::CTREPCM, 2, 3};
DoubleSolenoid solenoid{0, 4, frc::PneumaticsModuleType::CTREPCM, 2, 3};
// Bootstrap it into reverse
solenoid.Set(DoubleSolenoid::kReverse);
@@ -64,12 +64,12 @@ TEST(DoubleSolenoidCTRETest, Toggle) {
}
TEST(DoubleSolenoidCTRETest, InvalidForwardPort) {
EXPECT_THROW(DoubleSolenoid(0, frc::PneumaticsModuleType::CTREPCM, 100, 1),
EXPECT_THROW(DoubleSolenoid(0, 0, frc::PneumaticsModuleType::CTREPCM, 100, 1),
std::runtime_error);
}
TEST(DoubleSolenoidCTRETest, InvalidReversePort) {
EXPECT_THROW(DoubleSolenoid(0, frc::PneumaticsModuleType::CTREPCM, 0, 100),
EXPECT_THROW(DoubleSolenoid(0, 0, frc::PneumaticsModuleType::CTREPCM, 0, 100),
std::runtime_error);
}
} // namespace frc

View File

@@ -12,7 +12,7 @@
namespace frc {
TEST(DoubleSolenoidREVTest, ValidInitialization) {
DoubleSolenoid solenoid{3, frc::PneumaticsModuleType::CTREPCM, 2, 3};
DoubleSolenoid solenoid{0, 3, frc::PneumaticsModuleType::CTREPCM, 2, 3};
solenoid.Set(DoubleSolenoid::kReverse);
EXPECT_EQ(DoubleSolenoid::kReverse, solenoid.Get());
@@ -25,29 +25,29 @@ TEST(DoubleSolenoidREVTest, ValidInitialization) {
TEST(DoubleSolenoidREVTest, ThrowForwardPortAlreadyInitialized) {
// Single solenoid that is reused for forward port
Solenoid solenoid{5, frc::PneumaticsModuleType::CTREPCM, 2};
Solenoid solenoid{0, 5, frc::PneumaticsModuleType::CTREPCM, 2};
EXPECT_THROW(DoubleSolenoid(5, frc::PneumaticsModuleType::CTREPCM, 2, 3),
std::runtime_error);
}
TEST(DoubleSolenoidREVTest, ThrowReversePortAlreadyInitialized) {
// Single solenoid that is reused for forward port
Solenoid solenoid{6, frc::PneumaticsModuleType::CTREPCM, 3};
Solenoid solenoid{0, 6, frc::PneumaticsModuleType::CTREPCM, 3};
EXPECT_THROW(DoubleSolenoid(6, frc::PneumaticsModuleType::CTREPCM, 2, 3),
std::runtime_error);
}
TEST(DoubleSolenoidREVTest, ThrowBothPortsAlreadyInitialized) {
PneumaticsControlModule pcm{6};
PneumaticsControlModule pcm{0, 6};
// Single solenoid that is reused for forward port
Solenoid solenoid0(6, frc::PneumaticsModuleType::CTREPCM, 2);
Solenoid solenoid1(6, frc::PneumaticsModuleType::CTREPCM, 3);
Solenoid solenoid0(0, 6, frc::PneumaticsModuleType::CTREPCM, 2);
Solenoid solenoid1(0, 6, frc::PneumaticsModuleType::CTREPCM, 3);
EXPECT_THROW(DoubleSolenoid(6, frc::PneumaticsModuleType::CTREPCM, 2, 3),
std::runtime_error);
}
TEST(DoubleSolenoidREVTest, Toggle) {
DoubleSolenoid solenoid{4, frc::PneumaticsModuleType::CTREPCM, 2, 3};
DoubleSolenoid solenoid{0, 4, frc::PneumaticsModuleType::CTREPCM, 2, 3};
// Bootstrap it into reverse
solenoid.Set(DoubleSolenoid::kReverse);
@@ -64,12 +64,12 @@ TEST(DoubleSolenoidREVTest, Toggle) {
}
TEST(DoubleSolenoidREVTest, InvalidForwardPort) {
EXPECT_THROW(DoubleSolenoid(0, frc::PneumaticsModuleType::CTREPCM, 100, 1),
EXPECT_THROW(DoubleSolenoid(0, 0, frc::PneumaticsModuleType::CTREPCM, 100, 1),
std::runtime_error);
}
TEST(DoubleSolenoidREVTest, InvalidReversePort) {
EXPECT_THROW(DoubleSolenoid(0, frc::PneumaticsModuleType::CTREPCM, 0, 100),
EXPECT_THROW(DoubleSolenoid(0, 0, frc::PneumaticsModuleType::CTREPCM, 0, 100),
std::runtime_error);
}
} // namespace frc

View File

@@ -11,7 +11,7 @@
namespace frc {
TEST(SolenoidCTRETest, ValidInitialization) {
Solenoid solenoid{3, frc::PneumaticsModuleType::CTREPCM, 2};
Solenoid solenoid{0, 3, frc::PneumaticsModuleType::CTREPCM, 2};
EXPECT_EQ(2, solenoid.GetChannel());
solenoid.Set(true);
@@ -22,24 +22,24 @@ TEST(SolenoidCTRETest, ValidInitialization) {
}
TEST(SolenoidCTRETest, DoubleInitialization) {
Solenoid solenoid{3, frc::PneumaticsModuleType::CTREPCM, 2};
EXPECT_THROW(Solenoid(3, frc::PneumaticsModuleType::CTREPCM, 2),
Solenoid solenoid{0, 3, frc::PneumaticsModuleType::CTREPCM, 2};
EXPECT_THROW(Solenoid(0, 3, frc::PneumaticsModuleType::CTREPCM, 2),
std::runtime_error);
}
TEST(SolenoidCTRETest, DoubleInitializationFromDoubleSolenoid) {
DoubleSolenoid solenoid{3, frc::PneumaticsModuleType::CTREPCM, 2, 3};
EXPECT_THROW(Solenoid(3, frc::PneumaticsModuleType::CTREPCM, 2),
DoubleSolenoid solenoid{0, 3, frc::PneumaticsModuleType::CTREPCM, 2, 3};
EXPECT_THROW(Solenoid(0, 3, frc::PneumaticsModuleType::CTREPCM, 2),
std::runtime_error);
}
TEST(SolenoidCTRETest, InvalidChannel) {
EXPECT_THROW(Solenoid(3, frc::PneumaticsModuleType::CTREPCM, 100),
EXPECT_THROW(Solenoid(0, 3, frc::PneumaticsModuleType::CTREPCM, 100),
std::runtime_error);
}
TEST(SolenoidCTRETest, Toggle) {
Solenoid solenoid{3, frc::PneumaticsModuleType::CTREPCM, 2};
Solenoid solenoid{0, 3, frc::PneumaticsModuleType::CTREPCM, 2};
solenoid.Set(true);
EXPECT_TRUE(solenoid.Get());

View File

@@ -11,7 +11,7 @@
namespace frc {
TEST(SolenoidREVTest, ValidInitialization) {
Solenoid solenoid{3, frc::PneumaticsModuleType::REVPH, 2};
Solenoid solenoid{0, 3, frc::PneumaticsModuleType::REVPH, 2};
EXPECT_EQ(2, solenoid.GetChannel());
solenoid.Set(true);
@@ -22,24 +22,24 @@ TEST(SolenoidREVTest, ValidInitialization) {
}
TEST(SolenoidREVTest, DoubleInitialization) {
Solenoid solenoid{3, frc::PneumaticsModuleType::REVPH, 2};
EXPECT_THROW(Solenoid(3, frc::PneumaticsModuleType::REVPH, 2),
Solenoid solenoid{0, 3, frc::PneumaticsModuleType::REVPH, 2};
EXPECT_THROW(Solenoid(0, 3, frc::PneumaticsModuleType::REVPH, 2),
std::runtime_error);
}
TEST(SolenoidREVTest, DoubleInitializationFromDoubleSolenoid) {
DoubleSolenoid solenoid{3, frc::PneumaticsModuleType::REVPH, 2, 3};
EXPECT_THROW(Solenoid(3, frc::PneumaticsModuleType::REVPH, 2),
DoubleSolenoid solenoid{0, 3, frc::PneumaticsModuleType::REVPH, 2, 3};
EXPECT_THROW(Solenoid(0, 3, frc::PneumaticsModuleType::REVPH, 2),
std::runtime_error);
}
TEST(SolenoidREVTest, InvalidChannel) {
EXPECT_THROW(Solenoid(3, frc::PneumaticsModuleType::REVPH, 100),
EXPECT_THROW(Solenoid(0, 3, frc::PneumaticsModuleType::REVPH, 100),
std::runtime_error);
}
TEST(SolenoidREVTest, Toggle) {
Solenoid solenoid{3, frc::PneumaticsModuleType::REVPH, 2};
Solenoid solenoid{0, 3, frc::PneumaticsModuleType::REVPH, 2};
solenoid.Set(true);
EXPECT_TRUE(solenoid.Get());

View File

@@ -22,14 +22,14 @@ TEST(CTREPCMSimTest, InitializedCallback) {
BooleanCallback callback;
auto cb = sim.RegisterInitializedCallback(callback.GetCallback(), false);
PneumaticsControlModule pcm;
PneumaticsControlModule pcm{0};
EXPECT_TRUE(sim.GetInitialized());
EXPECT_TRUE(callback.WasTriggered());
EXPECT_TRUE(callback.GetLastValue());
}
TEST(CTREPCMSimTest, SolenoidOutput) {
PneumaticsControlModule pcm;
PneumaticsControlModule pcm{0};
CTREPCMSim sim(pcm);
sim.ResetData();
@@ -80,7 +80,7 @@ TEST(CTREPCMSimTest, SolenoidOutput) {
}
TEST(CTREPCMSimTest, SetCompressorOn) {
PneumaticsControlModule pcm;
PneumaticsControlModule pcm{0};
CTREPCMSim sim(pcm);
sim.ResetData();
@@ -97,7 +97,7 @@ TEST(CTREPCMSimTest, SetCompressorOn) {
}
TEST(CTREPCMSimTest, SetEnableDigital) {
PneumaticsControlModule pcm;
PneumaticsControlModule pcm{0};
CTREPCMSim sim(pcm);
sim.ResetData();
@@ -116,7 +116,7 @@ TEST(CTREPCMSimTest, SetEnableDigital) {
}
TEST(CTREPCMSimTest, SetPressureSwitchEnabled) {
PneumaticsControlModule pcm;
PneumaticsControlModule pcm{0};
CTREPCMSim sim(pcm);
sim.ResetData();
@@ -133,7 +133,7 @@ TEST(CTREPCMSimTest, SetPressureSwitchEnabled) {
}
TEST(CTREPCMSimTest, SetCompressorCurrent) {
PneumaticsControlModule pcm;
PneumaticsControlModule pcm{0};
CTREPCMSim sim(pcm);
sim.ResetData();

View File

@@ -22,7 +22,7 @@ TEST(PowerDistributionSimTest, Initialize) {
BooleanCallback callback;
auto cb = sim.RegisterInitializedCallback(callback.GetCallback(), false);
PowerDistribution pdp(2, frc::PowerDistribution::ModuleType::kCTRE);
PowerDistribution pdp(0, 2, frc::PowerDistribution::ModuleType::kCTRE);
EXPECT_TRUE(sim.GetInitialized());
EXPECT_TRUE(callback.WasTriggered());
EXPECT_TRUE(callback.GetLastValue());
@@ -35,7 +35,7 @@ TEST(PowerDistributionSimTest, Initialize) {
TEST(PowerDistributionSimTest, SetTemperature) {
HAL_Initialize(500, 0);
PowerDistribution pdp{2, frc::PowerDistribution::ModuleType::kCTRE};
PowerDistribution pdp{0, 2, frc::PowerDistribution::ModuleType::kCTRE};
PowerDistributionSim sim(pdp);
DoubleCallback callback;
@@ -50,7 +50,7 @@ TEST(PowerDistributionSimTest, SetTemperature) {
TEST(PowerDistributionSimTest, SetVoltage) {
HAL_Initialize(500, 0);
PowerDistribution pdp{2, frc::PowerDistribution::ModuleType::kCTRE};
PowerDistribution pdp{0, 2, frc::PowerDistribution::ModuleType::kCTRE};
PowerDistributionSim sim(pdp);
DoubleCallback callback;
@@ -65,7 +65,7 @@ TEST(PowerDistributionSimTest, SetVoltage) {
TEST(PowerDistributionSimTest, SetCurrent) {
HAL_Initialize(500, 0);
PowerDistribution pdp{2, frc::PowerDistribution::ModuleType::kCTRE};
PowerDistribution pdp{0, 2, frc::PowerDistribution::ModuleType::kCTRE};
PowerDistributionSim sim(pdp);
for (int channel = 0; channel < HAL_GetNumCTREPDPChannels(); ++channel) {
@@ -84,7 +84,7 @@ TEST(PowerDistributionSimTest, SetCurrent) {
TEST(PowerDistributionSimTest, GetAllCurrents) {
HAL_Initialize(500, 0);
PowerDistribution pdp{2, frc::PowerDistribution::ModuleType::kRev};
PowerDistribution pdp{0, 2, frc::PowerDistribution::ModuleType::kRev};
PowerDistributionSim sim(pdp);
// setup

View File

@@ -22,18 +22,18 @@ TEST(REVPHSimTest, InitializedCallback) {
BooleanCallback callback;
auto cb = sim.RegisterInitializedCallback(callback.GetCallback(), false);
PneumaticHub ph;
PneumaticHub ph{0};
EXPECT_TRUE(sim.GetInitialized());
EXPECT_TRUE(callback.WasTriggered());
EXPECT_TRUE(callback.GetLastValue());
}
TEST(REVPHSimTest, SolenoidOutput) {
PneumaticHub ph;
PneumaticHub ph{0};
REVPHSim sim(ph);
sim.ResetData();
DoubleSolenoid doubleSolenoid{1, frc::PneumaticsModuleType::REVPH, 3, 4};
DoubleSolenoid doubleSolenoid{0, 1, frc::PneumaticsModuleType::REVPH, 3, 4};
BooleanCallback callback3;
BooleanCallback callback4;
@@ -80,7 +80,7 @@ TEST(REVPHSimTest, SolenoidOutput) {
}
TEST(REVPHSimTest, SetCompressorOn) {
PneumaticHub ph;
PneumaticHub ph{0};
REVPHSim sim(ph);
sim.ResetData();
@@ -97,7 +97,7 @@ TEST(REVPHSimTest, SetCompressorOn) {
}
TEST(REVPHSimTest, SetEnableDigital) {
PneumaticHub ph;
PneumaticHub ph{0};
REVPHSim sim(ph);
sim.ResetData();
@@ -118,7 +118,7 @@ TEST(REVPHSimTest, SetEnableDigital) {
}
TEST(REVPHSimTest, SetEnableAnalog) {
PneumaticHub ph;
PneumaticHub ph{0};
REVPHSim sim(ph);
sim.ResetData();
@@ -139,7 +139,7 @@ TEST(REVPHSimTest, SetEnableAnalog) {
}
TEST(REVPHSimTest, SetEnableHybrid) {
PneumaticHub ph;
PneumaticHub ph{0};
REVPHSim sim(ph);
sim.ResetData();
@@ -160,7 +160,7 @@ TEST(REVPHSimTest, SetEnableHybrid) {
}
TEST(REVPHSimTest, SetPressureSwitchEnabled) {
PneumaticHub ph;
PneumaticHub ph{0};
REVPHSim sim(ph);
sim.ResetData();
@@ -177,7 +177,7 @@ TEST(REVPHSimTest, SetPressureSwitchEnabled) {
}
TEST(REVPHSimTest, SetCompressorCurrent) {
PneumaticHub ph;
PneumaticHub ph{0};
REVPHSim sim(ph);
sim.ResetData();

View File

@@ -51,7 +51,7 @@ class Robot : public frc::TimedRobot {
private:
// Object for dealing with the Power Distribution Panel (PDP).
frc::PowerDistribution m_pdp;
frc::PowerDistribution m_pdp{0};
};
#ifndef RUNNING_FRC_TESTS

View File

@@ -9,7 +9,7 @@
using namespace HatchConstants;
HatchSubsystem::HatchSubsystem()
: m_hatchSolenoid{frc::PneumaticsModuleType::CTREPCM,
: m_hatchSolenoid{0, frc::PneumaticsModuleType::CTREPCM,
kHatchSolenoidPorts[0], kHatchSolenoidPorts[1]} {}
frc2::CommandPtr HatchSubsystem::GrabHatchCommand() {

View File

@@ -9,7 +9,7 @@
using namespace HatchConstants;
HatchSubsystem::HatchSubsystem()
: m_hatchSolenoid{frc::PneumaticsModuleType::CTREPCM,
: m_hatchSolenoid{0, frc::PneumaticsModuleType::CTREPCM,
kHatchSolenoidPorts[0], kHatchSolenoidPorts[1]} {}
void HatchSubsystem::GrabHatch() {

View File

@@ -30,7 +30,7 @@ class Intake : public frc2::SubsystemBase {
frc::PWMSparkMax m_motor{IntakeConstants::kMotorPort};
// Double solenoid connected to two channels of a PCM with the default CAN ID
frc::DoubleSolenoid m_piston{frc::PneumaticsModuleType::CTREPCM,
frc::DoubleSolenoid m_piston{0, frc::PneumaticsModuleType::CTREPCM,
IntakeConstants::kSolenoidPorts[0],
IntakeConstants::kSolenoidPorts[1]};
};

View File

@@ -40,5 +40,5 @@ class Pneumatics : frc2::SubsystemBase {
kScale, kOffset};
// Compressor connected to a PH with a default CAN ID
frc::Compressor m_compressor{frc::PneumaticsModuleType::CTREPCM};
frc::Compressor m_compressor{0, frc::PneumaticsModuleType::CTREPCM};
};

View File

@@ -44,15 +44,16 @@ class Robot : public frc::TimedRobot {
// Solenoid corresponds to a single solenoid.
// In this case, it's connected to channel 0 of a PH with the default CAN
// ID.
frc::Solenoid m_solenoid{frc::PneumaticsModuleType::REVPH, 0};
frc::Solenoid m_solenoid{0, frc::PneumaticsModuleType::REVPH, 0};
// DoubleSolenoid corresponds to a double solenoid.
// In this case, it's connected to channels 1 and 2 of a PH with the default
// CAN ID.
frc::DoubleSolenoid m_doubleSolenoid{frc::PneumaticsModuleType::REVPH, 1, 2};
frc::DoubleSolenoid m_doubleSolenoid{0, frc::PneumaticsModuleType::REVPH, 1,
2};
// Compressor connected to a PH with a default CAN ID
frc::Compressor m_compressor{frc::PneumaticsModuleType::REVPH};
frc::Compressor m_compressor{0, frc::PneumaticsModuleType::REVPH};
static constexpr int kSolenoidButton = 1;
static constexpr int kDoubleSolenoidForward = 2;

View File

@@ -18,7 +18,7 @@ class Intake {
private:
frc::PWMSparkMax m_motor{IntakeConstants::kMotorPort};
frc::DoubleSolenoid m_piston{frc::PneumaticsModuleType::CTREPCM,
frc::DoubleSolenoid m_piston{0, frc::PneumaticsModuleType::CTREPCM,
IntakeConstants::kPistonFwdChannel,
IntakeConstants::kPistonRevChannel};
};

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;

View File

@@ -13,7 +13,7 @@ import org.junit.jupiter.api.Test;
class DoubleSolenoidTestCTRE {
@Test
void testValidInitialization() {
try (DoubleSolenoid solenoid = new DoubleSolenoid(3, PneumaticsModuleType.CTREPCM, 2, 3)) {
try (DoubleSolenoid solenoid = new DoubleSolenoid(0, 3, PneumaticsModuleType.CTREPCM, 2, 3)) {
solenoid.set(DoubleSolenoid.Value.kReverse);
assertEquals(DoubleSolenoid.Value.kReverse, solenoid.get());
@@ -29,10 +29,10 @@ class DoubleSolenoidTestCTRE {
void testThrowForwardPortAlreadyInitialized() {
try (
// Single solenoid that is reused for forward port
Solenoid solenoid = new Solenoid(5, PneumaticsModuleType.CTREPCM, 2)) {
Solenoid solenoid = new Solenoid(0, 5, PneumaticsModuleType.CTREPCM, 2)) {
assertThrows(
AllocationException.class,
() -> new DoubleSolenoid(5, PneumaticsModuleType.CTREPCM, 2, 3));
() -> new DoubleSolenoid(0, 5, PneumaticsModuleType.CTREPCM, 2, 3));
}
}
@@ -40,10 +40,10 @@ class DoubleSolenoidTestCTRE {
void testThrowReversePortAlreadyInitialized() {
try (
// Single solenoid that is reused for forward port
Solenoid solenoid = new Solenoid(6, PneumaticsModuleType.CTREPCM, 3)) {
Solenoid solenoid = new Solenoid(0, 6, PneumaticsModuleType.CTREPCM, 3)) {
assertThrows(
AllocationException.class,
() -> new DoubleSolenoid(6, PneumaticsModuleType.CTREPCM, 2, 3));
() -> new DoubleSolenoid(0, 6, PneumaticsModuleType.CTREPCM, 2, 3));
}
}
@@ -51,17 +51,17 @@ class DoubleSolenoidTestCTRE {
void testThrowBothPortsAlreadyInitialized() {
try (
// Single solenoid that is reused for forward port
Solenoid solenoid0 = new Solenoid(6, PneumaticsModuleType.CTREPCM, 2);
Solenoid solenoid1 = new Solenoid(6, PneumaticsModuleType.CTREPCM, 3)) {
Solenoid solenoid0 = new Solenoid(0, 6, PneumaticsModuleType.CTREPCM, 2);
Solenoid solenoid1 = new Solenoid(0, 6, PneumaticsModuleType.CTREPCM, 3)) {
assertThrows(
AllocationException.class,
() -> new DoubleSolenoid(6, PneumaticsModuleType.CTREPCM, 2, 3));
() -> new DoubleSolenoid(0, 6, PneumaticsModuleType.CTREPCM, 2, 3));
}
}
@Test
void testToggle() {
try (DoubleSolenoid solenoid = new DoubleSolenoid(4, PneumaticsModuleType.CTREPCM, 2, 3)) {
try (DoubleSolenoid solenoid = new DoubleSolenoid(0, 4, PneumaticsModuleType.CTREPCM, 2, 3)) {
// Bootstrap it into reverse
solenoid.set(DoubleSolenoid.Value.kReverse);
@@ -82,13 +82,13 @@ class DoubleSolenoidTestCTRE {
void testInvalidForwardPort() {
assertThrows(
IllegalArgumentException.class,
() -> new DoubleSolenoid(0, PneumaticsModuleType.CTREPCM, 100, 1));
() -> new DoubleSolenoid(0, 0, PneumaticsModuleType.CTREPCM, 100, 1));
}
@Test
void testInvalidReversePort() {
assertThrows(
IllegalArgumentException.class,
() -> new DoubleSolenoid(0, PneumaticsModuleType.CTREPCM, 0, 100));
() -> new DoubleSolenoid(0, 0, PneumaticsModuleType.CTREPCM, 0, 100));
}
}

View File

@@ -13,7 +13,7 @@ import org.junit.jupiter.api.Test;
class DoubleSolenoidTestREV {
@Test
void testValidInitialization() {
try (DoubleSolenoid solenoid = new DoubleSolenoid(3, PneumaticsModuleType.REVPH, 2, 3)) {
try (DoubleSolenoid solenoid = new DoubleSolenoid(0, 3, PneumaticsModuleType.REVPH, 2, 3)) {
solenoid.set(DoubleSolenoid.Value.kReverse);
assertEquals(DoubleSolenoid.Value.kReverse, solenoid.get());
@@ -29,9 +29,10 @@ class DoubleSolenoidTestREV {
void testThrowForwardPortAlreadyInitialized() {
try (
// Single solenoid that is reused for forward port
Solenoid solenoid = new Solenoid(5, PneumaticsModuleType.REVPH, 2)) {
Solenoid solenoid = new Solenoid(0, 5, PneumaticsModuleType.REVPH, 2)) {
assertThrows(
AllocationException.class, () -> new DoubleSolenoid(5, PneumaticsModuleType.REVPH, 2, 3));
AllocationException.class,
() -> new DoubleSolenoid(0, 5, PneumaticsModuleType.REVPH, 2, 3));
}
}
@@ -39,9 +40,10 @@ class DoubleSolenoidTestREV {
void testThrowReversePortAlreadyInitialized() {
try (
// Single solenoid that is reused for forward port
Solenoid solenoid = new Solenoid(6, PneumaticsModuleType.REVPH, 3)) {
Solenoid solenoid = new Solenoid(0, 6, PneumaticsModuleType.REVPH, 3)) {
assertThrows(
AllocationException.class, () -> new DoubleSolenoid(6, PneumaticsModuleType.REVPH, 2, 3));
AllocationException.class,
() -> new DoubleSolenoid(0, 6, PneumaticsModuleType.REVPH, 2, 3));
}
}
@@ -49,16 +51,17 @@ class DoubleSolenoidTestREV {
void testThrowBothPortsAlreadyInitialized() {
try (
// Single solenoid that is reused for forward port
Solenoid solenoid0 = new Solenoid(6, PneumaticsModuleType.REVPH, 2);
Solenoid solenoid1 = new Solenoid(6, PneumaticsModuleType.REVPH, 3)) {
Solenoid solenoid0 = new Solenoid(0, 6, PneumaticsModuleType.REVPH, 2);
Solenoid solenoid1 = new Solenoid(0, 6, PneumaticsModuleType.REVPH, 3)) {
assertThrows(
AllocationException.class, () -> new DoubleSolenoid(6, PneumaticsModuleType.REVPH, 2, 3));
AllocationException.class,
() -> new DoubleSolenoid(0, 6, PneumaticsModuleType.REVPH, 2, 3));
}
}
@Test
void testToggle() {
try (DoubleSolenoid solenoid = new DoubleSolenoid(4, PneumaticsModuleType.REVPH, 2, 3)) {
try (DoubleSolenoid solenoid = new DoubleSolenoid(0, 4, PneumaticsModuleType.REVPH, 2, 3)) {
// Bootstrap it into reverse
solenoid.set(DoubleSolenoid.Value.kReverse);
@@ -79,13 +82,13 @@ class DoubleSolenoidTestREV {
void testInvalidForwardPort() {
assertThrows(
IllegalArgumentException.class,
() -> new DoubleSolenoid(1, PneumaticsModuleType.REVPH, 100, 1));
() -> new DoubleSolenoid(0, 1, PneumaticsModuleType.REVPH, 100, 1));
}
@Test
void testInvalidReversePort() {
assertThrows(
IllegalArgumentException.class,
() -> new DoubleSolenoid(1, PneumaticsModuleType.REVPH, 0, 100));
() -> new DoubleSolenoid(0, 1, PneumaticsModuleType.REVPH, 0, 100));
}
}

View File

@@ -15,7 +15,7 @@ class PowerDistributionTest {
@Test
void testGetAllCurrents() {
HAL.initialize(500, 0);
PowerDistribution pdp = new PowerDistribution(1, ModuleType.kRev);
PowerDistribution pdp = new PowerDistribution(0, 1, ModuleType.kRev);
PDPSim sim = new PDPSim(pdp);
for (int i = 0; i < pdp.getNumChannels(); i++) {

View File

@@ -15,7 +15,7 @@ import org.junit.jupiter.api.Test;
class SolenoidTestCTRE {
@Test
void testValidInitialization() {
try (Solenoid solenoid = new Solenoid(3, PneumaticsModuleType.CTREPCM, 2)) {
try (Solenoid solenoid = new Solenoid(0, 3, PneumaticsModuleType.CTREPCM, 2)) {
assertEquals(2, solenoid.getChannel());
solenoid.set(true);
@@ -28,29 +28,30 @@ class SolenoidTestCTRE {
@Test
void testDoubleInitialization() {
try (Solenoid solenoid = new Solenoid(3, PneumaticsModuleType.CTREPCM, 2)) {
try (Solenoid solenoid = new Solenoid(0, 3, PneumaticsModuleType.CTREPCM, 2)) {
assertThrows(
AllocationException.class, () -> new Solenoid(3, PneumaticsModuleType.CTREPCM, 2));
AllocationException.class, () -> new Solenoid(0, 3, PneumaticsModuleType.CTREPCM, 2));
}
}
@Test
void testDoubleInitializationFromDoubleSolenoid() {
try (DoubleSolenoid solenoid = new DoubleSolenoid(3, PneumaticsModuleType.CTREPCM, 2, 3)) {
try (DoubleSolenoid solenoid = new DoubleSolenoid(0, 3, PneumaticsModuleType.CTREPCM, 2, 3)) {
assertThrows(
AllocationException.class, () -> new Solenoid(3, PneumaticsModuleType.CTREPCM, 2));
AllocationException.class, () -> new Solenoid(0, 3, PneumaticsModuleType.CTREPCM, 2));
}
}
@Test
void testInvalidChannel() {
assertThrows(
IllegalArgumentException.class, () -> new Solenoid(3, PneumaticsModuleType.CTREPCM, 100));
IllegalArgumentException.class,
() -> new Solenoid(0, 3, PneumaticsModuleType.CTREPCM, 100));
}
@Test
void testToggle() {
try (Solenoid solenoid = new Solenoid(3, PneumaticsModuleType.CTREPCM, 2)) {
try (Solenoid solenoid = new Solenoid(0, 3, PneumaticsModuleType.CTREPCM, 2)) {
solenoid.set(true);
assertTrue(solenoid.get());

View File

@@ -15,7 +15,7 @@ import org.junit.jupiter.api.Test;
class SolenoidTestREV {
@Test
void testValidInitialization() {
try (Solenoid solenoid = new Solenoid(3, PneumaticsModuleType.REVPH, 2)) {
try (Solenoid solenoid = new Solenoid(0, 3, PneumaticsModuleType.REVPH, 2)) {
assertEquals(2, solenoid.getChannel());
solenoid.set(true);
@@ -28,27 +28,29 @@ class SolenoidTestREV {
@Test
void testDoubleInitialization() {
try (Solenoid solenoid = new Solenoid(3, PneumaticsModuleType.REVPH, 2)) {
assertThrows(AllocationException.class, () -> new Solenoid(3, PneumaticsModuleType.REVPH, 2));
try (Solenoid solenoid = new Solenoid(0, 3, PneumaticsModuleType.REVPH, 2)) {
assertThrows(
AllocationException.class, () -> new Solenoid(0, 3, PneumaticsModuleType.REVPH, 2));
}
}
@Test
void testDoubleInitializationFromDoubleSolenoid() {
try (DoubleSolenoid solenoid = new DoubleSolenoid(3, PneumaticsModuleType.REVPH, 2, 3)) {
assertThrows(AllocationException.class, () -> new Solenoid(3, PneumaticsModuleType.REVPH, 2));
try (DoubleSolenoid solenoid = new DoubleSolenoid(0, 3, PneumaticsModuleType.REVPH, 2, 3)) {
assertThrows(
AllocationException.class, () -> new Solenoid(0, 3, PneumaticsModuleType.REVPH, 2));
}
}
@Test
void testInvalidChannel() {
assertThrows(
IllegalArgumentException.class, () -> new Solenoid(3, PneumaticsModuleType.REVPH, 100));
IllegalArgumentException.class, () -> new Solenoid(0, 3, PneumaticsModuleType.REVPH, 100));
}
@Test
void testToggle() {
try (Solenoid solenoid = new Solenoid(3, PneumaticsModuleType.REVPH, 2)) {
try (Solenoid solenoid = new Solenoid(0, 3, PneumaticsModuleType.REVPH, 2)) {
solenoid.set(true);
assertTrue(solenoid.get());

View File

@@ -16,6 +16,6 @@ class CANStatusTest {
void canStatusGetDoesntThrow() {
HAL.initialize(500, 0);
CANStatus status = new CANStatus();
assertDoesNotThrow(() -> CANJNI.getCANStatus(status));
assertDoesNotThrow(() -> CANJNI.getCANStatus(0, status));
}
}

Some files were not shown because too many files have changed in this diff Show More