mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-22 01:11:42 +00:00
[hal, wpilib] PWM Rewrite (#7845)
The HAL will only contain the output period and the raw microseconds. Higher level things such as SimDevice can handle everything else.
This commit is contained in:
@@ -42,13 +42,6 @@ constexpr int32_t kPwmDisabled = 0;
|
||||
|
||||
struct DigitalPort {
|
||||
uint8_t channel;
|
||||
bool configSet = false;
|
||||
bool eliminateDeadband = false;
|
||||
int32_t maxPwm = 0;
|
||||
int32_t deadbandMaxPwm = 0;
|
||||
int32_t centerPwm = 0;
|
||||
int32_t deadbandMinPwm = 0;
|
||||
int32_t minPwm = 0;
|
||||
int32_t filterIndex = 0;
|
||||
std::string previousAllocation;
|
||||
};
|
||||
|
||||
@@ -21,46 +21,6 @@ namespace hal::init {
|
||||
void InitializePWM() {}
|
||||
} // namespace hal::init
|
||||
|
||||
static inline int32_t GetMaxPositivePwm(DigitalPort* port) {
|
||||
return port->maxPwm;
|
||||
}
|
||||
|
||||
static inline int32_t GetMinPositivePwm(DigitalPort* port) {
|
||||
if (port->eliminateDeadband) {
|
||||
return port->deadbandMaxPwm;
|
||||
} else {
|
||||
return port->centerPwm + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int32_t GetCenterPwm(DigitalPort* port) {
|
||||
return port->centerPwm;
|
||||
}
|
||||
|
||||
static inline int32_t GetMaxNegativePwm(DigitalPort* port) {
|
||||
if (port->eliminateDeadband) {
|
||||
return port->deadbandMinPwm;
|
||||
} else {
|
||||
return port->centerPwm - 1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int32_t GetMinNegativePwm(DigitalPort* port) {
|
||||
return port->minPwm;
|
||||
}
|
||||
|
||||
static inline int32_t GetPositiveScaleFactor(DigitalPort* port) {
|
||||
return GetMaxPositivePwm(port) - GetMinPositivePwm(port);
|
||||
} ///< The scale for positive speeds.
|
||||
|
||||
static inline int32_t GetNegativeScaleFactor(DigitalPort* port) {
|
||||
return GetMaxNegativePwm(port) - GetMinNegativePwm(port);
|
||||
} ///< The scale for negative speeds.
|
||||
|
||||
static inline int32_t GetFullRangeScaleFactor(DigitalPort* port) {
|
||||
return GetMaxPositivePwm(port) - GetMinNegativePwm(port);
|
||||
} ///< The scale for positions.
|
||||
|
||||
extern "C" {
|
||||
|
||||
HAL_DigitalHandle HAL_InitializePWMPort(int32_t channel,
|
||||
@@ -103,8 +63,8 @@ HAL_DigitalHandle HAL_InitializePWMPort(int32_t channel,
|
||||
|
||||
SimPWMData[origChannel].initialized = true;
|
||||
|
||||
// Defaults to allow an always valid config.
|
||||
HAL_SetPWMConfigMicroseconds(handle, 2000, 1501, 1500, 1499, 1000, status);
|
||||
// Disable output.
|
||||
HAL_SetPWMPulseTimeMicroseconds(handle, 0, status);
|
||||
|
||||
port->previousAllocation = allocationLocation ? allocationLocation : "";
|
||||
|
||||
@@ -125,58 +85,12 @@ HAL_Bool HAL_CheckPWMChannel(int32_t channel) {
|
||||
return channel < kNumPWMChannels && channel >= 0;
|
||||
}
|
||||
|
||||
void HAL_SetPWMConfigMicroseconds(HAL_DigitalHandle pwmPortHandle, int32_t max,
|
||||
int32_t deadbandMax, int32_t center,
|
||||
int32_t deadbandMin, int32_t min,
|
||||
int32_t* status) {
|
||||
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
||||
void HAL_SetPWMSimDevice(HAL_DigitalHandle handle, HAL_SimDeviceHandle device) {
|
||||
auto port = digitalChannelHandles->Get(handle, HAL_HandleEnum::PWM);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
port->maxPwm = max;
|
||||
port->deadbandMaxPwm = deadbandMax;
|
||||
port->deadbandMinPwm = deadbandMin;
|
||||
port->centerPwm = center;
|
||||
port->minPwm = min;
|
||||
port->configSet = true;
|
||||
}
|
||||
|
||||
void HAL_GetPWMConfigMicroseconds(HAL_DigitalHandle pwmPortHandle,
|
||||
int32_t* maxPwm, int32_t* deadbandMaxPwm,
|
||||
int32_t* centerPwm, int32_t* deadbandMinPwm,
|
||||
int32_t* minPwm, int32_t* status) {
|
||||
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
*maxPwm = port->maxPwm;
|
||||
*deadbandMaxPwm = port->deadbandMaxPwm;
|
||||
*deadbandMinPwm = port->deadbandMinPwm;
|
||||
*centerPwm = port->centerPwm;
|
||||
*minPwm = port->minPwm;
|
||||
}
|
||||
|
||||
void HAL_SetPWMEliminateDeadband(HAL_DigitalHandle pwmPortHandle,
|
||||
HAL_Bool eliminateDeadband, int32_t* status) {
|
||||
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
port->eliminateDeadband = eliminateDeadband;
|
||||
}
|
||||
|
||||
HAL_Bool HAL_GetPWMEliminateDeadband(HAL_DigitalHandle pwmPortHandle,
|
||||
int32_t* status) {
|
||||
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return false;
|
||||
}
|
||||
return port->eliminateDeadband;
|
||||
SimPWMData[port->channel].simDevice = device;
|
||||
}
|
||||
|
||||
void HAL_SetPWMPulseTimeMicroseconds(HAL_DigitalHandle pwmPortHandle,
|
||||
@@ -188,129 +102,6 @@ void HAL_SetPWMPulseTimeMicroseconds(HAL_DigitalHandle pwmPortHandle,
|
||||
}
|
||||
|
||||
SimPWMData[port->channel].pulseMicrosecond = value;
|
||||
|
||||
DigitalPort* dPort = port.get();
|
||||
double speed = 0.0;
|
||||
|
||||
if (value == kPwmDisabled) {
|
||||
speed = 0.0;
|
||||
} else if (value > GetMaxPositivePwm(dPort)) {
|
||||
speed = 1.0;
|
||||
} else if (value < GetMinNegativePwm(dPort)) {
|
||||
speed = -1.0;
|
||||
} else if (value > GetMinPositivePwm(dPort)) {
|
||||
speed = static_cast<double>(value - GetMinPositivePwm(dPort)) /
|
||||
static_cast<double>(GetPositiveScaleFactor(dPort));
|
||||
} else if (value < GetMaxNegativePwm(dPort)) {
|
||||
speed = static_cast<double>(value - GetMaxNegativePwm(dPort)) /
|
||||
static_cast<double>(GetNegativeScaleFactor(dPort));
|
||||
} else {
|
||||
speed = 0.0;
|
||||
}
|
||||
|
||||
SimPWMData[port->channel].speed = speed;
|
||||
|
||||
double pos = 0.0;
|
||||
|
||||
if (value < GetMinNegativePwm(dPort)) {
|
||||
pos = 0.0;
|
||||
} else if (value > GetMaxPositivePwm(dPort)) {
|
||||
pos = 1.0;
|
||||
} else {
|
||||
pos = static_cast<double>(value - GetMinNegativePwm(dPort)) /
|
||||
static_cast<double>(GetFullRangeScaleFactor(dPort));
|
||||
}
|
||||
|
||||
SimPWMData[port->channel].position = pos;
|
||||
}
|
||||
|
||||
void HAL_SetPWMSpeed(HAL_DigitalHandle pwmPortHandle, double speed,
|
||||
int32_t* status) {
|
||||
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
if (!port->configSet) {
|
||||
*status = INCOMPATIBLE_STATE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (std::isfinite(speed)) {
|
||||
speed = std::clamp(speed, -1.0, 1.0);
|
||||
} else {
|
||||
speed = 0.0;
|
||||
}
|
||||
|
||||
DigitalPort* dPort = port.get();
|
||||
|
||||
// calculate the desired output pwm value by scaling the speed appropriately
|
||||
int32_t rawValue;
|
||||
if (speed == 0.0) {
|
||||
rawValue = GetCenterPwm(dPort);
|
||||
} else if (speed > 0.0) {
|
||||
rawValue =
|
||||
std::lround(speed * static_cast<double>(GetPositiveScaleFactor(dPort)) +
|
||||
static_cast<double>(GetMinPositivePwm(dPort)));
|
||||
} else {
|
||||
rawValue =
|
||||
std::lround(speed * static_cast<double>(GetNegativeScaleFactor(dPort)) +
|
||||
static_cast<double>(GetMaxNegativePwm(dPort)));
|
||||
}
|
||||
|
||||
if (!((rawValue >= GetMinNegativePwm(dPort)) &&
|
||||
(rawValue <= GetMaxPositivePwm(dPort))) ||
|
||||
rawValue == kPwmDisabled) {
|
||||
*status = HAL_PWM_SCALE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
HAL_SetPWMPulseTimeMicroseconds(pwmPortHandle, rawValue, status);
|
||||
}
|
||||
|
||||
void HAL_SetPWMPosition(HAL_DigitalHandle pwmPortHandle, double pos,
|
||||
int32_t* status) {
|
||||
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
if (!port->configSet) {
|
||||
*status = INCOMPATIBLE_STATE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (pos < 0.0) {
|
||||
pos = 0.0;
|
||||
} else if (pos > 1.0) {
|
||||
pos = 1.0;
|
||||
}
|
||||
|
||||
DigitalPort* dPort = port.get();
|
||||
|
||||
// note, need to perform the multiplication below as floating point before
|
||||
// converting to int
|
||||
int32_t rawValue = static_cast<int32_t>(
|
||||
(pos * static_cast<double>(GetFullRangeScaleFactor(dPort))) +
|
||||
GetMinNegativePwm(dPort));
|
||||
|
||||
if (rawValue == kPwmDisabled) {
|
||||
*status = HAL_PWM_SCALE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
HAL_SetPWMPulseTimeMicroseconds(pwmPortHandle, rawValue, status);
|
||||
}
|
||||
|
||||
void HAL_SetPWMDisabled(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
|
||||
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
SimPWMData[port->channel].pulseMicrosecond = 0;
|
||||
SimPWMData[port->channel].position = 0;
|
||||
SimPWMData[port->channel].speed = 0;
|
||||
}
|
||||
|
||||
int32_t HAL_GetPWMPulseTimeMicroseconds(HAL_DigitalHandle pwmPortHandle,
|
||||
@@ -324,88 +115,15 @@ int32_t HAL_GetPWMPulseTimeMicroseconds(HAL_DigitalHandle pwmPortHandle,
|
||||
return SimPWMData[port->channel].pulseMicrosecond;
|
||||
}
|
||||
|
||||
double HAL_GetPWMSpeed(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
|
||||
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
if (!port->configSet) {
|
||||
*status = INCOMPATIBLE_STATE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
double speed = SimPWMData[port->channel].speed;
|
||||
if (speed > 1) {
|
||||
speed = 1;
|
||||
}
|
||||
if (speed < -1) {
|
||||
speed = -1;
|
||||
}
|
||||
return speed;
|
||||
}
|
||||
|
||||
double HAL_GetPWMPosition(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
|
||||
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
if (!port->configSet) {
|
||||
*status = INCOMPATIBLE_STATE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
double position = SimPWMData[port->channel].position;
|
||||
if (position > 1) {
|
||||
position = 1;
|
||||
}
|
||||
if (position < 0) {
|
||||
position = 0;
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
||||
void HAL_LatchPWMZero(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
|
||||
void HAL_SetPWMOutputPeriod(HAL_DigitalHandle pwmPortHandle, int32_t period,
|
||||
int32_t* status) {
|
||||
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
SimPWMData[port->channel].zeroLatch = true;
|
||||
SimPWMData[port->channel].zeroLatch = false;
|
||||
SimPWMData[port->channel].outputPeriod = period;
|
||||
}
|
||||
|
||||
void HAL_SetPWMAlwaysHighMode(HAL_DigitalHandle pwmPortHandle,
|
||||
int32_t* status) {
|
||||
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
SimPWMData[port->channel].pulseMicrosecond = 0xFFFF;
|
||||
SimPWMData[port->channel].position = 0xFFFF;
|
||||
SimPWMData[port->channel].speed = 0xFFFF;
|
||||
}
|
||||
|
||||
void HAL_SetPWMPeriodScale(HAL_DigitalHandle pwmPortHandle, int32_t squelchMask,
|
||||
int32_t* status) {
|
||||
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
SimPWMData[port->channel].periodScale = squelchMask;
|
||||
}
|
||||
|
||||
int32_t HAL_GetPWMLoopTiming(int32_t* status) {
|
||||
return kExpectedLoopTiming;
|
||||
}
|
||||
|
||||
uint64_t HAL_GetPWMCycleStartTime(int32_t* status) {
|
||||
return 0;
|
||||
}
|
||||
} // extern "C"
|
||||
|
||||
@@ -17,11 +17,9 @@ void InitializePWMData() {
|
||||
PWMData* hal::SimPWMData;
|
||||
void PWMData::ResetData() {
|
||||
initialized.Reset(false);
|
||||
simDevice = 0;
|
||||
pulseMicrosecond.Reset(0);
|
||||
speed.Reset(0);
|
||||
position.Reset(0);
|
||||
periodScale.Reset(0);
|
||||
zeroLatch.Reset(false);
|
||||
outputPeriod.Reset(0);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
@@ -29,16 +27,17 @@ void HALSIM_ResetPWMData(int32_t index) {
|
||||
SimPWMData[index].ResetData();
|
||||
}
|
||||
|
||||
HAL_SimDeviceHandle HALSIM_GetPWMSimDevice(int32_t index) {
|
||||
return SimPWMData[index].simDevice;
|
||||
}
|
||||
|
||||
#define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME) \
|
||||
HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, HALSIM, PWM##CAPINAME, SimPWMData, \
|
||||
LOWERNAME)
|
||||
|
||||
DEFINE_CAPI(HAL_Bool, Initialized, initialized)
|
||||
DEFINE_CAPI(int32_t, PulseMicrosecond, pulseMicrosecond)
|
||||
DEFINE_CAPI(double, Speed, speed)
|
||||
DEFINE_CAPI(double, Position, position)
|
||||
DEFINE_CAPI(int32_t, PeriodScale, periodScale)
|
||||
DEFINE_CAPI(HAL_Bool, ZeroLatch, zeroLatch)
|
||||
DEFINE_CAPI(int32_t, OutputPeriod, outputPeriod)
|
||||
|
||||
#define REGISTER(NAME) \
|
||||
SimPWMData[index].NAME.RegisterCallback(callback, param, initialNotify)
|
||||
@@ -47,9 +46,6 @@ void HALSIM_RegisterPWMAllCallbacks(int32_t index, HAL_NotifyCallback callback,
|
||||
void* param, HAL_Bool initialNotify) {
|
||||
REGISTER(initialized);
|
||||
REGISTER(pulseMicrosecond);
|
||||
REGISTER(speed);
|
||||
REGISTER(position);
|
||||
REGISTER(periodScale);
|
||||
REGISTER(zeroLatch);
|
||||
REGISTER(outputPeriod);
|
||||
}
|
||||
} // extern "C"
|
||||
|
||||
@@ -11,20 +11,15 @@ namespace hal {
|
||||
class PWMData {
|
||||
HAL_SIMDATAVALUE_DEFINE_NAME(Initialized)
|
||||
HAL_SIMDATAVALUE_DEFINE_NAME(PulseMicrosecond)
|
||||
HAL_SIMDATAVALUE_DEFINE_NAME(Speed)
|
||||
HAL_SIMDATAVALUE_DEFINE_NAME(Position)
|
||||
HAL_SIMDATAVALUE_DEFINE_NAME(PeriodScale)
|
||||
HAL_SIMDATAVALUE_DEFINE_NAME(ZeroLatch)
|
||||
HAL_SIMDATAVALUE_DEFINE_NAME(OutputPeriod)
|
||||
|
||||
public:
|
||||
SimDataValue<HAL_Bool, HAL_MakeBoolean, GetInitializedName> initialized{
|
||||
false};
|
||||
std::atomic<HAL_SimDeviceHandle> simDevice;
|
||||
SimDataValue<int32_t, HAL_MakeInt, GetPulseMicrosecondName> pulseMicrosecond{
|
||||
0};
|
||||
SimDataValue<double, HAL_MakeDouble, GetSpeedName> speed{0};
|
||||
SimDataValue<double, HAL_MakeDouble, GetPositionName> position{0};
|
||||
SimDataValue<int32_t, HAL_MakeInt, GetPeriodScaleName> periodScale{0};
|
||||
SimDataValue<HAL_Bool, HAL_MakeBoolean, GetZeroLatchName> zeroLatch{false};
|
||||
SimDataValue<int32_t, HAL_MakeInt, GetOutputPeriodName> outputPeriod{0};
|
||||
|
||||
virtual void ResetData();
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user