/*----------------------------------------------------------------------------*/ /* Copyright (c) FIRST 2016. All Rights Reserved. */ /* 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 "HAL/Encoder.h" #include "ChipObject.h" #include "EncoderInternal.h" #include "FPGAEncoder.h" #include "HAL/Counter.h" #include "HAL/Errors.h" #include "PortsInternal.h" #include "handles/LimitedClassedHandleResource.h" using namespace hal; Encoder::Encoder(HAL_Handle digitalSourceHandleA, HAL_AnalogTriggerType analogTriggerTypeA, HAL_Handle digitalSourceHandleB, HAL_AnalogTriggerType analogTriggerTypeB, bool reverseDirection, HAL_EncoderEncodingType encodingType, int32_t* status) { m_encodingType = encodingType; switch (encodingType) { case HAL_Encoder_k4X: { m_encodingScale = 4; m_encoder = HAL_InitializeFPGAEncoder( digitalSourceHandleA, analogTriggerTypeA, digitalSourceHandleB, analogTriggerTypeB, reverseDirection, &m_index, status); if (*status != 0) { return; } m_counter = HAL_kInvalidHandle; SetMaxPeriod(.5, status); break; } case HAL_Encoder_k1X: case HAL_Encoder_k2X: { SetupCounter(digitalSourceHandleA, analogTriggerTypeA, digitalSourceHandleB, analogTriggerTypeB, reverseDirection, encodingType, status); m_encodingScale = encodingType == HAL_Encoder_k1X ? 1 : 2; break; } default: *status = PARAMETER_OUT_OF_RANGE; return; } } void Encoder::SetupCounter(HAL_Handle digitalSourceHandleA, HAL_AnalogTriggerType analogTriggerTypeA, HAL_Handle digitalSourceHandleB, HAL_AnalogTriggerType analogTriggerTypeB, bool reverseDirection, HAL_EncoderEncodingType encodingType, int32_t* status) { m_encodingScale = encodingType == HAL_Encoder_k1X ? 1 : 2; m_counter = HAL_InitializeCounter(HAL_Counter_kExternalDirection, &m_index, status); if (*status != 0) return; HAL_SetCounterMaxPeriod(m_counter, 0.5, status); if (*status != 0) return; HAL_SetCounterUpSource(m_counter, digitalSourceHandleA, analogTriggerTypeA, status); if (*status != 0) return; HAL_SetCounterDownSource(m_counter, digitalSourceHandleB, analogTriggerTypeB, status); if (*status != 0) return; if (encodingType == HAL_Encoder_k1X) { HAL_SetCounterUpSourceEdge(m_counter, true, false, status); HAL_SetCounterAverageSize(m_counter, 1, status); } else { HAL_SetCounterUpSourceEdge(m_counter, true, true, status); HAL_SetCounterAverageSize(m_counter, 2, status); } HAL_SetCounterDownSourceEdge(m_counter, reverseDirection, true, status); } Encoder::~Encoder() { if (m_counter != HAL_kInvalidHandle) { int32_t status = 0; HAL_FreeCounter(m_counter, &status); } else { int32_t status = 0; HAL_FreeFPGAEncoder(m_encoder, &status); } } // CounterBase interface int32_t Encoder::Get(int32_t* status) const { return (int32_t)(GetRaw(status) * DecodingScaleFactor()); } int32_t Encoder::GetRaw(int32_t* status) const { if (m_counter) { return HAL_GetCounter(m_counter, status); } else { return HAL_GetFPGAEncoder(m_encoder, status); } } int32_t Encoder::GetEncodingScale(int32_t* status) const { return m_encodingScale; } void Encoder::Reset(int32_t* status) { if (m_counter) { HAL_ResetCounter(m_counter, status); } else { HAL_ResetFPGAEncoder(m_encoder, status); } } double Encoder::GetPeriod(int32_t* status) const { if (m_counter) { return HAL_GetCounterPeriod(m_counter, status) / DecodingScaleFactor(); } else { return HAL_GetFPGAEncoderPeriod(m_encoder, status); } } void Encoder::SetMaxPeriod(double maxPeriod, int32_t* status) { if (m_counter) { HAL_SetCounterMaxPeriod(m_counter, maxPeriod, status); } else { HAL_SetFPGAEncoderMaxPeriod(m_encoder, maxPeriod, status); } } bool Encoder::GetStopped(int32_t* status) const { if (m_counter) { return HAL_GetCounterStopped(m_counter, status); } else { return HAL_GetFPGAEncoderStopped(m_encoder, status); } } bool Encoder::GetDirection(int32_t* status) const { if (m_counter) { return HAL_GetCounterDirection(m_counter, status); } else { return HAL_GetFPGAEncoderDirection(m_encoder, status); } } double Encoder::GetDistance(int32_t* status) const { return GetRaw(status) * DecodingScaleFactor() * m_distancePerPulse; } double Encoder::GetRate(int32_t* status) const { return m_distancePerPulse / GetPeriod(status); } void Encoder::SetMinRate(double minRate, int32_t* status) { SetMaxPeriod(m_distancePerPulse / minRate, status); } void Encoder::SetDistancePerPulse(double distancePerPulse, int32_t* status) { m_distancePerPulse = distancePerPulse; } void Encoder::SetReverseDirection(bool reverseDirection, int32_t* status) { if (m_counter) { HAL_SetCounterReverseDirection(m_counter, reverseDirection, status); } else { HAL_SetFPGAEncoderReverseDirection(m_encoder, reverseDirection, status); } } void Encoder::SetSamplesToAverage(int samplesToAverage, int32_t* status) { if (samplesToAverage < 1 || samplesToAverage > 127) { *status = PARAMETER_OUT_OF_RANGE; return; } if (m_counter) { HAL_SetCounterSamplesToAverage(m_counter, samplesToAverage, status); } else { HAL_SetFPGAEncoderSamplesToAverage(m_encoder, samplesToAverage, status); } } int32_t Encoder::GetSamplesToAverage(int32_t* status) const { if (m_counter) { return HAL_GetCounterSamplesToAverage(m_counter, status); } else { return HAL_GetFPGAEncoderSamplesToAverage(m_encoder, status); } } void Encoder::SetIndexSource(HAL_Handle digitalSourceHandle, HAL_AnalogTriggerType analogTriggerType, HAL_EncoderIndexingType type, int32_t* status) { if (m_counter) { *status = HAL_COUNTER_NOT_SUPPORTED; return; } bool activeHigh = (type == HAL_kResetWhileHigh) || (type == HAL_kResetOnRisingEdge); bool edgeSensitive = (type == HAL_kResetOnFallingEdge) || (type == HAL_kResetOnRisingEdge); HAL_SetFPGAEncoderIndexSource(m_encoder, digitalSourceHandle, analogTriggerType, activeHigh, edgeSensitive, status); } double Encoder::DecodingScaleFactor() const { switch (m_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; } } static LimitedClassedHandleResource encoderHandles; extern "C" { HAL_EncoderHandle HAL_InitializeEncoder( HAL_Handle digitalSourceHandleA, HAL_AnalogTriggerType analogTriggerTypeA, HAL_Handle digitalSourceHandleB, HAL_AnalogTriggerType analogTriggerTypeB, bool reverseDirection, HAL_EncoderEncodingType encodingType, int32_t* status) { auto encoder = std::make_shared( digitalSourceHandleA, analogTriggerTypeA, digitalSourceHandleB, analogTriggerTypeB, reverseDirection, encodingType, status); if (*status != 0) return HAL_kInvalidHandle; // return in creation error auto handle = encoderHandles.Allocate(encoder); if (handle == HAL_kInvalidHandle) { *status = NO_AVAILABLE_RESOURCES; return HAL_kInvalidHandle; } return handle; } void HAL_FreeEncoder(HAL_EncoderHandle encoder_handle, int32_t* status) { encoderHandles.Free(encoder_handle); } int32_t HAL_GetEncoder(HAL_EncoderHandle encoder_handle, int32_t* status) { auto encoder = encoderHandles.Get(encoder_handle); if (encoder == nullptr) { *status = HAL_HANDLE_ERROR; return 0; } return encoder->Get(status); } int32_t HAL_GetEncoderRaw(HAL_EncoderHandle encoder_handle, int32_t* status) { auto encoder = encoderHandles.Get(encoder_handle); if (encoder == nullptr) { *status = HAL_HANDLE_ERROR; return 0; } return encoder->GetRaw(status); } int32_t HAL_GetEncoderEncodingScale(HAL_EncoderHandle encoder_handle, int32_t* status) { auto encoder = encoderHandles.Get(encoder_handle); if (encoder == nullptr) { *status = HAL_HANDLE_ERROR; return 0; } return encoder->GetEncodingScale(status); } void HAL_ResetEncoder(HAL_EncoderHandle encoder_handle, int32_t* status) { auto encoder = encoderHandles.Get(encoder_handle); if (encoder == nullptr) { *status = HAL_HANDLE_ERROR; return; } encoder->Reset(status); } int32_t HAL_GetEncoderPeriod(HAL_EncoderHandle encoder_handle, int32_t* status) { auto encoder = encoderHandles.Get(encoder_handle); if (encoder == nullptr) { *status = HAL_HANDLE_ERROR; return 0; } return encoder->GetPeriod(status); } void HAL_SetEncoderMaxPeriod(HAL_EncoderHandle encoder_handle, double maxPeriod, int32_t* status) { auto encoder = encoderHandles.Get(encoder_handle); if (encoder == nullptr) { *status = HAL_HANDLE_ERROR; return; } encoder->SetMaxPeriod(maxPeriod, status); } uint8_t HAL_GetEncoderStopped(HAL_EncoderHandle encoder_handle, int32_t* status) { auto encoder = encoderHandles.Get(encoder_handle); if (encoder == nullptr) { *status = HAL_HANDLE_ERROR; return 0; } return encoder->GetStopped(status); } uint8_t HAL_GetEncoderDirection(HAL_EncoderHandle encoder_handle, int32_t* status) { auto encoder = encoderHandles.Get(encoder_handle); if (encoder == nullptr) { *status = HAL_HANDLE_ERROR; return 0; } return encoder->GetDirection(status); } double HAL_GetEncoderDistance(HAL_EncoderHandle encoder_handle, int32_t* status) { auto encoder = encoderHandles.Get(encoder_handle); if (encoder == nullptr) { *status = HAL_HANDLE_ERROR; return 0; } return encoder->GetDistance(status); } double HAL_GetEncoderRate(HAL_EncoderHandle encoder_handle, int32_t* status) { auto encoder = encoderHandles.Get(encoder_handle); if (encoder == nullptr) { *status = HAL_HANDLE_ERROR; return 0; } return encoder->GetRate(status); } void HAL_SetEncoderMinRate(HAL_EncoderHandle encoder_handle, double minRate, int32_t* status) { auto encoder = encoderHandles.Get(encoder_handle); if (encoder == nullptr) { *status = HAL_HANDLE_ERROR; return; } encoder->SetMinRate(minRate, status); } void HAL_SetEncoderDistancePerPulse(HAL_EncoderHandle encoder_handle, double distancePerPulse, int32_t* status) { auto encoder = encoderHandles.Get(encoder_handle); if (encoder == nullptr) { *status = HAL_HANDLE_ERROR; return; } encoder->SetDistancePerPulse(distancePerPulse, status); } void HAL_SetEncoderReverseDirection(HAL_EncoderHandle encoder_handle, uint8_t reverseDirection, int32_t* status) { auto encoder = encoderHandles.Get(encoder_handle); if (encoder == nullptr) { *status = HAL_HANDLE_ERROR; return; } encoder->SetReverseDirection(reverseDirection, status); } void HAL_SetEncoderSamplesToAverage(HAL_EncoderHandle encoder_handle, int32_t samplesToAverage, int32_t* status) { auto encoder = encoderHandles.Get(encoder_handle); if (encoder == nullptr) { *status = HAL_HANDLE_ERROR; return; } encoder->SetSamplesToAverage(samplesToAverage, status); } int32_t HAL_GetEncoderSamplesToAverage(HAL_EncoderHandle encoder_handle, int32_t* status) { auto encoder = encoderHandles.Get(encoder_handle); if (encoder == nullptr) { *status = HAL_HANDLE_ERROR; return 0; } return encoder->GetSamplesToAverage(status); } double HAL_GetEncoderDecodingScaleFactor(HAL_EncoderHandle encoder_handle, int32_t* status) { auto encoder = encoderHandles.Get(encoder_handle); if (encoder == nullptr) { *status = HAL_HANDLE_ERROR; return 0; } return encoder->DecodingScaleFactor(); } double HAL_GetEncoderDistancePerPulse(HAL_EncoderHandle encoder_handle, int32_t* status) { auto encoder = encoderHandles.Get(encoder_handle); if (encoder == nullptr) { *status = HAL_HANDLE_ERROR; return 0; } return encoder->GetDistancePerPulse(); } HAL_EncoderEncodingType HAL_GetEncoderEncodingType( HAL_EncoderHandle encoder_handle, int32_t* status) { auto encoder = encoderHandles.Get(encoder_handle); if (encoder == nullptr) { *status = HAL_HANDLE_ERROR; return HAL_Encoder_k4X; // default to k4X } return encoder->GetEncodingType(); } void HAL_SetEncoderIndexSource(HAL_EncoderHandle encoder_handle, HAL_Handle digitalSourceHandle, HAL_AnalogTriggerType analogTriggerType, HAL_EncoderIndexingType type, int32_t* status) { auto encoder = encoderHandles.Get(encoder_handle); if (encoder == nullptr) { *status = HAL_HANDLE_ERROR; return; } encoder->SetIndexSource(digitalSourceHandle, analogTriggerType, type, status); } int32_t HAL_GetEncoderFPGAIndex(HAL_EncoderHandle encoder_handle, int32_t* status) { auto encoder = encoderHandles.Get(encoder_handle); if (encoder == nullptr) { *status = HAL_HANDLE_ERROR; return 0; } return encoder->GetFPGAIndex(); } }