2016-07-03 15:22:22 -07:00
|
|
|
/*----------------------------------------------------------------------------*/
|
2018-01-02 09:20:21 -08:00
|
|
|
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
|
2016-07-03 15:22:22 -07:00
|
|
|
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
|
|
|
|
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
|
|
|
|
/* the project. */
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
#include "FPGAEncoder.h"
|
|
|
|
|
|
2016-07-20 22:05:17 -07:00
|
|
|
#include <memory>
|
|
|
|
|
|
2016-07-03 15:22:22 -07:00
|
|
|
#include "DigitalInternal.h"
|
2016-07-13 20:29:28 -07:00
|
|
|
#include "HAL/handles/LimitedHandleResource.h"
|
2018-05-13 22:02:47 -07:00
|
|
|
#include "HALInitializer.h"
|
2016-07-03 21:52:49 -07:00
|
|
|
#include "PortsInternal.h"
|
2016-07-03 15:22:22 -07:00
|
|
|
|
|
|
|
|
using namespace hal;
|
|
|
|
|
|
|
|
|
|
namespace {
|
2017-08-23 22:07:46 -07:00
|
|
|
|
2016-07-03 15:22:22 -07:00
|
|
|
struct Encoder {
|
2016-07-20 22:05:17 -07:00
|
|
|
std::unique_ptr<tEncoder> encoder;
|
2016-07-12 10:45:14 -07:00
|
|
|
uint8_t index;
|
2016-07-03 15:22:22 -07:00
|
|
|
};
|
2017-08-23 22:07:46 -07:00
|
|
|
|
|
|
|
|
} // namespace
|
2016-07-03 15:22:22 -07:00
|
|
|
|
2017-12-10 18:02:07 -08:00
|
|
|
static constexpr double DECODING_SCALING_FACTOR = 0.25;
|
2016-07-03 15:22:22 -07:00
|
|
|
|
2016-07-09 00:24:26 -07:00
|
|
|
static LimitedHandleResource<HAL_FPGAEncoderHandle, Encoder, kNumEncoders,
|
2017-12-10 18:02:07 -08:00
|
|
|
HAL_HandleEnum::FPGAEncoder>* fpgaEncoderHandles;
|
|
|
|
|
|
|
|
|
|
namespace hal {
|
|
|
|
|
namespace init {
|
|
|
|
|
void InitializeFPGAEncoder() {
|
|
|
|
|
static LimitedHandleResource<HAL_FPGAEncoderHandle, Encoder, kNumEncoders,
|
|
|
|
|
HAL_HandleEnum::FPGAEncoder>
|
|
|
|
|
feH;
|
|
|
|
|
fpgaEncoderHandles = &feH;
|
|
|
|
|
}
|
|
|
|
|
} // namespace init
|
|
|
|
|
} // namespace hal
|
2016-07-03 15:22:22 -07:00
|
|
|
|
|
|
|
|
extern "C" {
|
2017-08-23 22:07:46 -07:00
|
|
|
|
2016-07-09 00:24:26 -07:00
|
|
|
HAL_FPGAEncoderHandle HAL_InitializeFPGAEncoder(
|
|
|
|
|
HAL_Handle digitalSourceHandleA, HAL_AnalogTriggerType analogTriggerTypeA,
|
|
|
|
|
HAL_Handle digitalSourceHandleB, HAL_AnalogTriggerType analogTriggerTypeB,
|
2016-07-12 10:45:14 -07:00
|
|
|
HAL_Bool reverseDirection, int32_t* index, int32_t* status) {
|
2018-05-13 22:02:47 -07:00
|
|
|
hal::init::CheckInit();
|
2016-07-07 21:43:55 -07:00
|
|
|
bool routingAnalogTriggerA = false;
|
2016-08-12 13:45:28 -07:00
|
|
|
uint8_t routingChannelA = 0;
|
2016-07-07 21:43:55 -07:00
|
|
|
uint8_t routingModuleA = 0;
|
2016-08-12 13:45:28 -07:00
|
|
|
bool successA = remapDigitalSource(digitalSourceHandleA, analogTriggerTypeA,
|
|
|
|
|
routingChannelA, routingModuleA,
|
|
|
|
|
routingAnalogTriggerA);
|
2016-07-07 21:43:55 -07:00
|
|
|
bool routingAnalogTriggerB = false;
|
2016-08-12 13:45:28 -07:00
|
|
|
uint8_t routingChannelB = 0;
|
2016-07-07 21:43:55 -07:00
|
|
|
uint8_t routingModuleB = 0;
|
2016-08-12 13:45:28 -07:00
|
|
|
bool successB = remapDigitalSource(digitalSourceHandleB, analogTriggerTypeB,
|
|
|
|
|
routingChannelB, routingModuleB,
|
|
|
|
|
routingAnalogTriggerB);
|
2016-07-07 21:43:55 -07:00
|
|
|
|
|
|
|
|
if (!successA || !successB) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
2016-07-09 00:24:26 -07:00
|
|
|
return HAL_kInvalidHandle;
|
2016-07-07 21:43:55 -07:00
|
|
|
}
|
2016-07-03 15:22:22 -07:00
|
|
|
|
2017-12-10 18:02:07 -08:00
|
|
|
auto handle = fpgaEncoderHandles->Allocate();
|
2016-07-09 00:24:26 -07:00
|
|
|
if (handle == HAL_kInvalidHandle) { // out of resources
|
2016-07-03 15:22:22 -07:00
|
|
|
*status = NO_AVAILABLE_RESOURCES;
|
2016-07-09 00:24:26 -07:00
|
|
|
return HAL_kInvalidHandle;
|
2016-07-03 15:22:22 -07:00
|
|
|
}
|
|
|
|
|
|
2017-12-10 18:02:07 -08:00
|
|
|
auto encoder = fpgaEncoderHandles->Get(handle);
|
2016-07-03 15:22:22 -07:00
|
|
|
if (encoder == nullptr) { // will only error on thread issue
|
2016-07-07 21:43:55 -07:00
|
|
|
*status = HAL_HANDLE_ERROR;
|
2016-07-09 00:24:26 -07:00
|
|
|
return HAL_kInvalidHandle;
|
2016-07-03 15:22:22 -07:00
|
|
|
}
|
|
|
|
|
|
2016-07-12 10:45:14 -07:00
|
|
|
encoder->index = static_cast<uint8_t>(getHandleIndex(handle));
|
2016-07-03 15:22:22 -07:00
|
|
|
*index = encoder->index;
|
|
|
|
|
// TODO: if (index == ~0ul) { CloneError(quadEncoders); return; }
|
2016-07-20 22:05:17 -07:00
|
|
|
encoder->encoder.reset(tEncoder::create(encoder->index, status));
|
2016-07-07 21:43:55 -07:00
|
|
|
encoder->encoder->writeConfig_ASource_Module(routingModuleA, status);
|
2016-08-12 13:45:28 -07:00
|
|
|
encoder->encoder->writeConfig_ASource_Channel(routingChannelA, status);
|
2016-07-07 21:43:55 -07:00
|
|
|
encoder->encoder->writeConfig_ASource_AnalogTrigger(routingAnalogTriggerA,
|
2016-07-03 15:22:22 -07:00
|
|
|
status);
|
2016-07-07 21:43:55 -07:00
|
|
|
encoder->encoder->writeConfig_BSource_Module(routingModuleB, status);
|
2016-08-12 13:45:28 -07:00
|
|
|
encoder->encoder->writeConfig_BSource_Channel(routingChannelB, status);
|
2016-07-07 21:43:55 -07:00
|
|
|
encoder->encoder->writeConfig_BSource_AnalogTrigger(routingAnalogTriggerB,
|
2016-07-03 15:22:22 -07:00
|
|
|
status);
|
|
|
|
|
encoder->encoder->strobeReset(status);
|
|
|
|
|
encoder->encoder->writeConfig_Reverse(reverseDirection, status);
|
|
|
|
|
encoder->encoder->writeTimerConfig_AverageSize(4, status);
|
|
|
|
|
|
|
|
|
|
return handle;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-12 13:45:28 -07:00
|
|
|
void HAL_FreeFPGAEncoder(HAL_FPGAEncoderHandle fpgaEncoderHandle,
|
2016-07-09 00:24:26 -07:00
|
|
|
int32_t* status) {
|
2017-12-10 18:02:07 -08:00
|
|
|
fpgaEncoderHandles->Free(fpgaEncoderHandle);
|
2016-07-03 15:22:22 -07:00
|
|
|
}
|
|
|
|
|
|
2016-08-12 13:45:28 -07:00
|
|
|
void HAL_ResetFPGAEncoder(HAL_FPGAEncoderHandle fpgaEncoderHandle,
|
2016-07-09 00:24:26 -07:00
|
|
|
int32_t* status) {
|
2017-12-10 18:02:07 -08:00
|
|
|
auto encoder = fpgaEncoderHandles->Get(fpgaEncoderHandle);
|
2016-07-03 15:22:22 -07:00
|
|
|
if (encoder == nullptr) {
|
2016-07-07 21:43:55 -07:00
|
|
|
*status = HAL_HANDLE_ERROR;
|
2016-07-03 15:22:22 -07:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
encoder->encoder->strobeReset(status);
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-12 13:45:28 -07:00
|
|
|
int32_t HAL_GetFPGAEncoder(HAL_FPGAEncoderHandle fpgaEncoderHandle,
|
2016-07-09 00:24:26 -07:00
|
|
|
int32_t* status) {
|
2017-12-10 18:02:07 -08:00
|
|
|
auto encoder = fpgaEncoderHandles->Get(fpgaEncoderHandle);
|
2016-07-03 15:22:22 -07:00
|
|
|
if (encoder == nullptr) {
|
2016-07-07 21:43:55 -07:00
|
|
|
*status = HAL_HANDLE_ERROR;
|
2016-07-03 15:22:22 -07:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return encoder->encoder->readOutput_Value(status);
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-12 13:45:28 -07:00
|
|
|
double HAL_GetFPGAEncoderPeriod(HAL_FPGAEncoderHandle fpgaEncoderHandle,
|
2016-07-09 00:24:26 -07:00
|
|
|
int32_t* status) {
|
2017-12-10 18:02:07 -08:00
|
|
|
auto encoder = fpgaEncoderHandles->Get(fpgaEncoderHandle);
|
2016-07-03 15:22:22 -07:00
|
|
|
if (encoder == nullptr) {
|
2016-07-07 21:43:55 -07:00
|
|
|
*status = HAL_HANDLE_ERROR;
|
2016-07-03 15:22:22 -07:00
|
|
|
return 0.0;
|
|
|
|
|
}
|
|
|
|
|
tEncoder::tTimerOutput output = encoder->encoder->readTimerOutput(status);
|
|
|
|
|
double value;
|
|
|
|
|
if (output.Stalled) {
|
|
|
|
|
// Return infinity
|
|
|
|
|
double zero = 0.0;
|
|
|
|
|
value = 1.0 / zero;
|
|
|
|
|
} else {
|
|
|
|
|
// output.Period is a fixed point number that counts by 2 (24 bits, 25
|
|
|
|
|
// integer bits)
|
2016-07-10 17:47:44 -07:00
|
|
|
value = static_cast<double>(output.Period << 1) /
|
|
|
|
|
static_cast<double>(output.Count);
|
2016-07-03 15:22:22 -07:00
|
|
|
}
|
|
|
|
|
double measuredPeriod = value * 2.5e-8;
|
|
|
|
|
return measuredPeriod / DECODING_SCALING_FACTOR;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-12 13:45:28 -07:00
|
|
|
void HAL_SetFPGAEncoderMaxPeriod(HAL_FPGAEncoderHandle fpgaEncoderHandle,
|
2016-07-09 00:24:26 -07:00
|
|
|
double maxPeriod, int32_t* status) {
|
2017-12-10 18:02:07 -08:00
|
|
|
auto encoder = fpgaEncoderHandles->Get(fpgaEncoderHandle);
|
2016-07-03 15:22:22 -07:00
|
|
|
if (encoder == nullptr) {
|
2016-07-07 21:43:55 -07:00
|
|
|
*status = HAL_HANDLE_ERROR;
|
2016-07-03 15:22:22 -07:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
encoder->encoder->writeTimerConfig_StallPeriod(
|
2016-08-11 23:38:45 -07:00
|
|
|
static_cast<uint32_t>(maxPeriod * 4.0e8 * DECODING_SCALING_FACTOR),
|
|
|
|
|
status);
|
2016-07-03 15:22:22 -07:00
|
|
|
}
|
|
|
|
|
|
2016-08-12 13:45:28 -07:00
|
|
|
HAL_Bool HAL_GetFPGAEncoderStopped(HAL_FPGAEncoderHandle fpgaEncoderHandle,
|
2016-07-12 10:45:14 -07:00
|
|
|
int32_t* status) {
|
2017-12-10 18:02:07 -08:00
|
|
|
auto encoder = fpgaEncoderHandles->Get(fpgaEncoderHandle);
|
2016-07-03 15:22:22 -07:00
|
|
|
if (encoder == nullptr) {
|
2016-07-07 21:43:55 -07:00
|
|
|
*status = HAL_HANDLE_ERROR;
|
2016-07-03 15:22:22 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return encoder->encoder->readTimerOutput_Stalled(status) != 0;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-12 13:45:28 -07:00
|
|
|
HAL_Bool HAL_GetFPGAEncoderDirection(HAL_FPGAEncoderHandle fpgaEncoderHandle,
|
2016-07-12 10:45:14 -07:00
|
|
|
int32_t* status) {
|
2017-12-10 18:02:07 -08:00
|
|
|
auto encoder = fpgaEncoderHandles->Get(fpgaEncoderHandle);
|
2016-07-03 15:22:22 -07:00
|
|
|
if (encoder == nullptr) {
|
2016-07-07 21:43:55 -07:00
|
|
|
*status = HAL_HANDLE_ERROR;
|
2016-07-03 15:22:22 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return encoder->encoder->readOutput_Direction(status);
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-12 13:45:28 -07:00
|
|
|
void HAL_SetFPGAEncoderReverseDirection(HAL_FPGAEncoderHandle fpgaEncoderHandle,
|
|
|
|
|
HAL_Bool reverseDirection,
|
|
|
|
|
int32_t* status) {
|
2017-12-10 18:02:07 -08:00
|
|
|
auto encoder = fpgaEncoderHandles->Get(fpgaEncoderHandle);
|
2016-07-03 15:22:22 -07:00
|
|
|
if (encoder == nullptr) {
|
2016-07-07 21:43:55 -07:00
|
|
|
*status = HAL_HANDLE_ERROR;
|
2016-07-03 15:22:22 -07:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
encoder->encoder->writeConfig_Reverse(reverseDirection, status);
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-12 13:45:28 -07:00
|
|
|
void HAL_SetFPGAEncoderSamplesToAverage(HAL_FPGAEncoderHandle fpgaEncoderHandle,
|
|
|
|
|
int32_t samplesToAverage,
|
|
|
|
|
int32_t* status) {
|
2017-12-10 18:02:07 -08:00
|
|
|
auto encoder = fpgaEncoderHandles->Get(fpgaEncoderHandle);
|
2016-07-03 15:22:22 -07:00
|
|
|
if (encoder == nullptr) {
|
2016-07-07 21:43:55 -07:00
|
|
|
*status = HAL_HANDLE_ERROR;
|
2016-07-03 15:22:22 -07:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (samplesToAverage < 1 || samplesToAverage > 127) {
|
|
|
|
|
*status = PARAMETER_OUT_OF_RANGE;
|
|
|
|
|
}
|
|
|
|
|
encoder->encoder->writeTimerConfig_AverageSize(samplesToAverage, status);
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-12 10:45:14 -07:00
|
|
|
int32_t HAL_GetFPGAEncoderSamplesToAverage(
|
2016-08-12 13:45:28 -07:00
|
|
|
HAL_FPGAEncoderHandle fpgaEncoderHandle, int32_t* status) {
|
2017-12-10 18:02:07 -08:00
|
|
|
auto encoder = fpgaEncoderHandles->Get(fpgaEncoderHandle);
|
2016-07-03 15:22:22 -07:00
|
|
|
if (encoder == nullptr) {
|
2016-07-07 21:43:55 -07:00
|
|
|
*status = HAL_HANDLE_ERROR;
|
2016-07-03 15:22:22 -07:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return encoder->encoder->readTimerConfig_AverageSize(status);
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-12 13:45:28 -07:00
|
|
|
void HAL_SetFPGAEncoderIndexSource(HAL_FPGAEncoderHandle fpgaEncoderHandle,
|
2016-07-09 00:24:26 -07:00
|
|
|
HAL_Handle digitalSourceHandle,
|
|
|
|
|
HAL_AnalogTriggerType analogTriggerType,
|
2016-07-12 10:45:14 -07:00
|
|
|
HAL_Bool activeHigh, HAL_Bool edgeSensitive,
|
2016-07-09 00:24:26 -07:00
|
|
|
int32_t* status) {
|
2017-12-10 18:02:07 -08:00
|
|
|
auto encoder = fpgaEncoderHandles->Get(fpgaEncoderHandle);
|
2016-07-03 15:22:22 -07:00
|
|
|
if (encoder == nullptr) {
|
2016-07-07 21:43:55 -07:00
|
|
|
*status = HAL_HANDLE_ERROR;
|
2016-07-03 15:22:22 -07:00
|
|
|
return;
|
|
|
|
|
}
|
2016-07-07 21:43:55 -07:00
|
|
|
|
|
|
|
|
bool routingAnalogTrigger = false;
|
2016-08-12 13:45:28 -07:00
|
|
|
uint8_t routingChannel = 0;
|
2016-07-07 21:43:55 -07:00
|
|
|
uint8_t routingModule = 0;
|
|
|
|
|
bool success =
|
2016-08-12 13:45:28 -07:00
|
|
|
remapDigitalSource(digitalSourceHandle, analogTriggerType, routingChannel,
|
2016-07-07 21:43:55 -07:00
|
|
|
routingModule, routingAnalogTrigger);
|
|
|
|
|
if (!success) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-12 13:45:28 -07:00
|
|
|
encoder->encoder->writeConfig_IndexSource_Channel(routingChannel, status);
|
2016-07-07 21:43:55 -07:00
|
|
|
encoder->encoder->writeConfig_IndexSource_Module(routingModule, status);
|
|
|
|
|
encoder->encoder->writeConfig_IndexSource_AnalogTrigger(routingAnalogTrigger,
|
2016-07-03 15:22:22 -07:00
|
|
|
status);
|
|
|
|
|
encoder->encoder->writeConfig_IndexActiveHigh(activeHigh, status);
|
|
|
|
|
encoder->encoder->writeConfig_IndexEdgeSensitive(edgeSensitive, status);
|
|
|
|
|
}
|
2017-08-23 22:07:46 -07:00
|
|
|
|
|
|
|
|
} // extern "C"
|