diff --git a/hal/src/main/native/athena/AnalogGyro.cpp b/hal/src/main/native/athena/AnalogGyro.cpp index b8f4add6e2..83bc42f0be 100644 --- a/hal/src/main/native/athena/AnalogGyro.cpp +++ b/hal/src/main/native/athena/AnalogGyro.cpp @@ -4,12 +4,14 @@ #include "hal/AnalogGyro.h" +#include #include #include #include "AnalogInternal.h" #include "HALInitializer.h" +#include "HALInternal.h" #include "hal/AnalogAccumulator.h" #include "hal/AnalogInput.h" #include "hal/handles/IndexedHandleResource.h" @@ -21,6 +23,7 @@ struct AnalogGyro { double voltsPerDegreePerSecond; double offset; int32_t center; + std::string previousAllocation; }; } // namespace @@ -55,36 +58,43 @@ static void Wait(double seconds) { extern "C" { HAL_GyroHandle HAL_InitializeAnalogGyro(HAL_AnalogInputHandle analogHandle, + const char* allocationLocation, int32_t* status) { hal::init::CheckInit(); + // Handle will be type checked by HAL_IsAccumulatorChannel + int16_t channel = getHandleIndex(analogHandle); if (!HAL_IsAccumulatorChannel(analogHandle, status)) { if (*status == 0) { *status = HAL_INVALID_ACCUMULATOR_CHANNEL; + hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for Analog Gyro", + 0, kNumAccumulators, channel); } return HAL_kInvalidHandle; } - // handle known to be correct, so no need to type check - int16_t channel = getHandleIndex(analogHandle); - - auto handle = analogGyroHandles->Allocate(channel, status); + HAL_GyroHandle handle; + auto gyro = analogGyroHandles->Allocate(channel, &handle, status); if (*status != 0) { + if (gyro) { + hal::SetLastErrorPreviouslyAllocated(status, "Analog Gyro", channel, + gyro->previousAllocation); + } else { + hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for Analog Gyro", + 0, kNumAccumulators, channel); + } return HAL_kInvalidHandle; // failed to allocate. Pass error back. } // Initialize port structure - auto gyro = analogGyroHandles->Get(handle); - if (gyro == nullptr) { // would only error on thread issue - *status = HAL_HANDLE_ERROR; - return HAL_kInvalidHandle; - } gyro->handle = analogHandle; gyro->voltsPerDegreePerSecond = 0; gyro->offset = 0; gyro->center = 0; + gyro->previousAllocation = allocationLocation ? allocationLocation : ""; + return handle; } diff --git a/hal/src/main/native/athena/AnalogInput.cpp b/hal/src/main/native/athena/AnalogInput.cpp index 4fd77a654d..6b3add10e9 100644 --- a/hal/src/main/native/athena/AnalogInput.cpp +++ b/hal/src/main/native/athena/AnalogInput.cpp @@ -9,6 +9,7 @@ #include "AnalogInternal.h" #include "HALInitializer.h" +#include "HALInternal.h" #include "PortsInternal.h" #include "hal/AnalogAccumulator.h" #include "hal/handles/HandlesInternal.h" @@ -21,8 +22,9 @@ using namespace hal; extern "C" { -HAL_AnalogInputHandle HAL_InitializeAnalogInputPort(HAL_PortHandle portHandle, - int32_t* status) { +HAL_AnalogInputHandle HAL_InitializeAnalogInputPort( + HAL_PortHandle portHandle, const char* allocationLocation, + int32_t* status) { hal::init::CheckInit(); initializeAnalog(status); @@ -31,23 +33,28 @@ HAL_AnalogInputHandle HAL_InitializeAnalogInputPort(HAL_PortHandle portHandle, } int16_t channel = getPortHandleChannel(portHandle); - if (channel == InvalidHandleIndex) { - *status = PARAMETER_OUT_OF_RANGE; + if (channel == InvalidHandleIndex || channel >= kNumAnalogInputs) { + *status = RESOURCE_OUT_OF_RANGE; + hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for Analog Input", + 0, kNumAnalogInputs, channel); return HAL_kInvalidHandle; } - HAL_AnalogInputHandle handle = analogInputHandles->Allocate(channel, status); + HAL_AnalogInputHandle handle; + auto analog_port = analogInputHandles->Allocate(channel, &handle, status); if (*status != 0) { + if (analog_port) { + hal::SetLastErrorPreviouslyAllocated(status, "Analog Input", channel, + analog_port->previousAllocation); + } else { + hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for Analog Input", + 0, kNumAnalogInputs, channel); + } return HAL_kInvalidHandle; // failed to allocate. Pass error back. } // Initialize port structure - auto analog_port = analogInputHandles->Get(handle); - if (analog_port == nullptr) { // would only error on thread issue - *status = HAL_HANDLE_ERROR; - return HAL_kInvalidHandle; - } analog_port->channel = static_cast(channel); if (HAL_IsAccumulatorChannel(handle, status)) { analog_port->accumulator.reset(tAccumulator::create(channel, status)); @@ -59,6 +66,8 @@ HAL_AnalogInputHandle HAL_InitializeAnalogInputPort(HAL_PortHandle portHandle, analogInputSystem->writeScanList(channel, channel, status); HAL_SetAnalogAverageBits(handle, kDefaultAverageBits, status); HAL_SetAnalogOversampleBits(handle, kDefaultOversampleBits, status); + analog_port->previousAllocation = + allocationLocation ? allocationLocation : ""; return handle; } diff --git a/hal/src/main/native/athena/AnalogInternal.h b/hal/src/main/native/athena/AnalogInternal.h index d3403648f0..431c6242b7 100644 --- a/hal/src/main/native/athena/AnalogInternal.h +++ b/hal/src/main/native/athena/AnalogInternal.h @@ -7,6 +7,7 @@ #include #include +#include #include @@ -31,6 +32,7 @@ extern bool analogSampleRateSet; struct AnalogPort { uint8_t channel; std::unique_ptr accumulator; + std::string previousAllocation; }; extern IndexedHandleResource + #include "AnalogInternal.h" #include "HALInitializer.h" +#include "HALInternal.h" #include "PortsInternal.h" #include "hal/Errors.h" #include "hal/handles/HandlesInternal.h" @@ -17,6 +20,7 @@ namespace { struct AnalogOutput { uint8_t channel; + std::string previousAllocation; }; } // namespace @@ -36,8 +40,9 @@ void InitializeAnalogOutput() { extern "C" { -HAL_AnalogOutputHandle HAL_InitializeAnalogOutputPort(HAL_PortHandle portHandle, - int32_t* status) { +HAL_AnalogOutputHandle HAL_InitializeAnalogOutputPort( + HAL_PortHandle portHandle, const char* allocationLocation, + int32_t* status) { hal::init::CheckInit(); initializeAnalog(status); @@ -46,25 +51,31 @@ HAL_AnalogOutputHandle HAL_InitializeAnalogOutputPort(HAL_PortHandle portHandle, } int16_t channel = getPortHandleChannel(portHandle); - if (channel == InvalidHandleIndex) { - *status = PARAMETER_OUT_OF_RANGE; + if (channel == InvalidHandleIndex || channel >= kNumAnalogOutputs) { + *status = RESOURCE_OUT_OF_RANGE; + hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for Analog Output", + 0, kNumAnalogOutputs, channel); return HAL_kInvalidHandle; } - HAL_AnalogOutputHandle handle = - analogOutputHandles->Allocate(channel, status); + HAL_AnalogOutputHandle handle; + auto port = analogOutputHandles->Allocate(channel, &handle, status); if (*status != 0) { + if (port) { + hal::SetLastErrorPreviouslyAllocated(status, "Analog Output", channel, + port->previousAllocation); + } else { + hal::SetLastErrorIndexOutOfRange(status, + "Invalid Index for Analog Output", 0, + kNumAnalogOutputs, channel); + } return HAL_kInvalidHandle; // failed to allocate. Pass error back. } - auto port = analogOutputHandles->Get(handle); - if (port == nullptr) { // would only error on thread issue - *status = HAL_HANDLE_ERROR; - return HAL_kInvalidHandle; - } - port->channel = static_cast(channel); + port->previousAllocation = allocationLocation ? allocationLocation : ""; + return handle; } diff --git a/hal/src/main/native/athena/DIO.cpp b/hal/src/main/native/athena/DIO.cpp index 38c90e455f..75909a0702 100644 --- a/hal/src/main/native/athena/DIO.cpp +++ b/hal/src/main/native/athena/DIO.cpp @@ -11,6 +11,7 @@ #include "DigitalInternal.h" #include "HALInitializer.h" +#include "HALInternal.h" #include "PortsInternal.h" #include "hal/cpp/fpga_clock.h" #include "hal/handles/HandlesInternal.h" @@ -38,7 +39,9 @@ void InitializeDIO() { extern "C" { HAL_DigitalHandle HAL_InitializeDIOPort(HAL_PortHandle portHandle, - HAL_Bool input, int32_t* status) { + HAL_Bool input, + const char* allocationLocation, + int32_t* status) { hal::init::CheckInit(); initializeDigital(status); @@ -48,23 +51,28 @@ HAL_DigitalHandle HAL_InitializeDIOPort(HAL_PortHandle portHandle, int16_t channel = getPortHandleChannel(portHandle); if (channel == InvalidHandleIndex || channel >= kNumDigitalChannels) { - *status = PARAMETER_OUT_OF_RANGE; + *status = RESOURCE_OUT_OF_RANGE; + hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for DIO", 0, + kNumDigitalChannels, channel); return HAL_kInvalidHandle; } - auto handle = - digitalChannelHandles->Allocate(channel, HAL_HandleEnum::DIO, status); + HAL_DigitalHandle handle; + + auto port = digitalChannelHandles->Allocate(channel, HAL_HandleEnum::DIO, + &handle, status); if (*status != 0) { + if (port) { + hal::SetLastErrorPreviouslyAllocated(status, "PWM or DIO", channel, + port->previousAllocation); + } else { + hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for DIO", 0, + kNumDigitalChannels, channel); + } return HAL_kInvalidHandle; // failed to allocate. Pass error back. } - auto port = digitalChannelHandles->Get(handle, HAL_HandleEnum::DIO); - if (port == nullptr) { // would only occur on thread issue. - *status = HAL_HANDLE_ERROR; - return HAL_kInvalidHandle; - } - port->channel = static_cast(channel); std::scoped_lock lock(digitalDIOMutex); @@ -114,6 +122,7 @@ HAL_DigitalHandle HAL_InitializeDIOPort(HAL_PortHandle portHandle, } digitalSystem->writeOutputEnable(outputEnable, status); + port->previousAllocation = allocationLocation ? allocationLocation : ""; return handle; } diff --git a/hal/src/main/native/athena/DigitalInternal.h b/hal/src/main/native/athena/DigitalInternal.h index 79656ad5e2..6b1e9097b8 100644 --- a/hal/src/main/native/athena/DigitalInternal.h +++ b/hal/src/main/native/athena/DigitalInternal.h @@ -7,6 +7,7 @@ #include #include +#include #include @@ -70,6 +71,7 @@ struct DigitalPort { int32_t centerPwm = 0; int32_t deadbandMinPwm = 0; int32_t minPwm = 0; + std::string previousAllocation; }; extern DigitalHandleResource= kNumPWMChannels) { - *status = PARAMETER_OUT_OF_RANGE; + *status = RESOURCE_OUT_OF_RANGE; + hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for PWM", 0, + kNumPWMChannels, channel); return HAL_kInvalidHandle; } @@ -87,19 +91,22 @@ HAL_DigitalHandle HAL_InitializePWMPort(HAL_PortHandle portHandle, channel = remapMXPPWMChannel(channel) + 10; // remap MXP to proper channel } - auto handle = - digitalChannelHandles->Allocate(channel, HAL_HandleEnum::PWM, status); + HAL_DigitalHandle handle; + + auto port = digitalChannelHandles->Allocate(channel, HAL_HandleEnum::PWM, + &handle, status); if (*status != 0) { + if (port) { + hal::SetLastErrorPreviouslyAllocated(status, "PWM or DIO", channel, + port->previousAllocation); + } else { + hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for PWM", 0, + kNumPWMChannels, channel); + } return HAL_kInvalidHandle; // failed to allocate. Pass error back. } - auto port = digitalChannelHandles->Get(handle, HAL_HandleEnum::PWM); - if (port == nullptr) { // would only occur on thread issue. - *status = HAL_HANDLE_ERROR; - return HAL_kInvalidHandle; - } - port->channel = origChannel; if (port->channel > tPWM::kNumHdrRegisters - 1) { @@ -113,6 +120,8 @@ HAL_DigitalHandle HAL_InitializePWMPort(HAL_PortHandle portHandle, // Defaults to allow an always valid config. HAL_SetPWMConfig(handle, 2.0, 1.501, 1.5, 1.499, 1.0, status); + port->previousAllocation = allocationLocation ? allocationLocation : ""; + return handle; } void HAL_FreePWMPort(HAL_DigitalHandle pwmPortHandle, int32_t* status) { diff --git a/hal/src/main/native/athena/Relay.cpp b/hal/src/main/native/athena/Relay.cpp index 368ce1b730..a01dd9d52b 100644 --- a/hal/src/main/native/athena/Relay.cpp +++ b/hal/src/main/native/athena/Relay.cpp @@ -4,8 +4,11 @@ #include "hal/Relay.h" +#include + #include "DigitalInternal.h" #include "HALInitializer.h" +#include "HALInternal.h" #include "PortsInternal.h" #include "hal/handles/IndexedHandleResource.h" @@ -16,6 +19,7 @@ namespace { struct Relay { uint8_t channel; bool fwd; + std::string previousAllocation; }; } // namespace @@ -38,6 +42,7 @@ void InitializeRelay() { extern "C" { HAL_RelayHandle HAL_InitializeRelayPort(HAL_PortHandle portHandle, HAL_Bool fwd, + const char* allocationLocation, int32_t* status) { hal::init::CheckInit(); initializeDigital(status); @@ -47,8 +52,10 @@ HAL_RelayHandle HAL_InitializeRelayPort(HAL_PortHandle portHandle, HAL_Bool fwd, } int16_t channel = getPortHandleChannel(portHandle); - if (channel == InvalidHandleIndex) { - *status = PARAMETER_OUT_OF_RANGE; + if (channel == InvalidHandleIndex || channel >= kNumRelayChannels) { + *status = RESOURCE_OUT_OF_RANGE; + hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for Relay", 0, + kNumRelayChannels, channel); return HAL_kInvalidHandle; } @@ -56,18 +63,20 @@ HAL_RelayHandle HAL_InitializeRelayPort(HAL_PortHandle portHandle, HAL_Bool fwd, channel += kNumRelayHeaders; // add 4 to reverse channels } - auto handle = relayHandles->Allocate(channel, status); + HAL_RelayHandle handle; + auto port = relayHandles->Allocate(channel, &handle, status); if (*status != 0) { + if (port) { + hal::SetLastErrorPreviouslyAllocated(status, "Relay", channel, + port->previousAllocation); + } else { + hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for Relay", 0, + kNumRelayChannels, channel); + } return HAL_kInvalidHandle; // failed to allocate. Pass error back. } - auto port = relayHandles->Get(handle); - if (port == nullptr) { // would only occur on thread issue. - *status = HAL_HANDLE_ERROR; - return HAL_kInvalidHandle; - } - if (!fwd) { // Subtract number of headers to put channel in range channel -= kNumRelayHeaders; @@ -78,6 +87,7 @@ HAL_RelayHandle HAL_InitializeRelayPort(HAL_PortHandle portHandle, HAL_Bool fwd, } port->channel = static_cast(channel); + port->previousAllocation = allocationLocation ? allocationLocation : ""; return handle; } diff --git a/hal/src/main/native/athena/SPI.cpp b/hal/src/main/native/athena/SPI.cpp index a237f668ea..43843ebfed 100644 --- a/hal/src/main/native/athena/SPI.cpp +++ b/hal/src/main/native/athena/SPI.cpp @@ -75,14 +75,14 @@ static void CommonSPIPortInit(int32_t* status) { } // MISO if ((digitalHandles[3] = HAL_InitializeDIOPort(createPortHandleForSPI(29), - false, status)) == + false, nullptr, status)) == HAL_kInvalidHandle) { std::printf("Failed to allocate DIO 29 (MISO)\n"); return; } // MOSI if ((digitalHandles[4] = HAL_InitializeDIOPort(createPortHandleForSPI(30), - false, status)) == + false, nullptr, status)) == HAL_kInvalidHandle) { std::printf("Failed to allocate DIO 30 (MOSI)\n"); HAL_FreeDIOPort(digitalHandles[3]); // free the first port allocated @@ -133,7 +133,7 @@ void HAL_InitializeSPI(HAL_SPIPort port, int32_t* status) { } // CS1, Allocate if ((digitalHandles[0] = HAL_InitializeDIOPort(createPortHandleForSPI(26), - false, status)) == + false, nullptr, status)) == HAL_kInvalidHandle) { std::printf("Failed to allocate DIO 26 (CS1)\n"); CommonSPIPortFree(); @@ -156,7 +156,7 @@ void HAL_InitializeSPI(HAL_SPIPort port, int32_t* status) { } // CS2, Allocate if ((digitalHandles[1] = HAL_InitializeDIOPort(createPortHandleForSPI(27), - false, status)) == + false, nullptr, status)) == HAL_kInvalidHandle) { std::printf("Failed to allocate DIO 27 (CS2)\n"); CommonSPIPortFree(); @@ -179,7 +179,7 @@ void HAL_InitializeSPI(HAL_SPIPort port, int32_t* status) { } // CS3, Allocate if ((digitalHandles[2] = HAL_InitializeDIOPort(createPortHandleForSPI(28), - false, status)) == + false, nullptr, status)) == HAL_kInvalidHandle) { std::printf("Failed to allocate DIO 28 (CS3)\n"); CommonSPIPortFree(); @@ -201,20 +201,20 @@ void HAL_InitializeSPI(HAL_SPIPort port, int32_t* status) { return; } if ((digitalHandles[5] = HAL_InitializeDIOPort(createPortHandleForSPI(14), - false, status)) == + false, nullptr, status)) == HAL_kInvalidHandle) { wpi::outs() << "Failed to allocate DIO 14\n"; return; } if ((digitalHandles[6] = HAL_InitializeDIOPort(createPortHandleForSPI(15), - false, status)) == + false, nullptr, status)) == HAL_kInvalidHandle) { wpi::outs() << "Failed to allocate DIO 15\n"; HAL_FreeDIOPort(digitalHandles[5]); // free the first port allocated return; } if ((digitalHandles[7] = HAL_InitializeDIOPort(createPortHandleForSPI(16), - false, status)) == + false, nullptr, status)) == HAL_kInvalidHandle) { wpi::outs() << "Failed to allocate DIO 16\n"; HAL_FreeDIOPort(digitalHandles[5]); // free the first port allocated @@ -222,7 +222,7 @@ void HAL_InitializeSPI(HAL_SPIPort port, int32_t* status) { return; } if ((digitalHandles[8] = HAL_InitializeDIOPort(createPortHandleForSPI(17), - false, status)) == + false, nullptr, status)) == HAL_kInvalidHandle) { wpi::outs() << "Failed to allocate DIO 17\n"; HAL_FreeDIOPort(digitalHandles[5]); // free the first port allocated diff --git a/hal/src/main/native/athena/SerialPort.cpp b/hal/src/main/native/athena/SerialPort.cpp index 27f17397ed..cf34d7b5c0 100644 --- a/hal/src/main/native/athena/SerialPort.cpp +++ b/hal/src/main/native/athena/SerialPort.cpp @@ -70,19 +70,14 @@ HAL_SerialPortHandle HAL_InitializeSerialPort(HAL_SerialPort port, HAL_SerialPortHandle HAL_InitializeSerialPortDirect(HAL_SerialPort port, const char* portName, int32_t* status) { - auto handle = serialPortHandles->Allocate(static_cast(port), status); + HAL_SerialPortHandle handle; + auto serialPort = + serialPortHandles->Allocate(static_cast(port), &handle, status); if (*status != 0) { return HAL_kInvalidHandle; } - auto serialPort = serialPortHandles->Get(handle); - - if (serialPort == nullptr) { - *status = HAL_HANDLE_ERROR; - return HAL_kInvalidHandle; - } - serialPort->portId = open(portName, O_RDWR | O_NOCTTY); if (serialPort->portId < 0) { *status = errno; diff --git a/hal/src/main/native/athena/Solenoid.cpp b/hal/src/main/native/athena/Solenoid.cpp index 669b87674f..b12d8bf1a7 100644 --- a/hal/src/main/native/athena/Solenoid.cpp +++ b/hal/src/main/native/athena/Solenoid.cpp @@ -60,16 +60,12 @@ HAL_SolenoidHandle HAL_InitializeSolenoidPort(HAL_PortHandle portHandle, return HAL_kInvalidHandle; } - auto handle = solenoidHandles->Allocate( - module * kNumSolenoidChannels + channel, status); + HAL_SolenoidHandle handle; + auto solenoidPort = solenoidHandles->Allocate( + module * kNumSolenoidChannels + channel, &handle, status); if (*status != 0) { return HAL_kInvalidHandle; } - auto solenoidPort = solenoidHandles->Get(handle); - if (solenoidPort == nullptr) { // would only occur on thread issues - *status = HAL_HANDLE_ERROR; - return HAL_kInvalidHandle; - } solenoidPort->module = static_cast(module); solenoidPort->channel = static_cast(channel); diff --git a/hal/src/main/native/cpp/ErrorHandling.cpp b/hal/src/main/native/cpp/ErrorHandling.cpp index 9f10853b52..fa54e4676e 100644 --- a/hal/src/main/native/cpp/ErrorHandling.cpp +++ b/hal/src/main/native/cpp/ErrorHandling.cpp @@ -21,11 +21,31 @@ static LastErrorStorage& GetThreadLastError() { } namespace hal { -void SetLastError(int32_t status, const wpi::Twine& value) { +void SetLastError(int32_t* status, const wpi::Twine& value) { LastErrorStorage& lastError = GetThreadLastError(); lastError.message.clear(); value.toVector(lastError.message); - lastError.status = status; + lastError.status = *status; + *status = HAL_USE_LAST_ERROR; +} + +void SetLastErrorIndexOutOfRange(int32_t* status, const wpi::Twine& message, + int32_t minimum, int32_t maximum, + int32_t requested) { + SetLastError(status, message + "\n Status: " + wpi::Twine(*status) + + "\n Minimum: " + wpi::Twine(minimum) + + " Maximum: " + wpi::Twine(maximum) + + " Reequested: " + wpi::Twine(requested)); +} + +void SetLastErrorPreviouslyAllocated(int32_t* status, const wpi::Twine& message, + int32_t channel, + const wpi::Twine& previousAllocation) { + hal::SetLastError( + status, + message + " " + wpi::Twine(channel) + + " previously allocated.\nLocation of the previous allocation:\n" + + previousAllocation + "\nLocation of the current allocation:"); } } // namespace hal diff --git a/hal/src/main/native/cpp/jni/AnalogGyroJNI.cpp b/hal/src/main/native/cpp/jni/AnalogGyroJNI.cpp index 8a6b131837..154301f8e7 100644 --- a/hal/src/main/native/cpp/jni/AnalogGyroJNI.cpp +++ b/hal/src/main/native/cpp/jni/AnalogGyroJNI.cpp @@ -6,6 +6,8 @@ #include +#include + #include "HALUtil.h" #include "edu_wpi_first_hal_AnalogGyroJNI.h" #include "hal/AnalogGyro.h" @@ -24,8 +26,9 @@ Java_edu_wpi_first_hal_AnalogGyroJNI_initializeAnalogGyro (JNIEnv* env, jclass, jint id) { int32_t status = 0; - HAL_GyroHandle handle = - HAL_InitializeAnalogGyro((HAL_AnalogInputHandle)id, &status); + auto stack = wpi::java::GetJavaStackTrace(env, "edu.wpi.first"); + HAL_GyroHandle handle = HAL_InitializeAnalogGyro((HAL_AnalogInputHandle)id, + stack.c_str(), &status); // Analog input does range checking, so we don't need to do so. CheckStatusForceThrow(env, status); return (jint)handle; diff --git a/hal/src/main/native/cpp/jni/AnalogJNI.cpp b/hal/src/main/native/cpp/jni/AnalogJNI.cpp index 04ec3a405e..5f0abce6be 100644 --- a/hal/src/main/native/cpp/jni/AnalogJNI.cpp +++ b/hal/src/main/native/cpp/jni/AnalogJNI.cpp @@ -6,6 +6,8 @@ #include +#include + #include "HALUtil.h" #include "edu_wpi_first_hal_AnalogJNI.h" #include "hal/AnalogAccumulator.h" @@ -29,9 +31,10 @@ Java_edu_wpi_first_hal_AnalogJNI_initializeAnalogInputPort (JNIEnv* env, jclass, jint id) { int32_t status = 0; - auto analog = HAL_InitializeAnalogInputPort((HAL_PortHandle)id, &status); - CheckStatusRange(env, status, 0, HAL_GetNumAnalogInputs(), - hal::getPortHandleChannel((HAL_PortHandle)id)); + auto stack = wpi::java::GetJavaStackTrace(env, "edu.wpi.first"); + auto analog = + HAL_InitializeAnalogInputPort((HAL_PortHandle)id, stack.c_str(), &status); + CheckStatusForceThrow(env, status); return (jint)analog; } @@ -57,10 +60,10 @@ Java_edu_wpi_first_hal_AnalogJNI_initializeAnalogOutputPort (JNIEnv* env, jclass, jint id) { int32_t status = 0; - HAL_AnalogOutputHandle analog = - HAL_InitializeAnalogOutputPort((HAL_PortHandle)id, &status); - CheckStatusRange(env, status, 0, HAL_GetNumAnalogOutputs(), - hal::getPortHandleChannel((HAL_PortHandle)id)); + auto stack = wpi::java::GetJavaStackTrace(env, "edu.wpi.first"); + HAL_AnalogOutputHandle analog = HAL_InitializeAnalogOutputPort( + (HAL_PortHandle)id, stack.c_str(), &status); + CheckStatusForceThrow(env, status); return (jlong)analog; } diff --git a/hal/src/main/native/cpp/jni/DIOJNI.cpp b/hal/src/main/native/cpp/jni/DIOJNI.cpp index 5dc59c8bda..236754169e 100644 --- a/hal/src/main/native/cpp/jni/DIOJNI.cpp +++ b/hal/src/main/native/cpp/jni/DIOJNI.cpp @@ -6,6 +6,8 @@ #include +#include + #include "HALUtil.h" #include "edu_wpi_first_hal_DIOJNI.h" #include "hal/DIO.h" @@ -27,10 +29,10 @@ Java_edu_wpi_first_hal_DIOJNI_initializeDIOPort (JNIEnv* env, jclass, jint id, jboolean input) { int32_t status = 0; - auto dio = HAL_InitializeDIOPort((HAL_PortHandle)id, - static_cast(input), &status); - CheckStatusRange(env, status, 0, HAL_GetNumDigitalChannels(), - hal::getPortHandleChannel((HAL_PortHandle)id)); + auto stack = wpi::java::GetJavaStackTrace(env, "edu.wpi.first"); + auto dio = HAL_InitializeDIOPort( + (HAL_PortHandle)id, static_cast(input), stack.c_str(), &status); + CheckStatusForceThrow(env, status); return (jint)dio; } diff --git a/hal/src/main/native/cpp/jni/HALUtil.cpp b/hal/src/main/native/cpp/jni/HALUtil.cpp index cbeb9c97ee..9894942f12 100644 --- a/hal/src/main/native/cpp/jni/HALUtil.cpp +++ b/hal/src/main/native/cpp/jni/HALUtil.cpp @@ -83,15 +83,13 @@ void ThrowUncleanStatusException(JNIEnv* env, wpi::StringRef msg, env->Throw(static_cast(exception)); } -void ThrowAllocationException(JNIEnv* env, int32_t minRange, int32_t maxRange, - int32_t requestedValue, int32_t status) { - const char* message = HAL_GetLastError(&status); +void ThrowAllocationException(JNIEnv* env, const char* lastError, + int32_t status) { wpi::SmallString<1024> buf; wpi::raw_svector_ostream oss(buf); - oss << " Code: " << status << ". " << message - << ", Minimum Value: " << minRange << ", Maximum Value: " << maxRange - << ", Requested Value: " << requestedValue; - env->ThrowNew(allocationExCls, buf.c_str()); + + oss << "Code: " << status << '\n' << lastError; + allocationExCls.Throw(env, buf.c_str()); } @@ -107,10 +105,11 @@ void ReportError(JNIEnv* env, int32_t status, bool doThrow) { if (status == 0) { return; } + const char* message = HAL_GetLastError(&status); if (status == HAL_HANDLE_ERROR) { ThrowHalHandleException(env, status); + return; } - const char* message = HAL_GetLastError(&status); if (doThrow && status < 0) { wpi::SmallString<1024> buf; wpi::raw_svector_ostream oss(buf); @@ -132,17 +131,19 @@ void ThrowError(JNIEnv* env, int32_t status, int32_t minRange, int32_t maxRange, if (status == 0) { return; } + const char* lastError = HAL_GetLastError(&status); if (status == NO_AVAILABLE_RESOURCES || status == RESOURCE_IS_ALLOCATED || status == RESOURCE_OUT_OF_RANGE) { - ThrowAllocationException(env, minRange, maxRange, requestedValue, status); + ThrowAllocationException(env, lastError, status); + return; } if (status == HAL_HANDLE_ERROR) { ThrowHalHandleException(env, status); + return; } - const char* message = HAL_GetErrorMessage(status); wpi::SmallString<1024> buf; wpi::raw_svector_ostream oss(buf); - oss << " Code: " << status << ". " << message; + oss << " Code: " << status << ". " << lastError; ThrowUncleanStatusException(env, buf.c_str(), status); } diff --git a/hal/src/main/native/cpp/jni/PWMJNI.cpp b/hal/src/main/native/cpp/jni/PWMJNI.cpp index 5099dba7d9..e83f11bcdf 100644 --- a/hal/src/main/native/cpp/jni/PWMJNI.cpp +++ b/hal/src/main/native/cpp/jni/PWMJNI.cpp @@ -6,6 +6,8 @@ #include +#include + #include "HALUtil.h" #include "edu_wpi_first_hal_PWMJNI.h" #include "hal/DIO.h" @@ -27,9 +29,9 @@ Java_edu_wpi_first_hal_PWMJNI_initializePWMPort (JNIEnv* env, jclass, jint id) { int32_t status = 0; - auto pwm = HAL_InitializePWMPort((HAL_PortHandle)id, &status); - CheckStatusRange(env, status, 0, HAL_GetNumPWMChannels(), - hal::getPortHandleChannel((HAL_PortHandle)id)); + auto stack = wpi::java::GetJavaStackTrace(env, "edu.wpi.first"); + auto pwm = HAL_InitializePWMPort((HAL_PortHandle)id, stack.c_str(), &status); + CheckStatusForceThrow(env, status); return (jint)pwm; } diff --git a/hal/src/main/native/cpp/jni/RelayJNI.cpp b/hal/src/main/native/cpp/jni/RelayJNI.cpp index 0bb7fa45e8..9e31a9da10 100644 --- a/hal/src/main/native/cpp/jni/RelayJNI.cpp +++ b/hal/src/main/native/cpp/jni/RelayJNI.cpp @@ -6,6 +6,8 @@ #include +#include + #include "HALUtil.h" #include "edu_wpi_first_hal_RelayJNI.h" #include "hal/Ports.h" @@ -26,10 +28,10 @@ Java_edu_wpi_first_hal_RelayJNI_initializeRelayPort (JNIEnv* env, jclass, jint id, jboolean fwd) { int32_t status = 0; + auto stack = wpi::java::GetJavaStackTrace(env, "edu.wpi.first"); HAL_RelayHandle handle = HAL_InitializeRelayPort( - (HAL_PortHandle)id, static_cast(fwd), &status); - CheckStatusRange(env, status, 0, HAL_GetNumRelayChannels(), - hal::getPortHandleChannel((HAL_PortHandle)id)); + (HAL_PortHandle)id, static_cast(fwd), stack.c_str(), &status); + CheckStatusForceThrow(env, status); return (jint)handle; } diff --git a/hal/src/main/native/include/hal/AnalogGyro.h b/hal/src/main/native/include/hal/AnalogGyro.h index 79e0f7d16e..16171b1384 100644 --- a/hal/src/main/native/include/hal/AnalogGyro.h +++ b/hal/src/main/native/include/hal/AnalogGyro.h @@ -22,9 +22,12 @@ extern "C" { * Initializes an analog gyro. * * @param handle handle to the analog port + * @param allocationLocation the location where the allocation is occuring + * (can be null) * @return the initialized gyro handle */ HAL_GyroHandle HAL_InitializeAnalogGyro(HAL_AnalogInputHandle handle, + const char* allocationLocation, int32_t* status); /** diff --git a/hal/src/main/native/include/hal/AnalogInput.h b/hal/src/main/native/include/hal/AnalogInput.h index bcfc633000..8275ea26d1 100644 --- a/hal/src/main/native/include/hal/AnalogInput.h +++ b/hal/src/main/native/include/hal/AnalogInput.h @@ -22,10 +22,12 @@ extern "C" { * Initializes the analog input port using the given port object. * * @param portHandle Handle to the port to initialize. + * @param allocationLocation the location where the allocation is occuring + * (can be null) * @return the created analog input handle */ -HAL_AnalogInputHandle HAL_InitializeAnalogInputPort(HAL_PortHandle portHandle, - int32_t* status); +HAL_AnalogInputHandle HAL_InitializeAnalogInputPort( + HAL_PortHandle portHandle, const char* allocationLocation, int32_t* status); /** * Frees an analog input port. diff --git a/hal/src/main/native/include/hal/AnalogOutput.h b/hal/src/main/native/include/hal/AnalogOutput.h index b104315b39..ef013af95e 100644 --- a/hal/src/main/native/include/hal/AnalogOutput.h +++ b/hal/src/main/native/include/hal/AnalogOutput.h @@ -22,10 +22,12 @@ extern "C" { * Initializes the analog output port using the given port object. * * @param handle handle to the port + * @param allocationLocation the location where the allocation is occuring + * (can be null) * @return the created analog output handle */ -HAL_AnalogOutputHandle HAL_InitializeAnalogOutputPort(HAL_PortHandle portHandle, - int32_t* status); +HAL_AnalogOutputHandle HAL_InitializeAnalogOutputPort( + HAL_PortHandle portHandle, const char* allocationLocation, int32_t* status); /** * Frees an analog output port. diff --git a/hal/src/main/native/include/hal/DIO.h b/hal/src/main/native/include/hal/DIO.h index cdfdd354bd..306321478e 100644 --- a/hal/src/main/native/include/hal/DIO.h +++ b/hal/src/main/native/include/hal/DIO.h @@ -21,12 +21,16 @@ extern "C" { /** * Creates a new instance of a digital port. * - * @param portHandle the port handle to create from - * @param input true for input, false for output - * @return the created digital handle + * @param portHandle the port handle to create from + * @param input true for input, false for output + * @param allocationLocation the location where the allocation is occuring + * (can be null) + * @return the created digital handle */ HAL_DigitalHandle HAL_InitializeDIOPort(HAL_PortHandle portHandle, - HAL_Bool input, int32_t* status); + HAL_Bool input, + const char* allocationLocation, + int32_t* status); /** * Checks if a DIO channel is valid. diff --git a/hal/src/main/native/include/hal/Errors.h b/hal/src/main/native/include/hal/Errors.h index 1e87f54cb2..6444ea6c9e 100644 --- a/hal/src/main/native/include/hal/Errors.h +++ b/hal/src/main/native/include/hal/Errors.h @@ -41,6 +41,8 @@ #define ERR_FRCSystem_NoDSConnection_MESSAGE \ "FRCSystem: No driver station connected" +#define HAL_SUCCESS 0 + #define SAMPLE_RATE_TOO_HIGH 1001 #define SAMPLE_RATE_TOO_HIGH_MESSAGE \ "HAL: Analog module sample rate is too high" diff --git a/hal/src/main/native/include/hal/PWM.h b/hal/src/main/native/include/hal/PWM.h index e0fa945c44..04bfc4f73e 100644 --- a/hal/src/main/native/include/hal/PWM.h +++ b/hal/src/main/native/include/hal/PWM.h @@ -22,9 +22,12 @@ extern "C" { * Initializes a PWM port. * * @param portHandle the port to initialize + * @param allocationLocation the location where the allocation is occuring + * (can be null) * @return the created pwm handle */ HAL_DigitalHandle HAL_InitializePWMPort(HAL_PortHandle portHandle, + const char* allocationLocation, int32_t* status); /** diff --git a/hal/src/main/native/include/hal/Relay.h b/hal/src/main/native/include/hal/Relay.h index 5fa714ac9f..d59da0a669 100644 --- a/hal/src/main/native/include/hal/Relay.h +++ b/hal/src/main/native/include/hal/Relay.h @@ -26,9 +26,12 @@ extern "C" { * * @param portHandle the port handle to initialize * @param fwd true for the forward port, false for the reverse port + * @param allocationLocation the location where the allocation is occuring + * (can be null) * @return the created relay handle */ HAL_RelayHandle HAL_InitializeRelayPort(HAL_PortHandle portHandle, HAL_Bool fwd, + const char* allocationLocation, int32_t* status); /** diff --git a/hal/src/main/native/include/hal/handles/DigitalHandleResource.h b/hal/src/main/native/include/hal/handles/DigitalHandleResource.h index 85a14a7d62..5154a43aad 100644 --- a/hal/src/main/native/include/hal/handles/DigitalHandleResource.h +++ b/hal/src/main/native/include/hal/handles/DigitalHandleResource.h @@ -22,7 +22,7 @@ namespace hal { * allows a limited number of handles that are allocated by index. * The enum value is separate, as 2 enum values are allowed per handle * Because they are allocated by index, each individual index holds its own - * mutex, which reduces contention heavily.] + * mutex, which reduces contention heavily. * * @tparam THandle The Handle Type (Must be typedefed from HAL_Handle) * @tparam TStruct The struct type held by this resource @@ -38,7 +38,8 @@ class DigitalHandleResource : public HandleBase { DigitalHandleResource(const DigitalHandleResource&) = delete; DigitalHandleResource& operator=(const DigitalHandleResource&) = delete; - THandle Allocate(int16_t index, HAL_HandleEnum enumValue, int32_t* status); + std::shared_ptr Allocate(int16_t index, HAL_HandleEnum enumValue, + THandle* handle, int32_t* status); int16_t GetIndex(THandle handle, HAL_HandleEnum enumValue) { return getHandleTypedIndex(handle, enumValue, m_version); } @@ -52,21 +53,27 @@ class DigitalHandleResource : public HandleBase { }; template -THandle DigitalHandleResource::Allocate( - int16_t index, HAL_HandleEnum enumValue, int32_t* status) { +std::shared_ptr +DigitalHandleResource::Allocate( + int16_t index, HAL_HandleEnum enumValue, THandle* handle, int32_t* status) { // don't acquire the lock if we can fail early. if (index < 0 || index >= size) { + *handle = HAL_kInvalidHandle; *status = RESOURCE_OUT_OF_RANGE; - return HAL_kInvalidHandle; + return nullptr; } std::scoped_lock lock(m_handleMutexes[index]); // check for allocation, otherwise allocate and return a valid handle if (m_structures[index] != nullptr) { + *handle = HAL_kInvalidHandle; *status = RESOURCE_IS_ALLOCATED; - return HAL_kInvalidHandle; + return m_structures[index]; } m_structures[index] = std::make_shared(); - return static_cast(hal::createHandle(index, enumValue, m_version)); + *handle = + static_cast(hal::createHandle(index, enumValue, m_version)); + *status = HAL_SUCCESS; + return m_structures[index]; } template diff --git a/hal/src/main/native/include/hal/handles/IndexedHandleResource.h b/hal/src/main/native/include/hal/handles/IndexedHandleResource.h index 2f158e1913..2e921eebcf 100644 --- a/hal/src/main/native/include/hal/handles/IndexedHandleResource.h +++ b/hal/src/main/native/include/hal/handles/IndexedHandleResource.h @@ -39,7 +39,8 @@ class IndexedHandleResource : public HandleBase { IndexedHandleResource(const IndexedHandleResource&) = delete; IndexedHandleResource& operator=(const IndexedHandleResource&) = delete; - THandle Allocate(int16_t index, int32_t* status); + std::shared_ptr Allocate(int16_t index, THandle* handle, + int32_t* status); int16_t GetIndex(THandle handle) { return getHandleTypedIndex(handle, enumValue, m_version); } @@ -54,21 +55,27 @@ class IndexedHandleResource : public HandleBase { template -THandle IndexedHandleResource::Allocate( - int16_t index, int32_t* status) { +std::shared_ptr +IndexedHandleResource::Allocate( + int16_t index, THandle* handle, int32_t* status) { // don't acquire the lock if we can fail early. if (index < 0 || index >= size) { *status = RESOURCE_OUT_OF_RANGE; - return HAL_kInvalidHandle; + *handle = HAL_kInvalidHandle; + return nullptr; } std::scoped_lock lock(m_handleMutexes[index]); // check for allocation, otherwise allocate and return a valid handle if (m_structures[index] != nullptr) { *status = RESOURCE_IS_ALLOCATED; - return HAL_kInvalidHandle; + *handle = HAL_kInvalidHandle; + return m_structures[index]; } m_structures[index] = std::make_shared(); - return static_cast(hal::createHandle(index, enumValue, m_version)); + *handle = + static_cast(hal::createHandle(index, enumValue, m_version)); + *status = HAL_SUCCESS; + return m_structures[index]; } template + #include "HALInitializer.h" +#include "HALInternal.h" #include "PortsInternal.h" #include "hal/AnalogAccumulator.h" #include "hal/Errors.h" @@ -15,6 +18,7 @@ namespace { struct AnalogGyro { HAL_AnalogInputHandle handle; uint8_t index; + std::string previousAllocation; }; } // namespace @@ -34,36 +38,41 @@ void InitializeAnalogGyro() { extern "C" { HAL_GyroHandle HAL_InitializeAnalogGyro(HAL_AnalogInputHandle analogHandle, + const char* allocationLocation, int32_t* status) { hal::init::CheckInit(); + // Handle will be type checked by HAL_IsAccumulatorChannel + int16_t channel = getHandleIndex(analogHandle); if (!HAL_IsAccumulatorChannel(analogHandle, status)) { if (*status == 0) { *status = HAL_INVALID_ACCUMULATOR_CHANNEL; + hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for Analog Gyro", + 0, kNumAccumulators, channel); } return HAL_kInvalidHandle; } - // handle known to be correct, so no need to type check - int16_t channel = getHandleIndex(analogHandle); - - auto handle = analogGyroHandles->Allocate(channel, status); + HAL_GyroHandle handle; + auto gyro = analogGyroHandles->Allocate(channel, &handle, status); if (*status != 0) { + if (gyro) { + hal::SetLastErrorPreviouslyAllocated(status, "Analog Gyro", channel, + gyro->previousAllocation); + } else { + hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for Analog Gyro", + 0, kNumAccumulators, channel); + } return HAL_kInvalidHandle; // failed to allocate. Pass error back. } - // Initialize port structure - auto gyro = analogGyroHandles->Get(handle); - if (gyro == nullptr) { // would only error on thread issue - *status = HAL_HANDLE_ERROR; - return HAL_kInvalidHandle; - } - gyro->handle = analogHandle; gyro->index = channel; SimAnalogGyroData[channel].initialized = true; + gyro->previousAllocation = allocationLocation ? allocationLocation : ""; + return handle; } diff --git a/hal/src/main/native/sim/AnalogInput.cpp b/hal/src/main/native/sim/AnalogInput.cpp index 3a9f572f05..4697dc2493 100644 --- a/hal/src/main/native/sim/AnalogInput.cpp +++ b/hal/src/main/native/sim/AnalogInput.cpp @@ -6,6 +6,7 @@ #include "AnalogInternal.h" #include "HALInitializer.h" +#include "HALInternal.h" #include "PortsInternal.h" #include "hal/AnalogAccumulator.h" #include "hal/handles/HandlesInternal.h" @@ -18,28 +19,32 @@ void InitializeAnalogInput() {} } // namespace hal::init extern "C" { -HAL_AnalogInputHandle HAL_InitializeAnalogInputPort(HAL_PortHandle portHandle, - int32_t* status) { +HAL_AnalogInputHandle HAL_InitializeAnalogInputPort( + HAL_PortHandle portHandle, const char* allocationLocation, + int32_t* status) { hal::init::CheckInit(); int16_t channel = getPortHandleChannel(portHandle); - if (channel == InvalidHandleIndex) { - *status = PARAMETER_OUT_OF_RANGE; + if (channel == InvalidHandleIndex || channel >= kNumAnalogInputs) { + *status = RESOURCE_OUT_OF_RANGE; + hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for Analog Input", + 0, kNumAnalogInputs, channel); return HAL_kInvalidHandle; } - HAL_AnalogInputHandle handle = analogInputHandles->Allocate(channel, status); + HAL_AnalogInputHandle handle; + auto analog_port = analogInputHandles->Allocate(channel, &handle, status); if (*status != 0) { + if (analog_port) { + hal::SetLastErrorPreviouslyAllocated(status, "Analog Input", channel, + analog_port->previousAllocation); + } else { + hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for Analog Input", + 0, kNumAnalogInputs, channel); + } return HAL_kInvalidHandle; // failed to allocate. Pass error back. } - // Initialize port structure - auto analog_port = analogInputHandles->Get(handle); - if (analog_port == nullptr) { // would only error on thread issue - *status = HAL_HANDLE_ERROR; - return HAL_kInvalidHandle; - } - analog_port->channel = static_cast(channel); if (HAL_IsAccumulatorChannel(handle, status)) { analog_port->isAccumulator = true; @@ -51,6 +56,9 @@ HAL_AnalogInputHandle HAL_InitializeAnalogInputPort(HAL_PortHandle portHandle, SimAnalogInData[channel].accumulatorInitialized = false; SimAnalogInData[channel].simDevice = 0; + analog_port->previousAllocation = + allocationLocation ? allocationLocation : ""; + return handle; } void HAL_FreeAnalogInputPort(HAL_AnalogInputHandle analogPortHandle) { diff --git a/hal/src/main/native/sim/AnalogInternal.h b/hal/src/main/native/sim/AnalogInternal.h index 835fddd8f1..89cb3593c3 100644 --- a/hal/src/main/native/sim/AnalogInternal.h +++ b/hal/src/main/native/sim/AnalogInternal.h @@ -6,6 +6,8 @@ #include +#include + #include "PortsInternal.h" #include "hal/handles/HandlesInternal.h" #include "hal/handles/IndexedHandleResource.h" @@ -20,6 +22,7 @@ static constexpr uint32_t kAccumulatorChannels[] = {0, 1}; struct AnalogPort { uint8_t channel; bool isAccumulator; + std::string previousAllocation; }; extern IndexedHandleResource + #include "HALInitializer.h" +#include "HALInternal.h" #include "PortsInternal.h" #include "hal/Errors.h" #include "hal/handles/HandlesInternal.h" @@ -16,6 +19,7 @@ using namespace hal; namespace { struct AnalogOutput { uint8_t channel; + std::string previousAllocation; }; } // namespace @@ -33,32 +37,39 @@ void InitializeAnalogOutput() { } // namespace hal::init extern "C" { -HAL_AnalogOutputHandle HAL_InitializeAnalogOutputPort(HAL_PortHandle portHandle, - int32_t* status) { +HAL_AnalogOutputHandle HAL_InitializeAnalogOutputPort( + HAL_PortHandle portHandle, const char* allocationLocation, + int32_t* status) { hal::init::CheckInit(); int16_t channel = getPortHandleChannel(portHandle); - if (channel == InvalidHandleIndex) { - *status = PARAMETER_OUT_OF_RANGE; + if (channel == InvalidHandleIndex || channel >= kNumAnalogOutputs) { + *status = RESOURCE_OUT_OF_RANGE; + hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for Analog Output", + 0, kNumAnalogOutputs, channel); return HAL_kInvalidHandle; } - HAL_AnalogOutputHandle handle = - analogOutputHandles->Allocate(channel, status); + HAL_AnalogOutputHandle handle; + auto port = analogOutputHandles->Allocate(channel, &handle, status); if (*status != 0) { + if (port) { + hal::SetLastErrorPreviouslyAllocated(status, "Analog Output", channel, + port->previousAllocation); + } else { + hal::SetLastErrorIndexOutOfRange(status, + "Invalid Index for Analog Output", 0, + kNumAnalogOutputs, channel); + } return HAL_kInvalidHandle; // failed to allocate. Pass error back. } - auto port = analogOutputHandles->Get(handle); - if (port == nullptr) { // would only error on thread issue - *status = HAL_HANDLE_ERROR; - return HAL_kInvalidHandle; - } - port->channel = static_cast(channel); // Initialize sim analog input SimAnalogOutData[channel].initialized = true; + + port->previousAllocation = allocationLocation ? allocationLocation : ""; return handle; } diff --git a/hal/src/main/native/sim/DIO.cpp b/hal/src/main/native/sim/DIO.cpp index 4cb3d38810..0b85cd83dc 100644 --- a/hal/src/main/native/sim/DIO.cpp +++ b/hal/src/main/native/sim/DIO.cpp @@ -6,6 +6,7 @@ #include "DigitalInternal.h" #include "HALInitializer.h" +#include "HALInternal.h" #include "PortsInternal.h" #include "hal/handles/HandlesInternal.h" #include "hal/handles/LimitedHandleResource.h" @@ -31,36 +32,41 @@ void InitializeDIO() { extern "C" { HAL_DigitalHandle HAL_InitializeDIOPort(HAL_PortHandle portHandle, - HAL_Bool input, int32_t* status) { + HAL_Bool input, + const char* allocationLocation, + int32_t* status) { hal::init::CheckInit(); - if (*status != 0) { - return HAL_kInvalidHandle; - } int16_t channel = getPortHandleChannel(portHandle); if (channel == InvalidHandleIndex) { - *status = PARAMETER_OUT_OF_RANGE; + *status = RESOURCE_OUT_OF_RANGE; + hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for DIO", 0, + kNumDigitalChannels, channel); return HAL_kInvalidHandle; } - auto handle = - digitalChannelHandles->Allocate(channel, HAL_HandleEnum::DIO, status); + HAL_DigitalHandle handle; + + auto port = digitalChannelHandles->Allocate(channel, HAL_HandleEnum::DIO, + &handle, status); if (*status != 0) { + if (port) { + hal::SetLastErrorPreviouslyAllocated(status, "PWM or DIO", channel, + port->previousAllocation); + } else { + hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for DIO", 0, + kNumDigitalChannels, channel); + } return HAL_kInvalidHandle; // failed to allocate. Pass error back. } - auto port = digitalChannelHandles->Get(handle, HAL_HandleEnum::DIO); - if (port == nullptr) { // would only occur on thread issue. - *status = HAL_HANDLE_ERROR; - return HAL_kInvalidHandle; - } - port->channel = static_cast(channel); SimDIOData[channel].initialized = true; SimDIOData[channel].isInput = input; SimDIOData[channel].simDevice = 0; + port->previousAllocation = allocationLocation ? allocationLocation : ""; return handle; } diff --git a/hal/src/main/native/sim/DigitalInternal.h b/hal/src/main/native/sim/DigitalInternal.h index 080eb6fbe8..cd1ac5fcb5 100644 --- a/hal/src/main/native/sim/DigitalInternal.h +++ b/hal/src/main/native/sim/DigitalInternal.h @@ -6,6 +6,8 @@ #include +#include + #include "PortsInternal.h" #include "hal/AnalogTrigger.h" #include "hal/handles/DigitalHandleResource.h" @@ -56,6 +58,7 @@ struct DigitalPort { int32_t centerPwm = 0; int32_t deadbandMinPwm = 0; int32_t minPwm = 0; + std::string previousAllocation; }; extern DigitalHandleResource + +#include + +namespace hal { +void SetLastError(int32_t* status, const wpi::Twine& value); +void SetLastErrorIndexOutOfRange(int32_t* status, const wpi::Twine& message, + int32_t minimum, int32_t maximum, + int32_t channel); +void SetLastErrorPreviouslyAllocated(int32_t* status, const wpi::Twine& message, + int32_t channel, + const wpi::Twine& previousAllocation); +} // namespace hal diff --git a/hal/src/main/native/sim/PWM.cpp b/hal/src/main/native/sim/PWM.cpp index 06105e9981..698769fede 100644 --- a/hal/src/main/native/sim/PWM.cpp +++ b/hal/src/main/native/sim/PWM.cpp @@ -7,6 +7,7 @@ #include "ConstantsInternal.h" #include "DigitalInternal.h" #include "HALInitializer.h" +#include "HALInternal.h" #include "PortsInternal.h" #include "hal/handles/HandlesInternal.h" #include "mockdata/PWMDataInternal.h" @@ -20,15 +21,15 @@ void InitializePWM() {} extern "C" { HAL_DigitalHandle HAL_InitializePWMPort(HAL_PortHandle portHandle, + const char* allocationLocation, int32_t* status) { hal::init::CheckInit(); - if (*status != 0) { - return HAL_kInvalidHandle; - } int16_t channel = getPortHandleChannel(portHandle); if (channel == InvalidHandleIndex) { - *status = PARAMETER_OUT_OF_RANGE; + *status = RESOURCE_OUT_OF_RANGE; + hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for PWM", 0, + kNumPWMChannels, channel); return HAL_kInvalidHandle; } @@ -40,19 +41,22 @@ HAL_DigitalHandle HAL_InitializePWMPort(HAL_PortHandle portHandle, channel = remapMXPPWMChannel(channel) + 10; // remap MXP to proper channel } - auto handle = - digitalChannelHandles->Allocate(channel, HAL_HandleEnum::PWM, status); + HAL_DigitalHandle handle; + + auto port = digitalChannelHandles->Allocate(channel, HAL_HandleEnum::PWM, + &handle, status); if (*status != 0) { + if (port) { + hal::SetLastErrorPreviouslyAllocated(status, "PWM or DIO", channel, + port->previousAllocation); + } else { + hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for PWM", 0, + kNumPWMChannels, channel); + } return HAL_kInvalidHandle; // failed to allocate. Pass error back. } - auto port = digitalChannelHandles->Get(handle, HAL_HandleEnum::PWM); - if (port == nullptr) { // would only occur on thread issue. - *status = HAL_HANDLE_ERROR; - return HAL_kInvalidHandle; - } - port->channel = origChannel; SimPWMData[origChannel].initialized = true; @@ -60,6 +64,8 @@ HAL_DigitalHandle HAL_InitializePWMPort(HAL_PortHandle portHandle, // Defaults to allow an always valid config. HAL_SetPWMConfig(handle, 2.0, 1.501, 1.5, 1.499, 1.0, status); + port->previousAllocation = allocationLocation ? allocationLocation : ""; + return handle; } void HAL_FreePWMPort(HAL_DigitalHandle pwmPortHandle, int32_t* status) { diff --git a/hal/src/main/native/sim/Relay.cpp b/hal/src/main/native/sim/Relay.cpp index 7ba0438d50..4dfcdaf2a4 100644 --- a/hal/src/main/native/sim/Relay.cpp +++ b/hal/src/main/native/sim/Relay.cpp @@ -4,7 +4,10 @@ #include "hal/Relay.h" +#include + #include "HALInitializer.h" +#include "HALInternal.h" #include "PortsInternal.h" #include "hal/handles/IndexedHandleResource.h" #include "mockdata/RelayDataInternal.h" @@ -15,6 +18,7 @@ namespace { struct Relay { uint8_t channel; bool fwd; + std::string previousAllocation; }; } // namespace @@ -32,6 +36,7 @@ void InitializeRelay() { extern "C" { HAL_RelayHandle HAL_InitializeRelayPort(HAL_PortHandle portHandle, HAL_Bool fwd, + const char* allocationLocation, int32_t* status) { hal::init::CheckInit(); if (*status != 0) { @@ -39,8 +44,10 @@ HAL_RelayHandle HAL_InitializeRelayPort(HAL_PortHandle portHandle, HAL_Bool fwd, } int16_t channel = getPortHandleChannel(portHandle); - if (channel == InvalidHandleIndex) { - *status = PARAMETER_OUT_OF_RANGE; + if (channel == InvalidHandleIndex || channel >= kNumRelayChannels) { + *status = RESOURCE_OUT_OF_RANGE; + hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for Relay", 0, + kNumRelayChannels, channel); return HAL_kInvalidHandle; } @@ -48,18 +55,20 @@ HAL_RelayHandle HAL_InitializeRelayPort(HAL_PortHandle portHandle, HAL_Bool fwd, channel += kNumRelayHeaders; // add 4 to reverse channels } - auto handle = relayHandles->Allocate(channel, status); + HAL_RelayHandle handle; + auto port = relayHandles->Allocate(channel, &handle, status); if (*status != 0) { + if (port) { + hal::SetLastErrorPreviouslyAllocated(status, "Relay", channel, + port->previousAllocation); + } else { + hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for Relay", 0, + kNumRelayChannels, channel); + } return HAL_kInvalidHandle; // failed to allocate. Pass error back. } - auto port = relayHandles->Get(handle); - if (port == nullptr) { // would only occur on thread issue. - *status = HAL_HANDLE_ERROR; - return HAL_kInvalidHandle; - } - if (!fwd) { // Subtract number of headers to put channel in range channel -= kNumRelayHeaders; @@ -73,6 +82,7 @@ HAL_RelayHandle HAL_InitializeRelayPort(HAL_PortHandle portHandle, HAL_Bool fwd, } port->channel = static_cast(channel); + port->previousAllocation = allocationLocation ? allocationLocation : ""; return handle; } diff --git a/hal/src/main/native/sim/Solenoid.cpp b/hal/src/main/native/sim/Solenoid.cpp index 81be01a351..e59b393562 100644 --- a/hal/src/main/native/sim/Solenoid.cpp +++ b/hal/src/main/native/sim/Solenoid.cpp @@ -55,17 +55,13 @@ HAL_SolenoidHandle HAL_InitializeSolenoidPort(HAL_PortHandle portHandle, return HAL_kInvalidHandle; } - auto handle = solenoidHandles->Allocate( - module * kNumSolenoidChannels + channel, status); + HAL_SolenoidHandle handle; + auto solenoidPort = solenoidHandles->Allocate( + module * kNumSolenoidChannels + channel, &handle, status); if (handle == HAL_kInvalidHandle) { // out of resources *status = NO_AVAILABLE_RESOURCES; return HAL_kInvalidHandle; } - auto solenoidPort = solenoidHandles->Get(handle); - if (solenoidPort == nullptr) { // would only occur on thread issues - *status = HAL_HANDLE_ERROR; - return HAL_kInvalidHandle; - } solenoidPort->module = static_cast(module); solenoidPort->channel = static_cast(channel); diff --git a/hal/src/test/native/cpp/mockdata/AnalogInDataTests.cpp b/hal/src/test/native/cpp/mockdata/AnalogInDataTests.cpp index d9fbe01389..c657ebe36d 100644 --- a/hal/src/test/native/cpp/mockdata/AnalogInDataTests.cpp +++ b/hal/src/test/native/cpp/mockdata/AnalogInDataTests.cpp @@ -36,16 +36,18 @@ TEST(AnalogInSimTests, TestAnalogInInitialization) { status = 0; portHandle = 8000; gTestAnalogInCallbackName = "Unset"; - analogInHandle = HAL_InitializeAnalogInputPort(portHandle, &status); + analogInHandle = HAL_InitializeAnalogInputPort(portHandle, nullptr, &status); EXPECT_EQ(HAL_kInvalidHandle, analogInHandle); - EXPECT_EQ(PARAMETER_OUT_OF_RANGE, status); + EXPECT_EQ(HAL_USE_LAST_ERROR, status); + HAL_GetLastError(&status); + EXPECT_EQ(RESOURCE_OUT_OF_RANGE, status); EXPECT_STREQ("Unset", gTestAnalogInCallbackName.c_str()); // Successful setup status = 0; portHandle = HAL_GetPort(INDEX_TO_TEST); gTestAnalogInCallbackName = "Unset"; - analogInHandle = HAL_InitializeAnalogInputPort(portHandle, &status); + analogInHandle = HAL_InitializeAnalogInputPort(portHandle, nullptr, &status); EXPECT_TRUE(HAL_kInvalidHandle != analogInHandle); EXPECT_EQ(0, status); EXPECT_STREQ("Initialized", gTestAnalogInCallbackName.c_str()); @@ -54,8 +56,10 @@ TEST(AnalogInSimTests, TestAnalogInInitialization) { status = 0; portHandle = HAL_GetPort(INDEX_TO_TEST); gTestAnalogInCallbackName = "Unset"; - analogInHandle = HAL_InitializeAnalogInputPort(portHandle, &status); + analogInHandle = HAL_InitializeAnalogInputPort(portHandle, nullptr, &status); EXPECT_EQ(HAL_kInvalidHandle, analogInHandle); + EXPECT_EQ(HAL_USE_LAST_ERROR, status); + HAL_GetLastError(&status); EXPECT_EQ(RESOURCE_IS_ALLOCATED, status); EXPECT_STREQ("Unset", gTestAnalogInCallbackName.c_str()); @@ -69,7 +73,7 @@ TEST(AnalogInSimTests, TestAnalogInInitialization) { status = 0; portHandle = HAL_GetPort(INDEX_TO_TEST); gTestAnalogInCallbackName = "Unset"; - analogInHandle = HAL_InitializeAnalogInputPort(portHandle, &status); + analogInHandle = HAL_InitializeAnalogInputPort(portHandle, nullptr, &status); EXPECT_TRUE(HAL_kInvalidHandle != analogInHandle); EXPECT_EQ(0, status); EXPECT_STREQ("Initialized", gTestAnalogInCallbackName.c_str()); diff --git a/hal/src/test/native/cpp/mockdata/AnalogOutDataTests.cpp b/hal/src/test/native/cpp/mockdata/AnalogOutDataTests.cpp index 16e1d9d957..1ec14f4f19 100644 --- a/hal/src/test/native/cpp/mockdata/AnalogOutDataTests.cpp +++ b/hal/src/test/native/cpp/mockdata/AnalogOutDataTests.cpp @@ -36,16 +36,20 @@ TEST(AnalogOutSimTests, TestAnalogOutInitialization) { status = 0; portHandle = 8000; gTestAnalogOutCallbackName = "Unset"; - analogOutHandle = HAL_InitializeAnalogOutputPort(portHandle, &status); + analogOutHandle = + HAL_InitializeAnalogOutputPort(portHandle, nullptr, &status); EXPECT_EQ(HAL_kInvalidHandle, analogOutHandle); - EXPECT_EQ(PARAMETER_OUT_OF_RANGE, status); + EXPECT_EQ(HAL_USE_LAST_ERROR, status); + HAL_GetLastError(&status); + EXPECT_EQ(RESOURCE_OUT_OF_RANGE, status); EXPECT_STREQ("Unset", gTestAnalogOutCallbackName.c_str()); // Successful setup status = 0; portHandle = HAL_GetPort(INDEX_TO_TEST); gTestAnalogOutCallbackName = "Unset"; - analogOutHandle = HAL_InitializeAnalogOutputPort(portHandle, &status); + analogOutHandle = + HAL_InitializeAnalogOutputPort(portHandle, nullptr, &status); EXPECT_TRUE(HAL_kInvalidHandle != analogOutHandle); EXPECT_EQ(0, status); EXPECT_STREQ("Initialized", gTestAnalogOutCallbackName.c_str()); @@ -54,8 +58,11 @@ TEST(AnalogOutSimTests, TestAnalogOutInitialization) { status = 0; portHandle = HAL_GetPort(INDEX_TO_TEST); gTestAnalogOutCallbackName = "Unset"; - analogOutHandle = HAL_InitializeAnalogOutputPort(portHandle, &status); + analogOutHandle = + HAL_InitializeAnalogOutputPort(portHandle, nullptr, &status); EXPECT_EQ(HAL_kInvalidHandle, analogOutHandle); + EXPECT_EQ(HAL_USE_LAST_ERROR, status); + HAL_GetLastError(&status); EXPECT_EQ(RESOURCE_IS_ALLOCATED, status); EXPECT_STREQ("Unset", gTestAnalogOutCallbackName.c_str()); @@ -69,7 +76,8 @@ TEST(AnalogOutSimTests, TestAnalogOutInitialization) { status = 0; portHandle = HAL_GetPort(INDEX_TO_TEST); gTestAnalogOutCallbackName = "Unset"; - analogOutHandle = HAL_InitializeAnalogOutputPort(portHandle, &status); + analogOutHandle = + HAL_InitializeAnalogOutputPort(portHandle, nullptr, &status); EXPECT_TRUE(HAL_kInvalidHandle != analogOutHandle); EXPECT_EQ(0, status); EXPECT_STREQ("Initialized", gTestAnalogOutCallbackName.c_str()); diff --git a/hal/src/test/native/cpp/mockdata/DIODataTests.cpp b/hal/src/test/native/cpp/mockdata/DIODataTests.cpp index d584b45ec0..bc1345b091 100644 --- a/hal/src/test/native/cpp/mockdata/DIODataTests.cpp +++ b/hal/src/test/native/cpp/mockdata/DIODataTests.cpp @@ -36,16 +36,18 @@ TEST(DigitalIoSimTests, TestDigitalIoInitialization) { status = 0; portHandle = 8000; gTestDigitalIoCallbackName = "Unset"; - digitalIoHandle = HAL_InitializeDIOPort(portHandle, true, &status); + digitalIoHandle = HAL_InitializeDIOPort(portHandle, true, nullptr, &status); EXPECT_EQ(HAL_kInvalidHandle, digitalIoHandle); - EXPECT_EQ(PARAMETER_OUT_OF_RANGE, status); + EXPECT_EQ(HAL_USE_LAST_ERROR, status); + HAL_GetLastError(&status); + EXPECT_EQ(RESOURCE_OUT_OF_RANGE, status); EXPECT_STREQ("Unset", gTestDigitalIoCallbackName.c_str()); // Successful setup status = 0; portHandle = HAL_GetPort(INDEX_TO_TEST); gTestDigitalIoCallbackName = "Unset"; - digitalIoHandle = HAL_InitializeDIOPort(portHandle, true, &status); + digitalIoHandle = HAL_InitializeDIOPort(portHandle, true, nullptr, &status); EXPECT_TRUE(HAL_kInvalidHandle != digitalIoHandle); EXPECT_EQ(0, status); EXPECT_STREQ("Initialized", gTestDigitalIoCallbackName.c_str()); @@ -54,8 +56,10 @@ TEST(DigitalIoSimTests, TestDigitalIoInitialization) { status = 0; portHandle = HAL_GetPort(INDEX_TO_TEST); gTestDigitalIoCallbackName = "Unset"; - digitalIoHandle = HAL_InitializeDIOPort(portHandle, true, &status); + digitalIoHandle = HAL_InitializeDIOPort(portHandle, true, nullptr, &status); EXPECT_EQ(HAL_kInvalidHandle, digitalIoHandle); + EXPECT_EQ(HAL_USE_LAST_ERROR, status); + HAL_GetLastError(&status); EXPECT_EQ(RESOURCE_IS_ALLOCATED, status); EXPECT_STREQ("Unset", gTestDigitalIoCallbackName.c_str()); @@ -69,7 +73,7 @@ TEST(DigitalIoSimTests, TestDigitalIoInitialization) { status = 0; portHandle = HAL_GetPort(INDEX_TO_TEST); gTestDigitalIoCallbackName = "Unset"; - digitalIoHandle = HAL_InitializeDIOPort(portHandle, true, &status); + digitalIoHandle = HAL_InitializeDIOPort(portHandle, true, nullptr, &status); EXPECT_TRUE(HAL_kInvalidHandle != digitalIoHandle); EXPECT_EQ(0, status); EXPECT_STREQ("Initialized", gTestDigitalIoCallbackName.c_str()); diff --git a/hal/src/test/native/cpp/mockdata/PWMDataTests.cpp b/hal/src/test/native/cpp/mockdata/PWMDataTests.cpp index fb717971ac..c0bb7f0b31 100644 --- a/hal/src/test/native/cpp/mockdata/PWMDataTests.cpp +++ b/hal/src/test/native/cpp/mockdata/PWMDataTests.cpp @@ -35,16 +35,18 @@ TEST(PWMSimTests, TestPwmInitialization) { status = 0; portHandle = 8000; gTestPwmCallbackName = "Unset"; - pwmHandle = HAL_InitializePWMPort(portHandle, &status); + pwmHandle = HAL_InitializePWMPort(portHandle, nullptr, &status); EXPECT_EQ(HAL_kInvalidHandle, pwmHandle); - EXPECT_EQ(PARAMETER_OUT_OF_RANGE, status); + EXPECT_EQ(HAL_USE_LAST_ERROR, status); + HAL_GetLastError(&status); + EXPECT_EQ(RESOURCE_OUT_OF_RANGE, status); EXPECT_STREQ("Unset", gTestPwmCallbackName.c_str()); // Successful setup status = 0; portHandle = HAL_GetPort(INDEX_TO_TEST); gTestPwmCallbackName = "Unset"; - pwmHandle = HAL_InitializePWMPort(portHandle, &status); + pwmHandle = HAL_InitializePWMPort(portHandle, nullptr, &status); EXPECT_TRUE(HAL_kInvalidHandle != pwmHandle); EXPECT_EQ(0, status); EXPECT_STREQ("Initialized", gTestPwmCallbackName.c_str()); @@ -53,8 +55,10 @@ TEST(PWMSimTests, TestPwmInitialization) { status = 0; portHandle = HAL_GetPort(INDEX_TO_TEST); gTestPwmCallbackName = "Unset"; - pwmHandle = HAL_InitializePWMPort(portHandle, &status); + pwmHandle = HAL_InitializePWMPort(portHandle, nullptr, &status); EXPECT_EQ(HAL_kInvalidHandle, pwmHandle); + EXPECT_EQ(HAL_USE_LAST_ERROR, status); + HAL_GetLastError(&status); EXPECT_EQ(RESOURCE_IS_ALLOCATED, status); EXPECT_STREQ("Unset", gTestPwmCallbackName.c_str()); @@ -67,7 +71,7 @@ TEST(PWMSimTests, TestPwmInitialization) { status = 0; portHandle = HAL_GetPort(INDEX_TO_TEST); gTestPwmCallbackName = "Unset"; - pwmHandle = HAL_InitializePWMPort(portHandle, &status); + pwmHandle = HAL_InitializePWMPort(portHandle, nullptr, &status); EXPECT_TRUE(HAL_kInvalidHandle != pwmHandle); EXPECT_EQ(0, status); EXPECT_STREQ("Initialized", gTestPwmCallbackName.c_str()); diff --git a/hal/src/test/native/cpp/mockdata/RelayDataTests.cpp b/hal/src/test/native/cpp/mockdata/RelayDataTests.cpp index 6e5004667d..af85318006 100644 --- a/hal/src/test/native/cpp/mockdata/RelayDataTests.cpp +++ b/hal/src/test/native/cpp/mockdata/RelayDataTests.cpp @@ -35,16 +35,18 @@ TEST(RelaySimTests, TestRelayInitialization) { status = 0; portHandle = 8000; gTestRelayCallbackName = "Unset"; - pdpHandle = HAL_InitializeRelayPort(portHandle, true, &status); + pdpHandle = HAL_InitializeRelayPort(portHandle, true, nullptr, &status); EXPECT_EQ(HAL_kInvalidHandle, pdpHandle); - EXPECT_EQ(PARAMETER_OUT_OF_RANGE, status); + EXPECT_EQ(HAL_USE_LAST_ERROR, status); + HAL_GetLastError(&status); + EXPECT_EQ(RESOURCE_OUT_OF_RANGE, status); EXPECT_STREQ("Unset", gTestRelayCallbackName.c_str()); // Successful setup status = 0; portHandle = HAL_GetPort(INDEX_TO_TEST); gTestRelayCallbackName = "Unset"; - pdpHandle = HAL_InitializeRelayPort(portHandle, true, &status); + pdpHandle = HAL_InitializeRelayPort(portHandle, true, nullptr, &status); EXPECT_TRUE(HAL_kInvalidHandle != pdpHandle); EXPECT_EQ(0, status); EXPECT_STREQ("InitializedForward", gTestRelayCallbackName.c_str()); @@ -53,8 +55,10 @@ TEST(RelaySimTests, TestRelayInitialization) { status = 0; portHandle = HAL_GetPort(INDEX_TO_TEST); gTestRelayCallbackName = "Unset"; - pdpHandle = HAL_InitializeRelayPort(portHandle, true, &status); + pdpHandle = HAL_InitializeRelayPort(portHandle, true, nullptr, &status); EXPECT_EQ(HAL_kInvalidHandle, pdpHandle); + EXPECT_EQ(HAL_USE_LAST_ERROR, status); + HAL_GetLastError(&status); EXPECT_EQ(RESOURCE_IS_ALLOCATED, status); EXPECT_STREQ("Unset", gTestRelayCallbackName.c_str()); @@ -67,7 +71,7 @@ TEST(RelaySimTests, TestRelayInitialization) { status = 0; portHandle = HAL_GetPort(INDEX_TO_TEST); gTestRelayCallbackName = "Unset"; - pdpHandle = HAL_InitializeRelayPort(portHandle, true, &status); + pdpHandle = HAL_InitializeRelayPort(portHandle, true, nullptr, &status); EXPECT_TRUE(HAL_kInvalidHandle != pdpHandle); EXPECT_EQ(0, status); EXPECT_STREQ("InitializedForward", gTestRelayCallbackName.c_str()); diff --git a/wpilibc/src/main/native/cpp/AddressableLED.cpp b/wpilibc/src/main/native/cpp/AddressableLED.cpp index db297ffe46..6b8a751c19 100644 --- a/wpilibc/src/main/native/cpp/AddressableLED.cpp +++ b/wpilibc/src/main/native/cpp/AddressableLED.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "frc/Errors.h" @@ -17,7 +18,9 @@ using namespace frc; AddressableLED::AddressableLED(int port) { int32_t status = 0; - m_pwmHandle = HAL_InitializePWMPort(HAL_GetPort(port), &status); + auto stack = wpi::GetStackTrace(1); + m_pwmHandle = + HAL_InitializePWMPort(HAL_GetPort(port), stack.c_str(), &status); FRC_CheckErrorStatus(status, "Port " + wpi::Twine{port}); if (m_pwmHandle == HAL_kInvalidHandle) { return; diff --git a/wpilibc/src/main/native/cpp/AnalogGyro.cpp b/wpilibc/src/main/native/cpp/AnalogGyro.cpp index 504c27384b..cdbf0e0254 100644 --- a/wpilibc/src/main/native/cpp/AnalogGyro.cpp +++ b/wpilibc/src/main/native/cpp/AnalogGyro.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include "frc/AnalogInput.h" #include "frc/Base.h" @@ -111,7 +112,9 @@ void AnalogGyro::Reset() { void AnalogGyro::InitGyro() { if (m_gyroHandle == HAL_kInvalidHandle) { int32_t status = 0; - m_gyroHandle = HAL_InitializeAnalogGyro(m_analog->m_port, &status); + std::string stackTrace = wpi::GetStackTrace(1); + m_gyroHandle = + HAL_InitializeAnalogGyro(m_analog->m_port, stackTrace.c_str(), &status); if (status == PARAMETER_OUT_OF_RANGE) { throw FRC_MakeError(err::ParameterOutOfRange, "channel must be accumulator channel"); diff --git a/wpilibc/src/main/native/cpp/AnalogInput.cpp b/wpilibc/src/main/native/cpp/AnalogInput.cpp index e9191d8b92..dee97343ab 100644 --- a/wpilibc/src/main/native/cpp/AnalogInput.cpp +++ b/wpilibc/src/main/native/cpp/AnalogInput.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "frc/Errors.h" #include "frc/SensorUtil.h" @@ -28,7 +29,8 @@ AnalogInput::AnalogInput(int channel) { HAL_PortHandle port = HAL_GetPort(channel); int32_t status = 0; - m_port = HAL_InitializeAnalogInputPort(port, &status); + std::string stackTrace = wpi::GetStackTrace(1); + m_port = HAL_InitializeAnalogInputPort(port, stackTrace.c_str(), &status); FRC_CheckErrorStatus(status, "Analog Input " + wpi::Twine{channel}); HAL_Report(HALUsageReporting::kResourceType_AnalogChannel, channel + 1); diff --git a/wpilibc/src/main/native/cpp/AnalogOutput.cpp b/wpilibc/src/main/native/cpp/AnalogOutput.cpp index 1c86d17234..ce827f5a75 100644 --- a/wpilibc/src/main/native/cpp/AnalogOutput.cpp +++ b/wpilibc/src/main/native/cpp/AnalogOutput.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include "frc/Errors.h" #include "frc/SensorUtil.h" @@ -29,7 +30,8 @@ AnalogOutput::AnalogOutput(int channel) { HAL_PortHandle port = HAL_GetPort(m_channel); int32_t status = 0; - m_port = HAL_InitializeAnalogOutputPort(port, &status); + std::string stackTrace = wpi::GetStackTrace(1); + m_port = HAL_InitializeAnalogOutputPort(port, stackTrace.c_str(), &status); FRC_CheckErrorStatus(status, "analog output " + wpi::Twine(channel)); HAL_Report(HALUsageReporting::kResourceType_AnalogOutput, m_channel + 1); diff --git a/wpilibc/src/main/native/cpp/DigitalInput.cpp b/wpilibc/src/main/native/cpp/DigitalInput.cpp index 936067ad0b..b97e36cc46 100644 --- a/wpilibc/src/main/native/cpp/DigitalInput.cpp +++ b/wpilibc/src/main/native/cpp/DigitalInput.cpp @@ -4,12 +4,14 @@ #include "frc/DigitalInput.h" +#include #include #include #include #include #include +#include #include "frc/Errors.h" #include "frc/SensorUtil.h" @@ -26,7 +28,9 @@ DigitalInput::DigitalInput(int channel) { m_channel = channel; int32_t status = 0; - m_handle = HAL_InitializeDIOPort(HAL_GetPort(channel), true, &status); + std::string stackTrace = wpi::GetStackTrace(1); + m_handle = HAL_InitializeDIOPort(HAL_GetPort(channel), true, + stackTrace.c_str(), &status); FRC_CheckErrorStatus(status, "Digital Channel " + wpi::Twine{channel}); HAL_Report(HALUsageReporting::kResourceType_DigitalInput, channel + 1); diff --git a/wpilibc/src/main/native/cpp/DigitalOutput.cpp b/wpilibc/src/main/native/cpp/DigitalOutput.cpp index 41c5e4e1ec..351ac07ed5 100644 --- a/wpilibc/src/main/native/cpp/DigitalOutput.cpp +++ b/wpilibc/src/main/native/cpp/DigitalOutput.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include "frc/Errors.h" #include "frc/SensorUtil.h" @@ -27,7 +28,9 @@ DigitalOutput::DigitalOutput(int channel) { m_channel = channel; int32_t status = 0; - m_handle = HAL_InitializeDIOPort(HAL_GetPort(channel), false, &status); + std::string stackTrace = wpi::GetStackTrace(1); + m_handle = HAL_InitializeDIOPort(HAL_GetPort(channel), false, + stackTrace.c_str(), &status); FRC_CheckErrorStatus(status, "Digital Channel " + wpi::Twine{channel}); HAL_Report(HALUsageReporting::kResourceType_DigitalOutput, channel + 1); diff --git a/wpilibc/src/main/native/cpp/PWM.cpp b/wpilibc/src/main/native/cpp/PWM.cpp index d9c0a27454..b9aa1d8ffa 100644 --- a/wpilibc/src/main/native/cpp/PWM.cpp +++ b/wpilibc/src/main/native/cpp/PWM.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include "frc/Errors.h" #include "frc/SensorUtil.h" @@ -26,8 +27,10 @@ PWM::PWM(int channel, bool registerSendable) { return; } + auto stack = wpi::GetStackTrace(1); int32_t status = 0; - m_handle = HAL_InitializePWMPort(HAL_GetPort(channel), &status); + m_handle = + HAL_InitializePWMPort(HAL_GetPort(channel), stack.c_str(), &status); FRC_CheckErrorStatus(status, "PWM Channel " + wpi::Twine{channel}); m_channel = channel; diff --git a/wpilibc/src/main/native/cpp/Relay.cpp b/wpilibc/src/main/native/cpp/Relay.cpp index 66c63c3516..b5037b327d 100644 --- a/wpilibc/src/main/native/cpp/Relay.cpp +++ b/wpilibc/src/main/native/cpp/Relay.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "frc/Errors.h" @@ -31,13 +32,17 @@ Relay::Relay(int channel, Relay::Direction direction) if (m_direction == kBothDirections || m_direction == kForwardOnly) { int32_t status = 0; - m_forwardHandle = HAL_InitializeRelayPort(portHandle, true, &status); + std::string stackTrace = wpi::GetStackTrace(1); + m_forwardHandle = + HAL_InitializeRelayPort(portHandle, true, stackTrace.c_str(), &status); FRC_CheckErrorStatus(status, "Relay Channel " + wpi::Twine{m_channel}); HAL_Report(HALUsageReporting::kResourceType_Relay, m_channel + 1); } if (m_direction == kBothDirections || m_direction == kReverseOnly) { int32_t status = 0; - m_reverseHandle = HAL_InitializeRelayPort(portHandle, false, &status); + std::string stackTrace = wpi::GetStackTrace(1); + m_reverseHandle = + HAL_InitializeRelayPort(portHandle, false, stackTrace.c_str(), &status); FRC_CheckErrorStatus(status, "Relay Channel " + wpi::Twine{m_channel}); HAL_Report(HALUsageReporting::kResourceType_Relay, m_channel + 128); } diff --git a/wpilibcExamples/src/main/cpp/examples/HAL/c/Robot.c b/wpilibcExamples/src/main/cpp/examples/HAL/c/Robot.c index b7c0826bad..0db402bf76 100644 --- a/wpilibcExamples/src/main/cpp/examples/HAL/c/Robot.c +++ b/wpilibcExamples/src/main/cpp/examples/HAL/c/Robot.c @@ -62,7 +62,8 @@ int main(void) { // Create a Motor Controller status = 0; - HAL_DigitalHandle pwmPort = HAL_InitializePWMPort(HAL_GetPort(2), &status); + HAL_DigitalHandle pwmPort = + HAL_InitializePWMPort(HAL_GetPort(2), NULL, &status); if (status != 0) { const char* message = HAL_GetLastError(&status); @@ -75,7 +76,8 @@ int main(void) { // Create an Input status = 0; - HAL_DigitalHandle dio = HAL_InitializeDIOPort(HAL_GetPort(2), 1, &status); + HAL_DigitalHandle dio = + HAL_InitializeDIOPort(HAL_GetPort(2), 1, NULL, &status); if (status != 0) { const char* message = HAL_GetLastError(&status); diff --git a/wpiutil/src/main/native/include/wpi/jni_util.h b/wpiutil/src/main/native/include/wpi/jni_util.h index df3075c390..11e8f542c2 100644 --- a/wpiutil/src/main/native/include/wpi/jni_util.h +++ b/wpiutil/src/main/native/include/wpi/jni_util.h @@ -593,6 +593,81 @@ class JSingletonCallbackManager : public JCallbackManager { } }; +inline std::string GetJavaStackTrace(JNIEnv* env, StringRef skipPrefix) { + // create a throwable + static JClass throwableCls(env, "java/lang/Throwable"); + if (!throwableCls) { + return ""; + } + static jmethodID constructorId = nullptr; + if (!constructorId) { + constructorId = env->GetMethodID(throwableCls, "", "()V"); + } + JLocal throwable(env, env->NewObject(throwableCls, constructorId)); + + // retrieve information from the exception. + // get method id + // getStackTrace returns an array of StackTraceElement + static jmethodID getStackTraceId = nullptr; + if (!getStackTraceId) { + getStackTraceId = env->GetMethodID(throwableCls, "getStackTrace", + "()[Ljava/lang/StackTraceElement;"); + } + + // call getStackTrace + JLocal stackTrace( + env, static_cast( + env->CallObjectMethod(throwable, getStackTraceId))); + + if (!stackTrace) { + return ""; + } + + // get length of the array + jsize stackTraceLength = env->GetArrayLength(stackTrace); + + // get toString methodId of StackTraceElement class + static JClass stackTraceElementCls(env, "java/lang/StackTraceElement"); + if (!stackTraceElementCls) { + return ""; + } + static jmethodID toStringId = nullptr; + if (!toStringId) { + toStringId = env->GetMethodID(stackTraceElementCls, "toString", + "()Ljava/lang/String;"); + } + + bool foundFirst = false; + std::string buf; + raw_string_ostream oss(buf); + for (jsize i = 0; i < stackTraceLength; i++) { + // add the result of toString method of each element in the result + JLocal curStackTraceElement( + env, env->GetObjectArrayElement(stackTrace, i)); + + // call to string on the object + JLocal stackElementString( + env, static_cast( + env->CallObjectMethod(curStackTraceElement, toStringId))); + + if (!stackElementString) { + return ""; + } + + // add a line to res + JStringRef elem(env, stackElementString); + if (!foundFirst) { + if (elem.str().startswith(skipPrefix)) { + continue; + } + foundFirst = true; + } + oss << "\tat " << elem << '\n'; + } + + return oss.str(); +} + inline std::string GetJavaStackTrace(JNIEnv* env, std::string* func, StringRef excludeFuncPrefix) { // create a throwable