2020-12-26 14:12:05 -08:00
|
|
|
// 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.
|
2017-08-18 21:35:53 -07:00
|
|
|
|
2025-11-07 19:56:21 -05:00
|
|
|
#include "wpi/hal/DIO.h"
|
2017-08-18 21:35:53 -07:00
|
|
|
|
|
|
|
|
#include "DigitalInternal.h"
|
2018-05-13 22:02:47 -07:00
|
|
|
#include "HALInitializer.h"
|
2021-05-01 10:28:30 -07:00
|
|
|
#include "HALInternal.h"
|
2017-08-18 21:35:53 -07:00
|
|
|
#include "PortsInternal.h"
|
2018-07-20 00:03:45 -07:00
|
|
|
#include "mockdata/DIODataInternal.h"
|
|
|
|
|
#include "mockdata/DigitalPWMDataInternal.h"
|
2025-11-07 19:57:55 -05:00
|
|
|
#include "wpi/hal/handles/HandlesInternal.h"
|
|
|
|
|
#include "wpi/hal/handles/LimitedHandleResource.h"
|
2017-08-18 21:35:53 -07:00
|
|
|
|
2025-11-07 20:00:05 -05:00
|
|
|
using namespace wpi::hal;
|
2017-08-18 21:35:53 -07:00
|
|
|
|
|
|
|
|
static LimitedHandleResource<HAL_DigitalPWMHandle, uint8_t,
|
2017-12-10 19:38:53 -08:00
|
|
|
kNumDigitalPWMOutputs, HAL_HandleEnum::DigitalPWM>*
|
2017-08-18 21:35:53 -07:00
|
|
|
digitalPWMHandles;
|
|
|
|
|
|
2025-11-07 20:00:05 -05:00
|
|
|
namespace wpi::hal::init {
|
2017-12-10 19:38:53 -08:00
|
|
|
void InitializeDIO() {
|
|
|
|
|
static LimitedHandleResource<HAL_DigitalPWMHandle, uint8_t,
|
|
|
|
|
kNumDigitalPWMOutputs,
|
|
|
|
|
HAL_HandleEnum::DigitalPWM>
|
|
|
|
|
dpH;
|
|
|
|
|
digitalPWMHandles = &dpH;
|
|
|
|
|
}
|
2025-11-07 20:00:05 -05:00
|
|
|
} // namespace wpi::hal::init
|
2017-12-10 19:38:53 -08:00
|
|
|
|
2017-08-18 21:35:53 -07:00
|
|
|
extern "C" {
|
|
|
|
|
|
2025-01-30 18:59:34 -08:00
|
|
|
HAL_DigitalHandle HAL_InitializeDIOPort(int32_t channel, HAL_Bool input,
|
2021-05-01 10:28:30 -07:00
|
|
|
const char* allocationLocation,
|
|
|
|
|
int32_t* status) {
|
2025-11-07 20:00:05 -05:00
|
|
|
wpi::hal::init::CheckInit();
|
2017-08-18 21:35:53 -07:00
|
|
|
|
2025-01-30 18:59:34 -08:00
|
|
|
if (channel < 0 || channel >= kNumDigitalChannels) {
|
2021-05-01 10:28:30 -07:00
|
|
|
*status = RESOURCE_OUT_OF_RANGE;
|
2025-11-07 20:00:05 -05:00
|
|
|
wpi::hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for DIO", 0,
|
2021-05-01 10:28:30 -07:00
|
|
|
kNumDigitalChannels, channel);
|
2017-08-18 21:35:53 -07:00
|
|
|
return HAL_kInvalidHandle;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-01 10:28:30 -07:00
|
|
|
HAL_DigitalHandle handle;
|
|
|
|
|
|
|
|
|
|
auto port = digitalChannelHandles->Allocate(channel, HAL_HandleEnum::DIO,
|
|
|
|
|
&handle, status);
|
2017-08-18 21:35:53 -07:00
|
|
|
|
2020-12-28 12:58:06 -08:00
|
|
|
if (*status != 0) {
|
2021-05-01 10:28:30 -07:00
|
|
|
if (port) {
|
2025-11-07 20:00:05 -05:00
|
|
|
wpi::hal::SetLastErrorPreviouslyAllocated(status, "PWM or DIO", channel,
|
2021-05-01 10:28:30 -07:00
|
|
|
port->previousAllocation);
|
|
|
|
|
} else {
|
2025-11-07 20:00:05 -05:00
|
|
|
wpi::hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for DIO", 0,
|
2021-05-01 10:28:30 -07:00
|
|
|
kNumDigitalChannels, channel);
|
|
|
|
|
}
|
2017-08-18 21:35:53 -07:00
|
|
|
return HAL_kInvalidHandle; // failed to allocate. Pass error back.
|
2020-12-28 12:58:06 -08:00
|
|
|
}
|
2017-08-18 21:35:53 -07:00
|
|
|
|
|
|
|
|
port->channel = static_cast<uint8_t>(channel);
|
|
|
|
|
|
2018-09-03 16:08:07 -07:00
|
|
|
SimDIOData[channel].initialized = true;
|
|
|
|
|
SimDIOData[channel].isInput = input;
|
2019-10-04 22:56:24 -07:00
|
|
|
SimDIOData[channel].simDevice = 0;
|
2024-05-28 00:18:19 -04:00
|
|
|
SimDIOData[channel].value = true;
|
2021-05-01 10:28:30 -07:00
|
|
|
port->previousAllocation = allocationLocation ? allocationLocation : "";
|
2017-08-18 21:35:53 -07:00
|
|
|
|
|
|
|
|
return handle;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HAL_Bool HAL_CheckDIOChannel(int32_t channel) {
|
|
|
|
|
return channel < kNumDigitalChannels && channel >= 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void HAL_FreeDIOPort(HAL_DigitalHandle dioPortHandle) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
|
2017-08-18 21:35:53 -07:00
|
|
|
// no status, so no need to check for a proper free.
|
2017-12-10 19:38:53 -08:00
|
|
|
digitalChannelHandles->Free(dioPortHandle, HAL_HandleEnum::DIO);
|
2020-12-28 12:58:06 -08:00
|
|
|
if (port == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2019-08-09 16:14:46 -07:00
|
|
|
SimDIOData[port->channel].initialized = false;
|
2017-08-18 21:35:53 -07:00
|
|
|
}
|
|
|
|
|
|
2019-10-04 22:56:24 -07:00
|
|
|
void HAL_SetDIOSimDevice(HAL_DigitalHandle handle, HAL_SimDeviceHandle device) {
|
|
|
|
|
auto port = digitalChannelHandles->Get(handle, HAL_HandleEnum::DIO);
|
2020-12-28 12:58:06 -08:00
|
|
|
if (port == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2019-10-04 22:56:24 -07:00
|
|
|
SimDIOData[port->channel].simDevice = device;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-18 21:35:53 -07:00
|
|
|
HAL_DigitalPWMHandle HAL_AllocateDigitalPWM(int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto handle = digitalPWMHandles->Allocate();
|
2017-08-18 21:35:53 -07:00
|
|
|
if (handle == HAL_kInvalidHandle) {
|
|
|
|
|
*status = NO_AVAILABLE_RESOURCES;
|
|
|
|
|
return HAL_kInvalidHandle;
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-10 19:38:53 -08:00
|
|
|
auto id = digitalPWMHandles->Get(handle);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (id == nullptr) { // would only occur on thread issue.
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return HAL_kInvalidHandle;
|
|
|
|
|
}
|
|
|
|
|
*id = static_cast<uint8_t>(getHandleIndex(handle));
|
|
|
|
|
|
2018-09-03 16:08:07 -07:00
|
|
|
SimDigitalPWMData[*id].initialized = true;
|
2017-08-18 21:35:53 -07:00
|
|
|
|
|
|
|
|
return handle;
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-07 13:58:15 -04:00
|
|
|
void HAL_FreeDigitalPWM(HAL_DigitalPWMHandle pwmGenerator) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto port = digitalPWMHandles->Get(pwmGenerator);
|
|
|
|
|
digitalPWMHandles->Free(pwmGenerator);
|
2020-12-28 12:58:06 -08:00
|
|
|
if (port == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-08-18 21:35:53 -07:00
|
|
|
int32_t id = *port;
|
2018-09-03 16:08:07 -07:00
|
|
|
SimDigitalPWMData[id].initialized = false;
|
2017-08-18 21:35:53 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void HAL_SetDigitalPWMRate(double rate, int32_t* status) {
|
|
|
|
|
// Currently rounding in the log rate domain... heavy weight toward picking a
|
|
|
|
|
// higher freq.
|
|
|
|
|
// TODO: Round in the linear rate domain.
|
|
|
|
|
// uint8_t pwmPeriodPower = static_cast<uint8_t>(
|
2023-04-28 20:52:03 -07:00
|
|
|
// std::log2(1.0 / (kExpectedLoopTiming * 0.25E-6 * rate)) + 0.5);
|
2017-08-18 21:35:53 -07:00
|
|
|
// TODO(THAD) : Add a case to set this in the simulator
|
|
|
|
|
// digitalSystem->writePWMPeriodPower(pwmPeriodPower, status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void HAL_SetDigitalPWMDutyCycle(HAL_DigitalPWMHandle pwmGenerator,
|
|
|
|
|
double dutyCycle, int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto port = digitalPWMHandles->Get(pwmGenerator);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (port == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
int32_t id = *port;
|
2020-12-28 12:58:06 -08:00
|
|
|
if (dutyCycle > 1.0) {
|
|
|
|
|
dutyCycle = 1.0;
|
|
|
|
|
}
|
|
|
|
|
if (dutyCycle < 0.0) {
|
|
|
|
|
dutyCycle = 0.0;
|
|
|
|
|
}
|
2018-09-03 16:08:07 -07:00
|
|
|
SimDigitalPWMData[id].dutyCycle = dutyCycle;
|
2017-08-18 21:35:53 -07:00
|
|
|
}
|
|
|
|
|
|
2022-12-14 18:15:34 -08:00
|
|
|
void HAL_SetDigitalPWMPPS(HAL_DigitalPWMHandle pwmGenerator, double dutyCycle,
|
|
|
|
|
int32_t* status) {
|
|
|
|
|
auto port = digitalPWMHandles->Get(pwmGenerator);
|
|
|
|
|
if (port == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
int32_t id = *port;
|
|
|
|
|
if (dutyCycle > 1.0) {
|
|
|
|
|
dutyCycle = 1.0;
|
|
|
|
|
}
|
|
|
|
|
if (dutyCycle < 0.0) {
|
|
|
|
|
dutyCycle = 0.0;
|
|
|
|
|
}
|
|
|
|
|
SimDigitalPWMData[id].dutyCycle = dutyCycle;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-18 21:35:53 -07:00
|
|
|
void HAL_SetDigitalPWMOutputChannel(HAL_DigitalPWMHandle pwmGenerator,
|
|
|
|
|
int32_t channel, int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto port = digitalPWMHandles->Get(pwmGenerator);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (port == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
int32_t id = *port;
|
2018-09-03 16:08:07 -07:00
|
|
|
SimDigitalPWMData[id].pin = channel;
|
2017-08-18 21:35:53 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void HAL_SetDIO(HAL_DigitalHandle dioPortHandle, HAL_Bool value,
|
|
|
|
|
int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (port == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (value != 0 && value != 1) {
|
2020-12-28 12:58:06 -08:00
|
|
|
if (value != 0) {
|
|
|
|
|
value = 1;
|
|
|
|
|
}
|
2017-08-18 21:35:53 -07:00
|
|
|
}
|
2021-06-13 15:00:43 -07:00
|
|
|
if (SimDIOData[port->channel].isInput) {
|
|
|
|
|
*status = PARAMETER_OUT_OF_RANGE;
|
2025-11-07 20:00:05 -05:00
|
|
|
wpi::hal::SetLastError(status, "Cannot set output of an input channel");
|
2021-06-13 15:00:43 -07:00
|
|
|
return;
|
|
|
|
|
}
|
2018-09-03 16:08:07 -07:00
|
|
|
SimDIOData[port->channel].value = value;
|
2017-08-18 21:35:53 -07:00
|
|
|
}
|
|
|
|
|
|
2018-02-12 16:05:10 -08:00
|
|
|
void HAL_SetDIODirection(HAL_DigitalHandle dioPortHandle, HAL_Bool input,
|
|
|
|
|
int32_t* status) {
|
|
|
|
|
auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
|
|
|
|
|
if (port == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-03 16:08:07 -07:00
|
|
|
SimDIOData[port->channel].isInput = input;
|
2018-02-12 16:05:10 -08:00
|
|
|
}
|
|
|
|
|
|
2017-08-18 21:35:53 -07:00
|
|
|
HAL_Bool HAL_GetDIO(HAL_DigitalHandle dioPortHandle, int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (port == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2018-09-03 16:08:07 -07:00
|
|
|
HAL_Bool value = SimDIOData[port->channel].value;
|
2020-12-28 12:58:06 -08:00
|
|
|
if (value > 1) {
|
|
|
|
|
value = 1;
|
|
|
|
|
}
|
|
|
|
|
if (value < 0) {
|
|
|
|
|
value = 0;
|
|
|
|
|
}
|
2017-08-18 21:35:53 -07:00
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HAL_Bool HAL_GetDIODirection(HAL_DigitalHandle dioPortHandle, int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (port == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2018-09-03 16:08:07 -07:00
|
|
|
HAL_Bool value = SimDIOData[port->channel].isInput;
|
2020-12-28 12:58:06 -08:00
|
|
|
if (value > 1) {
|
|
|
|
|
value = 1;
|
|
|
|
|
}
|
|
|
|
|
if (value < 0) {
|
|
|
|
|
value = 0;
|
|
|
|
|
}
|
2017-08-18 21:35:53 -07:00
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-02 16:49:42 -07:00
|
|
|
void HAL_Pulse(HAL_DigitalHandle dioPortHandle, double pulseLengthSeconds,
|
2017-08-18 21:35:53 -07:00
|
|
|
int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (port == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// TODO (Thad) Add this
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-02 16:49:42 -07:00
|
|
|
void HAL_PulseMultiple(uint32_t channelMask, double pulseLengthSeconds,
|
|
|
|
|
int32_t* status) {
|
|
|
|
|
// TODO (Thad) Add this
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-18 21:35:53 -07:00
|
|
|
HAL_Bool HAL_IsPulsing(HAL_DigitalHandle dioPortHandle, int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (port == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
// TODO (Thad) Add this
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HAL_Bool HAL_IsAnyPulsing(int32_t* status) {
|
|
|
|
|
return false; // TODO(Thad) Figure this out
|
|
|
|
|
}
|
2017-10-16 19:56:08 -07:00
|
|
|
} // extern "C"
|