[hal] Resource classes: Use expected, refactor errors (#8768)

Also revamp SetLastError et al; Instead of taking status by pointer,
take by value and return new status instead. Rename from SetLast to Make
to make this new usage obvious.

Also move declarations for the error functions from duplicated in the
per-target HALInternal.hpp to a common ErrorHandling.hpp.
This commit is contained in:
Peter Johnson
2026-04-17 20:19:38 -07:00
committed by GitHub
parent 6cb6903780
commit a97214df43
31 changed files with 309 additions and 406 deletions

View File

@@ -8,9 +8,9 @@
#include "DigitalInternal.hpp"
#include "HALInitializer.hpp"
#include "HALInternal.hpp"
#include "PortsInternal.hpp"
#include "mockdata/AddressableLEDDataInternal.hpp"
#include "wpi/hal/ErrorHandling.hpp"
#include "wpi/hal/Errors.h"
#include "wpi/hal/handles/HandlesInternal.hpp"
@@ -26,30 +26,21 @@ HAL_AddressableLEDHandle HAL_InitializeAddressableLED(
wpi::hal::init::CheckInit();
if (channel < 0 || channel >= kNumAddressableLEDs) {
*status = RESOURCE_OUT_OF_RANGE;
wpi::hal::SetLastErrorIndexOutOfRange(status,
"Invalid Index for AddressableLED", 0,
kNumAddressableLEDs, channel);
*status = MakeErrorIndexOutOfRange(RESOURCE_OUT_OF_RANGE,
"Invalid Index for AddressableLED", 0,
kNumAddressableLEDs, channel);
return HAL_INVALID_HANDLE;
}
HAL_DigitalHandle handle;
auto resource = digitalChannelHandles->Allocate(
channel, HAL_HandleEnum::ADDRESSABLE_LED, "AddressableLED");
auto port = digitalChannelHandles->Allocate(
channel, HAL_HandleEnum::ADDRESSABLE_LED, &handle, status);
if (*status != 0) {
if (port) {
wpi::hal::SetLastErrorPreviouslyAllocated(status, "PWM or DIO", channel,
port->previousAllocation);
} else {
wpi::hal::SetLastErrorIndexOutOfRange(status,
"Invalid Index for AddressableLED",
0, kNumAddressableLEDs, channel);
}
if (!resource) {
*status = resource.error();
return HAL_INVALID_HANDLE; // failed to allocate. Pass error back.
}
auto [handle, port] = *resource;
port->channel = static_cast<uint8_t>(channel);
SimAddressableLEDData[channel].start = 0;
@@ -80,9 +71,8 @@ void HAL_SetAddressableLEDStart(HAL_AddressableLEDHandle handle, int32_t start,
return;
}
if (start > HAL_ADDRESSABLE_LED_MAX_LEN || start < 0) {
*status = PARAMETER_OUT_OF_RANGE;
wpi::hal::SetLastError(
status,
*status = MakeError(
PARAMETER_OUT_OF_RANGE,
fmt::format(
"LED start must be less than or equal to {}. {} was requested",
HAL_ADDRESSABLE_LED_MAX_LEN, start));
@@ -100,9 +90,8 @@ void HAL_SetAddressableLEDLength(HAL_AddressableLEDHandle handle,
return;
}
if (length > HAL_ADDRESSABLE_LED_MAX_LEN || length < 0) {
*status = PARAMETER_OUT_OF_RANGE;
wpi::hal::SetLastError(
status,
*status = MakeError(
PARAMETER_OUT_OF_RANGE,
fmt::format(
"LED length must be less than or equal to {}. {} was requested",
HAL_ADDRESSABLE_LED_MAX_LEN, length));

View File

@@ -6,9 +6,9 @@
#include "AnalogInternal.hpp"
#include "HALInitializer.hpp"
#include "HALInternal.hpp"
#include "PortsInternal.hpp"
#include "mockdata/AnalogInDataInternal.hpp"
#include "wpi/hal/ErrorHandling.hpp"
using namespace wpi::hal;
@@ -21,27 +21,20 @@ HAL_AnalogInputHandle HAL_InitializeAnalogInputPort(
int32_t channel, const char* allocationLocation, int32_t* status) {
wpi::hal::init::CheckInit();
if (channel < 0 || channel >= kNumAnalogInputs) {
*status = RESOURCE_OUT_OF_RANGE;
wpi::hal::SetLastErrorIndexOutOfRange(
status, "Invalid Index for Analog Input", 0, kNumAnalogInputs, channel);
*status = MakeErrorIndexOutOfRange(RESOURCE_OUT_OF_RANGE,
"Invalid Index for Analog Input", 0,
kNumAnalogInputs, channel);
return HAL_INVALID_HANDLE;
}
HAL_AnalogInputHandle handle;
auto analog_port = analogInputHandles->Allocate(channel, &handle, status);
auto resource = analogInputHandles->Allocate(channel, "Analog");
if (*status != 0) {
if (analog_port) {
wpi::hal::SetLastErrorPreviouslyAllocated(
status, "Analog Input", channel, analog_port->previousAllocation);
} else {
wpi::hal::SetLastErrorIndexOutOfRange(status,
"Invalid Index for Analog Input", 0,
kNumAnalogInputs, channel);
}
if (!resource) {
*status = resource.error();
return HAL_INVALID_HANDLE; // failed to allocate. Pass error back.
}
auto [handle, analog_port] = *resource;
analog_port->channel = static_cast<uint8_t>(channel);
SimAnalogInData[channel].initialized = true;

View File

@@ -7,9 +7,9 @@
#include <string>
#include "HALInitializer.hpp"
#include "HALInternal.hpp"
#include "PortsInternal.hpp"
#include "mockdata/CTREPCMDataInternal.hpp"
#include "wpi/hal/ErrorHandling.hpp"
#include "wpi/hal/Errors.h"
#include "wpi/hal/handles/IndexedHandleResource.hpp"
@@ -40,21 +40,14 @@ HAL_CTREPCMHandle HAL_InitializeCTREPCM(int32_t busId, int32_t module,
int32_t* status) {
wpi::hal::init::CheckInit();
HAL_CTREPCMHandle handle;
auto pcm = pcmHandles->Allocate(module, &handle, status);
auto resource = pcmHandles->Allocate(module, "CTRE PCM");
if (*status != 0) {
if (pcm) {
wpi::hal::SetLastErrorPreviouslyAllocated(status, "CTRE PCM", module,
pcm->previousAllocation);
} else {
wpi::hal::SetLastErrorIndexOutOfRange(status,
"Invalid Index for CTRE PCM", 0,
kNumCTREPCMModules - 1, module);
}
if (!resource) {
*status = resource.error();
return HAL_INVALID_HANDLE; // failed to allocate. Pass error back.
}
auto [handle, pcm] = *resource;
pcm->previousAllocation = allocationLocation ? allocationLocation : "";
pcm->module = module;

View File

@@ -6,10 +6,11 @@
#include "DigitalInternal.hpp"
#include "HALInitializer.hpp"
#include "HALInternal.hpp"
#include "PortsInternal.hpp"
#include "mockdata/DIODataInternal.hpp"
#include "mockdata/DigitalPWMDataInternal.hpp"
#include "wpi/hal/ErrorHandling.hpp"
#include "wpi/hal/Errors.h"
#include "wpi/hal/handles/HandlesInternal.hpp"
#include "wpi/hal/handles/LimitedHandleResource.hpp"
@@ -37,28 +38,21 @@ HAL_DigitalHandle HAL_InitializeDIOPort(int32_t channel, HAL_Bool input,
wpi::hal::init::CheckInit();
if (channel < 0 || channel >= kNumDigitalChannels) {
*status = RESOURCE_OUT_OF_RANGE;
wpi::hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for DIO", 0,
kNumDigitalChannels, channel);
*status =
MakeErrorIndexOutOfRange(RESOURCE_OUT_OF_RANGE, "Invalid Index for DIO",
0, kNumDigitalChannels, channel);
return HAL_INVALID_HANDLE;
}
HAL_DigitalHandle handle;
auto resource =
digitalChannelHandles->Allocate(channel, HAL_HandleEnum::DIO, "DIO");
auto port = digitalChannelHandles->Allocate(channel, HAL_HandleEnum::DIO,
&handle, status);
if (*status != 0) {
if (port) {
wpi::hal::SetLastErrorPreviouslyAllocated(status, "PWM or DIO", channel,
port->previousAllocation);
} else {
wpi::hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for DIO", 0,
kNumDigitalChannels, channel);
}
if (!resource) {
*status = resource.error();
return HAL_INVALID_HANDLE; // failed to allocate. Pass error back.
}
auto [handle, port] = *resource;
port->channel = static_cast<uint8_t>(channel);
SimDIOData[channel].initialized = true;
@@ -189,8 +183,8 @@ void HAL_SetDIO(HAL_DigitalHandle dioPortHandle, HAL_Bool value,
}
}
if (SimDIOData[port->channel].isInput) {
*status = PARAMETER_OUT_OF_RANGE;
wpi::hal::SetLastError(status, "Cannot set output of an input channel");
*status = MakeError(PARAMETER_OUT_OF_RANGE,
"Cannot set output of an input channel");
return;
}
SimDIOData[port->channel].value = value;

View File

@@ -7,9 +7,9 @@
#include <string>
#include "HALInitializer.hpp"
#include "HALInternal.hpp"
#include "PortsInternal.hpp"
#include "mockdata/DutyCycleDataInternal.hpp"
#include "wpi/hal/ErrorHandling.hpp"
#include "wpi/hal/Errors.h"
#include "wpi/hal/handles/HandlesInternal.hpp"
#include "wpi/hal/handles/IndexedHandleResource.hpp"
@@ -42,20 +42,14 @@ HAL_DutyCycleHandle HAL_InitializeDutyCycle(int32_t channel,
int32_t* status) {
wpi::hal::init::CheckInit();
HAL_DutyCycleHandle handle = HAL_INVALID_HANDLE;
auto dutyCycle = dutyCycleHandles->Allocate(channel, &handle, status);
auto resource = dutyCycleHandles->Allocate(channel, "Duty Cycle");
if (*status != 0) {
if (dutyCycle) {
wpi::hal::SetLastErrorPreviouslyAllocated(status, "SmartIo", channel,
dutyCycle->previousAllocation);
} else {
wpi::hal::SetLastErrorIndexOutOfRange(
status, "Invalid Index for Duty Cycle", 0, kNumDutyCycles, channel);
}
if (!resource) {
*status = resource.error();
return HAL_INVALID_HANDLE; // failed to allocate. Pass error back.
}
auto [handle, dutyCycle] = *resource;
int16_t index = getHandleIndex(handle);
SimDutyCycleData[index].initialized = true;
SimDutyCycleData[index].simDevice = 0;

View File

@@ -8,9 +8,9 @@
#include "CounterInternal.hpp"
#include "HALInitializer.hpp"
#include "HALInternal.hpp"
#include "PortsInternal.hpp"
#include "mockdata/EncoderDataInternal.hpp"
#include "wpi/hal/ErrorHandling.hpp"
#include "wpi/hal/Errors.h"
#include "wpi/hal/handles/HandlesInternal.hpp"
#include "wpi/hal/handles/LimitedHandleResource.hpp"
@@ -271,8 +271,7 @@ void HAL_SetEncoderMinRate(HAL_EncoderHandle encoderHandle, double minRate,
}
if (minRate == 0.0) {
*status = PARAMETER_OUT_OF_RANGE;
wpi::hal::SetLastError(status, "minRate must not be 0");
*status = MakeError(PARAMETER_OUT_OF_RANGE, "minRate must not be 0");
return;
}
@@ -288,8 +287,8 @@ void HAL_SetEncoderDistancePerPulse(HAL_EncoderHandle encoderHandle,
}
if (distancePerPulse == 0.0) {
*status = PARAMETER_OUT_OF_RANGE;
wpi::hal::SetLastError(status, "distancePerPulse must not be 0");
*status =
MakeError(PARAMETER_OUT_OF_RANGE, "distancePerPulse must not be 0");
return;
}
encoder->distancePerPulse = distancePerPulse;

View File

@@ -1,19 +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.
#pragma once
#include <stdint.h>
#include <string_view>
namespace wpi::hal {
void SetLastError(int32_t* status, std::string_view value);
void SetLastErrorIndexOutOfRange(int32_t* status, std::string_view message,
int32_t minimum, int32_t maximum,
int32_t channel);
void SetLastErrorPreviouslyAllocated(int32_t* status, std::string_view message,
int32_t channel,
std::string_view previousAllocation);
} // namespace wpi::hal

View File

@@ -6,9 +6,9 @@
#include "DigitalInternal.hpp"
#include "HALInitializer.hpp"
#include "HALInternal.hpp"
#include "PortsInternal.hpp"
#include "mockdata/PWMDataInternal.hpp"
#include "wpi/hal/ErrorHandling.hpp"
#include "wpi/hal/handles/HandlesInternal.hpp"
using namespace wpi::hal;
@@ -25,9 +25,9 @@ HAL_DigitalHandle HAL_InitializePWMPort(int32_t channel,
wpi::hal::init::CheckInit();
if (channel < 0 || channel >= kNumPWMChannels) {
*status = RESOURCE_OUT_OF_RANGE;
wpi::hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for PWM", 0,
kNumPWMChannels, channel);
*status =
MakeErrorIndexOutOfRange(RESOURCE_OUT_OF_RANGE, "Invalid Index for PWM",
0, kNumPWMChannels, channel);
return HAL_INVALID_HANDLE;
}
@@ -39,22 +39,15 @@ HAL_DigitalHandle HAL_InitializePWMPort(int32_t channel,
channel = remapMXPPWMChannel(channel) + 10; // remap MXP to proper channel
}
HAL_DigitalHandle handle;
auto resource =
digitalChannelHandles->Allocate(channel, HAL_HandleEnum::PWM, "PWM");
auto port = digitalChannelHandles->Allocate(channel, HAL_HandleEnum::PWM,
&handle, status);
if (*status != 0) {
if (port) {
wpi::hal::SetLastErrorPreviouslyAllocated(status, "PWM or DIO", channel,
port->previousAllocation);
} else {
wpi::hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for PWM", 0,
kNumPWMChannels, channel);
}
if (!resource) {
*status = resource.error();
return HAL_INVALID_HANDLE; // failed to allocate. Pass error back.
}
auto [handle, port] = *resource;
port->channel = origChannel;
SimPWMData[origChannel].initialized = true;

View File

@@ -8,10 +8,10 @@
#include "CANAPIInternal.hpp"
#include "HALInitializer.hpp"
#include "HALInternal.hpp"
#include "PortsInternal.hpp"
#include "mockdata/PowerDistributionDataInternal.hpp"
#include "wpi/hal/CANAPI.h"
#include "wpi/hal/ErrorHandling.hpp"
#include "wpi/hal/Errors.h"
using namespace wpi::hal;
@@ -32,9 +32,9 @@ HAL_PowerDistributionHandle HAL_InitializePowerDistribution(
const char* allocationLocation, int32_t* status) {
if (type == HAL_POWER_DISTRIBUTION_AUTOMATIC) {
if (module != HAL_DEFAULT_POWER_DISTRIBUTION_MODULE) {
*status = PARAMETER_OUT_OF_RANGE;
wpi::hal::SetLastError(
status, "Automatic PowerDistributionType must have default module");
*status =
MakeError(PARAMETER_OUT_OF_RANGE,
"Automatic PowerDistributionType must have default module");
return HAL_INVALID_HANDLE;
}
@@ -44,14 +44,14 @@ HAL_PowerDistributionHandle HAL_InitializePowerDistribution(
}
if (!HAL_CheckPowerDistributionModule(module, type)) {
*status = RESOURCE_OUT_OF_RANGE;
if (type == HAL_PowerDistributionType::HAL_POWER_DISTRIBUTION_CTRE) {
wpi::hal::SetLastErrorIndexOutOfRange(status,
"Invalid Index for CTRE PDP", 0,
kNumCTREPDPModules - 1, module);
*status = MakeErrorIndexOutOfRange(RESOURCE_OUT_OF_RANGE,
"Invalid Index for CTRE PDP", 0,
kNumCTREPDPModules - 1, module);
} else {
wpi::hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for REV PDH",
1, kNumREVPDHModules, module);
*status = MakeErrorIndexOutOfRange(RESOURCE_OUT_OF_RANGE,
"Invalid Index for REV PDH", 1,
kNumREVPDHModules, module);
}
return HAL_INVALID_HANDLE;
}

View File

@@ -7,9 +7,9 @@
#include <string>
#include "HALInitializer.hpp"
#include "HALInternal.hpp"
#include "PortsInternal.hpp"
#include "mockdata/REVPHDataInternal.hpp"
#include "wpi/hal/ErrorHandling.hpp"
#include "wpi/hal/Errors.h"
#include "wpi/hal/handles/IndexedHandleResource.hpp"
@@ -41,27 +41,21 @@ HAL_REVPHHandle HAL_InitializeREVPH(int32_t busId, int32_t module,
wpi::hal::init::CheckInit();
if (!HAL_CheckREVPHModuleNumber(module)) {
*status = RESOURCE_OUT_OF_RANGE;
wpi::hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for REV PH", 1,
kNumREVPHModules, module);
*status = MakeErrorIndexOutOfRange(RESOURCE_OUT_OF_RANGE,
"Invalid Index for REV PH", 1,
kNumREVPHModules, module);
return HAL_INVALID_HANDLE;
}
HAL_REVPHHandle handle;
// Module starts at 1
auto pcm = pcmHandles->Allocate(module - 1, &handle, status);
auto resource = pcmHandles->Allocate(module - 1, "REV PH", 1);
if (*status != 0) {
if (pcm) {
wpi::hal::SetLastErrorPreviouslyAllocated(status, "REV PH", module,
pcm->previousAllocation);
} else {
wpi::hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for REV PH",
1, kNumREVPHModules, module);
}
if (!resource) {
*status = resource.error();
return HAL_INVALID_HANDLE; // failed to allocate. Pass error back.
}
auto [handle, pcm] = *resource;
pcm->previousAllocation = allocationLocation ? allocationLocation : "";
pcm->module = module;