mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-07-03 03:01:44 +00:00
[hal, wpilib] Update Addressable LED support (#8100)
This commit is contained in:
@@ -13,7 +13,7 @@
|
||||
using namespace hal;
|
||||
using namespace wpi::java;
|
||||
|
||||
static_assert(sizeof(jbyte) * 4 == sizeof(HAL_AddressableLEDData));
|
||||
static_assert(sizeof(jbyte) * 3 == sizeof(HAL_AddressableLEDData));
|
||||
|
||||
static_assert(edu_wpi_first_hal_AddressableLEDJNI_COLOR_ORDER_RGB ==
|
||||
HAL_ALED_RGB);
|
||||
@@ -36,12 +36,12 @@ extern "C" {
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_edu_wpi_first_hal_AddressableLEDJNI_initialize
|
||||
(JNIEnv* env, jclass, jint handle)
|
||||
(JNIEnv* env, jclass, jint channel)
|
||||
{
|
||||
int32_t status = 0;
|
||||
auto ret = HAL_InitializeAddressableLED(
|
||||
static_cast<HAL_DigitalHandle>(handle), &status);
|
||||
CheckStatus(env, status);
|
||||
auto stack = wpi::java::GetJavaStackTrace(env, "edu.wpi.first");
|
||||
auto ret = HAL_InitializeAddressableLED(channel, stack.c_str(), &status);
|
||||
CheckStatusForceThrow(env, status);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -61,17 +61,16 @@ Java_edu_wpi_first_hal_AddressableLEDJNI_free
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_AddressableLEDJNI
|
||||
* Method: setColorOrder
|
||||
* Method: setStart
|
||||
* Signature: (II)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_edu_wpi_first_hal_AddressableLEDJNI_setColorOrder
|
||||
(JNIEnv* env, jclass, jint handle, jint colorOrder)
|
||||
Java_edu_wpi_first_hal_AddressableLEDJNI_setStart
|
||||
(JNIEnv* env, jclass, jint handle, jint start)
|
||||
{
|
||||
int32_t status = 0;
|
||||
HAL_SetAddressableLEDColorOrder(
|
||||
static_cast<HAL_AddressableLEDHandle>(handle),
|
||||
static_cast<HAL_AddressableLEDColorOrder>(colorOrder), &status);
|
||||
HAL_SetAddressableLEDStart(static_cast<HAL_AddressableLEDHandle>(handle),
|
||||
start, &status);
|
||||
CheckStatus(env, status);
|
||||
}
|
||||
|
||||
@@ -93,80 +92,79 @@ Java_edu_wpi_first_hal_AddressableLEDJNI_setLength
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_AddressableLEDJNI
|
||||
* Method: setData
|
||||
* Signature: (I[B)V
|
||||
* Signature: (II[BII)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_edu_wpi_first_hal_AddressableLEDJNI_setData
|
||||
(JNIEnv* env, jclass, jint handle, jbyteArray arr)
|
||||
(JNIEnv* env, jclass, jint outStart, jint colorOrder, jbyteArray data,
|
||||
jint start, jint len)
|
||||
{
|
||||
if (!data) {
|
||||
ThrowNullPointerException(env, "data is null");
|
||||
return;
|
||||
}
|
||||
if (start < 0) {
|
||||
ThrowIndexOutOfBoundsException(env, "start must be >= 0");
|
||||
return;
|
||||
}
|
||||
if (len < 0) {
|
||||
ThrowIndexOutOfBoundsException(env, "len must be >= 0");
|
||||
return;
|
||||
}
|
||||
JSpan<const jbyte> cdata{env, data};
|
||||
if (static_cast<unsigned int>(start + len) > cdata.size()) {
|
||||
ThrowIndexOutOfBoundsException(
|
||||
env, "start + len must be smaller than array length");
|
||||
return;
|
||||
}
|
||||
if ((len % 3) != 0) {
|
||||
ThrowIndexOutOfBoundsException(env, "len must be a multiple of 3");
|
||||
return;
|
||||
}
|
||||
auto rawdata = cdata.uarray().subspan(start, len);
|
||||
int32_t status = 0;
|
||||
JSpan<const jbyte> jArrRef{env, arr};
|
||||
HAL_WriteAddressableLEDData(
|
||||
static_cast<HAL_AddressableLEDHandle>(handle),
|
||||
reinterpret_cast<const HAL_AddressableLEDData*>(jArrRef.data()),
|
||||
jArrRef.size() / 4, &status);
|
||||
CheckStatus(env, status);
|
||||
HAL_SetAddressableLEDData(
|
||||
outStart, rawdata.size() / 3,
|
||||
static_cast<HAL_AddressableLEDColorOrder>(colorOrder),
|
||||
reinterpret_cast<const HAL_AddressableLEDData*>(rawdata.data()), &status);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_AddressableLEDJNI
|
||||
* Method: setBitTiming
|
||||
* Signature: (IIIII)V
|
||||
* Method: setDataFromBuffer
|
||||
* Signature: (IILjava/lang/Object;II)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_edu_wpi_first_hal_AddressableLEDJNI_setBitTiming
|
||||
(JNIEnv* env, jclass, jint handle, jint highTime0, jint lowTime0,
|
||||
jint highTime1, jint lowTime1)
|
||||
Java_edu_wpi_first_hal_AddressableLEDJNI_setDataFromBuffer
|
||||
(JNIEnv* env, jclass, jint outStart, jint colorOrder, jobject data,
|
||||
jint start, jint len)
|
||||
{
|
||||
if (!data) {
|
||||
ThrowNullPointerException(env, "data is null");
|
||||
return;
|
||||
}
|
||||
if (start < 0) {
|
||||
ThrowIndexOutOfBoundsException(env, "start must be >= 0");
|
||||
return;
|
||||
}
|
||||
if (len < 0) {
|
||||
ThrowIndexOutOfBoundsException(env, "len must be >= 0");
|
||||
return;
|
||||
}
|
||||
JSpan<const jbyte> cdata{env, data, static_cast<size_t>(start + len)};
|
||||
if (!cdata) {
|
||||
ThrowIllegalArgumentException(env, "data must be a native ByteBuffer");
|
||||
return;
|
||||
}
|
||||
if ((len % 3) != 0) {
|
||||
ThrowIndexOutOfBoundsException(env, "len must be a multiple of 3");
|
||||
return;
|
||||
}
|
||||
auto rawdata = cdata.uarray().subspan(start, len);
|
||||
int32_t status = 0;
|
||||
HAL_SetAddressableLEDBitTiming(static_cast<HAL_AddressableLEDHandle>(handle),
|
||||
highTime0, lowTime0, highTime1, lowTime1,
|
||||
&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);
|
||||
HAL_SetAddressableLEDData(
|
||||
outStart, rawdata.size() / 3,
|
||||
static_cast<HAL_AddressableLEDColorOrder>(colorOrder),
|
||||
reinterpret_cast<const HAL_AddressableLEDData*>(rawdata.data()), &status);
|
||||
}
|
||||
} // extern "C"
|
||||
|
||||
@@ -40,6 +40,7 @@ static_assert(edu_wpi_first_hal_HALUtil_RUNTIME_SYSTEMCORE ==
|
||||
|
||||
static JavaVM* jvm = nullptr;
|
||||
static JException illegalArgExCls;
|
||||
static JException indexOobExCls;
|
||||
static JException boundaryExCls;
|
||||
static JException allocationExCls;
|
||||
static JException halHandleExCls;
|
||||
@@ -68,6 +69,7 @@ static const JClassInit classes[] = {
|
||||
|
||||
static const JExceptionInit exceptions[] = {
|
||||
{"java/lang/IllegalArgumentException", &illegalArgExCls},
|
||||
{"java/lang/IndexOutOfBoundsException", &indexOobExCls},
|
||||
{"edu/wpi/first/hal/util/BoundaryException", &boundaryExCls},
|
||||
{"edu/wpi/first/hal/util/AllocationException", &allocationExCls},
|
||||
{"edu/wpi/first/hal/util/HalHandleException", &halHandleExCls},
|
||||
@@ -159,6 +161,10 @@ void ThrowIllegalArgumentException(JNIEnv* env, std::string_view msg) {
|
||||
illegalArgExCls.Throw(env, msg);
|
||||
}
|
||||
|
||||
void ThrowIndexOutOfBoundsException(JNIEnv* env, std::string_view msg) {
|
||||
indexOobExCls.Throw(env, msg);
|
||||
}
|
||||
|
||||
void ThrowBoundaryException(JNIEnv* env, double value, double lower,
|
||||
double upper) {
|
||||
static jmethodID getMessage = nullptr;
|
||||
|
||||
@@ -46,6 +46,7 @@ void ThrowNullPointerException(JNIEnv* env, std::string_view msg);
|
||||
void ThrowCANStreamOverflowException(JNIEnv* env, jobjectArray messages,
|
||||
jint length);
|
||||
void ThrowIllegalArgumentException(JNIEnv* env, std::string_view msg);
|
||||
void ThrowIndexOutOfBoundsException(JNIEnv* env, std::string_view msg);
|
||||
void ThrowBoundaryException(JNIEnv* env, double value, double lower,
|
||||
double upper);
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "edu_wpi_first_hal_simulation_AddressableLEDDataJNI.h"
|
||||
#include "hal/simulation/AddressableLEDData.h"
|
||||
|
||||
static_assert(sizeof(jbyte) * 4 == sizeof(HAL_AddressableLEDData));
|
||||
static_assert(sizeof(jbyte) * 3 == sizeof(HAL_AddressableLEDData));
|
||||
|
||||
using namespace hal;
|
||||
using namespace wpi::java;
|
||||
@@ -71,53 +71,52 @@ Java_edu_wpi_first_hal_simulation_AddressableLEDDataJNI_setInitialized
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_simulation_AddressableLEDDataJNI
|
||||
* Method: registerOutputPortCallback
|
||||
* Method: registerStartCallback
|
||||
* Signature: (ILjava/lang/Object;Z)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_edu_wpi_first_hal_simulation_AddressableLEDDataJNI_registerOutputPortCallback
|
||||
Java_edu_wpi_first_hal_simulation_AddressableLEDDataJNI_registerStartCallback
|
||||
(JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
|
||||
{
|
||||
return sim::AllocateCallback(
|
||||
env, index, callback, initialNotify,
|
||||
&HALSIM_RegisterAddressableLEDOutputPortCallback);
|
||||
return sim::AllocateCallback(env, index, callback, initialNotify,
|
||||
&HALSIM_RegisterAddressableLEDStartCallback);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_simulation_AddressableLEDDataJNI
|
||||
* Method: cancelOutputPortCallback
|
||||
* Method: cancelStartCallback
|
||||
* Signature: (II)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_edu_wpi_first_hal_simulation_AddressableLEDDataJNI_cancelOutputPortCallback
|
||||
Java_edu_wpi_first_hal_simulation_AddressableLEDDataJNI_cancelStartCallback
|
||||
(JNIEnv* env, jclass, jint index, jint handle)
|
||||
{
|
||||
return sim::FreeCallback(env, handle, index,
|
||||
&HALSIM_CancelAddressableLEDOutputPortCallback);
|
||||
&HALSIM_CancelAddressableLEDStartCallback);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_simulation_AddressableLEDDataJNI
|
||||
* Method: getOutputPort
|
||||
* Method: getStart
|
||||
* Signature: (I)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_edu_wpi_first_hal_simulation_AddressableLEDDataJNI_getOutputPort
|
||||
Java_edu_wpi_first_hal_simulation_AddressableLEDDataJNI_getStart
|
||||
(JNIEnv*, jclass, jint index)
|
||||
{
|
||||
return HALSIM_GetAddressableLEDOutputPort(index);
|
||||
return HALSIM_GetAddressableLEDStart(index);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_simulation_AddressableLEDDataJNI
|
||||
* Method: setOutputPort
|
||||
* Method: setStart
|
||||
* Signature: (II)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_edu_wpi_first_hal_simulation_AddressableLEDDataJNI_setOutputPort
|
||||
Java_edu_wpi_first_hal_simulation_AddressableLEDDataJNI_setStart
|
||||
(JNIEnv*, jclass, jint index, jint value)
|
||||
{
|
||||
HALSIM_SetAddressableLEDOutputPort(index, value);
|
||||
HALSIM_SetAddressableLEDStart(index, value);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -170,96 +169,50 @@ Java_edu_wpi_first_hal_simulation_AddressableLEDDataJNI_setLength
|
||||
HALSIM_SetAddressableLEDLength(index, value);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_simulation_AddressableLEDDataJNI
|
||||
* Method: registerRunningCallback
|
||||
* Signature: (ILjava/lang/Object;Z)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_edu_wpi_first_hal_simulation_AddressableLEDDataJNI_registerRunningCallback
|
||||
(JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
|
||||
{
|
||||
return sim::AllocateCallback(env, index, callback, initialNotify,
|
||||
&HALSIM_RegisterAddressableLEDRunningCallback);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_simulation_AddressableLEDDataJNI
|
||||
* Method: cancelRunningCallback
|
||||
* Signature: (II)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_edu_wpi_first_hal_simulation_AddressableLEDDataJNI_cancelRunningCallback
|
||||
(JNIEnv* env, jclass, jint index, jint handle)
|
||||
{
|
||||
return sim::FreeCallback(env, handle, index,
|
||||
&HALSIM_CancelAddressableLEDRunningCallback);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_simulation_AddressableLEDDataJNI
|
||||
* Method: getRunning
|
||||
* Signature: (I)Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_edu_wpi_first_hal_simulation_AddressableLEDDataJNI_getRunning
|
||||
(JNIEnv*, jclass, jint index)
|
||||
{
|
||||
return HALSIM_GetAddressableLEDRunning(index);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_simulation_AddressableLEDDataJNI
|
||||
* Method: setRunning
|
||||
* Signature: (IZ)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_edu_wpi_first_hal_simulation_AddressableLEDDataJNI_setRunning
|
||||
(JNIEnv*, jclass, jint index, jboolean value)
|
||||
{
|
||||
HALSIM_SetAddressableLEDRunning(index, value);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_simulation_AddressableLEDDataJNI
|
||||
* Method: registerDataCallback
|
||||
* Signature: (ILjava/lang/Object;)I
|
||||
* Signature: (Ljava/lang/Object;)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_edu_wpi_first_hal_simulation_AddressableLEDDataJNI_registerDataCallback
|
||||
(JNIEnv* env, jclass, jint index, jobject callback)
|
||||
(JNIEnv* env, jclass, jobject callback)
|
||||
{
|
||||
return sim::AllocateConstBufferCallback(
|
||||
env, index, callback, &HALSIM_RegisterAddressableLEDDataCallback);
|
||||
env, -1, callback,
|
||||
[](int32_t, HAL_ConstBufferCallback callback, void* param) {
|
||||
return HALSIM_RegisterAddressableLEDDataCallback(callback, param);
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_simulation_AddressableLEDDataJNI
|
||||
* Method: cancelDataCallback
|
||||
* Signature: (II)V
|
||||
* Signature: (I)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_edu_wpi_first_hal_simulation_AddressableLEDDataJNI_cancelDataCallback
|
||||
(JNIEnv* env, jclass, jint index, jint handle)
|
||||
(JNIEnv* env, jclass, jint handle)
|
||||
{
|
||||
sim::FreeConstBufferCallback(env, handle, index,
|
||||
&HALSIM_CancelAddressableLEDDataCallback);
|
||||
sim::FreeConstBufferCallback(env, handle, -1, [](int32_t, int32_t uid) {
|
||||
HALSIM_CancelAddressableLEDDataCallback(uid);
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_simulation_AddressableLEDDataJNI
|
||||
* Method: getData
|
||||
* Signature: (I)[B
|
||||
* Signature: (II)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL
|
||||
Java_edu_wpi_first_hal_simulation_AddressableLEDDataJNI_getData
|
||||
(JNIEnv* env, jclass, jint index)
|
||||
(JNIEnv* env, jclass, jint start, jint length)
|
||||
{
|
||||
auto data =
|
||||
std::make_unique<HAL_AddressableLEDData[]>(HAL_kAddressableLEDMaxLength);
|
||||
int32_t length = HALSIM_GetAddressableLEDData(index, data.get());
|
||||
length = HALSIM_GetAddressableLEDData(start, length, data.get());
|
||||
return MakeJByteArray(
|
||||
env, std::span(reinterpret_cast<jbyte*>(data.get()), length * 4));
|
||||
env, std::span(reinterpret_cast<jbyte*>(data.get()), length * 3));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -269,13 +222,13 @@ Java_edu_wpi_first_hal_simulation_AddressableLEDDataJNI_getData
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_edu_wpi_first_hal_simulation_AddressableLEDDataJNI_setData
|
||||
(JNIEnv* env, jclass, jint index, jbyteArray arr)
|
||||
(JNIEnv* env, jclass, jint start, jbyteArray arr)
|
||||
{
|
||||
JSpan<const jbyte> jArrRef{env, arr};
|
||||
auto arrRef = jArrRef.array();
|
||||
HALSIM_SetAddressableLEDData(
|
||||
index, reinterpret_cast<const HAL_AddressableLEDData*>(arrRef.data()),
|
||||
arrRef.size() / 4);
|
||||
start, arrRef.size() / 3,
|
||||
reinterpret_cast<const HAL_AddressableLEDData*>(arrRef.data()));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -290,16 +243,4 @@ Java_edu_wpi_first_hal_simulation_AddressableLEDDataJNI_resetData
|
||||
HALSIM_ResetAddressableLEDData(index);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_simulation_AddressableLEDDataJNI
|
||||
* Method: findForChannel
|
||||
* Signature: (I)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_edu_wpi_first_hal_simulation_AddressableLEDDataJNI_findForChannel
|
||||
(JNIEnv*, jclass, jint channel)
|
||||
{
|
||||
return HALSIM_FindAddressableLEDForChannel(channel);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
@@ -20,14 +20,16 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Initialize Addressable LED using a PWM Digital handle.
|
||||
* Creates a new instance of an addressable LED.
|
||||
*
|
||||
* @param[in] outputPort handle of the digital port for PWM
|
||||
* @param[in] channel the smartio channel
|
||||
* @param[in] allocationLocation the location where the allocation is occurring
|
||||
* (can be null)
|
||||
* @param[out] status the error code, or 0 for success
|
||||
* @return Addressable LED handle
|
||||
*/
|
||||
HAL_AddressableLEDHandle HAL_InitializeAddressableLED(
|
||||
HAL_DigitalHandle outputPort, int32_t* status);
|
||||
int32_t channel, const char* allocationLocation, int32_t* status);
|
||||
|
||||
/**
|
||||
* Free the Addressable LED Handle.
|
||||
@@ -37,34 +39,26 @@ HAL_AddressableLEDHandle HAL_InitializeAddressableLED(
|
||||
void HAL_FreeAddressableLED(HAL_AddressableLEDHandle handle);
|
||||
|
||||
/**
|
||||
* Sets the color order for the addressable LED output. The default order is
|
||||
* GRB. This will take effect on the next call to HAL_WriteAddressableLEDData().
|
||||
* @param[in] handle the Addressable LED handle
|
||||
* @param[in] colorOrder the color order
|
||||
* @param[out] status the error code, or 0 for success
|
||||
*/
|
||||
void HAL_SetAddressableLEDColorOrder(HAL_AddressableLEDHandle handle,
|
||||
HAL_AddressableLEDColorOrder colorOrder,
|
||||
int32_t* status);
|
||||
|
||||
/**
|
||||
* Set the Addressable LED PWM Digital port.
|
||||
* Sets the start buffer location used for the LED strip.
|
||||
*
|
||||
* <p>All addressable LEDs use a single backing buffer 1024 LEDs in size.
|
||||
* The max length for a single output is 1024 LEDs (with an offset of zero).
|
||||
*
|
||||
* @param[in] handle the Addressable LED handle
|
||||
* @param[in] outputPort The digital handle of the PWM port
|
||||
* @param[in] start the strip start, in LEDs
|
||||
* @param[out] status the error code, or 0 for success
|
||||
*/
|
||||
void HAL_SetAddressableLEDOutputPort(HAL_AddressableLEDHandle handle,
|
||||
HAL_DigitalHandle outputPort,
|
||||
int32_t* status);
|
||||
void HAL_SetAddressableLEDStart(HAL_AddressableLEDHandle handle, int32_t start,
|
||||
int32_t* status);
|
||||
|
||||
/**
|
||||
* Sets the length of the LED strip.
|
||||
*
|
||||
* <p>The max length is 5460 LEDs.
|
||||
* <p>All addressable LEDs use a single backing buffer 1024 LEDs in size.
|
||||
* The max length for a single output is 1024 LEDs (with an offset of zero).
|
||||
*
|
||||
* @param[in] handle the Addressable LED handle
|
||||
* @param[in] length the strip length
|
||||
* @param[in] length the strip length, in LEDs
|
||||
* @param[out] status the error code, or 0 for success
|
||||
*/
|
||||
void HAL_SetAddressableLEDLength(HAL_AddressableLEDHandle handle,
|
||||
@@ -73,68 +67,19 @@ void HAL_SetAddressableLEDLength(HAL_AddressableLEDHandle handle,
|
||||
/**
|
||||
* 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.
|
||||
* <p>All addressable LEDs use a single backing buffer 1024 LEDs in size.
|
||||
* This function may be used to set part of or all of the buffer.
|
||||
*
|
||||
* @param[in] handle the Addressable LED handle
|
||||
* @param[in] start the strip start, in LEDs
|
||||
* @param[in] length the strip length, in LEDs
|
||||
* @param[in] colorOrder the color order
|
||||
* @param[in] data the buffer to write
|
||||
* @param[in] length the strip length
|
||||
* @param[out] status the error code, or 0 for success
|
||||
*/
|
||||
void HAL_WriteAddressableLEDData(HAL_AddressableLEDHandle handle,
|
||||
const struct HAL_AddressableLEDData* data,
|
||||
int32_t length, int32_t* status);
|
||||
|
||||
/**
|
||||
* Sets the bit timing.
|
||||
*
|
||||
* <p>By default, the driver is set up to drive WS2812B and WS2815, so nothing
|
||||
* needs to be set for those.
|
||||
*
|
||||
* @param[in] handle the Addressable LED handle
|
||||
* @param[in] highTime0 high time for 0 bit in nanoseconds (default 400 ns)
|
||||
* @param[in] lowTime0 low time for 0 bit in nanoseconds (default 900 ns)
|
||||
* @param[in] highTime1 high time for 1 bit in nanoseconds (default 900 ns)
|
||||
* @param[in] lowTime1 low time for 1 bit in nanoseconds (default 600 ns)
|
||||
* @param[out] status the error code, or 0 for success
|
||||
*/
|
||||
void HAL_SetAddressableLEDBitTiming(HAL_AddressableLEDHandle handle,
|
||||
int32_t highTime0, int32_t lowTime0,
|
||||
int32_t highTime1, int32_t lowTime1,
|
||||
int32_t* status);
|
||||
|
||||
/**
|
||||
* Sets the sync time.
|
||||
*
|
||||
* <p>The sync time is the time to hold output so LEDs enable. Default set for
|
||||
* WS2812B and WS2815.
|
||||
*
|
||||
* @param[in] handle the Addressable LED handle
|
||||
* @param[in] syncTime the sync time in microseconds (default 280 μs)
|
||||
* @param[out] status the error code, or 0 for success
|
||||
*/
|
||||
void HAL_SetAddressableLEDSyncTime(HAL_AddressableLEDHandle handle,
|
||||
int32_t syncTime, int32_t* status);
|
||||
|
||||
/**
|
||||
* Starts the output.
|
||||
*
|
||||
* <p>The output writes continuously.
|
||||
*
|
||||
* @param[in] handle the Addressable LED handle
|
||||
* @param[out] status the error code, or 0 for success
|
||||
*/
|
||||
void HAL_StartAddressableLEDOutput(HAL_AddressableLEDHandle handle,
|
||||
int32_t* status);
|
||||
|
||||
/**
|
||||
* Stops the output.
|
||||
*
|
||||
* @param[in] handle the Addressable LED handle
|
||||
* @param[out] status the error code, or 0 for success
|
||||
*/
|
||||
void HAL_StopAddressableLEDOutput(HAL_AddressableLEDHandle handle,
|
||||
int32_t* status);
|
||||
void HAL_SetAddressableLEDData(int32_t start, int32_t length,
|
||||
HAL_AddressableLEDColorOrder colorOrder,
|
||||
const struct HAL_AddressableLEDData* data,
|
||||
int32_t* status);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
||||
@@ -7,15 +7,14 @@
|
||||
#include <hal/Types.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/** max length of LED strip supported by FPGA. */
|
||||
#define HAL_kAddressableLEDMaxLength 5460
|
||||
/** max length of LED strip supported by device. */
|
||||
#define HAL_kAddressableLEDMaxLength 1024
|
||||
|
||||
/** structure for holding one LED's color data. */
|
||||
struct HAL_AddressableLEDData {
|
||||
uint8_t b; ///< blue value
|
||||
uint8_t g; ///< green value
|
||||
uint8_t r; ///< red value
|
||||
uint8_t padding;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,8 +12,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int32_t HALSIM_FindAddressableLEDForChannel(int32_t channel);
|
||||
|
||||
void HALSIM_ResetAddressableLEDData(int32_t index);
|
||||
|
||||
int32_t HALSIM_RegisterAddressableLEDInitializedCallback(
|
||||
@@ -23,12 +21,13 @@ void HALSIM_CancelAddressableLEDInitializedCallback(int32_t index, int32_t uid);
|
||||
HAL_Bool HALSIM_GetAddressableLEDInitialized(int32_t index);
|
||||
void HALSIM_SetAddressableLEDInitialized(int32_t index, HAL_Bool initialized);
|
||||
|
||||
int32_t HALSIM_RegisterAddressableLEDOutputPortCallback(
|
||||
int32_t index, HAL_NotifyCallback callback, void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelAddressableLEDOutputPortCallback(int32_t index, int32_t uid);
|
||||
int32_t HALSIM_GetAddressableLEDOutputPort(int32_t index);
|
||||
void HALSIM_SetAddressableLEDOutputPort(int32_t index, int32_t outputPort);
|
||||
int32_t HALSIM_RegisterAddressableLEDStartCallback(int32_t index,
|
||||
HAL_NotifyCallback callback,
|
||||
void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelAddressableLEDStartCallback(int32_t index, int32_t uid);
|
||||
int32_t HALSIM_GetAddressableLEDStart(int32_t index);
|
||||
void HALSIM_SetAddressableLEDStart(int32_t index, int32_t start);
|
||||
|
||||
int32_t HALSIM_RegisterAddressableLEDLengthCallback(int32_t index,
|
||||
HAL_NotifyCallback callback,
|
||||
@@ -38,21 +37,13 @@ void HALSIM_CancelAddressableLEDLengthCallback(int32_t index, int32_t uid);
|
||||
int32_t HALSIM_GetAddressableLEDLength(int32_t index);
|
||||
void HALSIM_SetAddressableLEDLength(int32_t index, int32_t length);
|
||||
|
||||
int32_t HALSIM_RegisterAddressableLEDRunningCallback(
|
||||
int32_t index, HAL_NotifyCallback callback, void* param,
|
||||
HAL_Bool initialNotify);
|
||||
void HALSIM_CancelAddressableLEDRunningCallback(int32_t index, int32_t uid);
|
||||
HAL_Bool HALSIM_GetAddressableLEDRunning(int32_t index);
|
||||
void HALSIM_SetAddressableLEDRunning(int32_t index, HAL_Bool running);
|
||||
|
||||
int32_t HALSIM_RegisterAddressableLEDDataCallback(
|
||||
int32_t index, HAL_ConstBufferCallback callback, void* param);
|
||||
void HALSIM_CancelAddressableLEDDataCallback(int32_t index, int32_t uid);
|
||||
int32_t HALSIM_GetAddressableLEDData(int32_t index,
|
||||
HAL_ConstBufferCallback callback, void* param);
|
||||
void HALSIM_CancelAddressableLEDDataCallback(int32_t uid);
|
||||
int32_t HALSIM_GetAddressableLEDData(int32_t start, int32_t length,
|
||||
struct HAL_AddressableLEDData* data);
|
||||
void HALSIM_SetAddressableLEDData(int32_t index,
|
||||
const struct HAL_AddressableLEDData* data,
|
||||
int32_t length);
|
||||
void HALSIM_SetAddressableLEDData(int32_t start, int32_t length,
|
||||
const struct HAL_AddressableLEDData* data);
|
||||
|
||||
void HALSIM_RegisterAddressableLEDAllCallbacks(int32_t index,
|
||||
HAL_NotifyCallback callback,
|
||||
|
||||
@@ -12,108 +12,90 @@
|
||||
#include "PortsInternal.h"
|
||||
#include "hal/Errors.h"
|
||||
#include "hal/handles/HandlesInternal.h"
|
||||
#include "hal/handles/LimitedHandleResource.h"
|
||||
#include "hal/handles/IndexedHandleResource.h"
|
||||
#include "mockdata/AddressableLEDDataInternal.h"
|
||||
|
||||
using namespace hal;
|
||||
|
||||
namespace {
|
||||
struct AddressableLED {
|
||||
uint8_t index;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
static LimitedHandleResource<HAL_AddressableLEDHandle, AddressableLED,
|
||||
kNumAddressableLEDs,
|
||||
HAL_HandleEnum::AddressableLED>* ledHandles;
|
||||
|
||||
namespace hal::init {
|
||||
void InitializeAddressableLED() {
|
||||
static LimitedHandleResource<HAL_AddressableLEDHandle, AddressableLED,
|
||||
kNumAddressableLEDs,
|
||||
HAL_HandleEnum::AddressableLED>
|
||||
dcH;
|
||||
ledHandles = &dcH;
|
||||
}
|
||||
void InitializeAddressableLED() {}
|
||||
} // namespace hal::init
|
||||
|
||||
extern "C" {
|
||||
HAL_AddressableLEDHandle HAL_InitializeAddressableLED(
|
||||
HAL_DigitalHandle outputPort, int32_t* status) {
|
||||
int32_t channel, const char* allocationLocation, int32_t* status) {
|
||||
hal::init::CheckInit();
|
||||
|
||||
auto digitalPort =
|
||||
hal::digitalChannelHandles->Get(outputPort, hal::HAL_HandleEnum::PWM);
|
||||
if (channel < 0 || channel >= kNumAddressableLEDs) {
|
||||
*status = RESOURCE_OUT_OF_RANGE;
|
||||
hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for AddressableLED",
|
||||
0, kNumAddressableLEDs, channel);
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
|
||||
if (!digitalPort) {
|
||||
// If DIO was passed, channel error, else generic error
|
||||
if (getHandleType(outputPort) == hal::HAL_HandleEnum::DIO) {
|
||||
*status = HAL_LED_CHANNEL_ERROR;
|
||||
HAL_DigitalHandle handle;
|
||||
|
||||
auto port = digitalChannelHandles->Allocate(
|
||||
channel, HAL_HandleEnum::AddressableLED, &handle, status);
|
||||
|
||||
if (*status != 0) {
|
||||
if (port) {
|
||||
hal::SetLastErrorPreviouslyAllocated(status, "PWM or DIO", channel,
|
||||
port->previousAllocation);
|
||||
} else {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
hal::SetLastErrorIndexOutOfRange(status,
|
||||
"Invalid Index for AddressableLED", 0,
|
||||
kNumAddressableLEDs, channel);
|
||||
}
|
||||
return HAL_kInvalidHandle;
|
||||
return HAL_kInvalidHandle; // failed to allocate. Pass error back.
|
||||
}
|
||||
|
||||
if (digitalPort->channel >= kNumPWMHeaders) {
|
||||
*status = HAL_LED_CHANNEL_ERROR;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
port->channel = static_cast<uint8_t>(channel);
|
||||
|
||||
HAL_AddressableLEDHandle handle = ledHandles->Allocate();
|
||||
if (handle == HAL_kInvalidHandle) {
|
||||
*status = NO_AVAILABLE_RESOURCES;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
SimAddressableLEDData[channel].start = 0;
|
||||
SimAddressableLEDData[channel].length = 0;
|
||||
SimAddressableLEDData[channel].initialized = true;
|
||||
port->previousAllocation = allocationLocation ? allocationLocation : "";
|
||||
|
||||
auto led = ledHandles->Get(handle);
|
||||
if (!led) { // would only occur on thread issue
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
|
||||
int16_t index = getHandleIndex(handle);
|
||||
SimAddressableLEDData[index].outputPort = digitalPort->channel;
|
||||
SimAddressableLEDData[index].length = 1;
|
||||
SimAddressableLEDData[index].running = false;
|
||||
SimAddressableLEDData[index].initialized = true;
|
||||
led->index = index;
|
||||
return handle;
|
||||
}
|
||||
|
||||
void HAL_FreeAddressableLED(HAL_AddressableLEDHandle handle) {
|
||||
auto led = ledHandles->Get(handle);
|
||||
ledHandles->Free(handle);
|
||||
if (!led) {
|
||||
auto port =
|
||||
digitalChannelHandles->Get(handle, HAL_HandleEnum::AddressableLED);
|
||||
// no status, so no need to check for a proper free.
|
||||
digitalChannelHandles->Free(handle, HAL_HandleEnum::AddressableLED);
|
||||
if (port == nullptr) {
|
||||
return;
|
||||
}
|
||||
SimAddressableLEDData[led->index].running = false;
|
||||
SimAddressableLEDData[led->index].initialized = false;
|
||||
SimAddressableLEDData[port->channel].initialized = false;
|
||||
}
|
||||
|
||||
void HAL_SetAddressableLEDColorOrder(HAL_AddressableLEDHandle handle,
|
||||
HAL_AddressableLEDColorOrder colorOrder,
|
||||
int32_t* status) {}
|
||||
|
||||
void HAL_SetAddressableLEDOutputPort(HAL_AddressableLEDHandle handle,
|
||||
HAL_DigitalHandle outputPort,
|
||||
int32_t* status) {
|
||||
auto led = ledHandles->Get(handle);
|
||||
if (!led) {
|
||||
void HAL_SetAddressableLEDStart(HAL_AddressableLEDHandle handle, int32_t start,
|
||||
int32_t* status) {
|
||||
auto port =
|
||||
digitalChannelHandles->Get(handle, HAL_HandleEnum::AddressableLED);
|
||||
if (!port) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
if (auto port = digitalChannelHandles->Get(outputPort, HAL_HandleEnum::PWM)) {
|
||||
SimAddressableLEDData[led->index].outputPort = port->channel;
|
||||
} else {
|
||||
SimAddressableLEDData[led->index].outputPort = -1;
|
||||
if (start > HAL_kAddressableLEDMaxLength || start < 0) {
|
||||
*status = PARAMETER_OUT_OF_RANGE;
|
||||
hal::SetLastError(
|
||||
status,
|
||||
fmt::format(
|
||||
"LED start must be less than or equal to {}. {} was requested",
|
||||
HAL_kAddressableLEDMaxLength, start));
|
||||
return;
|
||||
}
|
||||
SimAddressableLEDData[port->channel].start = start;
|
||||
}
|
||||
|
||||
void HAL_SetAddressableLEDLength(HAL_AddressableLEDHandle handle,
|
||||
int32_t length, int32_t* status) {
|
||||
auto led = ledHandles->Get(handle);
|
||||
if (!led) {
|
||||
auto port =
|
||||
digitalChannelHandles->Get(handle, HAL_HandleEnum::AddressableLED);
|
||||
if (!port) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
@@ -126,54 +108,13 @@ void HAL_SetAddressableLEDLength(HAL_AddressableLEDHandle handle,
|
||||
HAL_kAddressableLEDMaxLength, length));
|
||||
return;
|
||||
}
|
||||
SimAddressableLEDData[led->index].length = length;
|
||||
SimAddressableLEDData[port->channel].length = length;
|
||||
}
|
||||
|
||||
void HAL_WriteAddressableLEDData(HAL_AddressableLEDHandle handle,
|
||||
const struct HAL_AddressableLEDData* data,
|
||||
int32_t length, int32_t* status) {
|
||||
auto led = ledHandles->Get(handle);
|
||||
if (!led) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
if (length > SimAddressableLEDData[led->index].length) {
|
||||
*status = PARAMETER_OUT_OF_RANGE;
|
||||
hal::SetLastError(
|
||||
status,
|
||||
fmt::format(
|
||||
"Data length must be less than or equal to {}. {} was requested",
|
||||
SimAddressableLEDData[led->index].length.Get(), length));
|
||||
return;
|
||||
}
|
||||
SimAddressableLEDData[led->index].SetData(data, length);
|
||||
}
|
||||
|
||||
void HAL_SetAddressableLEDBitTiming(HAL_AddressableLEDHandle handle,
|
||||
int32_t highTime0, int32_t lowTime0,
|
||||
int32_t highTime1, int32_t lowTime1,
|
||||
int32_t* status) {}
|
||||
|
||||
void HAL_SetAddressableLEDSyncTime(HAL_AddressableLEDHandle handle,
|
||||
int32_t syncTime, int32_t* status) {}
|
||||
|
||||
void HAL_StartAddressableLEDOutput(HAL_AddressableLEDHandle handle,
|
||||
int32_t* status) {
|
||||
auto led = ledHandles->Get(handle);
|
||||
if (!led) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
SimAddressableLEDData[led->index].running = true;
|
||||
}
|
||||
|
||||
void HAL_StopAddressableLEDOutput(HAL_AddressableLEDHandle handle,
|
||||
int32_t* status) {
|
||||
auto led = ledHandles->Get(handle);
|
||||
if (!led) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
SimAddressableLEDData[led->index].running = false;
|
||||
void HAL_SetAddressableLEDData(int32_t start, int32_t length,
|
||||
HAL_AddressableLEDColorOrder colorOrder,
|
||||
const struct HAL_AddressableLEDData* data,
|
||||
int32_t* status) {
|
||||
SimAddressableLEDDataBuffer->SetData(start, length, data);
|
||||
}
|
||||
} // extern "C"
|
||||
|
||||
@@ -32,7 +32,7 @@ constexpr int32_t kNumREVPDHChannels = 24;
|
||||
constexpr int32_t kNumPDSimModules = kNumREVPDHModules;
|
||||
constexpr int32_t kNumPDSimChannels = kNumREVPDHChannels;
|
||||
constexpr int32_t kNumDutyCycles = 6;
|
||||
constexpr int32_t kNumAddressableLEDs = 1;
|
||||
constexpr int32_t kNumAddressableLEDs = 6;
|
||||
constexpr int32_t kNumREVPHModules = 63;
|
||||
constexpr int32_t kNumREVPHChannels = 16;
|
||||
constexpr int32_t kSPIAccelerometers = 5;
|
||||
|
||||
@@ -14,62 +14,64 @@ namespace hal::init {
|
||||
void InitializeAddressableLEDData() {
|
||||
static AddressableLEDData sad[kNumAddressableLEDs];
|
||||
::hal::SimAddressableLEDData = sad;
|
||||
static AddressableLEDDataBuffer buf;
|
||||
::hal::SimAddressableLEDDataBuffer = &buf;
|
||||
}
|
||||
} // namespace hal::init
|
||||
|
||||
AddressableLEDData* hal::SimAddressableLEDData;
|
||||
AddressableLEDDataBuffer* hal::SimAddressableLEDDataBuffer;
|
||||
|
||||
void AddressableLEDData::ResetData() {
|
||||
initialized.Reset(false);
|
||||
outputPort.Reset(-1);
|
||||
length.Reset(1);
|
||||
running.Reset(false);
|
||||
data.Reset();
|
||||
start.Reset(0);
|
||||
length.Reset(0);
|
||||
}
|
||||
|
||||
void AddressableLEDData::SetData(const HAL_AddressableLEDData* d, int32_t len) {
|
||||
len = (std::min)(HAL_kAddressableLEDMaxLength, len);
|
||||
void AddressableLEDDataBuffer::SetData(int32_t start, int32_t len,
|
||||
const HAL_AddressableLEDData* d) {
|
||||
if ((start + len) > HAL_kAddressableLEDMaxLength) {
|
||||
len = HAL_kAddressableLEDMaxLength - start;
|
||||
}
|
||||
if (len <= 0) {
|
||||
return;
|
||||
}
|
||||
{
|
||||
std::scoped_lock lock(m_dataMutex);
|
||||
std::memcpy(m_data, d, len * sizeof(d[0]));
|
||||
std::memcpy(&m_data[start], d, len * sizeof(d[0]));
|
||||
}
|
||||
data(reinterpret_cast<const uint8_t*>(d), len * sizeof(d[0]));
|
||||
}
|
||||
|
||||
int32_t AddressableLEDData::GetData(HAL_AddressableLEDData* d) {
|
||||
int32_t AddressableLEDDataBuffer::GetData(int32_t start, int32_t len,
|
||||
HAL_AddressableLEDData* d) {
|
||||
if ((start + len) > HAL_kAddressableLEDMaxLength) {
|
||||
len = HAL_kAddressableLEDMaxLength - start;
|
||||
}
|
||||
if (len <= 0) {
|
||||
return 0;
|
||||
}
|
||||
std::scoped_lock lock(m_dataMutex);
|
||||
int32_t len = length;
|
||||
if (d) {
|
||||
std::memcpy(d, m_data, len * sizeof(d[0]));
|
||||
std::memcpy(d, &m_data[start], len * sizeof(d[0]));
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
int32_t HALSIM_FindAddressableLEDForChannel(int32_t channel) {
|
||||
for (int i = 0; i < kNumAddressableLEDs; ++i) {
|
||||
if (SimAddressableLEDData[i].initialized &&
|
||||
SimAddressableLEDData[i].outputPort == channel) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void HALSIM_ResetAddressableLEDData(int32_t index) {
|
||||
SimAddressableLEDData[index].ResetData();
|
||||
}
|
||||
|
||||
int32_t HALSIM_GetAddressableLEDData(int32_t index,
|
||||
int32_t HALSIM_GetAddressableLEDData(int32_t start, int32_t length,
|
||||
struct HAL_AddressableLEDData* data) {
|
||||
return SimAddressableLEDData[index].GetData(data);
|
||||
return SimAddressableLEDDataBuffer->GetData(start, length, data);
|
||||
}
|
||||
|
||||
void HALSIM_SetAddressableLEDData(int32_t index,
|
||||
const struct HAL_AddressableLEDData* data,
|
||||
int32_t length) {
|
||||
SimAddressableLEDData[index].SetData(data, length);
|
||||
void HALSIM_SetAddressableLEDData(int32_t start, int32_t length,
|
||||
const struct HAL_AddressableLEDData* data) {
|
||||
SimAddressableLEDDataBuffer->SetData(start, length, data);
|
||||
}
|
||||
|
||||
#define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME) \
|
||||
@@ -77,14 +79,14 @@ void HALSIM_SetAddressableLEDData(int32_t index,
|
||||
SimAddressableLEDData, LOWERNAME)
|
||||
|
||||
DEFINE_CAPI(HAL_Bool, Initialized, initialized)
|
||||
DEFINE_CAPI(int32_t, OutputPort, outputPort)
|
||||
DEFINE_CAPI(int32_t, Start, start)
|
||||
DEFINE_CAPI(int32_t, Length, length)
|
||||
DEFINE_CAPI(HAL_Bool, Running, running)
|
||||
|
||||
#undef DEFINE_CAPI
|
||||
#define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME) \
|
||||
HAL_SIMCALLBACKREGISTRY_DEFINE_CAPI(TYPE, HALSIM, AddressableLED##CAPINAME, \
|
||||
SimAddressableLEDData, LOWERNAME)
|
||||
#define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME) \
|
||||
HAL_SIMCALLBACKREGISTRY_DEFINE_CAPI_NOINDEX( \
|
||||
TYPE, HALSIM, AddressableLED##CAPINAME, SimAddressableLEDDataBuffer, \
|
||||
LOWERNAME)
|
||||
|
||||
DEFINE_CAPI(HAL_ConstBufferCallback, Data, data)
|
||||
|
||||
@@ -97,8 +99,7 @@ void HALSIM_RegisterAddressableLEDAllCallbacks(int32_t index,
|
||||
void* param,
|
||||
HAL_Bool initialNotify) {
|
||||
REGISTER(initialized);
|
||||
REGISTER(outputPort);
|
||||
REGISTER(start);
|
||||
REGISTER(length);
|
||||
REGISTER(running);
|
||||
}
|
||||
} // extern "C"
|
||||
|
||||
@@ -15,26 +15,29 @@
|
||||
namespace hal {
|
||||
class AddressableLEDData {
|
||||
HAL_SIMDATAVALUE_DEFINE_NAME(Initialized)
|
||||
HAL_SIMDATAVALUE_DEFINE_NAME(OutputPort)
|
||||
HAL_SIMDATAVALUE_DEFINE_NAME(Start)
|
||||
HAL_SIMDATAVALUE_DEFINE_NAME(Length)
|
||||
HAL_SIMDATAVALUE_DEFINE_NAME(Running)
|
||||
|
||||
public:
|
||||
SimDataValue<HAL_Bool, HAL_MakeBoolean, GetInitializedName> initialized{
|
||||
false};
|
||||
SimDataValue<int32_t, HAL_MakeInt, GetStartName> start{0};
|
||||
SimDataValue<int32_t, HAL_MakeInt, GetLengthName> length{0};
|
||||
|
||||
void ResetData();
|
||||
};
|
||||
extern AddressableLEDData* SimAddressableLEDData;
|
||||
|
||||
class AddressableLEDDataBuffer {
|
||||
HAL_SIMDATAVALUE_DEFINE_NAME(Data)
|
||||
|
||||
wpi::recursive_spinlock m_dataMutex;
|
||||
HAL_AddressableLEDData m_data[HAL_kAddressableLEDMaxLength];
|
||||
|
||||
public:
|
||||
void SetData(const HAL_AddressableLEDData* d, int32_t len);
|
||||
int32_t GetData(HAL_AddressableLEDData* d);
|
||||
|
||||
SimDataValue<HAL_Bool, HAL_MakeBoolean, GetInitializedName> initialized{
|
||||
false};
|
||||
SimDataValue<int32_t, HAL_MakeInt, GetOutputPortName> outputPort{-1};
|
||||
SimDataValue<int32_t, HAL_MakeInt, GetLengthName> length{1};
|
||||
SimDataValue<HAL_Bool, HAL_MakeBoolean, GetRunningName> running{false};
|
||||
void SetData(int32_t start, int32_t len, const HAL_AddressableLEDData* d);
|
||||
int32_t GetData(int32_t start, int32_t len, HAL_AddressableLEDData* d);
|
||||
SimCallbackRegistry<HAL_ConstBufferCallback, GetDataName> data;
|
||||
|
||||
void ResetData();
|
||||
};
|
||||
extern AddressableLEDData* SimAddressableLEDData;
|
||||
extern AddressableLEDDataBuffer* SimAddressableLEDDataBuffer;
|
||||
} // namespace hal
|
||||
|
||||
@@ -4,85 +4,152 @@
|
||||
|
||||
#include "hal/AddressableLED.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <networktables/NetworkTableInstance.h>
|
||||
#include <networktables/RawTopic.h>
|
||||
|
||||
#include "HALInitializer.h"
|
||||
#include "HALInternal.h"
|
||||
#include "PortsInternal.h"
|
||||
#include "SmartIo.h"
|
||||
#include "SystemServerInternal.h"
|
||||
#include "hal/AddressableLEDTypes.h"
|
||||
#include "hal/Errors.h"
|
||||
#include "hal/cpp/fpga_clock.h"
|
||||
|
||||
using namespace hal;
|
||||
|
||||
#define LEDS_PREFIX "/leds/"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr const char* kRawKey = LEDS_PREFIX "raw";
|
||||
|
||||
struct AddressableLEDs {
|
||||
explicit AddressableLEDs(nt::NetworkTableInstance inst)
|
||||
: rawPub{inst.GetRawTopic(kRawKey).Publish(
|
||||
"raw", {.periodic = 0.005, .sendAll = true})} {}
|
||||
|
||||
nt::RawPublisher rawPub;
|
||||
uint8_t s_buffer[HAL_kAddressableLEDMaxLength * 3];
|
||||
};
|
||||
|
||||
static AddressableLEDs* leds;
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace hal::init {
|
||||
void InitializeAddressableLED() {}
|
||||
void InitializeAddressableLED() {
|
||||
static AddressableLEDs leds_static{hal::GetSystemServer()};
|
||||
leds = &leds_static;
|
||||
}
|
||||
} // namespace hal::init
|
||||
|
||||
extern "C" {
|
||||
|
||||
HAL_AddressableLEDHandle HAL_InitializeAddressableLED(
|
||||
HAL_DigitalHandle outputPort, int32_t* status) {
|
||||
int32_t channel, const char* allocationLocation, int32_t* status) {
|
||||
hal::init::CheckInit();
|
||||
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return HAL_kInvalidHandle;
|
||||
if (channel < 0 || channel >= kNumSmartIo) {
|
||||
*status = RESOURCE_OUT_OF_RANGE;
|
||||
hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for AddressableLED",
|
||||
0, kNumSmartIo, channel);
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
|
||||
HAL_DigitalHandle handle;
|
||||
|
||||
auto port = smartIoHandles->Allocate(channel, HAL_HandleEnum::AddressableLED,
|
||||
&handle, status);
|
||||
|
||||
if (*status != 0) {
|
||||
if (port) {
|
||||
hal::SetLastErrorPreviouslyAllocated(status, "SmartIo", channel,
|
||||
port->previousAllocation);
|
||||
} else {
|
||||
hal::SetLastErrorIndexOutOfRange(
|
||||
status, "Invalid Index for AddressableLED", 0, kNumSmartIo, channel);
|
||||
}
|
||||
return HAL_kInvalidHandle; // failed to allocate. Pass error back.
|
||||
}
|
||||
|
||||
port->channel = channel;
|
||||
|
||||
*status = port->InitializeMode(SmartIoMode::AddressableLED);
|
||||
if (*status != 0) {
|
||||
smartIoHandles->Free(handle, HAL_HandleEnum::AddressableLED);
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
|
||||
port->previousAllocation = allocationLocation ? allocationLocation : "";
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
void HAL_FreeAddressableLED(HAL_AddressableLEDHandle handle) {}
|
||||
void HAL_FreeAddressableLED(HAL_AddressableLEDHandle handle) {
|
||||
auto port = smartIoHandles->Get(handle, HAL_HandleEnum::AddressableLED);
|
||||
if (port == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
void HAL_SetAddressableLEDColorOrder(HAL_AddressableLEDHandle handle,
|
||||
HAL_AddressableLEDColorOrder colorOrder,
|
||||
int32_t* status) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
smartIoHandles->Free(handle, HAL_HandleEnum::AddressableLED);
|
||||
|
||||
// Wait for no other object to hold this handle.
|
||||
auto start = hal::fpga_clock::now();
|
||||
while (port.use_count() != 1) {
|
||||
auto current = hal::fpga_clock::now();
|
||||
if (start + std::chrono::seconds(1) < current) {
|
||||
std::puts("AddressableLED handle free timeout");
|
||||
std::fflush(stdout);
|
||||
break;
|
||||
}
|
||||
std::this_thread::yield();
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_SetAddressableLEDOutputPort(HAL_AddressableLEDHandle handle,
|
||||
HAL_DigitalHandle outputPort,
|
||||
int32_t* status) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
void HAL_SetAddressableLEDStart(HAL_AddressableLEDHandle handle, int32_t start,
|
||||
int32_t* status) {
|
||||
auto port = smartIoHandles->Get(handle, HAL_HandleEnum::AddressableLED);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
*status = port->SetLedStart(start);
|
||||
}
|
||||
|
||||
void HAL_SetAddressableLEDLength(HAL_AddressableLEDHandle handle,
|
||||
int32_t length, int32_t* status) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
auto port = smartIoHandles->Get(handle, HAL_HandleEnum::AddressableLED);
|
||||
if (port == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
*status = port->SetLedLength(length);
|
||||
}
|
||||
|
||||
static_assert(sizeof(HAL_AddressableLEDData) == sizeof(uint32_t),
|
||||
"LED Data must be 32 bit");
|
||||
static_assert(sizeof(HAL_AddressableLEDData) == 3, "LED Data must be 3 bytes");
|
||||
|
||||
void HAL_WriteAddressableLEDData(HAL_AddressableLEDHandle handle,
|
||||
const struct HAL_AddressableLEDData* data,
|
||||
int32_t length, int32_t* status) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
void HAL_SetAddressableLEDBitTiming(HAL_AddressableLEDHandle handle,
|
||||
int32_t highTime0, int32_t lowTime0,
|
||||
int32_t highTime1, int32_t lowTime1,
|
||||
int32_t* status) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
void HAL_SetAddressableLEDSyncTime(HAL_AddressableLEDHandle handle,
|
||||
int32_t syncTime, int32_t* status) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
void HAL_StartAddressableLEDOutput(HAL_AddressableLEDHandle handle,
|
||||
int32_t* status) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
void HAL_StopAddressableLEDOutput(HAL_AddressableLEDHandle handle,
|
||||
int32_t* status) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
void HAL_SetAddressableLEDData(int32_t start, int32_t length,
|
||||
HAL_AddressableLEDColorOrder colorOrder,
|
||||
const struct HAL_AddressableLEDData* data,
|
||||
int32_t* status) {
|
||||
if (start < 0 || start >= HAL_kAddressableLEDMaxLength || length < 0 ||
|
||||
(start + length) >= HAL_kAddressableLEDMaxLength) {
|
||||
*status = PARAMETER_OUT_OF_RANGE;
|
||||
return;
|
||||
}
|
||||
// TODO: handle color order
|
||||
std::memcpy(&leds->s_buffer[start * 3], data, length * 3);
|
||||
leds->rawPub.Set(leds->s_buffer);
|
||||
}
|
||||
} // extern "C"
|
||||
|
||||
@@ -29,7 +29,7 @@ constexpr int32_t kNumCTREPDPChannels = 16;
|
||||
constexpr int32_t kNumREVPDHModules = 63;
|
||||
constexpr int32_t kNumREVPDHChannels = 24;
|
||||
constexpr int32_t kNumDutyCycles = 0;
|
||||
constexpr int32_t kNumAddressableLEDs = 0;
|
||||
constexpr int32_t kNumAddressableLEDs = 6;
|
||||
constexpr int32_t kNumREVPHModules = 63;
|
||||
constexpr int32_t kNumREVPHChannels = 16;
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
#include "HALInitializer.h"
|
||||
#include "SystemServerInternal.h"
|
||||
#include "hal/AddressableLEDTypes.h"
|
||||
#include "hal/Errors.h"
|
||||
|
||||
namespace hal {
|
||||
|
||||
@@ -42,6 +44,10 @@ int32_t SmartIo::InitializeMode(SmartIoMode mode) {
|
||||
inst.GetIntegerTopic(subTableString + "valset").Publish(options);
|
||||
periodSetPublisher =
|
||||
inst.GetIntegerTopic(subTableString + "periodset").Publish(options);
|
||||
ledcountPublisher =
|
||||
inst.GetIntegerTopic(subTableString + "ledcount").Publish(options);
|
||||
ledoffsetPublisher =
|
||||
inst.GetIntegerTopic(subTableString + "ledoffset").Publish(options);
|
||||
|
||||
currentMode = mode;
|
||||
switch (mode) {
|
||||
@@ -50,6 +56,10 @@ int32_t SmartIo::InitializeMode(SmartIoMode mode) {
|
||||
case SmartIoMode::PwmOutput:
|
||||
setPublisher.Set(0);
|
||||
break;
|
||||
case SmartIoMode::AddressableLED:
|
||||
ledcountPublisher.Set(0);
|
||||
ledoffsetPublisher.Set(0);
|
||||
break;
|
||||
|
||||
// These don't need to set any value
|
||||
case SmartIoMode::DigitalInput:
|
||||
@@ -189,4 +199,26 @@ int32_t SmartIo::GetCounter(int32_t* value) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t SmartIo::SetLedStart(int32_t start) {
|
||||
if (currentMode != SmartIoMode::AddressableLED) {
|
||||
return INCOMPATIBLE_STATE;
|
||||
}
|
||||
if (start < 0 || start >= HAL_kAddressableLEDMaxLength) {
|
||||
return PARAMETER_OUT_OF_RANGE;
|
||||
}
|
||||
ledoffsetPublisher.Set(start);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t SmartIo::SetLedLength(int32_t length) {
|
||||
if (currentMode != SmartIoMode::AddressableLED) {
|
||||
return INCOMPATIBLE_STATE;
|
||||
}
|
||||
if (length < 0 || length >= HAL_kAddressableLEDMaxLength) {
|
||||
return PARAMETER_OUT_OF_RANGE;
|
||||
}
|
||||
ledcountPublisher.Set(length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace hal
|
||||
|
||||
@@ -25,6 +25,7 @@ enum class SmartIoMode {
|
||||
PwmOutput = 4,
|
||||
SingleCounterRising = 5,
|
||||
SingleCounterFalling = 6,
|
||||
AddressableLED = 13,
|
||||
};
|
||||
|
||||
enum class PwmOutputPeriod {
|
||||
@@ -46,6 +47,9 @@ struct SmartIo {
|
||||
nt::IntegerPublisher periodSetPublisher;
|
||||
nt::IntegerSubscriber periodGetSubscriber;
|
||||
|
||||
nt::IntegerPublisher ledcountPublisher;
|
||||
nt::IntegerPublisher ledoffsetPublisher;
|
||||
|
||||
int32_t InitializeMode(SmartIoMode mode);
|
||||
int32_t SwitchDioDirection(bool input);
|
||||
|
||||
@@ -63,6 +67,9 @@ struct SmartIo {
|
||||
int32_t GetAnalogInput(uint16_t* value);
|
||||
|
||||
int32_t GetCounter(int32_t* count);
|
||||
|
||||
int32_t SetLedStart(int32_t start);
|
||||
int32_t SetLedLength(int32_t length);
|
||||
};
|
||||
|
||||
extern DigitalHandleResource<HAL_DigitalHandle, SmartIo, kNumSmartIo>*
|
||||
|
||||
@@ -8,32 +8,27 @@
|
||||
|
||||
extern "C" {
|
||||
|
||||
int32_t HALSIM_FindAddressableLEDForChannel(int32_t channel) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void HALSIM_ResetAddressableLEDData(int32_t index) {}
|
||||
|
||||
int32_t HALSIM_GetAddressableLEDData(int32_t index,
|
||||
int32_t HALSIM_GetAddressableLEDData(int32_t start, int32_t length,
|
||||
struct HAL_AddressableLEDData* data) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void HALSIM_SetAddressableLEDData(int32_t index,
|
||||
const struct HAL_AddressableLEDData* data,
|
||||
int32_t length) {}
|
||||
void HALSIM_SetAddressableLEDData(int32_t start, int32_t length,
|
||||
const struct HAL_AddressableLEDData* data) {}
|
||||
|
||||
#define DEFINE_CAPI(TYPE, CAPINAME, RETURN) \
|
||||
HAL_SIMDATAVALUE_STUB_CAPI(TYPE, HALSIM, AddressableLED##CAPINAME, RETURN)
|
||||
|
||||
DEFINE_CAPI(HAL_Bool, Initialized, false)
|
||||
DEFINE_CAPI(int32_t, OutputPort, 0)
|
||||
DEFINE_CAPI(int32_t, Start, 0)
|
||||
DEFINE_CAPI(int32_t, Length, 0)
|
||||
DEFINE_CAPI(HAL_Bool, Running, false)
|
||||
|
||||
#undef DEFINE_CAPI
|
||||
#define DEFINE_CAPI(TYPE, CAPINAME, RETURN) \
|
||||
HAL_SIMCALLBACKREGISTRY_STUB_CAPI(TYPE, HALSIM, AddressableLED##CAPINAME)
|
||||
#define DEFINE_CAPI(TYPE, CAPINAME, RETURN) \
|
||||
HAL_SIMCALLBACKREGISTRY_STUB_CAPI_NOINDEX(TYPE, HALSIM, \
|
||||
AddressableLED##CAPINAME)
|
||||
|
||||
DEFINE_CAPI(HAL_ConstBufferCallback, Data, data)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user