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,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);
}

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"

View File

@@ -149,6 +149,7 @@ model {
}
myRobotCppStatic(NativeExecutableSpec) {
targetBuildTypes 'debug'
nativeUtils.excludeBinariesFromStrip(it)
sources {
cpp {
source {

View 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);
}

View 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

View File

@@ -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.
*/

View 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);
}
}

View File

@@ -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;
}
}

View File

@@ -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.