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
|
|
|
|
2018-07-20 00:03:45 -07:00
|
|
|
#include "hal/Encoder.h"
|
2017-08-18 21:35:53 -07:00
|
|
|
|
|
|
|
|
#include "CounterInternal.h"
|
2018-05-13 22:02:47 -07:00
|
|
|
#include "HALInitializer.h"
|
2017-08-18 21:35:53 -07:00
|
|
|
#include "PortsInternal.h"
|
2018-07-20 00:03:45 -07:00
|
|
|
#include "hal/Errors.h"
|
|
|
|
|
#include "hal/handles/HandlesInternal.h"
|
|
|
|
|
#include "hal/handles/LimitedHandleResource.h"
|
|
|
|
|
#include "mockdata/EncoderDataInternal.h"
|
2017-08-18 21:35:53 -07:00
|
|
|
|
|
|
|
|
using namespace hal;
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
struct Encoder {
|
|
|
|
|
HAL_Handle nativeHandle;
|
|
|
|
|
HAL_EncoderEncodingType encodingType;
|
|
|
|
|
double distancePerPulse;
|
|
|
|
|
uint8_t index;
|
|
|
|
|
};
|
|
|
|
|
struct Empty {};
|
2017-10-16 19:56:08 -07:00
|
|
|
} // namespace
|
2017-08-18 21:35:53 -07:00
|
|
|
|
|
|
|
|
static LimitedHandleResource<HAL_EncoderHandle, Encoder,
|
|
|
|
|
kNumEncoders + kNumCounters,
|
2017-12-10 19:38:53 -08:00
|
|
|
HAL_HandleEnum::Encoder>* encoderHandles;
|
2017-08-18 21:35:53 -07:00
|
|
|
|
|
|
|
|
static LimitedHandleResource<HAL_FPGAEncoderHandle, Empty, kNumEncoders,
|
2017-12-10 19:38:53 -08:00
|
|
|
HAL_HandleEnum::FPGAEncoder>* fpgaEncoderHandles;
|
|
|
|
|
|
|
|
|
|
namespace hal {
|
|
|
|
|
namespace init {
|
|
|
|
|
void InitializeEncoder() {
|
|
|
|
|
static LimitedHandleResource<HAL_FPGAEncoderHandle, Empty, kNumEncoders,
|
|
|
|
|
HAL_HandleEnum::FPGAEncoder>
|
|
|
|
|
feH;
|
|
|
|
|
fpgaEncoderHandles = &feH;
|
|
|
|
|
static LimitedHandleResource<HAL_EncoderHandle, Encoder,
|
|
|
|
|
kNumEncoders + kNumCounters,
|
|
|
|
|
HAL_HandleEnum::Encoder>
|
|
|
|
|
eH;
|
|
|
|
|
encoderHandles = &eH;
|
|
|
|
|
}
|
|
|
|
|
} // namespace init
|
|
|
|
|
} // namespace hal
|
2017-08-18 21:35:53 -07:00
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
|
HAL_EncoderHandle HAL_InitializeEncoder(
|
|
|
|
|
HAL_Handle digitalSourceHandleA, HAL_AnalogTriggerType analogTriggerTypeA,
|
|
|
|
|
HAL_Handle digitalSourceHandleB, HAL_AnalogTriggerType analogTriggerTypeB,
|
|
|
|
|
HAL_Bool reverseDirection, HAL_EncoderEncodingType encodingType,
|
|
|
|
|
int32_t* status) {
|
2018-05-13 22:02:47 -07:00
|
|
|
hal::init::CheckInit();
|
2017-08-18 21:35:53 -07:00
|
|
|
HAL_Handle nativeHandle = HAL_kInvalidHandle;
|
|
|
|
|
if (encodingType == HAL_EncoderEncodingType::HAL_Encoder_k4X) {
|
|
|
|
|
// k4x, allocate encoder
|
2017-12-10 19:38:53 -08:00
|
|
|
nativeHandle = fpgaEncoderHandles->Allocate();
|
2017-08-18 21:35:53 -07:00
|
|
|
} else {
|
|
|
|
|
// k2x or k1x, allocate counter
|
2017-12-10 19:38:53 -08:00
|
|
|
nativeHandle = counterHandles->Allocate();
|
2017-08-18 21:35:53 -07:00
|
|
|
}
|
|
|
|
|
if (nativeHandle == HAL_kInvalidHandle) {
|
|
|
|
|
*status = NO_AVAILABLE_RESOURCES;
|
|
|
|
|
return HAL_kInvalidHandle;
|
|
|
|
|
}
|
2017-12-10 19:38:53 -08:00
|
|
|
auto handle = encoderHandles->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 encoder = encoderHandles->Get(handle);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (encoder == nullptr) { // would only occur on thread issue
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return HAL_kInvalidHandle;
|
|
|
|
|
}
|
|
|
|
|
int16_t index = getHandleIndex(handle);
|
2018-09-03 16:08:07 -07:00
|
|
|
SimEncoderData[index].digitalChannelA = getHandleIndex(digitalSourceHandleA);
|
2019-10-04 17:29:34 -07:00
|
|
|
SimEncoderData[index].digitalChannelB = getHandleIndex(digitalSourceHandleB);
|
2018-09-03 16:08:07 -07:00
|
|
|
SimEncoderData[index].initialized = true;
|
|
|
|
|
SimEncoderData[index].reverseDirection = reverseDirection;
|
2019-10-04 22:56:24 -07:00
|
|
|
SimEncoderData[index].simDevice = 0;
|
2017-08-18 21:35:53 -07:00
|
|
|
// TODO: Add encoding type to Sim data
|
|
|
|
|
encoder->index = index;
|
|
|
|
|
encoder->nativeHandle = nativeHandle;
|
|
|
|
|
encoder->encodingType = encodingType;
|
|
|
|
|
encoder->distancePerPulse = 1.0;
|
|
|
|
|
return handle;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void HAL_FreeEncoder(HAL_EncoderHandle encoderHandle, int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto encoder = encoderHandles->Get(encoderHandle);
|
|
|
|
|
encoderHandles->Free(encoderHandle);
|
2020-12-28 12:58:06 -08:00
|
|
|
if (encoder == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-08-18 21:35:53 -07:00
|
|
|
if (isHandleType(encoder->nativeHandle, HAL_HandleEnum::FPGAEncoder)) {
|
2017-12-10 19:38:53 -08:00
|
|
|
fpgaEncoderHandles->Free(encoder->nativeHandle);
|
2017-08-18 21:35:53 -07:00
|
|
|
} else if (isHandleType(encoder->nativeHandle, HAL_HandleEnum::Counter)) {
|
2017-12-10 19:38:53 -08:00
|
|
|
counterHandles->Free(encoder->nativeHandle);
|
2017-08-18 21:35:53 -07:00
|
|
|
}
|
2018-09-03 16:08:07 -07:00
|
|
|
SimEncoderData[encoder->index].initialized = false;
|
2017-08-18 21:35:53 -07:00
|
|
|
}
|
|
|
|
|
|
2019-10-04 22:56:24 -07:00
|
|
|
void HAL_SetEncoderSimDevice(HAL_EncoderHandle handle,
|
|
|
|
|
HAL_SimDeviceHandle device) {
|
|
|
|
|
auto encoder = encoderHandles->Get(handle);
|
2020-12-28 12:58:06 -08:00
|
|
|
if (encoder == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2019-10-04 22:56:24 -07:00
|
|
|
SimEncoderData[encoder->index].simDevice = device;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-18 21:35:53 -07:00
|
|
|
static inline int EncodingScaleFactor(Encoder* encoder) {
|
|
|
|
|
switch (encoder->encodingType) {
|
|
|
|
|
case HAL_Encoder_k1X:
|
|
|
|
|
return 1;
|
|
|
|
|
case HAL_Encoder_k2X:
|
|
|
|
|
return 2;
|
|
|
|
|
case HAL_Encoder_k4X:
|
|
|
|
|
return 4;
|
|
|
|
|
default:
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline double DecodingScaleFactor(Encoder* encoder) {
|
|
|
|
|
switch (encoder->encodingType) {
|
|
|
|
|
case HAL_Encoder_k1X:
|
|
|
|
|
return 1.0;
|
|
|
|
|
case HAL_Encoder_k2X:
|
|
|
|
|
return 0.5;
|
|
|
|
|
case HAL_Encoder_k4X:
|
|
|
|
|
return 0.25;
|
|
|
|
|
default:
|
|
|
|
|
return 0.0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int32_t HAL_GetEncoder(HAL_EncoderHandle encoderHandle, int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto encoder = encoderHandles->Get(encoderHandle);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (encoder == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-03 16:08:07 -07:00
|
|
|
return SimEncoderData[encoder->index].count;
|
2017-08-18 21:35:53 -07:00
|
|
|
}
|
|
|
|
|
int32_t HAL_GetEncoderRaw(HAL_EncoderHandle encoderHandle, int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto encoder = encoderHandles->Get(encoderHandle);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (encoder == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-03 16:08:07 -07:00
|
|
|
return SimEncoderData[encoder->index].count /
|
2017-08-18 21:35:53 -07:00
|
|
|
DecodingScaleFactor(encoder.get());
|
|
|
|
|
}
|
|
|
|
|
int32_t HAL_GetEncoderEncodingScale(HAL_EncoderHandle encoderHandle,
|
|
|
|
|
int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto encoder = encoderHandles->Get(encoderHandle);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (encoder == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return EncodingScaleFactor(encoder.get());
|
|
|
|
|
}
|
|
|
|
|
void HAL_ResetEncoder(HAL_EncoderHandle encoderHandle, int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto encoder = encoderHandles->Get(encoderHandle);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (encoder == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-10 20:30:12 -08:00
|
|
|
SimEncoderData[encoder->index].reset = true;
|
2018-09-03 16:08:07 -07:00
|
|
|
SimEncoderData[encoder->index].count = 0;
|
|
|
|
|
SimEncoderData[encoder->index].period = std::numeric_limits<double>::max();
|
2017-08-18 21:35:53 -07:00
|
|
|
}
|
|
|
|
|
double HAL_GetEncoderPeriod(HAL_EncoderHandle encoderHandle, int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto encoder = encoderHandles->Get(encoderHandle);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (encoder == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-03 16:08:07 -07:00
|
|
|
return SimEncoderData[encoder->index].period;
|
2017-08-18 21:35:53 -07:00
|
|
|
}
|
|
|
|
|
void HAL_SetEncoderMaxPeriod(HAL_EncoderHandle encoderHandle, double maxPeriod,
|
|
|
|
|
int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto encoder = encoderHandles->Get(encoderHandle);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (encoder == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-03 16:08:07 -07:00
|
|
|
SimEncoderData[encoder->index].maxPeriod = maxPeriod;
|
2017-08-18 21:35:53 -07:00
|
|
|
}
|
|
|
|
|
HAL_Bool HAL_GetEncoderStopped(HAL_EncoderHandle encoderHandle,
|
|
|
|
|
int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto encoder = encoderHandles->Get(encoderHandle);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (encoder == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-03 16:08:07 -07:00
|
|
|
return SimEncoderData[encoder->index].period >
|
|
|
|
|
SimEncoderData[encoder->index].maxPeriod;
|
2017-08-18 21:35:53 -07:00
|
|
|
}
|
|
|
|
|
HAL_Bool HAL_GetEncoderDirection(HAL_EncoderHandle encoderHandle,
|
|
|
|
|
int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto encoder = encoderHandles->Get(encoderHandle);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (encoder == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-03 16:08:07 -07:00
|
|
|
return SimEncoderData[encoder->index].direction;
|
2017-08-18 21:35:53 -07:00
|
|
|
}
|
|
|
|
|
double HAL_GetEncoderDistance(HAL_EncoderHandle encoderHandle,
|
|
|
|
|
int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto encoder = encoderHandles->Get(encoderHandle);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (encoder == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-03 16:08:07 -07:00
|
|
|
return SimEncoderData[encoder->index].count * encoder->distancePerPulse;
|
2017-08-18 21:35:53 -07:00
|
|
|
}
|
|
|
|
|
double HAL_GetEncoderRate(HAL_EncoderHandle encoderHandle, int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto encoder = encoderHandles->Get(encoderHandle);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (encoder == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-03 16:08:07 -07:00
|
|
|
return encoder->distancePerPulse / SimEncoderData[encoder->index].period;
|
2017-08-18 21:35:53 -07:00
|
|
|
}
|
|
|
|
|
void HAL_SetEncoderMinRate(HAL_EncoderHandle encoderHandle, double minRate,
|
|
|
|
|
int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto encoder = encoderHandles->Get(encoderHandle);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (encoder == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (minRate == 0.0) {
|
|
|
|
|
*status = PARAMETER_OUT_OF_RANGE;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-03 16:08:07 -07:00
|
|
|
SimEncoderData[encoder->index].maxPeriod =
|
|
|
|
|
encoder->distancePerPulse / minRate;
|
2017-08-18 21:35:53 -07:00
|
|
|
}
|
|
|
|
|
void HAL_SetEncoderDistancePerPulse(HAL_EncoderHandle encoderHandle,
|
|
|
|
|
double distancePerPulse, int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto encoder = encoderHandles->Get(encoderHandle);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (encoder == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (distancePerPulse == 0.0) {
|
|
|
|
|
*status = PARAMETER_OUT_OF_RANGE;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
encoder->distancePerPulse = distancePerPulse;
|
2018-09-03 16:08:07 -07:00
|
|
|
SimEncoderData[encoder->index].distancePerPulse = distancePerPulse;
|
2017-08-18 21:35:53 -07:00
|
|
|
}
|
|
|
|
|
void HAL_SetEncoderReverseDirection(HAL_EncoderHandle encoderHandle,
|
|
|
|
|
HAL_Bool reverseDirection,
|
|
|
|
|
int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto encoder = encoderHandles->Get(encoderHandle);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (encoder == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-03 16:08:07 -07:00
|
|
|
SimEncoderData[encoder->index].reverseDirection = reverseDirection;
|
2017-08-18 21:35:53 -07:00
|
|
|
}
|
|
|
|
|
void HAL_SetEncoderSamplesToAverage(HAL_EncoderHandle encoderHandle,
|
|
|
|
|
int32_t samplesToAverage, int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto encoder = encoderHandles->Get(encoderHandle);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (encoder == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-03 16:08:07 -07:00
|
|
|
SimEncoderData[encoder->index].samplesToAverage = samplesToAverage;
|
2017-08-18 21:35:53 -07:00
|
|
|
}
|
|
|
|
|
int32_t HAL_GetEncoderSamplesToAverage(HAL_EncoderHandle encoderHandle,
|
|
|
|
|
int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto encoder = encoderHandles->Get(encoderHandle);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (encoder == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-03 16:08:07 -07:00
|
|
|
return SimEncoderData[encoder->index].samplesToAverage;
|
2017-08-18 21:35:53 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void HAL_SetEncoderIndexSource(HAL_EncoderHandle encoderHandle,
|
|
|
|
|
HAL_Handle digitalSourceHandle,
|
|
|
|
|
HAL_AnalogTriggerType analogTriggerType,
|
|
|
|
|
HAL_EncoderIndexingType type, int32_t* status) {
|
|
|
|
|
// Not implemented yet
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int32_t HAL_GetEncoderFPGAIndex(HAL_EncoderHandle encoderHandle,
|
|
|
|
|
int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto encoder = encoderHandles->Get(encoderHandle);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (encoder == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return encoder->index;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double HAL_GetEncoderDecodingScaleFactor(HAL_EncoderHandle encoderHandle,
|
|
|
|
|
int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto encoder = encoderHandles->Get(encoderHandle);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (encoder == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return 0.0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return DecodingScaleFactor(encoder.get());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double HAL_GetEncoderDistancePerPulse(HAL_EncoderHandle encoderHandle,
|
|
|
|
|
int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto encoder = encoderHandles->Get(encoderHandle);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (encoder == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return 0.0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return encoder->distancePerPulse;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HAL_EncoderEncodingType HAL_GetEncoderEncodingType(
|
|
|
|
|
HAL_EncoderHandle encoderHandle, int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto encoder = encoderHandles->Get(encoderHandle);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (encoder == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return HAL_Encoder_k4X; // default to k4x
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return encoder->encodingType;
|
|
|
|
|
}
|
2017-11-16 01:05:20 -08:00
|
|
|
} // extern "C"
|