Skip to content

Commit

Permalink
[hal] Add systemcore duty cycle (wpilibsuite#7682)
Browse files Browse the repository at this point in the history
  • Loading branch information
ThadHouse authored Jan 15, 2025
1 parent 24d6e87 commit 58cb395
Show file tree
Hide file tree
Showing 17 changed files with 138 additions and 233 deletions.
6 changes: 2 additions & 4 deletions hal/src/main/java/edu/wpi/first/hal/DutyCycleJNI.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,11 @@ public class DutyCycleJNI extends JNIWrapper {
/**
* Initialize a DutyCycle input.
*
* @param digitalSourceHandle the digital source to use (either a Digital Handle or a
* AnalogTrigger Handle)
* @param analogTriggerType the analog trigger type of the source if it is an analog trigger
* @param halPortHandle the port handle to create from
* @return the created duty cycle handle
* @see "HAL_InitializeDutyCycle"
*/
public static native int initialize(int digitalSourceHandle, int analogTriggerType);
public static native int initialize(int halPortHandle);

/**
* Free a DutyCycle.
Expand Down
12 changes: 7 additions & 5 deletions hal/src/main/native/cpp/jni/DutyCycleJNI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#include <jni.h>

#include <wpi/jni_util.h>

#include "HALUtil.h"
#include "edu_wpi_first_hal_DutyCycleJNI.h"
#include "hal/DutyCycle.h"
Expand All @@ -14,16 +16,16 @@ extern "C" {
/*
* Class: edu_wpi_first_hal_DutyCycleJNI
* Method: initialize
* Signature: (II)I
* Signature: (I)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_DutyCycleJNI_initialize
(JNIEnv* env, jclass, jint digitalSourceHandle, jint analogTriggerType)
(JNIEnv* env, jclass, jint portHandle)
{
int32_t status = 0;
auto handle = HAL_InitializeDutyCycle(
static_cast<HAL_Handle>(digitalSourceHandle),
static_cast<HAL_AnalogTriggerType>(analogTriggerType), &status);
auto stack = wpi::java::GetJavaStackTrace(env, "edu.wpi.first");
auto handle = HAL_InitializeDutyCycle(static_cast<HAL_Handle>(portHandle),
stack.c_str(), &status);
CheckStatus(env, status);
return handle;
}
Expand Down
12 changes: 5 additions & 7 deletions hal/src/main/native/include/hal/DutyCycle.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,14 @@ extern "C" {
/**
* Initialize a DutyCycle input.
*
* @param[in] digitalSourceHandle the digital source to use (either a
* HAL_DigitalHandle or a
* HAL_AnalogTriggerHandle)
* @param[in] triggerType the analog trigger type of the source if it is
* an analog trigger
* @param[in] portHandle the port handle to create from
* @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 duty cycle handle
*/
HAL_DutyCycleHandle HAL_InitializeDutyCycle(HAL_Handle digitalSourceHandle,
HAL_AnalogTriggerType triggerType,
HAL_DutyCycleHandle HAL_InitializeDutyCycle(HAL_PortHandle portHandle,
const char* allocationLocation,
int32_t* status);

/**
Expand Down
6 changes: 3 additions & 3 deletions hal/src/main/native/sim/DutyCycle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ void InitializeDutyCycle() {
} // namespace hal::init

extern "C" {
HAL_DutyCycleHandle HAL_InitializeDutyCycle(HAL_Handle digitalSourceHandle,
HAL_AnalogTriggerType triggerType,
HAL_DutyCycleHandle HAL_InitializeDutyCycle(HAL_PortHandle portHandle,
const char* allocationLocation,
int32_t* status) {
hal::init::CheckInit();

Expand All @@ -51,7 +51,7 @@ HAL_DutyCycleHandle HAL_InitializeDutyCycle(HAL_Handle digitalSourceHandle,
}

int16_t index = getHandleIndex(handle);
SimDutyCycleData[index].digitalChannel = getHandleIndex(digitalSourceHandle);
SimDutyCycleData[index].digitalChannel = getPortHandleChannel(portHandle);
SimDutyCycleData[index].initialized = true;
SimDutyCycleData[index].simDevice = 0;
dutyCycle->index = index;
Expand Down
78 changes: 71 additions & 7 deletions hal/src/main/native/systemcore/DutyCycle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,16 @@

#include "hal/DutyCycle.h"

#include <cstdio>
#include <memory>
#include <thread>

#include "HALInitializer.h"
#include "HALInternal.h"
#include "PortsInternal.h"
#include "SmartIo.h"
#include "hal/Errors.h"
#include "hal/cpp/fpga_clock.h"
#include "hal/handles/HandlesInternal.h"
#include "hal/handles/LimitedHandleResource.h"

Expand All @@ -19,15 +24,67 @@ void InitializeDutyCycle() {}
} // namespace hal::init

extern "C" {
HAL_DutyCycleHandle HAL_InitializeDutyCycle(HAL_Handle digitalSourceHandle,
HAL_AnalogTriggerType triggerType,
HAL_DutyCycleHandle HAL_InitializeDutyCycle(HAL_PortHandle portHandle,
const char* allocationLocation,
int32_t* status) {
hal::init::CheckInit();

*status = HAL_HANDLE_ERROR;
return HAL_kInvalidHandle;
int16_t channel = getPortHandleChannel(portHandle);
if (channel == InvalidHandleIndex || channel >= kNumSmartIo) {
*status = RESOURCE_OUT_OF_RANGE;
hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for DutyCycle", 0,
kNumSmartIo, channel);
return HAL_kInvalidHandle;
}

HAL_DigitalHandle handle;

auto port = smartIoHandles->Allocate(channel, HAL_HandleEnum::DutyCycle,
&handle, status);

if (*status != 0) {
if (port) {
hal::SetLastErrorPreviouslyAllocated(status, "SmartIo", channel,
port->previousAllocation);
} else {
hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for DutyCycle", 0,
kNumSmartIo, channel);
}
return HAL_kInvalidHandle; // failed to allocate. Pass error back.
}

port->channel = channel;

*status = port->InitializeMode(SmartIoMode::PwmInput);
if (*status != 0) {
smartIoHandles->Free(handle, HAL_HandleEnum::DutyCycle);
return HAL_kInvalidHandle;
}

port->previousAllocation = allocationLocation ? allocationLocation : "";

return handle;
}
void HAL_FreeDutyCycle(HAL_DutyCycleHandle dutyCycleHandle) {
auto port = smartIoHandles->Get(dutyCycleHandle, HAL_HandleEnum::DutyCycle);
if (port == nullptr) {
return;
}

smartIoHandles->Free(dutyCycleHandle, HAL_HandleEnum::DutyCycle);

// Wait for no other object to hold this handle.
auto start = hal::fpga_clock::now();
while (port.use_count() != 1) {
auto current = hal::fpga_clock::now();
if (start + std::chrono::seconds(1) < current) {
std::puts("DIO handle free timeout");
std::fflush(stdout);
break;
}
std::this_thread::yield();
}
}
void HAL_FreeDutyCycle(HAL_DutyCycleHandle dutyCycleHandle) {}

void HAL_SetDutyCycleSimDevice(HAL_EncoderHandle handle,
HAL_SimDeviceHandle device) {}
Expand All @@ -46,8 +103,15 @@ double HAL_GetDutyCycleOutput(HAL_DutyCycleHandle dutyCycleHandle,

int32_t HAL_GetDutyCycleHighTime(HAL_DutyCycleHandle dutyCycleHandle,
int32_t* status) {
*status = HAL_HANDLE_ERROR;
return 0;
auto port = smartIoHandles->Get(dutyCycleHandle, HAL_HandleEnum::DutyCycle);
if (port == nullptr) {
*status = HAL_HANDLE_ERROR;
return false;
}

uint16_t ret = false;
*status = port->GetPwmInputMicroseconds(&ret);
return ret;
}

int32_t HAL_GetDutyCycleOutputScaleFactor(HAL_DutyCycleHandle dutyCycleHandle,
Expand Down
11 changes: 11 additions & 0 deletions hal/src/main/native/systemcore/SmartIo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,17 @@ int32_t SmartIo::GetDigitalInput(bool* value) {
return 0;
}

int32_t SmartIo::GetPwmInputMicroseconds(uint16_t* microseconds) {
if (currentMode != SmartIoMode::PwmInput) {
return INCOMPATIBLE_STATE;
}

int val = getSubscriber.Get();
*microseconds = val;

return 0;
}

int32_t SmartIo::SetPwmOutputPeriod(PwmOutputPeriod period) {
if (currentMode != SmartIoMode::PwmOutput) {
return INCOMPATIBLE_STATE;
Expand Down
2 changes: 2 additions & 0 deletions hal/src/main/native/systemcore/SmartIo.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ struct SmartIo {
int32_t SetDigitalOutput(bool value);
int32_t GetDigitalInput(bool* value);

int32_t GetPwmInputMicroseconds(uint16_t* microseconds);

int32_t SetPwmOutputPeriod(PwmOutputPeriod period);

int32_t SetPwmMicroseconds(uint16_t microseconds);
Expand Down
39 changes: 13 additions & 26 deletions wpilibc/src/main/native/cpp/DutyCycle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,50 +4,37 @@

#include "frc/DutyCycle.h"

#include <string>
#include <utility>

#include <hal/DutyCycle.h>
#include <hal/FRCUsageReporting.h>
#include <hal/HALBase.h>
#include <wpi/NullDeleter.h>
#include <wpi/StackTrace.h>
#include <wpi/sendable/SendableBuilder.h>

#include "frc/DigitalSource.h"
#include "frc/Errors.h"
#include "frc/SensorUtil.h"

using namespace frc;

DutyCycle::DutyCycle(DigitalSource* source)
: m_source{source, wpi::NullDeleter<DigitalSource>()} {
if (!m_source) {
throw FRC_MakeError(err::NullParameter, "source");
}
InitDutyCycle();
}

DutyCycle::DutyCycle(DigitalSource& source)
: m_source{&source, wpi::NullDeleter<DigitalSource>()} {
InitDutyCycle();
}

DutyCycle::DutyCycle(std::shared_ptr<DigitalSource> source)
: m_source{std::move(source)} {
if (!m_source) {
throw FRC_MakeError(err::NullParameter, "source");
DutyCycle::DutyCycle(int channel) : m_channel{channel} {
if (!SensorUtil::CheckDigitalChannel(channel)) {
throw FRC_MakeError(err::ChannelIndexOutOfRange, "Channel {}", channel);
}
InitDutyCycle();
}

void DutyCycle::InitDutyCycle() {
int32_t status = 0;
m_handle =
HAL_InitializeDutyCycle(m_source->GetPortHandleForRouting(),
static_cast<HAL_AnalogTriggerType>(
m_source->GetAnalogTriggerTypeForRouting()),
&status);
std::string stackTrace = wpi::GetStackTrace(1);
m_handle = HAL_InitializeDutyCycle(HAL_GetPort(m_channel), stackTrace.c_str(),
&status);
FRC_CheckErrorStatus(status, "Channel {}", GetSourceChannel());
int index = GetFPGAIndex();
HAL_Report(HALUsageReporting::kResourceType_DutyCycle, index + 1);
wpi::SendableRegistry::AddLW(this, "Duty Cycle", index);
HAL_Report(HALUsageReporting::kResourceType_DutyCycle, m_channel + 1);
wpi::SendableRegistry::AddLW(this, "Duty Cycle", m_channel);
}

int DutyCycle::GetFPGAIndex() const {
Expand Down Expand Up @@ -86,7 +73,7 @@ unsigned int DutyCycle::GetOutputScaleFactor() const {
}

int DutyCycle::GetSourceChannel() const {
return m_source->GetChannel();
return m_channel;
}

void DutyCycle::InitSendable(wpi::SendableBuilder& builder) {
Expand Down
39 changes: 2 additions & 37 deletions wpilibc/src/main/native/cpp/DutyCycleEncoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@
using namespace frc;

DutyCycleEncoder::DutyCycleEncoder(int channel)
: m_dutyCycle{std::make_shared<DutyCycle>(
std::make_shared<DigitalInput>(channel))} {
: m_dutyCycle{std::make_shared<DutyCycle>(channel)} {
Init(1.0, 0.0);
}

Expand All @@ -38,25 +37,9 @@ DutyCycleEncoder::DutyCycleEncoder(std::shared_ptr<DutyCycle> dutyCycle)
Init(1.0, 0.0);
}

DutyCycleEncoder::DutyCycleEncoder(DigitalSource& digitalSource)
: m_dutyCycle{std::make_shared<DutyCycle>(digitalSource)} {
Init(1.0, 0.0);
}

DutyCycleEncoder::DutyCycleEncoder(DigitalSource* digitalSource)
: m_dutyCycle{std::make_shared<DutyCycle>(digitalSource)} {
Init(1.0, 0.0);
}

DutyCycleEncoder::DutyCycleEncoder(std::shared_ptr<DigitalSource> digitalSource)
: m_dutyCycle{std::make_shared<DutyCycle>(digitalSource)} {
Init(1.0, 0.0);
}

DutyCycleEncoder::DutyCycleEncoder(int channel, double fullRange,
double expectedZero)
: m_dutyCycle{std::make_shared<DutyCycle>(
std::make_shared<DigitalInput>(channel))} {
: m_dutyCycle{std::make_shared<DutyCycle>(channel)} {
Init(fullRange, expectedZero);
}

Expand All @@ -78,24 +61,6 @@ DutyCycleEncoder::DutyCycleEncoder(std::shared_ptr<DutyCycle> dutyCycle,
Init(fullRange, expectedZero);
}

DutyCycleEncoder::DutyCycleEncoder(DigitalSource& digitalSource,
double fullRange, double expectedZero)
: m_dutyCycle{std::make_shared<DutyCycle>(digitalSource)} {
Init(fullRange, expectedZero);
}

DutyCycleEncoder::DutyCycleEncoder(DigitalSource* digitalSource,
double fullRange, double expectedZero)
: m_dutyCycle{std::make_shared<DutyCycle>(digitalSource)} {
Init(fullRange, expectedZero);
}

DutyCycleEncoder::DutyCycleEncoder(std::shared_ptr<DigitalSource> digitalSource,
double fullRange, double expectedZero)
: m_dutyCycle{std::make_shared<DutyCycle>(digitalSource)} {
Init(fullRange, expectedZero);
}

void DutyCycleEncoder::Init(double fullRange, double expectedZero) {
m_simDevice = hal::SimDevice{"DutyCycle:DutyCycleEncoder",
m_dutyCycle->GetSourceChannel()};
Expand Down
26 changes: 4 additions & 22 deletions wpilibc/src/main/native/include/frc/DutyCycle.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,29 +36,11 @@ class DutyCycle : public wpi::Sendable, public wpi::SendableHelper<DutyCycle> {

public:
/**
* Constructs a DutyCycle input from a DigitalSource input.
* Constructs a DutyCycle input from a smartio channel.
*
* <p> This class does not own the inputted source.
*
* @param source The DigitalSource to use.
*/
explicit DutyCycle(DigitalSource& source);
/**
* Constructs a DutyCycle input from a DigitalSource input.
*
* <p> This class does not own the inputted source.
*
* @param source The DigitalSource to use.
*/
explicit DutyCycle(DigitalSource* source);
/**
* Constructs a DutyCycle input from a DigitalSource input.
*
* <p> This class does not own the inputted source.
*
* @param source The DigitalSource to use.
* @param source The channel to use.
*/
explicit DutyCycle(std::shared_ptr<DigitalSource> source);
explicit DutyCycle(int source);

DutyCycle(DutyCycle&&) = default;
DutyCycle& operator=(DutyCycle&&) = default;
Expand Down Expand Up @@ -121,7 +103,7 @@ class DutyCycle : public wpi::Sendable, public wpi::SendableHelper<DutyCycle> {

private:
void InitDutyCycle();
std::shared_ptr<DigitalSource> m_source;
int m_channel;
hal::Handle<HAL_DutyCycleHandle, HAL_FreeDutyCycle> m_handle;
};
} // namespace frc
Loading

0 comments on commit 58cb395

Please sign in to comment.