mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-07-01 02:41:48 +00:00
Add AddressableLED (#2092)
This commit is contained in:
committed by
Peter Johnson
parent
59507b12dc
commit
8ed2059074
23
hal/src/main/java/edu/wpi/first/hal/AddressableLEDJNI.java
Normal file
23
hal/src/main/java/edu/wpi/first/hal/AddressableLEDJNI.java
Normal file
@@ -0,0 +1,23 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
package edu.wpi.first.hal;
|
||||
|
||||
@SuppressWarnings("AbbreviationAsWordInName")
|
||||
public class AddressableLEDJNI extends JNIWrapper {
|
||||
public static native int initialize(int pwmHandle);
|
||||
public static native void free(int handle);
|
||||
|
||||
public static native void setLength(int handle, int length);
|
||||
public static native void setData(int handle, byte[] data);
|
||||
|
||||
public static native void setBitTiming(int handle, int lowTime0, int highTime0, int lowTime1, int highTime1);
|
||||
public static native void setSyncTime(int handle, int syncTime);
|
||||
|
||||
public static native void start(int handle);
|
||||
public static native void stop(int handle);
|
||||
}
|
||||
277
hal/src/main/native/athena/AddressableLED.cpp
Normal file
277
hal/src/main/native/athena/AddressableLED.cpp
Normal 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"
|
||||
@@ -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.
|
||||
|
||||
@@ -42,6 +42,7 @@ using namespace hal;
|
||||
namespace hal {
|
||||
namespace init {
|
||||
void InitializeHAL() {
|
||||
InitializeAddressableLED();
|
||||
InitializeAccelerometer();
|
||||
InitializeAnalogAccumulator();
|
||||
InitializeAnalogGyro();
|
||||
|
||||
@@ -19,6 +19,7 @@ static inline void CheckInit() {
|
||||
}
|
||||
|
||||
extern void InitializeAccelerometer();
|
||||
extern void InitializeAddressableLED();
|
||||
extern void InitializeAnalogAccumulator();
|
||||
extern void InitializeAnalogGyro();
|
||||
extern void InitializeAnalogInput();
|
||||
|
||||
@@ -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
|
||||
|
||||
143
hal/src/main/native/cpp/jni/AddressableLEDJNI.cpp
Normal file
143
hal/src/main/native/cpp/jni/AddressableLEDJNI.cpp
Normal 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"
|
||||
54
hal/src/main/native/include/hal/AddressableLED.h
Normal file
54
hal/src/main/native/include/hal/AddressableLED.h
Normal 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
|
||||
17
hal/src/main/native/include/hal/AddressableLEDTypes.h
Normal file
17
hal/src/main/native/include/hal/AddressableLEDTypes.h
Normal 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;
|
||||
};
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -68,6 +68,7 @@ enum class HAL_HandleEnum {
|
||||
SerialPort = 20,
|
||||
DutyCycle = 21,
|
||||
DMA = 22,
|
||||
AddressableLED = 23,
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
45
hal/src/main/native/sim/AddressableLED.cpp
Normal file
45
hal/src/main/native/sim/AddressableLED.cpp
Normal 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"
|
||||
@@ -149,6 +149,7 @@ model {
|
||||
}
|
||||
myRobotCppStatic(NativeExecutableSpec) {
|
||||
targetBuildTypes 'debug'
|
||||
nativeUtils.excludeBinariesFromStrip(it)
|
||||
sources {
|
||||
cpp {
|
||||
source {
|
||||
|
||||
101
wpilibc/src/main/native/cpp/AddressableLED.cpp
Normal file
101
wpilibc/src/main/native/cpp/AddressableLED.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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 "frc/AddressableLED.h"
|
||||
|
||||
#include <hal/AddressableLED.h>
|
||||
|
||||
#include "frc/PWM.h"
|
||||
#include "frc/WPIErrors.h"
|
||||
|
||||
using namespace frc;
|
||||
|
||||
AddressableLED::AddressableLED(PWM& output)
|
||||
: m_pwmOutput{&output, NullDeleter<PWM>()} {
|
||||
Init();
|
||||
}
|
||||
|
||||
AddressableLED::AddressableLED(PWM* output)
|
||||
: m_pwmOutput{output, NullDeleter<PWM>()} {
|
||||
if (m_pwmOutput == nullptr) {
|
||||
wpi_setWPIError(NullParameter);
|
||||
} else {
|
||||
Init();
|
||||
}
|
||||
}
|
||||
|
||||
AddressableLED::AddressableLED(std::shared_ptr<PWM> output)
|
||||
: m_pwmOutput{std::move(output)} {
|
||||
Init();
|
||||
}
|
||||
|
||||
AddressableLED::AddressableLED(int port)
|
||||
: m_pwmOutput{std::make_shared<PWM>(port)} {
|
||||
if (!m_pwmOutput->StatusIsFatal()) {
|
||||
Init();
|
||||
}
|
||||
}
|
||||
|
||||
AddressableLED::~AddressableLED() { HAL_FreeAddressableLED(m_handle); }
|
||||
|
||||
void AddressableLED::Init() {
|
||||
int32_t status = 0;
|
||||
m_handle = HAL_InitializeAddressableLED(m_pwmOutput->m_handle, &status);
|
||||
wpi_setHALError(status);
|
||||
}
|
||||
|
||||
void AddressableLED::SetLength(int length) {
|
||||
int32_t status = 0;
|
||||
HAL_SetAddressableLEDLength(m_handle, length, &status);
|
||||
wpi_setHALError(status);
|
||||
}
|
||||
|
||||
static_assert(sizeof(AddressableLED::LEDData) == sizeof(HAL_AddressableLEDData),
|
||||
"LED Structs MUST be the same size");
|
||||
|
||||
void AddressableLED::SetData(wpi::ArrayRef<LEDData> ledData) {
|
||||
int32_t status = 0;
|
||||
HAL_WriteAddressableLEDData(m_handle, ledData.begin(), ledData.size(),
|
||||
&status);
|
||||
wpi_setHALError(status);
|
||||
}
|
||||
|
||||
void AddressableLED::SetData(std::initializer_list<LEDData> ledData) {
|
||||
int32_t status = 0;
|
||||
HAL_WriteAddressableLEDData(m_handle, ledData.begin(), ledData.size(),
|
||||
&status);
|
||||
wpi_setHALError(status);
|
||||
}
|
||||
|
||||
void AddressableLED::SetBitTiming(units::nanosecond_t lowTime0,
|
||||
units::nanosecond_t highTime0,
|
||||
units::nanosecond_t lowTime1,
|
||||
units::nanosecond_t highTime1) {
|
||||
int32_t status = 0;
|
||||
HAL_SetAddressableLEDBitTiming(
|
||||
m_handle, lowTime0.to<int32_t>(), highTime0.to<int32_t>(),
|
||||
lowTime1.to<int32_t>(), highTime1.to<int32_t>(), &status);
|
||||
wpi_setHALError(status);
|
||||
}
|
||||
|
||||
void AddressableLED::SetSyncTime(units::microsecond_t syncTime) {
|
||||
int32_t status = 0;
|
||||
HAL_SetAddressableLEDSyncTime(m_handle, syncTime.to<int32_t>(), &status);
|
||||
wpi_setHALError(status);
|
||||
}
|
||||
|
||||
void AddressableLED::Start() {
|
||||
int32_t status = 0;
|
||||
HAL_StartAddressableLEDOutput(m_handle, &status);
|
||||
wpi_setHALError(status);
|
||||
}
|
||||
|
||||
void AddressableLED::Stop() {
|
||||
int32_t status = 0;
|
||||
HAL_StopAddressableLEDOutput(m_handle, &status);
|
||||
wpi_setHALError(status);
|
||||
}
|
||||
141
wpilibc/src/main/native/include/frc/AddressableLED.h
Normal file
141
wpilibc/src/main/native/include/frc/AddressableLED.h
Normal file
@@ -0,0 +1,141 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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 <memory>
|
||||
|
||||
#include <hal/AddressableLEDTypes.h>
|
||||
#include <hal/Types.h>
|
||||
#include <units/units.h>
|
||||
#include <wpi/ArrayRef.h>
|
||||
|
||||
#include "frc/ErrorBase.h"
|
||||
|
||||
namespace frc {
|
||||
class PWM;
|
||||
|
||||
/**
|
||||
* A class for driving addressable LEDs, such as WS2812s and NeoPixels.
|
||||
*/
|
||||
class AddressableLED : public ErrorBase {
|
||||
public:
|
||||
class LEDData : public HAL_AddressableLEDData {
|
||||
public:
|
||||
LEDData() : LEDData(0, 0, 0) {}
|
||||
LEDData(int _r, int _g, int _b) {
|
||||
r = _r;
|
||||
g = _g;
|
||||
b = _b;
|
||||
padding = 0;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructs a new driver from a PWM output.
|
||||
*
|
||||
* @param output the pwm output to use
|
||||
*/
|
||||
explicit AddressableLED(PWM& output);
|
||||
|
||||
/**
|
||||
* Constructs a new driver from a PWM output.
|
||||
*
|
||||
* @param output the pwm output to use
|
||||
*/
|
||||
explicit AddressableLED(PWM* output);
|
||||
|
||||
/**
|
||||
* Constructs a new driver from a PWM output.
|
||||
*
|
||||
* @param output the pwm output to use
|
||||
*/
|
||||
explicit AddressableLED(std::shared_ptr<PWM> output);
|
||||
|
||||
/**
|
||||
* Constructs a new driver for a specific port.
|
||||
*
|
||||
* @param port the output port to use (Must be a PWM port)
|
||||
*/
|
||||
explicit AddressableLED(int port);
|
||||
|
||||
~AddressableLED() override;
|
||||
|
||||
/**
|
||||
* Sets the length of the LED strip.
|
||||
*
|
||||
* <p>Calling this is an expensive call, so its best to call it once, then
|
||||
* just update data.
|
||||
*
|
||||
* @param length the strip length
|
||||
*/
|
||||
void SetLength(int length);
|
||||
|
||||
/**
|
||||
* Sets the led output data.
|
||||
*
|
||||
* <p>If the output is enabled, this will start writing the next data cycle.
|
||||
* It is safe to call, even while output is enabled.
|
||||
*
|
||||
* @param ledData the buffer to write
|
||||
*/
|
||||
void SetData(wpi::ArrayRef<LEDData> ledData);
|
||||
|
||||
/**
|
||||
* Sets the led output data.
|
||||
*
|
||||
* <p>If the output is enabled, this will start writing the next data cycle.
|
||||
* It is safe to call, even while output is enabled.
|
||||
*
|
||||
* @param ledData the buffer to write
|
||||
*/
|
||||
void SetData(std::initializer_list<LEDData> ledData);
|
||||
|
||||
/**
|
||||
* Sets the bit timing.
|
||||
*
|
||||
* <p>By default, the driver is set up to drive WS2812s, so nothing needs to
|
||||
* be set for those.
|
||||
*
|
||||
* @param lowTime0 low time for 0 bit
|
||||
* @param highTime0 high time for 0 bit
|
||||
* @param lowTime1 low time for 1 bit
|
||||
* @param highTime1 high time for 1 bit
|
||||
*/
|
||||
void SetBitTiming(units::nanosecond_t lowTime0, units::nanosecond_t highTime0,
|
||||
units::nanosecond_t lowTime1,
|
||||
units::nanosecond_t highTime1);
|
||||
|
||||
/**
|
||||
* Sets the sync time.
|
||||
*
|
||||
* <p>The sync time is the time to hold output so LEDs enable. Default set for
|
||||
* WS2812.
|
||||
*
|
||||
* @param syncTimeMicroSeconds the sync time
|
||||
*/
|
||||
void SetSyncTime(units::microsecond_t syncTime);
|
||||
|
||||
/**
|
||||
* Starts the output.
|
||||
*
|
||||
* <p>The output writes continously.
|
||||
*/
|
||||
void Start();
|
||||
|
||||
/**
|
||||
* Stops the output.
|
||||
*/
|
||||
void Stop();
|
||||
|
||||
private:
|
||||
void Init();
|
||||
|
||||
std::shared_ptr<PWM> m_pwmOutput;
|
||||
hal::Handle<HAL_AddressableLEDHandle> m_handle;
|
||||
};
|
||||
} // namespace frc
|
||||
@@ -17,7 +17,7 @@
|
||||
#include "frc/smartdashboard/SendableHelper.h"
|
||||
|
||||
namespace frc {
|
||||
|
||||
class AddressableLED;
|
||||
class SendableBuilder;
|
||||
|
||||
/**
|
||||
@@ -39,6 +39,7 @@ class SendableBuilder;
|
||||
*/
|
||||
class PWM : public MotorSafety, public Sendable, public SendableHelper<PWM> {
|
||||
public:
|
||||
friend class AddressableLED;
|
||||
/**
|
||||
* Represents the amount to multiply the minimum servo-pulse pwm period by.
|
||||
*/
|
||||
|
||||
122
wpilibj/src/main/java/edu/wpi/first/wpilibj/AddressableLED.java
Normal file
122
wpilibj/src/main/java/edu/wpi/first/wpilibj/AddressableLED.java
Normal file
@@ -0,0 +1,122 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
package edu.wpi.first.wpilibj;
|
||||
|
||||
import edu.wpi.first.hal.AddressableLEDJNI;
|
||||
|
||||
/**
|
||||
* A class for driving addressable LEDs, such as WS2812s and NeoPixels.
|
||||
*/
|
||||
public class AddressableLED implements AutoCloseable {
|
||||
private final PWM m_pwmOutput;
|
||||
private int m_handle;
|
||||
private final boolean m_ownsPwm;
|
||||
|
||||
/**
|
||||
* Constructs a new driver from a PWM output.
|
||||
*
|
||||
* @param output the pwm output to use
|
||||
*/
|
||||
public AddressableLED(PWM output) {
|
||||
m_pwmOutput = output;
|
||||
m_ownsPwm = false;
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new driver for a specific port.
|
||||
*
|
||||
* @param port the output port to use (Must be a PWM port)
|
||||
*/
|
||||
public AddressableLED(int port) {
|
||||
m_pwmOutput = new PWM(port);
|
||||
m_ownsPwm = true;
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
m_handle = AddressableLEDJNI.initialize(m_pwmOutput.m_handle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (m_handle != 0) {
|
||||
AddressableLEDJNI.free(m_handle);
|
||||
}
|
||||
if (m_ownsPwm) {
|
||||
m_pwmOutput.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the length of the LED strip.
|
||||
*
|
||||
* <p>Calling this is an expensive call, so its best to call it once, then just update data.
|
||||
*
|
||||
* @param length the strip length
|
||||
*/
|
||||
public void setLength(int length) {
|
||||
AddressableLEDJNI.setLength(m_handle, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the led output data.
|
||||
*
|
||||
* <p>If the output is enabled, this will start writing the next data cycle.
|
||||
* It is safe to call, even while output is enabled.
|
||||
*
|
||||
* @param buffer the buffer to write
|
||||
*/
|
||||
public void setData(AddressableLEDBuffer buffer) {
|
||||
AddressableLEDJNI.setData(m_handle, buffer.m_buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bit timing.
|
||||
*
|
||||
* <p>By default, the driver is set up to drive WS2812s, so nothing needs to be set for those.
|
||||
*
|
||||
* @param lowTime0NanoSeconds low time for 0 bit
|
||||
* @param highTime0NanoSeconds high time for 0 bit
|
||||
* @param lowTime1NanoSeconds low time for 1 bit
|
||||
* @param highTime1NanoSeconds high time for 1 bit
|
||||
*/
|
||||
public void setBitTiming(int lowTime0NanoSeconds, int highTime0NanoSeconds,
|
||||
int lowTime1NanoSeconds, int highTime1NanoSeconds) {
|
||||
AddressableLEDJNI.setBitTiming(m_handle, lowTime0NanoSeconds,
|
||||
highTime0NanoSeconds, lowTime1NanoSeconds,
|
||||
highTime1NanoSeconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the sync time.
|
||||
*
|
||||
* <p>The sync time is the time to hold output so LEDs enable. Default set for WS2812.
|
||||
*
|
||||
* @param syncTimeMicroSeconds the sync time
|
||||
*/
|
||||
public void setSyncTime(int syncTimeMicroSeconds) {
|
||||
AddressableLEDJNI.setSyncTime(m_handle, syncTimeMicroSeconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the output.
|
||||
*
|
||||
* <p>The output writes continously.
|
||||
*/
|
||||
public void start() {
|
||||
AddressableLEDJNI.start(m_handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the output.
|
||||
*/
|
||||
public void stop() {
|
||||
AddressableLEDJNI.stop(m_handle);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
package edu.wpi.first.wpilibj;
|
||||
|
||||
/**
|
||||
* Buffer storage for Addressable LEDs.
|
||||
*/
|
||||
public class AddressableLEDBuffer {
|
||||
byte[] m_buffer;
|
||||
|
||||
/**
|
||||
* Constructs a new LED buffer with the specified length.
|
||||
*
|
||||
* @param length The length of the buffer in pixels
|
||||
*/
|
||||
public AddressableLEDBuffer(int length) {
|
||||
m_buffer = new byte[length * 4];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a specific led in the buffer.
|
||||
*
|
||||
* @param index the index to write
|
||||
* @param r the r value
|
||||
* @param g the g value
|
||||
* @param b the b value
|
||||
*/
|
||||
@SuppressWarnings("ParameterName")
|
||||
public void setLED(int index, int r, int g, int b) {
|
||||
m_buffer[index * 4] = (byte) b;
|
||||
m_buffer[(index * 4) + 1] = (byte) g;
|
||||
m_buffer[(index * 4) + 2] = (byte) r;
|
||||
m_buffer[(index * 4) + 3] = 0;
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,9 @@ public class PWM extends MotorSafety implements Sendable, AutoCloseable {
|
||||
}
|
||||
|
||||
private final int m_channel;
|
||||
private int m_handle;
|
||||
|
||||
// Package private to use from AddressableLED
|
||||
int m_handle;
|
||||
|
||||
/**
|
||||
* Allocate a PWM given a channel.
|
||||
|
||||
Reference in New Issue
Block a user