[hal] Add support for DMA to Java (#3158)

This commit is contained in:
Thad House
2021-06-14 19:56:42 -07:00
committed by GitHub
parent 85144e47ff
commit 4a36f86c81
39 changed files with 2013 additions and 97 deletions

View File

@@ -11,6 +11,7 @@
#include <type_traits>
#include "AnalogInternal.h"
#include "ConstantsInternal.h"
#include "DigitalInternal.h"
#include "EncoderInternal.h"
#include "HALInternal.h"
@@ -103,19 +104,25 @@ HAL_DMAHandle HAL_InitializeDMA(int32_t* status) {
return HAL_kInvalidHandle;
}
dma->aDMA->writeConfig_ExternalClock(false, status);
if (*status != 0) {
dmaHandles->Free(handle);
return HAL_kInvalidHandle;
std::memset(&dma->captureStore, 0, sizeof(dma->captureStore));
tDMA::tConfig config;
std::memset(&config, 0, sizeof(config));
config.Pause = true;
dma->aDMA->writeConfig(config, status);
dma->aDMA->writeRate(1, status);
tDMA::tExternalTriggers newTrigger;
std::memset(&newTrigger, 0, sizeof(newTrigger));
for (unsigned char reg = 0; reg < tDMA::kNumExternalTriggersRegisters;
reg++) {
for (unsigned char bit = 0; bit < tDMA::kNumExternalTriggersElements;
bit++) {
dma->aDMA->writeExternalTriggers(reg, bit, newTrigger, status);
}
}
HAL_SetDMARate(handle, 1, status);
if (*status != 0) {
dmaHandles->Free(handle);
return HAL_kInvalidHandle;
}
HAL_SetDMAPause(handle, false, status);
return handle;
}
@@ -139,20 +146,44 @@ void HAL_SetDMAPause(HAL_DMAHandle handle, HAL_Bool pause, int32_t* status) {
return;
}
if (!dma->manager) {
*status = HAL_INVALID_DMA_STATE;
return;
}
dma->aDMA->writeConfig_Pause(pause, status);
}
void HAL_SetDMARate(HAL_DMAHandle handle, int32_t cycles, int32_t* status) {
void HAL_SetDMATimedTrigger(HAL_DMAHandle handle, double seconds,
int32_t* status) {
constexpr double baseMultipler = kSystemClockTicksPerMicrosecond * 1000000;
uint32_t cycles = static_cast<uint32_t>(baseMultipler * seconds);
HAL_SetDMATimedTriggerCycles(handle, cycles, status);
}
void HAL_SetDMATimedTriggerCycles(HAL_DMAHandle handle, uint32_t cycles,
int32_t* status) {
auto dma = dmaHandles->Get(handle);
if (!dma) {
*status = HAL_HANDLE_ERROR;
return;
}
if (dma->manager) {
*status = HAL_INVALID_DMA_ADDITION;
return;
}
if (cycles < 1) {
cycles = 1;
}
dma->aDMA->writeRate(static_cast<uint32_t>(cycles), status);
dma->aDMA->writeConfig_ExternalClock(false, status);
if (*status != 0) {
return;
}
dma->aDMA->writeRate(cycles, status);
}
void HAL_AddDMAEncoder(HAL_DMAHandle handle, HAL_EncoderHandle encoderHandle,
@@ -477,20 +508,20 @@ void HAL_AddDMAAnalogAccumulator(HAL_DMAHandle handle,
}
}
void HAL_SetDMAExternalTrigger(HAL_DMAHandle handle,
HAL_Handle digitalSourceHandle,
HAL_AnalogTriggerType analogTriggerType,
HAL_Bool rising, HAL_Bool falling,
int32_t* status) {
int32_t HAL_SetDMAExternalTrigger(HAL_DMAHandle handle,
HAL_Handle digitalSourceHandle,
HAL_AnalogTriggerType analogTriggerType,
HAL_Bool rising, HAL_Bool falling,
int32_t* status) {
auto dma = dmaHandles->Get(handle);
if (!dma) {
*status = HAL_HANDLE_ERROR;
return;
return 0;
}
if (dma->manager) {
*status = HAL_INVALID_DMA_ADDITION;
return;
return 0;
}
int index = 0;
@@ -504,21 +535,21 @@ void HAL_SetDMAExternalTrigger(HAL_DMAHandle handle,
if (index == 8) {
*status = NO_AVAILABLE_RESOURCES;
return;
return 0;
}
dma->captureStore.triggerChannels |= (1 << index);
auto channelIndex = index;
auto isExternalClock = dma->aDMA->readConfig_ExternalClock(status);
if (*status == 0 && !isExternalClock) {
dma->aDMA->writeConfig_ExternalClock(true, status);
if (*status != 0) {
return;
}
} else if (*status != 0) {
return;
dma->aDMA->writeConfig_ExternalClock(true, status);
if (*status != 0) {
return 0;
}
dma->aDMA->writeRate(1, status);
if (*status != 0) {
return 0;
}
uint8_t pin = 0;
@@ -532,7 +563,7 @@ void HAL_SetDMAExternalTrigger(HAL_DMAHandle handle,
hal::SetLastError(status,
"Digital Source unabled to be mapped properly. Likely "
"invalid handle passed.");
return;
return 0;
}
tDMA::tExternalTriggers newTrigger;
@@ -544,6 +575,55 @@ void HAL_SetDMAExternalTrigger(HAL_DMAHandle handle,
dma->aDMA->writeExternalTriggers(channelIndex / 4, channelIndex % 4,
newTrigger, status);
return index;
}
void HAL_ClearDMASensors(HAL_DMAHandle handle, int32_t* status) {
auto dma = dmaHandles->Get(handle);
if (!dma) {
*status = HAL_HANDLE_ERROR;
return;
}
if (dma->manager) {
*status = HAL_INVALID_DMA_STATE;
return;
}
bool existingExternal = dma->aDMA->readConfig_ExternalClock(status);
if (*status != 0) {
return;
}
tDMA::tConfig config;
std::memset(&config, 0, sizeof(config));
config.Pause = true;
config.ExternalClock = existingExternal;
dma->aDMA->writeConfig(config, status);
}
void HAL_ClearDMAExternalTriggers(HAL_DMAHandle handle, int32_t* status) {
auto dma = dmaHandles->Get(handle);
if (!dma) {
*status = HAL_HANDLE_ERROR;
return;
}
if (dma->manager) {
*status = HAL_INVALID_DMA_STATE;
return;
}
dma->captureStore.triggerChannels = 0;
tDMA::tExternalTriggers newTrigger;
std::memset(&newTrigger, 0, sizeof(newTrigger));
for (unsigned char reg = 0; reg < tDMA::kNumExternalTriggersRegisters;
reg++) {
for (unsigned char bit = 0; bit < tDMA::kNumExternalTriggersElements;
bit++) {
dma->aDMA->writeExternalTriggers(reg, bit, newTrigger, status);
}
}
}
void HAL_StartDMA(HAL_DMAHandle handle, int32_t queueDepth, int32_t* status) {
@@ -554,7 +634,7 @@ void HAL_StartDMA(HAL_DMAHandle handle, int32_t queueDepth, int32_t* status) {
}
if (dma->manager) {
*status = INCOMPATIBLE_STATE;
*status = HAL_INVALID_DMA_STATE;
return;
}
@@ -598,12 +678,15 @@ void HAL_StartDMA(HAL_DMAHandle handle, int32_t queueDepth, int32_t* status) {
dma->captureStore.captureSize = accum_size + 1;
}
dma->manager = std::make_unique<tDMAManager>(
g_DMA_index, queueDepth * dma->captureStore.captureSize, status);
uint32_t byteDepth = queueDepth * dma->captureStore.captureSize;
dma->manager = std::make_unique<tDMAManager>(g_DMA_index, byteDepth, status);
if (*status != 0) {
return;
}
dma->aDMA->writeConfig_Pause(false, status);
dma->manager->start(status);
dma->manager->stop(status);
dma->manager->start(status);
@@ -617,6 +700,8 @@ void HAL_StopDMA(HAL_DMAHandle handle, int32_t* status) {
}
if (dma->manager) {
dma->aDMA->writeConfig_Pause(true, status);
*status = 0;
dma->manager->stop(status);
dma->manager = nullptr;
}
@@ -629,7 +714,7 @@ void* HAL_GetDMADirectPointer(HAL_DMAHandle handle) {
enum HAL_DMAReadStatus HAL_ReadDMADirect(void* dmaPointer,
HAL_DMASample* dmaSample,
int32_t timeoutMs,
double timeoutSeconds,
int32_t* remainingOut,
int32_t* status) {
DMA* dma = static_cast<DMA*>(dmaPointer);
@@ -637,12 +722,13 @@ enum HAL_DMAReadStatus HAL_ReadDMADirect(void* dmaPointer,
size_t remainingBytes = 0;
if (!dma->manager) {
*status = INCOMPATIBLE_STATE;
*status = HAL_INVALID_DMA_STATE;
return HAL_DMA_ERROR;
}
dma->manager->read(dmaSample->readBuffer, dma->captureStore.captureSize,
timeoutMs, &remainingBytes, status);
static_cast<uint32_t>(timeoutSeconds * 1000),
&remainingBytes, status);
*remainingOut = remainingBytes / dma->captureStore.captureSize;
@@ -667,15 +753,16 @@ enum HAL_DMAReadStatus HAL_ReadDMADirect(void* dmaPointer,
}
enum HAL_DMAReadStatus HAL_ReadDMA(HAL_DMAHandle handle,
HAL_DMASample* dmaSample, int32_t timeoutMs,
int32_t* remainingOut, int32_t* status) {
HAL_DMASample* dmaSample,
double timeoutSeconds, int32_t* remainingOut,
int32_t* status) {
auto dma = dmaHandles->Get(handle);
if (!dma) {
*status = HAL_HANDLE_ERROR;
return HAL_DMA_ERROR;
}
return HAL_ReadDMADirect(dma.get(), dmaSample, timeoutMs, remainingOut,
return HAL_ReadDMADirect(dma.get(), dmaSample, timeoutSeconds, remainingOut,
status);
}

View File

@@ -165,9 +165,17 @@ bool remapDigitalSource(HAL_Handle digitalSourceHandle,
}
analogTrigger = false;
return true;
} else {
return false;
} else if (isHandleType(digitalSourceHandle, HAL_HandleEnum::PWM)) {
// PWM's on MXP port are supported as a digital source
int32_t index = getHandleIndex(digitalSourceHandle);
if (index >= kNumPWMHeaders) {
channel = remapMXPPWMChannel(index);
module = 1;
analogTrigger = false;
return true;
}
}
return false;
}
int32_t remapMXPChannel(int32_t channel) {

View File

@@ -254,7 +254,7 @@ bool GetEncoderBaseHandle(HAL_EncoderHandle handle,
HAL_FPGAEncoderHandle* fpgaHandle,
HAL_CounterHandle* counterHandle) {
auto encoder = encoderHandles->Get(handle);
if (!handle) {
if (!encoder) {
return false;
}

View File

@@ -219,6 +219,10 @@ const char* HAL_GetErrorMessage(int32_t code) {
return HAL_CAN_BUFFER_OVERRUN_MESSAGE;
case HAL_LED_CHANNEL_ERROR:
return HAL_LED_CHANNEL_ERROR_MESSAGE;
case HAL_INVALID_DMA_STATE:
return HAL_INVALID_DMA_STATE_MESSAGE;
case HAL_INVALID_DMA_ADDITION:
return HAL_INVALID_DMA_ADDITION_MESSAGE;
case HAL_USE_LAST_ERROR:
return HAL_USE_LAST_ERROR_MESSAGE;
default:

View File

@@ -296,6 +296,22 @@ Java_edu_wpi_first_hal_AnalogJNI_getAnalogVoltsToValue
return returnValue;
}
/*
* Class: edu_wpi_first_hal_AnalogJNI
* Method: getAnalogValueToVolts
* Signature: (II)D
*/
JNIEXPORT jdouble JNICALL
Java_edu_wpi_first_hal_AnalogJNI_getAnalogValueToVolts
(JNIEnv* env, jclass, jint id, jint rawValue)
{
int32_t status = 0;
jdouble returnValue =
HAL_GetAnalogValueToVolts((HAL_AnalogInputHandle)id, rawValue, &status);
CheckStatus(env, status);
return returnValue;
}
/*
* Class: edu_wpi_first_hal_AnalogJNI
* Method: getAnalogVoltage

View File

@@ -0,0 +1,416 @@
// 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.
#include <algorithm>
#include <cstring>
#include "HALUtil.h"
#include "edu_wpi_first_hal_DMAJNI.h"
#include "hal/DMA.h"
#include "hal/handles/HandlesInternal.h"
using namespace hal;
namespace hal {
bool GetEncoderBaseHandle(HAL_EncoderHandle handle,
HAL_FPGAEncoderHandle* fpgaEncoderHandle,
HAL_CounterHandle* counterHandle);
} // namespace hal
extern "C" {
/*
* Class: edu_wpi_first_hal_DMAJNI
* Method: initialize
* Signature: ()I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_DMAJNI_initialize
(JNIEnv* env, jclass)
{
int32_t status = 0;
auto handle = HAL_InitializeDMA(&status);
CheckStatusForceThrow(env, status);
return handle;
}
/*
* Class: edu_wpi_first_hal_DMAJNI
* Method: free
* Signature: (I)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_DMAJNI_free
(JNIEnv* env, jclass, jint handle)
{
HAL_FreeDMA(handle);
}
/*
* Class: edu_wpi_first_hal_DMAJNI
* Method: setPause
* Signature: (IZ)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_DMAJNI_setPause
(JNIEnv* env, jclass, jint handle, jboolean pause)
{
int32_t status = 0;
HAL_SetDMAPause(handle, pause, &status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_DMAJNI
* Method: setTimedTrigger
* Signature: (ID)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_DMAJNI_setTimedTrigger
(JNIEnv* env, jclass, jint handle, jdouble seconds)
{
int32_t status = 0;
HAL_SetDMATimedTrigger(handle, seconds, &status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_DMAJNI
* Method: setTimedTriggerCycles
* Signature: (II)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_DMAJNI_setTimedTriggerCycles
(JNIEnv* env, jclass, jint handle, jint cycles)
{
int32_t status = 0;
HAL_SetDMATimedTriggerCycles(handle, static_cast<uint32_t>(cycles), &status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_DMAJNI
* Method: addEncoder
* Signature: (II)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_DMAJNI_addEncoder
(JNIEnv* env, jclass, jint handle, jint encoderHandle)
{
int32_t status = 0;
HAL_AddDMAEncoder(handle, encoderHandle, &status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_DMAJNI
* Method: addEncoderPeriod
* Signature: (II)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_DMAJNI_addEncoderPeriod
(JNIEnv* env, jclass, jint handle, jint encoderHandle)
{
int32_t status = 0;
HAL_AddDMAEncoderPeriod(handle, encoderHandle, &status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_DMAJNI
* Method: addCounter
* Signature: (II)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_DMAJNI_addCounter
(JNIEnv* env, jclass, jint handle, jint counterHandle)
{
int32_t status = 0;
HAL_AddDMACounter(handle, counterHandle, &status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_DMAJNI
* Method: addCounterPeriod
* Signature: (II)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_DMAJNI_addCounterPeriod
(JNIEnv* env, jclass, jint handle, jint counterHandle)
{
int32_t status = 0;
HAL_AddDMACounterPeriod(handle, counterHandle, &status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_DMAJNI
* Method: addDutyCycle
* Signature: (II)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_DMAJNI_addDutyCycle
(JNIEnv* env, jclass, jint handle, jint dutyCycleHandle)
{
int32_t status = 0;
HAL_AddDMADutyCycle(handle, dutyCycleHandle, &status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_DMAJNI
* Method: addDigitalSource
* Signature: (II)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_DMAJNI_addDigitalSource
(JNIEnv* env, jclass, jint handle, jint digitalSourceHandle)
{
int32_t status = 0;
HAL_AddDMADigitalSource(handle, digitalSourceHandle, &status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_DMAJNI
* Method: addAnalogInput
* Signature: (II)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_DMAJNI_addAnalogInput
(JNIEnv* env, jclass, jint handle, jint analogInputHandle)
{
int32_t status = 0;
HAL_AddDMAAnalogInput(handle, analogInputHandle, &status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_DMAJNI
* Method: addAveragedAnalogInput
* Signature: (II)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_DMAJNI_addAveragedAnalogInput
(JNIEnv* env, jclass, jint handle, jint analogInputHandle)
{
int32_t status = 0;
HAL_AddDMAAveragedAnalogInput(handle, analogInputHandle, &status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_DMAJNI
* Method: addAnalogAccumulator
* Signature: (II)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_DMAJNI_addAnalogAccumulator
(JNIEnv* env, jclass, jint handle, jint analogInputHandle)
{
int32_t status = 0;
HAL_AddDMAAnalogAccumulator(handle, analogInputHandle, &status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_DMAJNI
* Method: setExternalTrigger
* Signature: (IIIZZ)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_DMAJNI_setExternalTrigger
(JNIEnv* env, jclass, jint handle, jint digitalSourceHandle,
jint analogTriggerType, jboolean rising, jboolean falling)
{
int32_t status = 0;
int32_t idx = HAL_SetDMAExternalTrigger(
handle, digitalSourceHandle,
static_cast<HAL_AnalogTriggerType>(analogTriggerType), rising, falling,
&status);
CheckStatus(env, status);
return idx;
}
/*
* Class: edu_wpi_first_hal_DMAJNI
* Method: clearSensors
* Signature: (I)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_DMAJNI_clearSensors
(JNIEnv* env, jclass, jint handle)
{
int32_t status = 0;
HAL_ClearDMASensors(handle, &status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_DMAJNI
* Method: clearExternalTriggers
* Signature: (I)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_DMAJNI_clearExternalTriggers
(JNIEnv* env, jclass, jint handle)
{
int32_t status = 0;
HAL_ClearDMAExternalTriggers(handle, &status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_DMAJNI
* Method: startDMA
* Signature: (II)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_DMAJNI_startDMA
(JNIEnv* env, jclass, jint handle, jint queueDepth)
{
int32_t status = 0;
HAL_StartDMA(handle, queueDepth, &status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_DMAJNI
* Method: stopDMA
* Signature: (I)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_DMAJNI_stopDMA
(JNIEnv* env, jclass, jint handle)
{
int32_t status = 0;
HAL_StopDMA(handle, &status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_DMAJNI
* Method: readDMA
* Signature: (ID[I[I)J
*/
JNIEXPORT jlong JNICALL
Java_edu_wpi_first_hal_DMAJNI_readDMA
(JNIEnv* env, jclass, jint handle, jdouble timeoutSeconds, jintArray buf,
jintArray store)
{
int32_t status = 0;
HAL_DMASample dmaSample;
std::memset(&dmaSample, 0, sizeof(dmaSample));
int32_t remaining = 0;
HAL_DMAReadStatus readStatus =
HAL_ReadDMA(handle, &dmaSample, timeoutSeconds, &remaining, &status);
CheckStatus(env, status);
static_assert(sizeof(uint32_t) == sizeof(jint), "Java ints must be 32 bits");
env->SetIntArrayRegion(buf, 0, dmaSample.captureSize,
reinterpret_cast<jint*>(dmaSample.readBuffer));
int32_t* nativeArr =
static_cast<int32_t*>(env->GetPrimitiveArrayCritical(store, nullptr));
std::copy_n(
dmaSample.channelOffsets,
sizeof(dmaSample.channelOffsets) / sizeof(dmaSample.channelOffsets[0]),
nativeArr);
nativeArr[22] = static_cast<int32_t>(dmaSample.captureSize);
nativeArr[23] = static_cast<int32_t>(dmaSample.triggerChannels);
nativeArr[24] = remaining;
nativeArr[25] = readStatus;
env->ReleasePrimitiveArrayCritical(store, nativeArr, JNI_ABORT);
return dmaSample.timeStamp;
}
// TODO sync these up
enum DMAOffsetConstants {
kEnable_AI0_Low = 0,
kEnable_AI0_High = 1,
kEnable_AIAveraged0_Low = 2,
kEnable_AIAveraged0_High = 3,
kEnable_AI1_Low = 4,
kEnable_AI1_High = 5,
kEnable_AIAveraged1_Low = 6,
kEnable_AIAveraged1_High = 7,
kEnable_Accumulator0 = 8,
kEnable_Accumulator1 = 9,
kEnable_DI = 10,
kEnable_AnalogTriggers = 11,
kEnable_Counters_Low = 12,
kEnable_Counters_High = 13,
kEnable_CounterTimers_Low = 14,
kEnable_CounterTimers_High = 15,
kEnable_Encoders_Low = 16,
kEnable_Encoders_High = 17,
kEnable_EncoderTimers_Low = 18,
kEnable_EncoderTimers_High = 19,
kEnable_DutyCycle_Low = 20,
kEnable_DutyCycle_High = 21,
};
/*
* Class: edu_wpi_first_hal_DMAJNI
* Method: getSensorReadData
* Signature: (I)Ljava/lang/Object;
*/
JNIEXPORT jobject JNICALL
Java_edu_wpi_first_hal_DMAJNI_getSensorReadData
(JNIEnv* env, jclass, jint handle)
{
HAL_Handle halHandle = static_cast<HAL_Handle>(handle);
// Check for encoder/counter handle
HAL_FPGAEncoderHandle fpgaEncoderHandle = 0;
HAL_CounterHandle counterHandle = 0;
bool validEncoderHandle =
hal::GetEncoderBaseHandle(halHandle, &fpgaEncoderHandle, &counterHandle);
if (validEncoderHandle) {
if (counterHandle != HAL_kInvalidHandle) {
int32_t cindex = getHandleIndex(counterHandle);
if (cindex < 4) {
return CreateDMABaseStore(env, kEnable_Counters_Low, cindex);
} else {
return CreateDMABaseStore(env, kEnable_Counters_High, cindex - 4);
}
} else {
int32_t cindex = getHandleIndex(fpgaEncoderHandle);
if (cindex < 4) {
return CreateDMABaseStore(env, kEnable_Encoders_Low, cindex);
} else {
return CreateDMABaseStore(env, kEnable_Encoders_High, cindex - 4);
}
}
}
HAL_HandleEnum handleType = getHandleType(halHandle);
int32_t index = getHandleIndex(halHandle);
if (handleType == HAL_HandleEnum::DIO) {
return CreateDMABaseStore(env, kEnable_DI, index);
} else if (handleType == HAL_HandleEnum::AnalogTrigger) {
return CreateDMABaseStore(env, kEnable_AnalogTriggers, index);
} else if (handleType == HAL_HandleEnum::AnalogInput) {
if (index < 4) {
return CreateDMABaseStore(env, kEnable_AI0_Low, index);
} else {
return CreateDMABaseStore(env, kEnable_AI0_High, index - 4);
}
} else if (handleType == HAL_HandleEnum::DutyCycle) {
if (index < 4) {
return CreateDMABaseStore(env, kEnable_DutyCycle_Low, index);
} else {
return CreateDMABaseStore(env, kEnable_DutyCycle_High, index - 4);
}
} else {
return nullptr;
}
}
} // extern "C"

View File

@@ -46,6 +46,7 @@ static JClass matchInfoDataCls;
static JClass accumulatorResultCls;
static JClass canDataCls;
static JClass halValueCls;
static JClass baseStoreCls;
static const JClassInit classes[] = {
{"edu/wpi/first/hal/PWMConfigDataResult", &pwmConfigDataResultCls},
@@ -53,7 +54,8 @@ static const JClassInit classes[] = {
{"edu/wpi/first/hal/MatchInfoData", &matchInfoDataCls},
{"edu/wpi/first/hal/AccumulatorResult", &accumulatorResultCls},
{"edu/wpi/first/hal/CANData", &canDataCls},
{"edu/wpi/first/hal/HALValue", &halValueCls}};
{"edu/wpi/first/hal/HALValue", &halValueCls},
{"edu/wpi/first/hal/DMAJNISample$BaseStore", &baseStoreCls}};
static const JExceptionInit exceptions[] = {
{"java/lang/IllegalArgumentException", &illegalArgExCls},
@@ -305,6 +307,11 @@ jobject CreateHALValue(JNIEnv* env, const HAL_Value& value) {
halValueCls, fromNative, static_cast<jint>(value.type), value1, value2);
}
jobject CreateDMABaseStore(JNIEnv* env, jint valueType, jint index) {
static jmethodID ctor = env->GetMethodID(baseStoreCls, "<init>", "(II)V");
return env->NewObject(baseStoreCls, ctor, valueType, index);
}
JavaVM* GetJVM() {
return jvm;
}

View File

@@ -75,6 +75,8 @@ jbyteArray SetCANDataObject(JNIEnv* env, jobject canData, int32_t length,
jobject CreateHALValue(JNIEnv* env, const HAL_Value& value);
jobject CreateDMABaseStore(JNIEnv* env, jint valueType, jint index);
JavaVM* GetJVM();
} // namespace hal

View File

@@ -62,7 +62,7 @@ void HAL_SetCounterAverageSize(HAL_CounterHandle counterHandle, int32_t size,
*
* @param counterHandle the counter handle
* @param digitalSourceHandle the digital source handle (either a
* HAL_AnalogTriggerHandle of a HAL_DigitalHandle)
* HAL_AnalogTriggerHandle or a HAL_DigitalHandle)
* @param analogTriggerType the analog trigger type if the source is an analog
* trigger
*/
@@ -96,7 +96,7 @@ void HAL_ClearCounterUpSource(HAL_CounterHandle counterHandle, int32_t* status);
*
* @param counterHandle the counter handle
* @param digitalSourceHandle the digital source handle (either a
* HAL_AnalogTriggerHandle of a HAL_DigitalHandle)
* HAL_AnalogTriggerHandle or a HAL_DigitalHandle)
* @param analogTriggerType the analog trigger type if the source is an analog
* trigger
*/

View File

@@ -4,22 +4,29 @@
#pragma once
#include <stdint.h>
#include "hal/AnalogTrigger.h"
#include "hal/Types.h"
/**
* @defgroup hal_dma DMA Functions
* @ingroup hal_capi
* @{
*/
// clang-format off
/**
* The DMA Read Status.
*/
HAL_ENUM(HAL_DMAReadStatus ) {
HAL_ENUM(HAL_DMAReadStatus) {
HAL_DMA_OK = 1,
HAL_DMA_TIMEOUT = 2,
HAL_DMA_ERROR = 3,
};
// clang-format on
/**
* Buffer for containing all DMA data for a specific sample.
*/
struct HAL_DMASample {
uint32_t readBuffer[74];
int32_t channelOffsets[22];
@@ -32,91 +39,380 @@ struct HAL_DMASample {
extern "C" {
#endif
/**
* Initializes an object for peforming DMA transfers.
*
* @return the created dma handle
*/
HAL_DMAHandle HAL_InitializeDMA(int32_t* status);
/**
* Frees a DMA object.
*
* @param handle the dma handle
*/
void HAL_FreeDMA(HAL_DMAHandle handle);
/**
* Pauses or unpauses a DMA transfer.
*
* This can only be called while DMA is running.
*
* @param handle the dma handle
* @param pause true to pause transfers, false to resume.
*/
void HAL_SetDMAPause(HAL_DMAHandle handle, HAL_Bool pause, int32_t* status);
void HAL_SetDMARate(HAL_DMAHandle handle, int32_t cycles, int32_t* status);
/**
* Sets DMA transfers to occur at a specific timed interval.
*
* This will remove any external triggers. Only timed or external is supported.
*
* Only 1 timed period is supported.
*
* This can only be called if DMA is not started.
*
* @param handle the dma handle
* @param periodSeconds the period to trigger in seconds
*/
void HAL_SetDMATimedTrigger(HAL_DMAHandle handle, double periodSeconds,
int32_t* status);
/**
* Sets DMA transfers to occur at a specific timed interval in FPGA cycles.
*
* This will remove any external triggers. Only timed or external is supported.
*
* Only 1 timed period is supported
*
* The FPGA currently runs at 40 MHz, but this can change.
* HAL_GetSystemClockTicksPerMicrosecond can be used to get a computable value
* for this.
*
* This can only be called if DMA is not started.
*
* @param handle the dma handle
* @param cycles the period to trigger in FPGA cycles
*/
void HAL_SetDMATimedTriggerCycles(HAL_DMAHandle handle, uint32_t cycles,
int32_t* status);
/**
* Adds position data for an encoder to be collected by DMA.
*
* This can only be called if DMA is not started.
*
* @param handle the dma handle
* @param encoderHandle the encoder to add
*/
void HAL_AddDMAEncoder(HAL_DMAHandle handle, HAL_EncoderHandle encoderHandle,
int32_t* status);
/**
* Adds timer data for an encoder to be collected by DMA.
*
* This can only be called if DMA is not started.
*
* @param handle the dma handle
* @param encoderHandle the encoder to add
*/
void HAL_AddDMAEncoderPeriod(HAL_DMAHandle handle,
HAL_EncoderHandle encoderHandle, int32_t* status);
/**
* Adds position data for an counter to be collected by DMA.
*
* This can only be called if DMA is not started.
*
* @param handle the dma handle
* @param counterHandle the counter to add
*/
void HAL_AddDMACounter(HAL_DMAHandle handle, HAL_CounterHandle counterHandle,
int32_t* status);
/**
* Adds timer data for an counter to be collected by DMA.
*
* @param handle the dma handle
* @param counterHandle the counter to add
*/
void HAL_AddDMACounterPeriod(HAL_DMAHandle handle,
HAL_CounterHandle counterHandle, int32_t* status);
/**
* Adds a digital source to be collected by DMA.
*
* This can only be called if DMA is not started.
*
* @param handle the dma handle
* @param digitalSourceHandle the digital source to add
*/
void HAL_AddDMADigitalSource(HAL_DMAHandle handle,
HAL_Handle digitalSourceHandle, int32_t* status);
/**
* Adds an analog input to be collected by DMA.
*
* This can only be called if DMA is not started.
*
* @param handle the dma handle
* @param aInHandle the analog input to add
*/
void HAL_AddDMAAnalogInput(HAL_DMAHandle handle,
HAL_AnalogInputHandle aInHandle, int32_t* status);
/**
* Adds averaged data of an analog input to be collected by DMA.
*
* This can only be called if DMA is not started.
*
* @param handle the dma handle
* @param aInHandle the analog input to add
*/
void HAL_AddDMAAveragedAnalogInput(HAL_DMAHandle handle,
HAL_AnalogInputHandle aInHandle,
int32_t* status);
/**
* Adds acuumulator data of an analog input to be collected by DMA.
*
* This can only be called if DMA is not started.
*
* @param handle the dma handle
* @param aInHandle the analog input to add
*/
void HAL_AddDMAAnalogAccumulator(HAL_DMAHandle handle,
HAL_AnalogInputHandle aInHandle,
int32_t* status);
/**
* Adds a duty cycle input to be collected by DMA.
*
* This can only be called if DMA is not started.
*
* @param handle the dma handle
* @param dutyCycleHandle the duty cycle input to add
*/
void HAL_AddDMADutyCycle(HAL_DMAHandle handle,
HAL_DutyCycleHandle dutyCycleHandle, int32_t* status);
void HAL_SetDMAExternalTrigger(HAL_DMAHandle handle,
HAL_Handle digitalSourceHandle,
HAL_AnalogTriggerType analogTriggerType,
HAL_Bool rising, HAL_Bool falling,
int32_t* status);
/**
* Sets DMA transfers to occur on an external trigger.
*
* This will remove any timed trigger set. Only timed or external is supported.
*
* Up to 8 external triggers are currently supported.
*
* This can only be called if DMA is not started.
*
* @param handle the dma handle
* @param digitalSourceHandle the digital source handle (either a
* HAL_AnalogTriggerHandle or a HAL_DigitalHandle)
* @param analogTriggerType the analog trigger type if the source is an analog
* trigger
* @param risingEdge true to trigger on rising
* @param fallingEdge true to trigger on falling
* @return the index of the trigger
*/
int32_t HAL_SetDMAExternalTrigger(HAL_DMAHandle handle,
HAL_Handle digitalSourceHandle,
HAL_AnalogTriggerType analogTriggerType,
HAL_Bool rising, HAL_Bool falling,
int32_t* status);
/**
* Clear all sensors from the DMA collection list.
*
* This can only be called if DMA is not started.
*
* @param handle the dma handle
*/
void HAL_ClearDMASensors(HAL_DMAHandle handle, int32_t* status);
/**
* Clear all external triggers from the DMA trigger list.
*
* This can only be called if DMA is not started.
*
* @param handle the dma handle
*/
void HAL_ClearDMAExternalTriggers(HAL_DMAHandle handle, int32_t* status);
/**
* Starts DMA Collection.
*
* @param handle the dma handle
* @param queueDepth the number of objects to be able to queue
*/
void HAL_StartDMA(HAL_DMAHandle handle, int32_t queueDepth, int32_t* status);
/**
* Stops DMA Collection.
*
* @param handle the dma handle
*/
void HAL_StopDMA(HAL_DMAHandle handle, int32_t* status);
/**
* Gets the direct pointer to the DMA object.
*
* This is only to be used if absolute maximum performance is required. This
* will only be valid until the handle is freed.
*
* @param handle the dma handle
*/
void* HAL_GetDMADirectPointer(HAL_DMAHandle handle);
/**
* Reads a DMA sample using a direct DMA pointer.
*
* See HAL_ReadDMA for full documentation.
*
* @param handle the dma handle
*/
enum HAL_DMAReadStatus HAL_ReadDMADirect(void* dmaPointer,
HAL_DMASample* dmaSample,
int32_t timeoutMs,
double timeoutSeconds,
int32_t* remainingOut,
int32_t* status);
/**
* Reads a DMA sample from the queue.
*
*
* @param handle the dma handle
* @param dmaSample the sample object to place data into
* @param timeoutSeconds the time to wait for data to be queued before timing
* out
* @param remainingOut the number of samples remaining in the queue
* @return the succes result of the sample read
*/
enum HAL_DMAReadStatus HAL_ReadDMA(HAL_DMAHandle handle,
HAL_DMASample* dmaSample, int32_t timeoutMs,
int32_t* remainingOut, int32_t* status);
HAL_DMASample* dmaSample,
double timeoutSeconds, int32_t* remainingOut,
int32_t* status);
// Sampling Code
// The following are helper functions for reading data from samples
/**
* Returns the timestamp of the sample.
* This is in the same time domain as HAL_GetFPGATime().
*
* @param dmaSample the sample to read from
* @return timestamp in microseconds since FPGA Initialization
*/
uint64_t HAL_GetDMASampleTime(const HAL_DMASample* dmaSample, int32_t* status);
/**
* Returns the raw distance data for an encoder from the sample.
*
* This can be scaled with DistancePerPulse and DecodingScaleFactor to match the
* result of GetDistance()
*
* @param dmaSample the sample to read from
* @param encoderHandle the encoder handle
* @return raw encoder ticks
*/
int32_t HAL_GetDMASampleEncoderRaw(const HAL_DMASample* dmaSample,
HAL_EncoderHandle encoderHandle,
int32_t* status);
/**
* Returns the distance data for an counter from the sample.
*
* @param dmaSample the sample to read from
* @param counterHandle the counter handle
* @return counter ticks
*/
int32_t HAL_GetDMASampleCounter(const HAL_DMASample* dmaSample,
HAL_CounterHandle counterHandle,
int32_t* status);
/**
* Returns the raw period data for an encoder from the sample.
*
* This can be scaled with DistancePerPulse and DecodingScaleFactor to match the
* result of GetRate()
*
* @param dmaSample the sample to read from
* @param encoderHandle the encoder handle
* @return raw encoder period
*/
int32_t HAL_GetDMASampleEncoderPeriodRaw(const HAL_DMASample* dmaSample,
HAL_EncoderHandle encoderHandle,
int32_t* status);
/**
* Returns the period data for an counter from the sample.
*
* @param dmaSample the sample to read from
* @param counterHandle the counter handle
* @return counter period
*/
int32_t HAL_GetDMASampleCounterPeriod(const HAL_DMASample* dmaSample,
HAL_CounterHandle counterHandle,
int32_t* status);
/**
* Returns the state of a digital source from the sample.
*
* @param dmaSample the sample to read from
* @param dSourceHandle the digital source handle
* @return digital source state
*/
HAL_Bool HAL_GetDMASampleDigitalSource(const HAL_DMASample* dmaSample,
HAL_Handle dSourceHandle,
int32_t* status);
/**
* Returns the raw analog data for an analog input from the sample.
*
* This can be scaled with HAL_GetAnalogValueToVolts to match GetVoltage().
*
* @param dmaSample the sample to read from
* @param aInHandle the analog input handle
* @return raw analog data
*/
int32_t HAL_GetDMASampleAnalogInputRaw(const HAL_DMASample* dmaSample,
HAL_AnalogInputHandle aInHandle,
int32_t* status);
/**
* Returns the raw averaged analog data for an analog input from the sample.
*
* This can be scaled with HAL_GetAnalogValueToVolts to match
* GetAveragedVoltage().
*
* @param dmaSample the sample to read from
* @param aInHandle the analog input handle
* @return raw averaged analog data
*/
int32_t HAL_GetDMASampleAveragedAnalogInputRaw(const HAL_DMASample* dmaSample,
HAL_AnalogInputHandle aInHandle,
int32_t* status);
/**
* Returns the analog accumulator data for an analog input from the sample.
*
* @param dmaSample the sample to read from
* @param aInHandle the analog input handle
* @param count the accumulator count
* @param value the accumulator value
*/
void HAL_GetDMASampleAnalogAccumulator(const HAL_DMASample* dmaSample,
HAL_AnalogInputHandle aInHandle,
int64_t* count, int64_t* value,
int32_t* status);
/**
* Returns the raw duty cycle input ratio data from the sample.
*
* Use HAL_GetDutyCycleOutputScaleFactor to scale this to a percentage.
*
* @param dmaSample the sample to read from
* @param dutyCycleHandle the duty cycle handle
* @return raw duty cycle input data
*/
int32_t HAL_GetDMASampleDutyCycleOutputRaw(const HAL_DMASample* dmaSample,
HAL_DutyCycleHandle dutyCycleHandle,
int32_t* status);
@@ -124,3 +420,4 @@ int32_t HAL_GetDMASampleDutyCycleOutputRaw(const HAL_DMASample* dmaSample,
#ifdef __cplusplus
} // extern "C"
#endif
/** @} */

View File

@@ -254,7 +254,7 @@ int32_t HAL_GetEncoderSamplesToAverage(HAL_EncoderHandle encoderHandle,
*
* @param encoderHandle the encoder handle
* @param digitalSourceHandle the index source handle (either a
* HAL_AnalogTriggerHandle of a HAL_DigitalHandle)
* HAL_AnalogTriggerHandle or a HAL_DigitalHandle)
* @param analogTriggerType the analog trigger type if the source is an analog
* trigger
* @param type the index triggering type

View File

@@ -101,6 +101,10 @@
#define HAL_INVALID_DMA_ADDITION_MESSAGE \
"HAL_AddDMA() only works before HAL_StartDMA()"
#define HAL_INVALID_DMA_STATE -1103
#define HAL_INVALID_DMA_STATE_MESSAGE \
"HAL_SetPause() only works before HAL_StartDMA()"
#define HAL_SERIAL_PORT_NOT_FOUND -1123
#define HAL_SERIAL_PORT_NOT_FOUND_MESSAGE \
"HAL: The specified serial port device was not found"

View File

@@ -78,7 +78,7 @@ int64_t HAL_ReadInterruptFallingTimestamp(HAL_InterruptHandle interruptHandle,
*
* @param interruptHandle the interrupt handle
* @param digitalSourceHandle the digital source handle (either a
* HAL_AnalogTriggerHandle of a HAL_DigitalHandle)
* HAL_AnalogTriggerHandle or a HAL_DigitalHandle)
* @param analogTriggerType the trigger type if the source is an AnalogTrigger
*/
void HAL_RequestInterrupts(HAL_InterruptHandle interruptHandle,

View File

@@ -11,7 +11,10 @@ HAL_DMAHandle HAL_InitializeDMA(int32_t* status) {
void HAL_FreeDMA(HAL_DMAHandle handle) {}
void HAL_SetDMAPause(HAL_DMAHandle handle, HAL_Bool pause, int32_t* status) {}
void HAL_SetDMARate(HAL_DMAHandle handle, int32_t cycles, int32_t* status) {}
void HAL_SetDMATimedTrigger(HAL_DMAHandle handle, double periodSeconds,
int32_t* status) {}
void HAL_SetDMATimedTriggerCycles(HAL_DMAHandle handle, uint32_t cycles,
int32_t* status) {}
void HAL_AddDMAEncoder(HAL_DMAHandle handle, HAL_EncoderHandle encoderHandle,
int32_t* status) {}
@@ -40,11 +43,16 @@ void HAL_AddDMADutyCycle(HAL_DMAHandle handle,
HAL_DutyCycleHandle dutyCycleHandle, int32_t* status) {
}
void HAL_SetDMAExternalTrigger(HAL_DMAHandle handle,
HAL_Handle digitalSourceHandle,
HAL_AnalogTriggerType analogTriggerType,
HAL_Bool rising, HAL_Bool falling,
int32_t* status) {}
int32_t HAL_SetDMAExternalTrigger(HAL_DMAHandle handle,
HAL_Handle digitalSourceHandle,
HAL_AnalogTriggerType analogTriggerType,
HAL_Bool rising, HAL_Bool falling,
int32_t* status) {
return 0;
}
void HAL_ClearDMASensors(HAL_DMAHandle handle, int32_t* status) {}
void HAL_ClearDMAExternalTriggers(HAL_DMAHandle handle, int32_t* status) {}
void HAL_StartDMA(HAL_DMAHandle handle, int32_t queueDepth, int32_t* status) {}
void HAL_StopDMA(HAL_DMAHandle handle, int32_t* status) {}
@@ -55,15 +63,16 @@ void* HAL_GetDMADirectPointer(HAL_DMAHandle handle) {
enum HAL_DMAReadStatus HAL_ReadDMADirect(void* dmaPointer,
HAL_DMASample* dmaSample,
int32_t timeoutMs,
double timeoutSeconds,
int32_t* remainingOut,
int32_t* status) {
return HAL_DMA_ERROR;
}
enum HAL_DMAReadStatus HAL_ReadDMA(HAL_DMAHandle handle,
HAL_DMASample* dmaSample, int32_t timeoutMs,
int32_t* remainingOut, int32_t* status) {
HAL_DMASample* dmaSample,
double timeoutSeconds, int32_t* remainingOut,
int32_t* status) {
return HAL_DMA_ERROR;
}

View File

@@ -18,6 +18,8 @@ using namespace hal;
namespace {
struct Encoder {
HAL_Handle nativeHandle;
HAL_FPGAEncoderHandle fpgaHandle;
HAL_CounterHandle counterHandle;
HAL_EncoderEncodingType encodingType;
double distancePerPulse;
uint8_t index;
@@ -46,6 +48,21 @@ void InitializeEncoder() {
}
} // namespace hal::init
namespace hal {
bool GetEncoderBaseHandle(HAL_EncoderHandle handle,
HAL_FPGAEncoderHandle* fpgaHandle,
HAL_CounterHandle* counterHandle) {
auto encoder = encoderHandles->Get(handle);
if (!handle) {
return false;
}
*fpgaHandle = encoder->fpgaHandle;
*counterHandle = encoder->counterHandle;
return true;
}
} // namespace hal
extern "C" {
HAL_EncoderHandle HAL_InitializeEncoder(
HAL_Handle digitalSourceHandleA, HAL_AnalogTriggerType analogTriggerTypeA,
@@ -86,6 +103,13 @@ HAL_EncoderHandle HAL_InitializeEncoder(
encoder->nativeHandle = nativeHandle;
encoder->encodingType = encodingType;
encoder->distancePerPulse = 1.0;
if (encodingType == HAL_EncoderEncodingType::HAL_Encoder_k4X) {
encoder->fpgaHandle = nativeHandle;
encoder->counterHandle = HAL_kInvalidHandle;
} else {
encoder->fpgaHandle = HAL_kInvalidHandle;
encoder->counterHandle = nativeHandle;
}
return handle;
}