Add FPGA Duty Cycle support (#1987)

This commit is contained in:
Thad House
2019-11-01 23:41:30 -07:00
committed by Peter Johnson
parent 509819d83f
commit 1d695a1660
42 changed files with 1744 additions and 72 deletions

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
/* Copyright (c) 2017-2019 FIRST. 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. */
@@ -63,7 +63,7 @@ int32_t hal::GetAnalogTriggerInputIndex(HAL_AnalogTriggerHandle handle,
extern "C" {
HAL_AnalogTriggerHandle HAL_InitializeAnalogTrigger(
HAL_AnalogInputHandle portHandle, int32_t* index, int32_t* status) {
HAL_AnalogInputHandle portHandle, int32_t* status) {
hal::init::CheckInit();
// ensure we are given a valid and active AnalogInput handle
auto analog_port = analogInputHandles->Get(portHandle);
@@ -83,7 +83,6 @@ HAL_AnalogTriggerHandle HAL_InitializeAnalogTrigger(
}
trigger->analogHandle = portHandle;
trigger->index = static_cast<uint8_t>(getHandleIndex(handle));
*index = trigger->index;
SimAnalogTriggerData[trigger->index].initialized = true;
@@ -92,6 +91,12 @@ HAL_AnalogTriggerHandle HAL_InitializeAnalogTrigger(
return handle;
}
HAL_AnalogTriggerHandle HAL_InitializeAnalogTriggerDutyCycle(
HAL_DutyCycleHandle dutyCycleHandle, int32_t* status) {
*status = HAL_SIM_NOT_SUPPORTED;
return HAL_kInvalidHandle;
}
void HAL_CleanAnalogTrigger(HAL_AnalogTriggerHandle analogTriggerHandle,
int32_t* status) {
auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
@@ -133,6 +138,13 @@ void HAL_SetAnalogTriggerLimitsRaw(HAL_AnalogTriggerHandle analogTriggerHandle,
SimAnalogTriggerData[trigger->index].triggerUpperBound = trigUpper;
SimAnalogTriggerData[trigger->index].triggerLowerBound = trigLower;
}
void HAL_SetAnalogTriggerLimitsDutyCycle(
HAL_AnalogTriggerHandle analogTriggerHandle, double lower, double upper,
int32_t* status) {
*status = HAL_SIM_NOT_SUPPORTED;
}
void HAL_SetAnalogTriggerLimitsVoltage(
HAL_AnalogTriggerHandle analogTriggerHandle, double lower, double upper,
int32_t* status) {
@@ -158,7 +170,7 @@ void HAL_SetAnalogTriggerAveraged(HAL_AnalogTriggerHandle analogTriggerHandle,
AnalogTriggerData* triggerData = &SimAnalogTriggerData[trigger->index];
if (triggerData->triggerMode.Get() == HALSIM_AnalogTriggerFiltered) {
if (triggerData->triggerMode.Get() != HALSIM_AnalogTriggerUnassigned) {
*status = INCOMPATIBLE_STATE;
return;
}
@@ -167,6 +179,25 @@ void HAL_SetAnalogTriggerAveraged(HAL_AnalogTriggerHandle analogTriggerHandle,
: HALSIM_AnalogTriggerUnassigned;
triggerData->triggerMode = setVal;
}
void HAL_SetAnalogTriggerDutyCycle(HAL_AnalogTriggerHandle analogTriggerHandle,
HAL_Bool useDutyCycle, int32_t* status) {
auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
if (trigger == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
AnalogTriggerData* triggerData = &SimAnalogTriggerData[trigger->index];
if (triggerData->triggerMode.Get() != HALSIM_AnalogTriggerUnassigned) {
*status = INCOMPATIBLE_STATE;
return;
}
auto setVal = useDutyCycle ? HALSIM_AnalogTriggerDutyCycle
: HALSIM_AnalogTriggerUnassigned;
triggerData->triggerMode = setVal;
}
void HAL_SetAnalogTriggerFiltered(HAL_AnalogTriggerHandle analogTriggerHandle,
HAL_Bool useFilteredValue, int32_t* status) {
auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
@@ -177,12 +208,12 @@ void HAL_SetAnalogTriggerFiltered(HAL_AnalogTriggerHandle analogTriggerHandle,
AnalogTriggerData* triggerData = &SimAnalogTriggerData[trigger->index];
if (triggerData->triggerMode.Get() == HALSIM_AnalogTriggerAveraged) {
if (triggerData->triggerMode.Get() != HALSIM_AnalogTriggerUnassigned) {
*status = INCOMPATIBLE_STATE;
return;
}
auto setVal = useFilteredValue ? HALSIM_AnalogTriggerAveraged
auto setVal = useFilteredValue ? HALSIM_AnalogTriggerFiltered
: HALSIM_AnalogTriggerUnassigned;
triggerData->triggerMode = setVal;
}
@@ -258,4 +289,15 @@ HAL_Bool HAL_GetAnalogTriggerOutput(HAL_AnalogTriggerHandle analogTriggerHandle,
return false;
}
}
int32_t HAL_GetAnalogTriggerFPGAIndex(
HAL_AnalogTriggerHandle analogTriggerHandle, int32_t* status) {
auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
if (trigger == nullptr) {
*status = HAL_HANDLE_ERROR;
return -1;
}
return trigger->index;
}
} // extern "C"

View File

@@ -0,0 +1,120 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 FIRST. 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/DutyCycle.h"
#include "HALInitializer.h"
#include "PortsInternal.h"
#include "hal/Errors.h"
#include "hal/handles/HandlesInternal.h"
#include "hal/handles/LimitedHandleResource.h"
#include "mockdata/DutyCycleDataInternal.h"
using namespace hal;
namespace {
struct DutyCycle {
uint8_t index;
};
struct Empty {};
} // namespace
static LimitedHandleResource<HAL_DutyCycleHandle, DutyCycle, kNumDutyCycles,
HAL_HandleEnum::DutyCycle>* dutyCycleHandles;
namespace hal {
namespace init {
void InitializeDutyCycle() {
static LimitedHandleResource<HAL_DutyCycleHandle, DutyCycle, kNumDutyCycles,
HAL_HandleEnum::DutyCycle>
dcH;
dutyCycleHandles = &dcH;
}
} // namespace init
} // namespace hal
extern "C" {
HAL_DutyCycleHandle HAL_InitializeDutyCycle(HAL_Handle digitalSourceHandle,
HAL_AnalogTriggerType triggerType,
int32_t* status) {
hal::init::CheckInit();
HAL_DutyCycleHandle handle = dutyCycleHandles->Allocate();
if (handle == HAL_kInvalidHandle) {
*status = NO_AVAILABLE_RESOURCES;
return HAL_kInvalidHandle;
}
auto dutyCycle = dutyCycleHandles->Get(handle);
if (dutyCycle == nullptr) { // would only occur on thread issue
*status = HAL_HANDLE_ERROR;
return HAL_kInvalidHandle;
}
int16_t index = getHandleIndex(handle);
SimDutyCycleData[index].digitalChannel = getHandleIndex(digitalSourceHandle);
SimDutyCycleData[index].initialized = true;
SimDutyCycleData[index].simDevice = 0;
dutyCycle->index = index;
return handle;
}
void HAL_FreeDutyCycle(HAL_DutyCycleHandle dutyCycleHandle) {
auto dutyCycle = dutyCycleHandles->Get(dutyCycleHandle);
dutyCycleHandles->Free(dutyCycleHandle);
if (dutyCycle == nullptr) return;
SimDutyCycleData[dutyCycle->index].initialized = false;
}
void HAL_SetDutyCycleSimDevice(HAL_EncoderHandle handle,
HAL_SimDeviceHandle device) {
auto dutyCycle = dutyCycleHandles->Get(handle);
if (dutyCycle == nullptr) return;
SimDutyCycleData[dutyCycle->index].simDevice = device;
}
int32_t HAL_GetDutyCycleFrequency(HAL_DutyCycleHandle dutyCycleHandle,
int32_t* status) {
auto dutyCycle = dutyCycleHandles->Get(dutyCycleHandle);
if (dutyCycle == nullptr) {
*status = HAL_HANDLE_ERROR;
return 0;
}
return SimDutyCycleData[dutyCycle->index].frequency;
}
double HAL_GetDutyCycleOutput(HAL_DutyCycleHandle dutyCycleHandle,
int32_t* status) {
auto dutyCycle = dutyCycleHandles->Get(dutyCycleHandle);
if (dutyCycle == nullptr) {
*status = HAL_HANDLE_ERROR;
return 0;
}
return SimDutyCycleData[dutyCycle->index].output;
}
int32_t HAL_GetDutyCycleOutputRaw(HAL_DutyCycleHandle dutyCycleHandle,
int32_t* status) {
auto dutyCycle = dutyCycleHandles->Get(dutyCycleHandle);
if (dutyCycle == nullptr) {
*status = HAL_HANDLE_ERROR;
return 0;
}
return SimDutyCycleData[dutyCycle->index].output *
HAL_GetDutyCycleOutputScaleFactor(dutyCycleHandle, status);
}
int32_t HAL_GetDutyCycleOutputScaleFactor(HAL_DutyCycleHandle dutyCycleHandle,
int32_t* status) {
return 4e7 - 1;
}
int32_t HAL_GetDutyCycleFPGAIndex(HAL_DutyCycleHandle dutyCycleHandle,
int32_t* status) {
auto dutyCycle = dutyCycleHandles->Get(dutyCycleHandle);
if (dutyCycle == nullptr) {
*status = HAL_HANDLE_ERROR;
return -1;
}
return dutyCycle->index;
}
} // extern "C"

View File

@@ -32,6 +32,7 @@ void InitializeHAL() {
InitializeCanData();
InitializeCANAPI();
InitializeDigitalPWMData();
InitializeDutyCycleData();
InitializeDIOData();
InitializeDriverStationData();
InitializeEncoderData();
@@ -56,6 +57,7 @@ void InitializeHAL() {
InitializeCounter();
InitializeDigitalInternal();
InitializeDIO();
InitializeDutyCycle();
InitializeDriverStation();
InitializeEncoder();
InitializeExtensions();
@@ -199,6 +201,8 @@ const char* HAL_GetErrorMessage(int32_t code) {
return HAL_PWM_SCALE_ERROR_MESSAGE;
case HAL_CAN_TIMEOUT:
return HAL_CAN_TIMEOUT_MESSAGE;
case HAL_SIM_NOT_SUPPORTED:
return HAL_SIM_NOT_SUPPORTED_MESSAGE;
default:
return "Unknown error status";
}

View File

@@ -26,7 +26,9 @@ extern void InitializeAnalogTriggerData();
extern void InitializeCanData();
extern void InitializeCANAPI();
extern void InitializeDigitalPWMData();
extern void InitializeDutyCycleData();
extern void InitializeDIOData();
extern void InitializeDutyCycle();
extern void InitializeDriverStationData();
extern void InitializeEncoderData();
extern void InitializeI2CData();

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
/* Copyright (c) 2016-2019 FIRST. 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. */
@@ -36,5 +36,5 @@ int32_t HAL_GetNumPCMModules(void) { return kNumPCMModules; }
int32_t HAL_GetNumSolenoidChannels(void) { return kNumSolenoidChannels; }
int32_t HAL_GetNumPDPModules(void) { return kNumPDPModules; }
int32_t HAL_GetNumPDPChannels(void) { return kNumPDPChannels; }
int32_t HAL_GetNumCanTalons(void) { return kNumCanTalons; }
int32_t HAL_GetNumDutyCycles(void) { return kNumDutyCycles; }
} // extern "C"

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
/* Copyright (c) 2016-2019 FIRST. 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. */
@@ -28,5 +28,5 @@ constexpr int32_t kNumPCMModules = 63;
constexpr int32_t kNumSolenoidChannels = 8;
constexpr int32_t kNumPDPModules = 63;
constexpr int32_t kNumPDPChannels = 16;
constexpr int32_t kNumCanTalons = 63;
constexpr int32_t kNumDutyCycles = 8;
} // namespace hal

View File

@@ -0,0 +1,178 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 FIRST. 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 <jni.h>
#include "CallbackStore.h"
#include "edu_wpi_first_hal_sim_mockdata_DutyCycleDataJNI.h"
#include "mockdata/DutyCycleData.h"
extern "C" {
/*
* Class: edu_wpi_first_hal_sim_mockdata_DutyCycleDataJNI
* Method: registerInitializedCallback
* Signature: (ILjava/lang/Object;Z)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_sim_mockdata_DutyCycleDataJNI_registerInitializedCallback
(JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
{
return sim::AllocateCallback(env, index, callback, initialNotify,
&HALSIM_RegisterDutyCycleInitializedCallback);
}
/*
* Class: edu_wpi_first_hal_sim_mockdata_DutyCycleDataJNI
* Method: cancelInitializedCallback
* Signature: (II)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_sim_mockdata_DutyCycleDataJNI_cancelInitializedCallback
(JNIEnv* env, jclass, jint index, jint handle)
{
return sim::FreeCallback(env, handle, index,
&HALSIM_CancelDutyCycleInitializedCallback);
}
/*
* Class: edu_wpi_first_hal_sim_mockdata_DutyCycleDataJNI
* Method: getInitialized
* Signature: (I)Z
*/
JNIEXPORT jboolean JNICALL
Java_edu_wpi_first_hal_sim_mockdata_DutyCycleDataJNI_getInitialized
(JNIEnv*, jclass, jint index)
{
return HALSIM_GetDutyCycleInitialized(index);
}
/*
* Class: edu_wpi_first_hal_sim_mockdata_DutyCycleDataJNI
* Method: setInitialized
* Signature: (IZ)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_sim_mockdata_DutyCycleDataJNI_setInitialized
(JNIEnv*, jclass, jint index, jboolean value)
{
HALSIM_SetDutyCycleInitialized(index, value);
}
/*
* Class: edu_wpi_first_hal_sim_mockdata_DutyCycleDataJNI
* Method: registerFrequencyCallback
* Signature: (ILjava/lang/Object;Z)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_sim_mockdata_DutyCycleDataJNI_registerFrequencyCallback
(JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
{
return sim::AllocateCallback(env, index, callback, initialNotify,
&HALSIM_RegisterDutyCycleFrequencyCallback);
}
/*
* Class: edu_wpi_first_hal_sim_mockdata_DutyCycleDataJNI
* Method: cancelFrequencyCallback
* Signature: (II)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_sim_mockdata_DutyCycleDataJNI_cancelFrequencyCallback
(JNIEnv* env, jclass, jint index, jint handle)
{
return sim::FreeCallback(env, handle, index,
&HALSIM_CancelDutyCycleFrequencyCallback);
}
/*
* Class: edu_wpi_first_hal_sim_mockdata_DutyCycleDataJNI
* Method: getFrequency
* Signature: (I)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_sim_mockdata_DutyCycleDataJNI_getFrequency
(JNIEnv*, jclass, jint index)
{
return HALSIM_GetDutyCycleFrequency(index);
}
/*
* Class: edu_wpi_first_hal_sim_mockdata_DutyCycleDataJNI
* Method: setFrequency
* Signature: (II)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_sim_mockdata_DutyCycleDataJNI_setFrequency
(JNIEnv*, jclass, jint index, jint value)
{
HALSIM_SetDutyCycleFrequency(index, value);
}
/*
* Class: edu_wpi_first_hal_sim_mockdata_DutyCycleDataJNI
* Method: registerOutputCallback
* Signature: (ILjava/lang/Object;Z)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_sim_mockdata_DutyCycleDataJNI_registerOutputCallback
(JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
{
return sim::AllocateCallback(env, index, callback, initialNotify,
&HALSIM_RegisterDutyCycleOutputCallback);
}
/*
* Class: edu_wpi_first_hal_sim_mockdata_DutyCycleDataJNI
* Method: cancelOutputCallback
* Signature: (II)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_sim_mockdata_DutyCycleDataJNI_cancelOutputCallback
(JNIEnv* env, jclass, jint index, jint handle)
{
return sim::FreeCallback(env, handle, index,
&HALSIM_CancelDutyCycleOutputCallback);
}
/*
* Class: edu_wpi_first_hal_sim_mockdata_DutyCycleDataJNI
* Method: getOutput
* Signature: (I)D
*/
JNIEXPORT jdouble JNICALL
Java_edu_wpi_first_hal_sim_mockdata_DutyCycleDataJNI_getOutput
(JNIEnv*, jclass, jint index)
{
return HALSIM_GetDutyCycleOutput(index);
}
/*
* Class: edu_wpi_first_hal_sim_mockdata_DutyCycleDataJNI
* Method: setOutput
* Signature: (ID)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_sim_mockdata_DutyCycleDataJNI_setOutput
(JNIEnv*, jclass, jint index, jdouble value)
{
HALSIM_SetDutyCycleOutput(index, value);
}
/*
* Class: edu_wpi_first_hal_sim_mockdata_DutyCycleDataJNI
* Method: resetData
* Signature: (I)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_sim_mockdata_DutyCycleDataJNI_resetData
(JNIEnv*, jclass, jint index)
{
HALSIM_ResetDutyCycleData(index);
}
} // extern "C"

View File

@@ -0,0 +1,63 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 FIRST. 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 "../PortsInternal.h"
#include "DutyCycleDataInternal.h"
using namespace hal;
namespace hal {
namespace init {
void InitializeDutyCycleData() {
static DutyCycleData sed[kNumDutyCycles];
::hal::SimDutyCycleData = sed;
}
} // namespace init
} // namespace hal
DutyCycleData* hal::SimDutyCycleData;
void DutyCycleData::ResetData() {
digitalChannel = 0;
initialized.Reset(false);
simDevice = 0;
frequency.Reset(0);
output.Reset(0);
}
extern "C" {
void HALSIM_ResetDutyCycleData(int32_t index) {
SimDutyCycleData[index].ResetData();
}
int32_t HALSIM_GetDutyCycleDigitalChannel(int32_t index) {
return SimDutyCycleData[index].digitalChannel;
}
HAL_SimDeviceHandle HALSIM_GetDutyCycleSimDevice(int32_t index) {
return SimDutyCycleData[index].simDevice;
}
#define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME) \
HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, HALSIM, DutyCycle##CAPINAME, \
SimDutyCycleData, LOWERNAME)
DEFINE_CAPI(HAL_Bool, Initialized, initialized)
DEFINE_CAPI(int32_t, Frequency, frequency)
DEFINE_CAPI(double, Output, output)
#define REGISTER(NAME) \
SimDutyCycleData[index].NAME.RegisterCallback(callback, param, initialNotify)
void HALSIM_RegisterDutyCycleAllCallbacks(int32_t index,
HAL_NotifyCallback callback,
void* param, HAL_Bool initialNotify) {
REGISTER(initialized);
REGISTER(frequency);
REGISTER(output);
}
} // extern "C"

View File

@@ -0,0 +1,33 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 FIRST. 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. */
/*----------------------------------------------------------------------------*/
#pragma once
#include <atomic>
#include <limits>
#include "mockdata/DutyCycleData.h"
#include "mockdata/SimDataValue.h"
namespace hal {
class DutyCycleData {
HAL_SIMDATAVALUE_DEFINE_NAME(Initialized)
HAL_SIMDATAVALUE_DEFINE_NAME(Output)
HAL_SIMDATAVALUE_DEFINE_NAME(Frequency)
public:
std::atomic<int32_t> digitalChannel{0};
SimDataValue<HAL_Bool, HAL_MakeBoolean, GetInitializedName> initialized{
false};
std::atomic<HAL_SimDeviceHandle> simDevice;
SimDataValue<int32_t, HAL_MakeInt, GetFrequencyName> frequency{0};
SimDataValue<double, HAL_MakeDouble, GetOutputName> output{0};
virtual void ResetData();
};
extern DutyCycleData* SimDutyCycleData;
} // namespace hal