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.
|
2016-05-26 12:56:39 -07:00
|
|
|
|
2018-07-20 00:03:45 -07:00
|
|
|
#include "hal/PWM.h"
|
2016-05-26 12:56:39 -07:00
|
|
|
|
2016-07-08 21:29:29 -07:00
|
|
|
#include "ConstantsInternal.h"
|
2016-05-26 12:56:39 -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"
|
2016-07-02 23:19:14 -07:00
|
|
|
#include "PortsInternal.h"
|
2018-07-20 00:03:45 -07:00
|
|
|
#include "hal/handles/HandlesInternal.h"
|
|
|
|
|
#include "mockdata/PWMDataInternal.h"
|
2016-05-26 12:56:39 -07:00
|
|
|
|
|
|
|
|
using namespace hal;
|
|
|
|
|
|
2020-12-28 01:19:59 -08:00
|
|
|
namespace hal::init {
|
2017-12-10 19:38:53 -08:00
|
|
|
void InitializePWM() {}
|
2020-12-28 01:19:59 -08:00
|
|
|
} // namespace hal::init
|
2017-12-10 19:38:53 -08:00
|
|
|
|
2016-05-26 12:56:39 -07:00
|
|
|
extern "C" {
|
|
|
|
|
|
2016-08-12 13:45:28 -07:00
|
|
|
HAL_DigitalHandle HAL_InitializePWMPort(HAL_PortHandle portHandle,
|
2021-05-01 10:28:30 -07:00
|
|
|
const char* allocationLocation,
|
2016-07-09 00:24:26 -07:00
|
|
|
int32_t* status) {
|
2018-05-13 22:02:47 -07:00
|
|
|
hal::init::CheckInit();
|
2016-06-30 21:39:09 -07:00
|
|
|
|
2016-08-12 13:45:28 -07:00
|
|
|
int16_t channel = getPortHandleChannel(portHandle);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (channel == InvalidHandleIndex) {
|
2021-05-01 10:28:30 -07:00
|
|
|
*status = RESOURCE_OUT_OF_RANGE;
|
|
|
|
|
hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for PWM", 0,
|
|
|
|
|
kNumPWMChannels, channel);
|
2016-07-09 00:24:26 -07:00
|
|
|
return HAL_kInvalidHandle;
|
2016-06-30 21:39:09 -07:00
|
|
|
}
|
|
|
|
|
|
2016-08-12 13:45:28 -07:00
|
|
|
uint8_t origChannel = static_cast<uint8_t>(channel);
|
2016-06-30 21:39:09 -07:00
|
|
|
|
2016-08-12 13:45:28 -07:00
|
|
|
if (origChannel < kNumPWMHeaders) {
|
|
|
|
|
channel += kNumDigitalChannels; // remap Headers to end of allocations
|
2016-05-26 12:56:39 -07:00
|
|
|
} else {
|
2016-08-12 13:45:28 -07:00
|
|
|
channel = remapMXPPWMChannel(channel) + 10; // remap MXP to proper channel
|
2016-06-30 21:39:09 -07:00
|
|
|
}
|
|
|
|
|
|
2021-05-01 10:28:30 -07:00
|
|
|
HAL_DigitalHandle handle;
|
|
|
|
|
|
|
|
|
|
auto port = digitalChannelHandles->Allocate(channel, HAL_HandleEnum::PWM,
|
|
|
|
|
&handle, status);
|
2016-06-30 21:39:09 -07:00
|
|
|
|
2020-12-28 12:58:06 -08:00
|
|
|
if (*status != 0) {
|
2021-05-01 10:28:30 -07:00
|
|
|
if (port) {
|
|
|
|
|
hal::SetLastErrorPreviouslyAllocated(status, "PWM or DIO", channel,
|
|
|
|
|
port->previousAllocation);
|
|
|
|
|
} else {
|
|
|
|
|
hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for PWM", 0,
|
|
|
|
|
kNumPWMChannels, channel);
|
|
|
|
|
}
|
2016-07-09 00:24:26 -07:00
|
|
|
return HAL_kInvalidHandle; // failed to allocate. Pass error back.
|
2020-12-28 12:58:06 -08:00
|
|
|
}
|
2016-06-30 21:39:09 -07:00
|
|
|
|
2016-08-12 13:45:28 -07:00
|
|
|
port->channel = origChannel;
|
2016-06-30 21:39:09 -07:00
|
|
|
|
2018-09-03 16:08:07 -07:00
|
|
|
SimPWMData[origChannel].initialized = true;
|
2016-06-30 21:39:09 -07:00
|
|
|
|
2018-03-03 01:56:49 -08:00
|
|
|
// Defaults to allow an always valid config.
|
2023-06-22 19:43:16 -07:00
|
|
|
HAL_SetPWMConfigMicroseconds(handle, 2000, 1501, 1500, 1499, 1000, status);
|
2018-03-03 01:56:49 -08:00
|
|
|
|
2021-05-01 10:28:30 -07:00
|
|
|
port->previousAllocation = allocationLocation ? allocationLocation : "";
|
|
|
|
|
|
2016-06-30 21:39:09 -07:00
|
|
|
return handle;
|
|
|
|
|
}
|
2016-08-12 13:45:28 -07:00
|
|
|
void HAL_FreePWMPort(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
2016-06-30 21:39:09 -07:00
|
|
|
if (port == nullptr) {
|
2016-07-03 17:27:06 -07:00
|
|
|
*status = HAL_HANDLE_ERROR;
|
2016-06-30 21:39:09 -07:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-03 16:08:07 -07:00
|
|
|
SimPWMData[port->channel].initialized = false;
|
2016-06-30 21:39:09 -07:00
|
|
|
|
2017-12-10 19:38:53 -08:00
|
|
|
digitalChannelHandles->Free(pwmPortHandle, HAL_HandleEnum::PWM);
|
2016-05-26 12:56:39 -07:00
|
|
|
}
|
|
|
|
|
|
2016-08-12 13:45:28 -07:00
|
|
|
HAL_Bool HAL_CheckPWMChannel(int32_t channel) {
|
|
|
|
|
return channel < kNumPWMChannels && channel >= 0;
|
2016-07-12 10:45:14 -07:00
|
|
|
}
|
2016-06-30 21:39:09 -07:00
|
|
|
|
2023-06-22 19:43:16 -07:00
|
|
|
void HAL_SetPWMConfigMicroseconds(HAL_DigitalHandle pwmPortHandle, int32_t max,
|
|
|
|
|
int32_t deadbandMax, int32_t center,
|
|
|
|
|
int32_t deadbandMin, int32_t min,
|
|
|
|
|
int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
2016-07-08 21:29:29 -07:00
|
|
|
if (port == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-22 19:43:16 -07:00
|
|
|
port->maxPwm = max;
|
|
|
|
|
port->deadbandMaxPwm = deadbandMax;
|
|
|
|
|
port->deadbandMinPwm = deadbandMin;
|
|
|
|
|
port->centerPwm = center;
|
|
|
|
|
port->minPwm = min;
|
2016-07-08 21:29:29 -07:00
|
|
|
port->configSet = true;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-22 19:43:16 -07:00
|
|
|
void HAL_GetPWMConfigMicroseconds(HAL_DigitalHandle pwmPortHandle,
|
|
|
|
|
int32_t* maxPwm, int32_t* deadbandMaxPwm,
|
|
|
|
|
int32_t* centerPwm, int32_t* deadbandMinPwm,
|
|
|
|
|
int32_t* minPwm, int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
2016-07-08 21:29:29 -07:00
|
|
|
if (port == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
*maxPwm = port->maxPwm;
|
|
|
|
|
*deadbandMaxPwm = port->deadbandMaxPwm;
|
|
|
|
|
*deadbandMinPwm = port->deadbandMinPwm;
|
|
|
|
|
*centerPwm = port->centerPwm;
|
|
|
|
|
*minPwm = port->minPwm;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-12 13:45:28 -07:00
|
|
|
void HAL_SetPWMEliminateDeadband(HAL_DigitalHandle pwmPortHandle,
|
2016-07-12 10:45:14 -07:00
|
|
|
HAL_Bool eliminateDeadband, int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
2016-07-08 21:29:29 -07:00
|
|
|
if (port == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
port->eliminateDeadband = eliminateDeadband;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-12 13:45:28 -07:00
|
|
|
HAL_Bool HAL_GetPWMEliminateDeadband(HAL_DigitalHandle pwmPortHandle,
|
2016-07-12 10:45:14 -07:00
|
|
|
int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
2016-07-08 21:29:29 -07:00
|
|
|
if (port == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return port->eliminateDeadband;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-22 19:43:16 -07:00
|
|
|
void HAL_SetPWMPulseTimeMicroseconds(HAL_DigitalHandle pwmPortHandle,
|
|
|
|
|
int32_t value, int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
2016-06-30 21:39:09 -07:00
|
|
|
if (port == nullptr) {
|
2016-07-03 17:27:06 -07:00
|
|
|
*status = HAL_HANDLE_ERROR;
|
2016-05-26 12:56:39 -07:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-22 19:43:16 -07:00
|
|
|
SimPWMData[port->channel].pulseMicrosecond = value;
|
2016-05-26 12:56:39 -07:00
|
|
|
}
|
|
|
|
|
|
2016-08-12 13:45:28 -07:00
|
|
|
void HAL_SetPWMSpeed(HAL_DigitalHandle pwmPortHandle, double speed,
|
2016-07-09 00:24:26 -07:00
|
|
|
int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
2016-07-08 21:29:29 -07:00
|
|
|
if (port == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!port->configSet) {
|
|
|
|
|
*status = INCOMPATIBLE_STATE;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (speed < -1.0) {
|
|
|
|
|
speed = -1.0;
|
|
|
|
|
} else if (speed > 1.0) {
|
|
|
|
|
speed = 1.0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-03 16:08:07 -07:00
|
|
|
SimPWMData[port->channel].speed = speed;
|
2016-07-08 21:29:29 -07:00
|
|
|
}
|
|
|
|
|
|
2016-08-12 13:45:28 -07:00
|
|
|
void HAL_SetPWMPosition(HAL_DigitalHandle pwmPortHandle, double pos,
|
2016-07-09 00:24:26 -07:00
|
|
|
int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
2016-07-08 21:29:29 -07:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-03 16:08:07 -07:00
|
|
|
SimPWMData[port->channel].position = pos;
|
2016-07-08 21:29:29 -07:00
|
|
|
}
|
|
|
|
|
|
2016-08-12 13:45:28 -07:00
|
|
|
void HAL_SetPWMDisabled(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (port == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-06-22 19:43:16 -07:00
|
|
|
SimPWMData[port->channel].pulseMicrosecond = 0;
|
2018-09-03 16:08:07 -07:00
|
|
|
SimPWMData[port->channel].position = 0;
|
|
|
|
|
SimPWMData[port->channel].speed = 0;
|
2016-07-08 21:29:29 -07:00
|
|
|
}
|
|
|
|
|
|
2023-06-22 19:43:16 -07:00
|
|
|
int32_t HAL_GetPWMPulseTimeMicroseconds(HAL_DigitalHandle pwmPortHandle,
|
|
|
|
|
int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
2016-06-30 21:39:09 -07:00
|
|
|
if (port == nullptr) {
|
2016-07-03 17:27:06 -07:00
|
|
|
*status = HAL_HANDLE_ERROR;
|
2016-05-26 12:56:39 -07:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-22 19:43:16 -07:00
|
|
|
return SimPWMData[port->channel].pulseMicrosecond;
|
2016-05-26 12:56:39 -07:00
|
|
|
}
|
|
|
|
|
|
2016-08-12 13:45:28 -07:00
|
|
|
double HAL_GetPWMSpeed(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
2016-07-08 21:29:29 -07:00
|
|
|
if (port == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (!port->configSet) {
|
|
|
|
|
*status = INCOMPATIBLE_STATE;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-03 16:08:07 -07:00
|
|
|
double speed = SimPWMData[port->channel].speed;
|
2020-12-28 12:58:06 -08:00
|
|
|
if (speed > 1) {
|
|
|
|
|
speed = 1;
|
|
|
|
|
}
|
|
|
|
|
if (speed < -1) {
|
|
|
|
|
speed = -1;
|
|
|
|
|
}
|
2017-08-18 21:35:53 -07:00
|
|
|
return speed;
|
2016-07-08 21:29:29 -07:00
|
|
|
}
|
|
|
|
|
|
2016-08-12 13:45:28 -07:00
|
|
|
double HAL_GetPWMPosition(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
2016-07-08 21:29:29 -07:00
|
|
|
if (port == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (!port->configSet) {
|
|
|
|
|
*status = INCOMPATIBLE_STATE;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-03 16:08:07 -07:00
|
|
|
double position = SimPWMData[port->channel].position;
|
2020-12-28 12:58:06 -08:00
|
|
|
if (position > 1) {
|
|
|
|
|
position = 1;
|
|
|
|
|
}
|
|
|
|
|
if (position < 0) {
|
|
|
|
|
position = 0;
|
|
|
|
|
}
|
2017-08-18 21:35:53 -07:00
|
|
|
return position;
|
2016-07-08 21:29:29 -07:00
|
|
|
}
|
|
|
|
|
|
2016-08-12 13:45:28 -07:00
|
|
|
void HAL_LatchPWMZero(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
2016-06-30 21:39:09 -07:00
|
|
|
if (port == nullptr) {
|
2016-07-03 17:27:06 -07:00
|
|
|
*status = HAL_HANDLE_ERROR;
|
2016-05-26 12:56:39 -07:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-03 16:08:07 -07:00
|
|
|
SimPWMData[port->channel].zeroLatch = true;
|
|
|
|
|
SimPWMData[port->channel].zeroLatch = false;
|
2016-05-26 12:56:39 -07:00
|
|
|
}
|
|
|
|
|
|
2023-06-22 19:43:16 -07:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-12 13:45:28 -07:00
|
|
|
void HAL_SetPWMPeriodScale(HAL_DigitalHandle pwmPortHandle, int32_t squelchMask,
|
|
|
|
|
int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
|
2016-06-30 21:39:09 -07:00
|
|
|
if (port == nullptr) {
|
2016-07-03 17:27:06 -07:00
|
|
|
*status = HAL_HANDLE_ERROR;
|
2016-05-26 12:56:39 -07:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-03 16:08:07 -07:00
|
|
|
SimPWMData[port->channel].periodScale = squelchMask;
|
2016-05-26 12:56:39 -07:00
|
|
|
}
|
|
|
|
|
|
2020-12-28 12:58:06 -08:00
|
|
|
int32_t HAL_GetPWMLoopTiming(int32_t* status) {
|
|
|
|
|
return kExpectedLoopTiming;
|
|
|
|
|
}
|
2017-10-27 18:03:10 -07:00
|
|
|
|
2020-12-28 12:58:06 -08:00
|
|
|
uint64_t HAL_GetPWMCycleStartTime(int32_t* status) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2017-11-16 01:05:20 -08:00
|
|
|
} // extern "C"
|