From a5df391166b1bed0da5663545752e4bdd1af43a6 Mon Sep 17 00:00:00 2001 From: Thad House Date: Fri, 2 Sep 2022 16:49:42 -0700 Subject: [PATCH] [hal, wpilib] Fix up DIO pulse API (#4387) The FPGA API takes microseconds directly, instead of a scaled value. Also add a new HAL level API to trigger multiple DIOs with the same pulse at once. --- .../main/java/edu/wpi/first/hal/DIOJNI.java | 4 +- hal/src/main/native/athena/DIO.cpp | 39 +++++++++++++++++-- hal/src/main/native/cpp/jni/DIOJNI.cpp | 14 +++++++ hal/src/main/native/include/hal/DIO.h | 17 +++++++- hal/src/main/native/sim/DIO.cpp | 7 +++- wpilibc/src/main/native/cpp/DigitalOutput.cpp | 4 +- .../main/native/include/frc/DigitalOutput.h | 7 ++-- .../src/main/native/include/frc/Ultrasonic.h | 4 +- .../edu/wpi/first/wpilibj/DigitalOutput.java | 11 ++++-- 9 files changed, 88 insertions(+), 19 deletions(-) diff --git a/hal/src/main/java/edu/wpi/first/hal/DIOJNI.java b/hal/src/main/java/edu/wpi/first/hal/DIOJNI.java index dab1aaf7b59..63c9c259f2a 100644 --- a/hal/src/main/java/edu/wpi/first/hal/DIOJNI.java +++ b/hal/src/main/java/edu/wpi/first/hal/DIOJNI.java @@ -22,7 +22,9 @@ public class DIOJNI extends JNIWrapper { public static native boolean getDIODirection(int dioPortHandle); - public static native void pulse(int dioPortHandle, double pulseLength); + public static native void pulse(int dioPortHandle, double pulseLengthSeconds); + + public static native void pulseMultiple(long channelMask, double pulseLengthSeconds); public static native boolean isPulsing(int dioPortHandle); diff --git a/hal/src/main/native/athena/DIO.cpp b/hal/src/main/native/athena/DIO.cpp index e9248f1ec63..01437043aa7 100644 --- a/hal/src/main/native/athena/DIO.cpp +++ b/hal/src/main/native/athena/DIO.cpp @@ -408,13 +408,24 @@ HAL_Bool HAL_GetDIODirection(HAL_DigitalHandle dioPortHandle, int32_t* status) { } } -void HAL_Pulse(HAL_DigitalHandle dioPortHandle, double pulseLength, +void HAL_Pulse(HAL_DigitalHandle dioPortHandle, double pulseLengthSeconds, int32_t* status) { auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO); if (port == nullptr) { *status = HAL_HANDLE_ERROR; return; } + + uint32_t pulseLengthMicroseconds = + static_cast(pulseLengthSeconds * 1e6); + + if (pulseLengthMicroseconds <= 0 || pulseLengthMicroseconds > 0xFFFF) { + *status = PARAMETER_OUT_OF_RANGE; + hal::SetLastError(status, + "Length must be between 1 and 65535 microseconds"); + return; + } + tDIO::tPulse pulse; if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) { @@ -426,9 +437,29 @@ void HAL_Pulse(HAL_DigitalHandle dioPortHandle, double pulseLength, } digitalSystem->writePulseLength( - static_cast(1.0e9 * pulseLength / - (pwmSystem->readLoopTiming(status) * 25)), - status); + static_cast(pulseLengthMicroseconds), status); + digitalSystem->writePulse(pulse, status); +} + +void HAL_PulseMultiple(uint32_t channelMask, double pulseLengthSeconds, + int32_t* status) { + uint32_t pulseLengthMicroseconds = + static_cast(pulseLengthSeconds * 1e6); + + if (pulseLengthMicroseconds <= 0 || pulseLengthMicroseconds > 0xFFFF) { + *status = PARAMETER_OUT_OF_RANGE; + hal::SetLastError(status, + "Length must be between 1 and 65535 microseconds"); + return; + } + + tDIO::tPulse pulse; + pulse.Headers = channelMask & 0x2FF; + pulse.MXP = (channelMask & 0xFFFF) >> 10; + pulse.SPIPort = (channelMask & 0x1F) >> 26; + + digitalSystem->writePulseLength( + static_cast(pulseLengthMicroseconds), status); digitalSystem->writePulse(pulse, status); } diff --git a/hal/src/main/native/cpp/jni/DIOJNI.cpp b/hal/src/main/native/cpp/jni/DIOJNI.cpp index 5cd6c2e9dfd..264a347ac66 100644 --- a/hal/src/main/native/cpp/jni/DIOJNI.cpp +++ b/hal/src/main/native/cpp/jni/DIOJNI.cpp @@ -144,6 +144,20 @@ Java_edu_wpi_first_hal_DIOJNI_pulse CheckStatus(env, status); } +/* + * Class: edu_wpi_first_hal_DIOJNI + * Method: pulseMultiple + * Signature: (JD)V + */ +JNIEXPORT void JNICALL +Java_edu_wpi_first_hal_DIOJNI_pulseMultiple + (JNIEnv* env, jclass, jlong channelMask, jdouble value) +{ + int32_t status = 0; + HAL_PulseMultiple(static_cast(channelMask), value, &status); + CheckStatus(env, status); +} + /* * Class: edu_wpi_first_hal_DIOJNI * Method: isPulsing diff --git a/hal/src/main/native/include/hal/DIO.h b/hal/src/main/native/include/hal/DIO.h index e094a0d15c1..e6a703b16cb 100644 --- a/hal/src/main/native/include/hal/DIO.h +++ b/hal/src/main/native/include/hal/DIO.h @@ -150,12 +150,25 @@ HAL_Bool HAL_GetDIODirection(HAL_DigitalHandle dioPortHandle, int32_t* status); * single pulse going at any time. * * @param[in] dioPortHandle the digital port handle - * @param[in] pulseLength the active length of the pulse (in seconds) + * @param[in] pulseLengthSeconds the active length of the pulse (in seconds) * @param[out] status Error status variable. 0 on success. */ -void HAL_Pulse(HAL_DigitalHandle dioPortHandle, double pulseLength, +void HAL_Pulse(HAL_DigitalHandle dioPortHandle, double pulseLengthSeconds, int32_t* status); +/** + * Generates a single digital pulse on multiple channels. + * + * Write a pulse to the channels enabled by the mask. There can only be a + * single pulse going at any time. + * + * @param[in] channelMask the channel mask + * @param[in] pulseLengthSeconds the active length of the pulse (in seconds) + * @param[out] status Error status variable. 0 on success. + */ +void HAL_PulseMultiple(uint32_t channelMask, double pulseLengthSeconds, + int32_t* status); + /** * Checks a DIO line to see if it is currently generating a pulse. * diff --git a/hal/src/main/native/sim/DIO.cpp b/hal/src/main/native/sim/DIO.cpp index 1b744a1625d..53c700cb2d5 100644 --- a/hal/src/main/native/sim/DIO.cpp +++ b/hal/src/main/native/sim/DIO.cpp @@ -225,7 +225,7 @@ HAL_Bool HAL_GetDIODirection(HAL_DigitalHandle dioPortHandle, int32_t* status) { return value; } -void HAL_Pulse(HAL_DigitalHandle dioPortHandle, double pulseLength, +void HAL_Pulse(HAL_DigitalHandle dioPortHandle, double pulseLengthSeconds, int32_t* status) { auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO); if (port == nullptr) { @@ -235,6 +235,11 @@ void HAL_Pulse(HAL_DigitalHandle dioPortHandle, double pulseLength, // TODO (Thad) Add this } +void HAL_PulseMultiple(uint32_t channelMask, double pulseLengthSeconds, + int32_t* status) { + // TODO (Thad) Add this +} + HAL_Bool HAL_IsPulsing(HAL_DigitalHandle dioPortHandle, int32_t* status) { auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO); if (port == nullptr) { diff --git a/wpilibc/src/main/native/cpp/DigitalOutput.cpp b/wpilibc/src/main/native/cpp/DigitalOutput.cpp index 5810e30eace..3890782a7de 100644 --- a/wpilibc/src/main/native/cpp/DigitalOutput.cpp +++ b/wpilibc/src/main/native/cpp/DigitalOutput.cpp @@ -76,9 +76,9 @@ int DigitalOutput::GetChannel() const { return m_channel; } -void DigitalOutput::Pulse(double length) { +void DigitalOutput::Pulse(units::second_t pulseLength) { int32_t status = 0; - HAL_Pulse(m_handle, length, &status); + HAL_Pulse(m_handle, pulseLength.to(), &status); FRC_CheckErrorStatus(status, "Channel {}", m_channel); } diff --git a/wpilibc/src/main/native/include/frc/DigitalOutput.h b/wpilibc/src/main/native/include/frc/DigitalOutput.h index 0e124f104e7..073f1568b68 100644 --- a/wpilibc/src/main/native/include/frc/DigitalOutput.h +++ b/wpilibc/src/main/native/include/frc/DigitalOutput.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include #include @@ -79,11 +80,11 @@ class DigitalOutput : public DigitalSource, * Output a single pulse on the digital output line. * * Send a single pulse on the digital output line where the pulse duration is - * specified in seconds. Maximum pulse length is 0.0016 seconds. + * specified in seconds. Maximum of 65535 microseconds. * - * @param length The pulse length in seconds + * @param pulseLength The pulse length in seconds */ - void Pulse(double length); + void Pulse(units::second_t pulseLength); /** * Determine if the pulse is still going. diff --git a/wpilibc/src/main/native/include/frc/Ultrasonic.h b/wpilibc/src/main/native/include/frc/Ultrasonic.h index 850f7b3337e..137a5b75aeb 100644 --- a/wpilibc/src/main/native/include/frc/Ultrasonic.h +++ b/wpilibc/src/main/native/include/frc/Ultrasonic.h @@ -164,8 +164,8 @@ class Ultrasonic : public wpi::Sendable, */ static void UltrasonicChecker(); - // Time (sec) for the ping trigger pulse. - static constexpr double kPingTime = 10 * 1e-6; + // Time (usec) for the ping trigger pulse. + static constexpr auto kPingTime = 10_us; // Max time (ms) between readings. static constexpr auto kMaxUltrasonicTime = 0.1_s; diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/DigitalOutput.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/DigitalOutput.java index 2c87df577df..1859d9318b3 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/DigitalOutput.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/DigitalOutput.java @@ -80,12 +80,15 @@ public int getChannel() { } /** - * Generate a single pulse. There can only be a single pulse going at any time. + * Output a single pulse on the digital output line. * - * @param pulseLength The length of the pulse. + *

Send a single pulse on the digital output line where the pulse duration is specified in + * seconds. Maximum of 65535 microseconds. + * + * @param pulseLengthSeconds The pulse length in seconds */ - public void pulse(final double pulseLength) { - DIOJNI.pulse(m_handle, pulseLength); + public void pulse(final double pulseLengthSeconds) { + DIOJNI.pulse(m_handle, pulseLengthSeconds); } /**