Add AddressableLED (#2092)

This commit is contained in:
Thad House
2019-11-17 16:39:38 -08:00
committed by Peter Johnson
parent 59507b12dc
commit 8ed2059074
20 changed files with 991 additions and 3 deletions

View File

@@ -0,0 +1,277 @@
/*----------------------------------------------------------------------------*/
/* 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/AddressableLED.h"
#include <cstring>
#include <FRC_FPGA_ChipObject/fpgainterfacecapi/NiFpga_HMB.h>
#include "ConstantsInternal.h"
#include "DigitalInternal.h"
#include "PortsInternal.h"
#include "hal/ChipObject.h"
#include "hal/handles/HandlesInternal.h"
#include "hal/handles/LimitedHandleResource.h"
using namespace hal;
constexpr int32_t kMaxStringSize = 5460;
extern "C" {
NiFpga_Status NiFpga_ClientFunctionCall(NiFpga_Session session, uint32_t group,
uint32_t functionId,
const void* inBuffer,
size_t inBufferSize, void* outBuffer,
size_t outBufferSize);
} // extern "C"
namespace {
struct AddressableLED {
std::unique_ptr<tLED> led;
void* ledBuffer;
size_t ledBufferSize;
int32_t stringLength = 1;
};
} // namespace
static LimitedHandleResource<
HAL_AddressableLEDHandle, AddressableLED, kNumAddressableLEDs,
HAL_HandleEnum::AddressableLED>* addressableLEDHandles;
namespace hal {
namespace init {
void InitializeAddressableLED() {
static LimitedHandleResource<HAL_AddressableLEDHandle, AddressableLED,
kNumAddressableLEDs,
HAL_HandleEnum::AddressableLED>
alH;
addressableLEDHandles = &alH;
}
} // namespace init
} // namespace hal
// Shim for broken ChipObject function
static const uint32_t clientFeature_hostMemoryBuffer = 0;
static const uint32_t hostMemoryBufferFunction_open = 2;
// Input arguments for HMB open
struct AtomicHMBOpenInputs {
const char* memoryName;
};
// Output arguments for HMB open
struct AtomicHMBOpenOutputs {
size_t size;
void* virtualAddress;
};
static NiFpga_Status OpenHostMemoryBuffer(NiFpga_Session session,
const char* memoryName,
void** virtualAddress, size_t* size) {
struct AtomicHMBOpenOutputs outputs;
struct AtomicHMBOpenInputs inputs;
inputs.memoryName = memoryName;
NiFpga_Status retval = NiFpga_ClientFunctionCall(
session, clientFeature_hostMemoryBuffer, hostMemoryBufferFunction_open,
&inputs, sizeof(struct AtomicHMBOpenInputs), &outputs,
sizeof(struct AtomicHMBOpenOutputs));
if (NiFpga_IsError(retval)) {
return retval;
}
*virtualAddress = outputs.virtualAddress;
if (size != NULL) {
*size = outputs.size;
}
return retval;
}
extern "C" {
HAL_AddressableLEDHandle HAL_InitializeAddressableLED(
HAL_DigitalHandle outputPort, int32_t* status) {
auto digitalPort =
hal::digitalChannelHandles->Get(outputPort, hal::HAL_HandleEnum::PWM);
if (!digitalPort) {
*status = HAL_HANDLE_ERROR;
return HAL_kInvalidHandle;
}
auto handle = addressableLEDHandles->Allocate();
if (handle == HAL_kInvalidHandle) {
*status = NO_AVAILABLE_RESOURCES;
return HAL_kInvalidHandle;
}
auto led = addressableLEDHandles->Get(handle);
if (!led) {
*status = HAL_HANDLE_ERROR;
return HAL_kInvalidHandle;
}
led->led.reset(tLED::create(status));
if (*status != 0) {
addressableLEDHandles->Free(handle);
return HAL_kInvalidHandle;
}
led->led->writeOutputSelect(digitalPort->channel, status);
if (*status != 0) {
addressableLEDHandles->Free(handle);
return HAL_kInvalidHandle;
}
led->ledBuffer = nullptr;
led->ledBufferSize = 0;
uint32_t session = led->led->getSystemInterface()->getHandle();
*status = OpenHostMemoryBuffer(session, "HMB_0_LED", &led->ledBuffer,
&led->ledBufferSize);
if (*status != 0) {
addressableLEDHandles->Free(handle);
return HAL_kInvalidHandle;
}
return handle;
}
void HAL_FreeAddressableLED(HAL_AddressableLEDHandle handle) {
addressableLEDHandles->Free(handle);
}
void HAL_SetAddressableLEDOutputPort(HAL_AddressableLEDHandle handle,
HAL_DigitalHandle outputPort,
int32_t* status) {
auto digitalPort =
hal::digitalChannelHandles->Get(outputPort, hal::HAL_HandleEnum::PWM);
if (!digitalPort) {
*status = HAL_HANDLE_ERROR;
return;
}
auto led = addressableLEDHandles->Get(handle);
if (!led) {
*status = HAL_HANDLE_ERROR;
return;
}
led->led->writeOutputSelect(digitalPort->channel, status);
}
void HAL_SetAddressableLEDLength(HAL_AddressableLEDHandle handle,
int32_t length, int32_t* status) {
auto led = addressableLEDHandles->Get(handle);
if (!led) {
*status = HAL_HANDLE_ERROR;
return;
}
if (length > kMaxStringSize) {
*status = PARAMETER_OUT_OF_RANGE;
return;
}
led->led->strobeReset(status);
while (led->led->readPixelWriteIndex(status) != 0) {
}
if (*status != 0) {
return;
}
led->led->writeStringLength(length, status);
led->stringLength = length;
}
static_assert(sizeof(HAL_AddressableLEDData) == sizeof(uint32_t),
"LED Data must be 32 bit");
void HAL_WriteAddressableLEDData(HAL_AddressableLEDHandle handle,
const struct HAL_AddressableLEDData* data,
int32_t length, int32_t* status) {
auto led = addressableLEDHandles->Get(handle);
if (!led) {
*status = HAL_HANDLE_ERROR;
return;
}
if (length > led->stringLength) {
*status = PARAMETER_OUT_OF_RANGE;
return;
}
std::memcpy(led->ledBuffer, data, length * sizeof(HAL_AddressableLEDData));
asm("dmb");
led->led->strobeLoad(status);
}
void HAL_SetAddressableLEDBitTiming(HAL_AddressableLEDHandle handle,
int32_t lowTime0NanoSeconds,
int32_t highTime0NanoSeconds,
int32_t lowTime1NanoSeconds,
int32_t highTime1NanoSeconds,
int32_t* status) {
auto led = addressableLEDHandles->Get(handle);
if (!led) {
*status = HAL_HANDLE_ERROR;
return;
}
led->led->writeLowBitTickTiming(1, highTime0NanoSeconds / 25, status);
led->led->writeLowBitTickTiming(0, lowTime0NanoSeconds / 25, status);
led->led->writeHighBitTickTiming(1, highTime1NanoSeconds / 25, status);
led->led->writeHighBitTickTiming(0, lowTime1NanoSeconds / 25, status);
}
void HAL_SetAddressableLEDSyncTime(HAL_AddressableLEDHandle handle,
int32_t syncTimeMicroSeconds,
int32_t* status) {
auto led = addressableLEDHandles->Get(handle);
if (!led) {
*status = HAL_HANDLE_ERROR;
return;
}
led->led->writeSyncTiming(syncTimeMicroSeconds, status);
}
void HAL_StartAddressableLEDOutput(HAL_AddressableLEDHandle handle,
int32_t* status) {
auto led = addressableLEDHandles->Get(handle);
if (!led) {
*status = HAL_HANDLE_ERROR;
return;
}
led->led->strobeStart(status);
}
void HAL_StopAddressableLEDOutput(HAL_AddressableLEDHandle handle,
int32_t* status) {
auto led = addressableLEDHandles->Get(handle);
if (!led) {
*status = HAL_HANDLE_ERROR;
return;
}
led->led->strobeAbort(status);
}
} // 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. */
@@ -96,6 +96,20 @@ bool remapDigitalSource(HAL_Handle digitalSourceHandle,
HAL_AnalogTriggerType analogTriggerType,
uint8_t& channel, uint8_t& module, bool& analogTrigger);
/**
* Remap the Digital Channel to map to the bitfield channel of the FPGA
*/
constexpr int32_t remapDigitalChannelToBitfieldChannel(int32_t channel) {
// First 10 are headers
if (channel < kNumDigitalHeaders) return channel;
// 2nd group of 16 are mxp. So if mxp port, add 6, since they start at 10
else if (channel < kNumDigitalMXPChannels)
return channel + 6;
// Assume SPI, so remove MXP channels
else
return channel - kNumDigitalMXPChannels;
}
/**
* Map DIO channel numbers from their physical number (10 to 26) to their
* position in the bit field.

View File

@@ -42,6 +42,7 @@ using namespace hal;
namespace hal {
namespace init {
void InitializeHAL() {
InitializeAddressableLED();
InitializeAccelerometer();
InitializeAnalogAccumulator();
InitializeAnalogGyro();

View File

@@ -19,6 +19,7 @@ static inline void CheckInit() {
}
extern void InitializeAccelerometer();
extern void InitializeAddressableLED();
extern void InitializeAnalogAccumulator();
extern void InitializeAnalogGyro();
extern void InitializeAnalogInput();

View File

@@ -36,5 +36,6 @@ constexpr int32_t kNumSolenoidChannels = 8;
constexpr int32_t kNumPDPModules = 63;
constexpr int32_t kNumPDPChannels = 16;
constexpr int32_t kNumDutyCycles = tDutyCycle::kNumSystems;
constexpr int32_t kNumAddressableLEDs = tLED::kNumSystems;
} // namespace hal

View File

@@ -0,0 +1,143 @@
/*----------------------------------------------------------------------------*/
/* 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 <wpi/jni_util.h>
#include "HALUtil.h"
#include "edu_wpi_first_hal_AddressableLEDJNI.h"
#include "hal/AddressableLED.h"
using namespace frc;
using namespace wpi::java;
extern "C" {
/*
* Class: edu_wpi_first_hal_AddressableLEDJNI
* Method: initialize
* Signature: (I)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_AddressableLEDJNI_initialize
(JNIEnv* env, jclass, jint handle)
{
int32_t status = 0;
auto ret = HAL_InitializeAddressableLED(
static_cast<HAL_DigitalHandle>(handle), &status);
CheckStatus(env, status);
return ret;
}
/*
* Class: edu_wpi_first_hal_AddressableLEDJNI
* Method: free
* Signature: (I)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_AddressableLEDJNI_free
(JNIEnv* env, jclass, jint handle)
{
HAL_FreeAddressableLED(static_cast<HAL_AddressableLEDHandle>(handle));
}
/*
* Class: edu_wpi_first_hal_AddressableLEDJNI
* Method: setLength
* Signature: (II)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_AddressableLEDJNI_setLength
(JNIEnv* env, jclass, jint handle, jint length)
{
int32_t status = 0;
HAL_SetAddressableLEDLength(static_cast<HAL_AddressableLEDHandle>(handle),
length, &status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_AddressableLEDJNI
* Method: setData
* Signature: (I[B)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_AddressableLEDJNI_setData
(JNIEnv* env, jclass, jint handle, jbyteArray arr)
{
int32_t status = 0;
JByteArrayRef jArrRef{env, arr};
auto arrRef = jArrRef.array();
HAL_WriteAddressableLEDData(
static_cast<HAL_AddressableLEDHandle>(handle),
reinterpret_cast<const HAL_AddressableLEDData*>(arrRef.data()),
arrRef.size() / 4, &status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_AddressableLEDJNI
* Method: setBitTiming
* Signature: (IIIII)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_AddressableLEDJNI_setBitTiming
(JNIEnv* env, jclass, jint handle, jint lowTime0, jint highTime0,
jint lowTime1, jint highTime1)
{
int32_t status = 0;
HAL_SetAddressableLEDBitTiming(static_cast<HAL_AddressableLEDHandle>(handle),
lowTime0, highTime0, lowTime1, highTime1,
&status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_AddressableLEDJNI
* Method: setSyncTime
* Signature: (II)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_AddressableLEDJNI_setSyncTime
(JNIEnv* env, jclass, jint handle, jint syncTime)
{
int32_t status = 0;
HAL_SetAddressableLEDSyncTime(static_cast<HAL_AddressableLEDHandle>(handle),
syncTime, &status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_AddressableLEDJNI
* Method: start
* Signature: (I)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_AddressableLEDJNI_start
(JNIEnv* env, jclass, jint handle)
{
int32_t status = 0;
HAL_StartAddressableLEDOutput(static_cast<HAL_AddressableLEDHandle>(handle),
&status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_AddressableLEDJNI
* Method: stop
* Signature: (I)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_AddressableLEDJNI_stop
(JNIEnv* env, jclass, jint handle)
{
int32_t status = 0;
HAL_StopAddressableLEDOutput(static_cast<HAL_AddressableLEDHandle>(handle),
&status);
CheckStatus(env, status);
}
} // extern "C"

View File

@@ -0,0 +1,54 @@
/*----------------------------------------------------------------------------*/
/* 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 <stdint.h>
#include "hal/AddressableLEDTypes.h"
#include "hal/Types.h"
#ifdef __cplusplus
extern "C" {
#endif
HAL_AddressableLEDHandle HAL_InitializeAddressableLED(
HAL_DigitalHandle outputPort, int32_t* status);
void HAL_FreeAddressableLED(HAL_AddressableLEDHandle handle);
void HAL_SetAddressableLEDOutputPort(HAL_AddressableLEDHandle handle,
HAL_DigitalHandle outputPort,
int32_t* status);
void HAL_SetAddressableLEDLength(HAL_AddressableLEDHandle handle,
int32_t length, int32_t* status);
void HAL_WriteAddressableLEDData(HAL_AddressableLEDHandle handle,
const struct HAL_AddressableLEDData* data,
int32_t length, int32_t* status);
void HAL_SetAddressableLEDBitTiming(HAL_AddressableLEDHandle handle,
int32_t lowTime0NanoSeconds,
int32_t highTime0NanoSeconds,
int32_t lowTime1NanoSeconds,
int32_t highTime1NanoSeconds,
int32_t* status);
void HAL_SetAddressableLEDSyncTime(HAL_AddressableLEDHandle handle,
int32_t syncTimeMicroSeconds,
int32_t* status);
void HAL_StartAddressableLEDOutput(HAL_AddressableLEDHandle handle,
int32_t* status);
void HAL_StopAddressableLEDOutput(HAL_AddressableLEDHandle handle,
int32_t* status);
#ifdef __cplusplus
} // extern "C"
#endif

View File

@@ -0,0 +1,17 @@
/*----------------------------------------------------------------------------*/
/* 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 <stdint.h>
struct HAL_AddressableLEDData {
uint8_t b;
uint8_t g;
uint8_t r;
uint8_t padding;
};

View File

@@ -28,6 +28,7 @@
#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tEncoder.h>
#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tGlobal.h>
#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tInterrupt.h>
#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tLED.h>
#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tPWM.h>
#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tPower.h>
#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tRelay.h>

View File

@@ -61,6 +61,8 @@ typedef HAL_Handle HAL_DMAHandle;
typedef HAL_Handle HAL_DutyCycleHandle;
typedef HAL_Handle HAL_AddressableLEDHandle;
typedef HAL_CANHandle HAL_PDPHandle;
typedef int32_t HAL_Bool;

View File

@@ -68,6 +68,7 @@ enum class HAL_HandleEnum {
SerialPort = 20,
DutyCycle = 21,
DMA = 22,
AddressableLED = 23,
};
/**

View File

@@ -0,0 +1,45 @@
/*----------------------------------------------------------------------------*/
/* 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/AddressableLED.h"
extern "C" {
HAL_AddressableLEDHandle HAL_InitializeAddressableLED(
HAL_DigitalHandle outputPort, int32_t* status) {
return HAL_kInvalidHandle;
}
void HAL_FreeAddressableLED(HAL_AddressableLEDHandle handle) {}
void HAL_SetAddressableLEDOutputPort(HAL_AddressableLEDHandle handle,
HAL_DigitalHandle outputPort,
int32_t* status) {}
void HAL_SetAddressableLEDLength(HAL_AddressableLEDHandle handle,
int32_t length, int32_t* status) {}
void HAL_WriteAddressableLEDData(HAL_AddressableLEDHandle handle,
const struct HAL_AddressableLEDData* data,
int32_t length, int32_t* status) {}
void HAL_SetAddressableLEDBitTiming(HAL_AddressableLEDHandle handle,
int32_t lowTime0NanoSeconds,
int32_t highTime0NanoSeconds,
int32_t lowTime1NanoSeconds,
int32_t highTime1NanoSeconds,
int32_t* status) {}
void HAL_SetAddressableLEDSyncTime(HAL_AddressableLEDHandle handle,
int32_t syncTimeMicroSeconds,
int32_t* status) {}
void HAL_StartAddressableLEDOutput(HAL_AddressableLEDHandle handle,
int32_t* status) {}
void HAL_StopAddressableLEDOutput(HAL_AddressableLEDHandle handle,
int32_t* status) {}
} // extern "C"