mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
[hal, wpilib] Update Addressable LED support (#8100)
This commit is contained in:
@@ -25,7 +25,6 @@ void glass::DisplayLEDDisplay(LEDDisplayModel* model, int index) {
|
||||
wpi::SmallVector<LEDDisplayModel::Data, 64> dataBuf;
|
||||
auto data = model->GetData(dataBuf);
|
||||
int length = data.size();
|
||||
bool running = model->IsRunning();
|
||||
auto& storage = GetStorage();
|
||||
|
||||
int& numColumns = storage.GetInt("columns", 10);
|
||||
@@ -35,7 +34,6 @@ void glass::DisplayLEDDisplay(LEDDisplayModel* model, int index) {
|
||||
|
||||
ImGui::PushItemWidth(ImGui::GetFontSize() * 7);
|
||||
ImGui::LabelText("Length", "%d", length);
|
||||
ImGui::LabelText("Running", "%s", running ? "Yes" : "No");
|
||||
ImGui::InputInt("Columns", &numColumns);
|
||||
{
|
||||
static const char* options[] = {"Row Major", "Column Major"};
|
||||
@@ -64,16 +62,9 @@ void glass::DisplayLEDDisplay(LEDDisplayModel* model, int index) {
|
||||
if (length > static_cast<int>(iData->colors.size())) {
|
||||
iData->colors.resize(length);
|
||||
}
|
||||
if (!running) {
|
||||
iData->colors[0] = IM_COL32(128, 128, 128, 255);
|
||||
for (int j = 0; j < length; ++j) {
|
||||
iData->values[j] = -1;
|
||||
}
|
||||
} else {
|
||||
for (int j = 0; j < length; ++j) {
|
||||
iData->values[j] = j + 1;
|
||||
iData->colors[j] = IM_COL32(data[j].r, data[j].g, data[j].b, 255);
|
||||
}
|
||||
for (int j = 0; j < length; ++j) {
|
||||
iData->values[j] = j + 1;
|
||||
iData->colors[j] = IM_COL32(data[j].r, data[j].g, data[j].b, 255);
|
||||
}
|
||||
|
||||
LEDConfig config;
|
||||
|
||||
@@ -30,15 +30,9 @@ void glass::DisplayPWM(PWMModel* model, int index, bool outputsEnabled) {
|
||||
wpi::format_to_n_c_str(label, sizeof(label), "PWM[{}]###name", index);
|
||||
}
|
||||
|
||||
int led = model->GetAddressableLED();
|
||||
|
||||
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 4);
|
||||
if (led >= 0) {
|
||||
ImGui::LabelText(label, "LED[%d]", led);
|
||||
} else {
|
||||
float val = outputsEnabled ? data->GetValue() : 0;
|
||||
data->LabelText(label, "%0.3f", val);
|
||||
}
|
||||
float val = outputsEnabled ? data->GetValue() : 0;
|
||||
data->LabelText(label, "%0.3f", val);
|
||||
if (PopupEditName("name", &name)) {
|
||||
data->SetName(name);
|
||||
}
|
||||
|
||||
@@ -23,11 +23,8 @@ class LEDDisplayModel : public glass::Model {
|
||||
uint8_t b;
|
||||
uint8_t g;
|
||||
uint8_t r;
|
||||
uint8_t padding;
|
||||
};
|
||||
|
||||
virtual bool IsRunning() = 0;
|
||||
|
||||
virtual std::span<const Data> GetData(wpi::SmallVectorImpl<Data>& buf) = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -16,9 +16,6 @@ class DoubleSource;
|
||||
|
||||
class PWMModel : public Model {
|
||||
public:
|
||||
// returns -1 if not an addressable LED
|
||||
virtual int GetAddressableLED() const = 0;
|
||||
|
||||
virtual DoubleSource* GetSpeedData() = 0;
|
||||
|
||||
virtual void SetSpeed(double val) = 0;
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
package edu.wpi.first.hal;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Addressable LED HAL JNI Methods.
|
||||
*
|
||||
@@ -18,13 +20,13 @@ public class AddressableLEDJNI extends JNIWrapper {
|
||||
public static final int COLOR_ORDER_GRB = 5;
|
||||
|
||||
/**
|
||||
* Initialize Addressable LED using a PWM Digital handle.
|
||||
* Create a new instance of an Addressable LED port.
|
||||
*
|
||||
* @param pwmHandle handle of the digital port for PWM
|
||||
* @param channel the smartio channel
|
||||
* @return Addressable LED handle
|
||||
* @see "HAL_InitializeAddressableLED"
|
||||
*/
|
||||
public static native int initialize(int pwmHandle);
|
||||
public static native int initialize(int channel);
|
||||
|
||||
/**
|
||||
* Free the Addressable LED Handle.
|
||||
@@ -35,82 +37,116 @@ public class AddressableLEDJNI extends JNIWrapper {
|
||||
public static native void free(int handle);
|
||||
|
||||
/**
|
||||
* Sets the color order for the addressable LED output. The default order is GRB.
|
||||
* Sets the start buffer location used for the LED strip.
|
||||
*
|
||||
* <p>This will take effect on the next call to {@link #setData(int, byte[])}.
|
||||
* <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 handle the Addressable LED handle
|
||||
* @param colorOrder the color order
|
||||
* @param start the strip start, in LEDs
|
||||
*/
|
||||
public static native void setColorOrder(int handle, int colorOrder);
|
||||
public static native void setStart(int handle, int start);
|
||||
|
||||
/**
|
||||
* 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 handle the Addressable LED handle
|
||||
* @param length the strip length
|
||||
* @see "HAL_SetAddressableLEDLength"
|
||||
* @param length the strip length, in LEDs
|
||||
*/
|
||||
public static native void setLength(int handle, 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.
|
||||
* <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 handle the Addressable LED handle
|
||||
* @param outStart the strip start in the backing buffer, in LEDs
|
||||
* @param colorOrder the color order
|
||||
* @param data the buffer to write
|
||||
* @see "HAL_WriteAddressableLEDData"
|
||||
*/
|
||||
public static native void setData(int handle, byte[] data);
|
||||
public static void setData(int outStart, int colorOrder, byte[] data) {
|
||||
setData(outStart, colorOrder, data, 0, data.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bit timing.
|
||||
* Sets the led output data.
|
||||
*
|
||||
* <p>By default, the driver is set up to drive WS2812B and WS2815, so nothing needs to be set for
|
||||
* those.
|
||||
* <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 handle the Addressable LED handle
|
||||
* @param highTime0 high time for 0 bit in nanoseconds (default 400 ns)
|
||||
* @param lowTime0 low time for 0 bit in nanoseconds (default 900 ns)
|
||||
* @param highTime1 high time for 1 bit in nanoseconds (default 900 ns)
|
||||
* @param lowTime1 low time for 1 bit in nanoseconds (default 600 ns)
|
||||
* @see "HAL_SetAddressableLEDBitTiming"
|
||||
* @param outStart the strip start in the backing buffer, in LEDs
|
||||
* @param colorOrder the color order
|
||||
* @param data the buffer to write
|
||||
* @param start offset into data, in bytes
|
||||
* @param len Length of data, in bytes
|
||||
*/
|
||||
public static native void setBitTiming(
|
||||
int handle, int highTime0, int lowTime0, int highTime1, int lowTime1);
|
||||
public static native void setData(int outStart, int colorOrder, byte[] data, int start, int len);
|
||||
|
||||
/**
|
||||
* Sets the sync time.
|
||||
* Sets the led output data.
|
||||
*
|
||||
* <p>The sync time is the time to hold output so LEDs enable. Default set for WS2812B and WS2815.
|
||||
* <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 handle the Addressable LED handle
|
||||
* @param syncTime the sync time in microseconds (default 280 μs)
|
||||
* @see "HAL_SetAddressableLEDSyncTime"
|
||||
* @param outStart the strip start in the backing buffer, in LEDs
|
||||
* @param colorOrder the color order
|
||||
* @param data the buffer to write
|
||||
*/
|
||||
public static native void setSyncTime(int handle, int syncTime);
|
||||
public static void setData(int outStart, int colorOrder, ByteBuffer data) {
|
||||
int pos = data.position();
|
||||
setData(outStart, colorOrder, data, pos, data.capacity() - pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the output.
|
||||
* Sets the led output data.
|
||||
*
|
||||
* <p>The output writes continuously.
|
||||
* <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 handle the Addressable LED handle
|
||||
* @see "HAL_StartAddressableLEDOutput"
|
||||
* @param outStart the strip start in the backing buffer, in LEDs
|
||||
* @param colorOrder the color order
|
||||
* @param data the buffer to write
|
||||
* @param start offset into data, in bytes
|
||||
* @param len Length of data, in bytes
|
||||
*/
|
||||
public static native void start(int handle);
|
||||
public static void setData(int outStart, int colorOrder, ByteBuffer data, int start, int len) {
|
||||
if (data.isDirect()) {
|
||||
if (start < 0) {
|
||||
throw new IndexOutOfBoundsException("start must be >= 0");
|
||||
}
|
||||
if (len < 0) {
|
||||
throw new IndexOutOfBoundsException("len must be >= 0");
|
||||
}
|
||||
if ((start + len) > data.capacity()) {
|
||||
throw new IndexOutOfBoundsException("start + len must be smaller than buffer capacity");
|
||||
}
|
||||
setDataFromBuffer(outStart, colorOrder, data, start, len);
|
||||
} else if (data.hasArray()) {
|
||||
setData(outStart, colorOrder, data.array(), data.arrayOffset() + start, len);
|
||||
} else {
|
||||
throw new UnsupportedOperationException("ByteBuffer must be direct or have a backing array");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the output.
|
||||
* Sets the led output data.
|
||||
*
|
||||
* @param handle the Addressable LED handle
|
||||
* @see "HAL_StopAddressableLEDOutput"
|
||||
* <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 outStart the strip start in the backing buffer, in LEDs
|
||||
* @param colorOrder the color order
|
||||
* @param data the buffer to write
|
||||
* @param start offset into data, in bytes
|
||||
* @param len Length of data, in bytes
|
||||
*/
|
||||
public static native void stop(int handle);
|
||||
private static native void setDataFromBuffer(
|
||||
int outStart, int colorOrder, ByteBuffer data, int start, int len);
|
||||
|
||||
/** Utility class. */
|
||||
private AddressableLEDJNI() {}
|
||||
|
||||
@@ -17,14 +17,14 @@ public class AddressableLEDDataJNI extends JNIWrapper {
|
||||
|
||||
public static native void setInitialized(int index, boolean initialized);
|
||||
|
||||
public static native int registerOutputPortCallback(
|
||||
public static native int registerStartCallback(
|
||||
int index, NotifyCallback callback, boolean initialNotify);
|
||||
|
||||
public static native void cancelOutputPortCallback(int index, int uid);
|
||||
public static native void cancelStartCallback(int index, int uid);
|
||||
|
||||
public static native int getOutputPort(int index);
|
||||
public static native int getStart(int index);
|
||||
|
||||
public static native void setOutputPort(int index, int outputPort);
|
||||
public static native void setStart(int index, int start);
|
||||
|
||||
public static native int registerLengthCallback(
|
||||
int index, NotifyCallback callback, boolean initialNotify);
|
||||
@@ -35,27 +35,16 @@ public class AddressableLEDDataJNI extends JNIWrapper {
|
||||
|
||||
public static native void setLength(int index, int length);
|
||||
|
||||
public static native int registerRunningCallback(
|
||||
int index, NotifyCallback callback, boolean initialNotify);
|
||||
public static native int registerDataCallback(ConstBufferCallback callback);
|
||||
|
||||
public static native void cancelRunningCallback(int index, int uid);
|
||||
public static native void cancelDataCallback(int uid);
|
||||
|
||||
public static native boolean getRunning(int index);
|
||||
public static native byte[] getData(int start, int length);
|
||||
|
||||
public static native void setRunning(int index, boolean running);
|
||||
|
||||
public static native int registerDataCallback(int index, ConstBufferCallback callback);
|
||||
|
||||
public static native void cancelDataCallback(int index, int uid);
|
||||
|
||||
public static native byte[] getData(int index);
|
||||
|
||||
public static native void setData(int index, byte[] data);
|
||||
public static native void setData(int start, byte[] data);
|
||||
|
||||
public static native void resetData(int index);
|
||||
|
||||
public static native int findForChannel(int channel);
|
||||
|
||||
/** Utility class. */
|
||||
private AddressableLEDDataJNI() {}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -19,22 +19,22 @@ using namespace halsimgui;
|
||||
namespace {
|
||||
class AddressableLEDModel : public glass::LEDDisplayModel {
|
||||
public:
|
||||
explicit AddressableLEDModel(int32_t index) : m_index{index} {}
|
||||
explicit AddressableLEDModel(int32_t channel) : m_channel{channel} {}
|
||||
|
||||
void Update() override {}
|
||||
bool Exists() override {
|
||||
return HALSIM_GetAddressableLEDInitialized(m_index);
|
||||
return HALSIM_GetAddressableLEDInitialized(m_channel);
|
||||
}
|
||||
|
||||
bool IsRunning() override { return HALSIM_GetAddressableLEDRunning(m_index); }
|
||||
|
||||
std::span<const Data> GetData(wpi::SmallVectorImpl<Data>&) override {
|
||||
size_t length = HALSIM_GetAddressableLEDData(m_index, m_data);
|
||||
size_t length = HALSIM_GetAddressableLEDData(
|
||||
HALSIM_GetAddressableLEDStart(m_channel),
|
||||
HALSIM_GetAddressableLEDLength(m_channel), m_data);
|
||||
return {reinterpret_cast<Data*>(m_data), length};
|
||||
}
|
||||
|
||||
private:
|
||||
int32_t m_index;
|
||||
int32_t m_channel;
|
||||
|
||||
HAL_AddressableLEDData m_data[HAL_kAddressableLEDMaxLength];
|
||||
};
|
||||
@@ -49,7 +49,7 @@ class AddressableLEDsModel : public glass::LEDDisplaysModel {
|
||||
size_t GetNumLEDDisplays() override { return m_models.size(); }
|
||||
|
||||
void ForEachLEDDisplay(
|
||||
wpi::function_ref<void(glass::LEDDisplayModel& model, int index)> func)
|
||||
wpi::function_ref<void(glass::LEDDisplayModel& model, int channel)> func)
|
||||
override;
|
||||
|
||||
private:
|
||||
@@ -83,7 +83,7 @@ bool AddressableLEDsModel::Exists() {
|
||||
}
|
||||
|
||||
void AddressableLEDsModel::ForEachLEDDisplay(
|
||||
wpi::function_ref<void(glass::LEDDisplayModel& model, int index)> func) {
|
||||
wpi::function_ref<void(glass::LEDDisplayModel& model, int channel)> func) {
|
||||
for (int i = 0; i < static_cast<int>(m_models.size()); ++i) {
|
||||
if (m_models[i]) {
|
||||
func(*m_models[i], i);
|
||||
|
||||
@@ -28,9 +28,6 @@ class PWMSimModel : public glass::PWMModel {
|
||||
|
||||
bool Exists() override { return HALSIM_GetPWMInitialized(m_index); }
|
||||
|
||||
void SetAddressableLED(int led) { m_led = led; }
|
||||
int GetAddressableLED() const override { return m_led; }
|
||||
|
||||
glass::DoubleSource* GetSpeedData() override { return &m_speed; }
|
||||
|
||||
void SetSpeed(double val) override {
|
||||
@@ -39,7 +36,6 @@ class PWMSimModel : public glass::PWMModel {
|
||||
|
||||
private:
|
||||
int32_t m_index;
|
||||
int m_led = -1;
|
||||
PWMPulseMicrosecondSource m_speed;
|
||||
};
|
||||
|
||||
@@ -68,21 +64,10 @@ void PWMsSimModel::Update() {
|
||||
if (!model) {
|
||||
model = std::make_unique<PWMSimModel>(i);
|
||||
}
|
||||
model->SetAddressableLED(-1);
|
||||
} else {
|
||||
model.reset();
|
||||
}
|
||||
}
|
||||
|
||||
static const int32_t numLED = HAL_GetNumAddressableLEDs();
|
||||
for (int32_t i = 0; i < numLED; ++i) {
|
||||
if (HALSIM_GetAddressableLEDInitialized(i)) {
|
||||
int32_t channel = HALSIM_GetAddressableLEDOutputPort(i);
|
||||
if (channel >= 0 && channel < numPWM && m_sources[channel]) {
|
||||
m_sources[channel]->SetAddressableLED(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PWMsSimModel::ForEachPWM(
|
||||
|
||||
@@ -31,12 +31,10 @@ HALSimWSProviderAddressableLED::~HALSimWSProviderAddressableLED() {
|
||||
|
||||
void HALSimWSProviderAddressableLED::RegisterCallbacks() {
|
||||
m_initCbKey = REGISTER(Initialized, "<init", bool, boolean);
|
||||
m_outputPortCbKey = REGISTER(OutputPort, "<output_port", int32_t, int);
|
||||
m_startCbKey = REGISTER(Start, "<start", int32_t, int);
|
||||
m_lengthCbKey = REGISTER(Length, "<length", int32_t, int);
|
||||
m_runningCbKey = REGISTER(Running, "<running", bool, boolean);
|
||||
|
||||
m_dataCbKey = HALSIM_RegisterAddressableLEDDataCallback(
|
||||
0,
|
||||
[](const char* name, void* param, const unsigned char* buffer,
|
||||
unsigned int count) {
|
||||
auto provider = static_cast<HALSimWSProviderAddressableLED*>(param);
|
||||
@@ -66,15 +64,13 @@ void HALSimWSProviderAddressableLED::CancelCallbacks() {
|
||||
|
||||
void HALSimWSProviderAddressableLED::DoCancelCallbacks() {
|
||||
HALSIM_CancelAddressableLEDInitializedCallback(m_channel, m_initCbKey);
|
||||
HALSIM_CancelAddressableLEDOutputPortCallback(m_channel, m_outputPortCbKey);
|
||||
HALSIM_CancelAddressableLEDStartCallback(m_channel, m_startCbKey);
|
||||
HALSIM_CancelAddressableLEDLengthCallback(m_channel, m_lengthCbKey);
|
||||
HALSIM_CancelAddressableLEDRunningCallback(m_channel, m_runningCbKey);
|
||||
HALSIM_CancelAddressableLEDDataCallback(m_channel, m_dataCbKey);
|
||||
HALSIM_CancelAddressableLEDDataCallback(m_dataCbKey);
|
||||
|
||||
m_initCbKey = 0;
|
||||
m_outputPortCbKey = 0;
|
||||
m_startCbKey = 0;
|
||||
m_lengthCbKey = 0;
|
||||
m_runningCbKey = 0;
|
||||
m_dataCbKey = 0;
|
||||
}
|
||||
} // namespace wpilibws
|
||||
|
||||
@@ -21,9 +21,8 @@ class HALSimWSProviderAddressableLED : public HALSimWSHalChanProvider {
|
||||
|
||||
private:
|
||||
int32_t m_initCbKey = 0;
|
||||
int32_t m_outputPortCbKey = 0;
|
||||
int32_t m_startCbKey = 0;
|
||||
int32_t m_lengthCbKey = 0;
|
||||
int32_t m_runningCbKey = 0;
|
||||
int32_t m_dataCbKey = 0;
|
||||
};
|
||||
} // namespace wpilibws
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#include "frc/AddressableLED.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <hal/AddressableLED.h>
|
||||
#include <hal/HALBase.h>
|
||||
#include <hal/PWM.h>
|
||||
@@ -12,39 +14,39 @@
|
||||
#include <wpi/StackTrace.h>
|
||||
|
||||
#include "frc/Errors.h"
|
||||
#include "frc/SensorUtil.h"
|
||||
|
||||
using namespace frc;
|
||||
|
||||
AddressableLED::AddressableLED(int port) : m_port{port} {
|
||||
AddressableLED::AddressableLED(int channel) : m_channel{channel} {
|
||||
if (!SensorUtil::CheckDigitalChannel(channel)) {
|
||||
throw FRC_MakeError(err::ChannelIndexOutOfRange, "Channel {}", channel);
|
||||
}
|
||||
|
||||
int32_t status = 0;
|
||||
|
||||
auto stack = wpi::GetStackTrace(1);
|
||||
m_pwmHandle = HAL_InitializePWMPort(port, stack.c_str(), &status);
|
||||
FRC_CheckErrorStatus(status, "Port {}", port);
|
||||
if (m_pwmHandle == HAL_kInvalidHandle) {
|
||||
return;
|
||||
}
|
||||
m_handle = HAL_InitializeAddressableLED(channel, stack.c_str(), &status);
|
||||
FRC_CheckErrorStatus(status, "Channel {}", channel);
|
||||
|
||||
m_handle = HAL_InitializeAddressableLED(m_pwmHandle, &status);
|
||||
FRC_CheckErrorStatus(status, "Port {}", port);
|
||||
if (m_handle == HAL_kInvalidHandle) {
|
||||
HAL_FreePWMPort(m_pwmHandle);
|
||||
}
|
||||
|
||||
HAL_ReportUsage("IO", port, "AddressableLED");
|
||||
HAL_ReportUsage("IO", channel, "AddressableLED");
|
||||
}
|
||||
|
||||
void AddressableLED::SetColorOrder(AddressableLED::ColorOrder order) {
|
||||
m_colorOrder = order;
|
||||
}
|
||||
|
||||
void AddressableLED::SetStart(int start) {
|
||||
m_start = start;
|
||||
int32_t status = 0;
|
||||
HAL_SetAddressableLEDColorOrder(
|
||||
m_handle, static_cast<HAL_AddressableLEDColorOrder>(order), &status);
|
||||
FRC_CheckErrorStatus(status, "Port {} Color order {}", m_port, order);
|
||||
HAL_SetAddressableLEDStart(m_handle, start, &status);
|
||||
FRC_CheckErrorStatus(status, "Channel {} start {}", m_channel, start);
|
||||
}
|
||||
|
||||
void AddressableLED::SetLength(int length) {
|
||||
m_length = length;
|
||||
int32_t status = 0;
|
||||
HAL_SetAddressableLEDLength(m_handle, length, &status);
|
||||
FRC_CheckErrorStatus(status, "Port {} length {}", m_port, length);
|
||||
FRC_CheckErrorStatus(status, "Channel {} length {}", m_channel, length);
|
||||
}
|
||||
|
||||
static_assert(sizeof(AddressableLED::LEDData) == sizeof(HAL_AddressableLEDData),
|
||||
@@ -52,45 +54,25 @@ static_assert(sizeof(AddressableLED::LEDData) == sizeof(HAL_AddressableLEDData),
|
||||
|
||||
void AddressableLED::SetData(std::span<const LEDData> ledData) {
|
||||
int32_t status = 0;
|
||||
HAL_WriteAddressableLEDData(m_handle, ledData.data(), ledData.size(),
|
||||
&status);
|
||||
FRC_CheckErrorStatus(status, "Port {}", m_port);
|
||||
HAL_SetAddressableLEDData(
|
||||
m_start, std::min(static_cast<size_t>(m_length), ledData.size()),
|
||||
static_cast<HAL_AddressableLEDColorOrder>(m_colorOrder), ledData.data(),
|
||||
&status);
|
||||
FRC_CheckErrorStatus(status, "Port {}", m_channel);
|
||||
}
|
||||
|
||||
void AddressableLED::SetData(std::initializer_list<LEDData> ledData) {
|
||||
int32_t status = 0;
|
||||
HAL_WriteAddressableLEDData(m_handle, ledData.begin(), ledData.size(),
|
||||
&status);
|
||||
FRC_CheckErrorStatus(status, "Port {}", m_port);
|
||||
SetData(std::span{ledData.begin(), ledData.end()});
|
||||
}
|
||||
|
||||
void AddressableLED::SetBitTiming(units::nanosecond_t highTime0,
|
||||
units::nanosecond_t lowTime0,
|
||||
units::nanosecond_t highTime1,
|
||||
units::nanosecond_t lowTime1) {
|
||||
void AddressableLED::SetGlobalData(int start, ColorOrder colorOrder,
|
||||
std::span<const LEDData> ledData) {
|
||||
int32_t status = 0;
|
||||
HAL_SetAddressableLEDBitTiming(
|
||||
m_handle, highTime0.to<int32_t>(), lowTime0.to<int32_t>(),
|
||||
highTime1.to<int32_t>(), lowTime1.to<int32_t>(), &status);
|
||||
FRC_CheckErrorStatus(status, "Port {}", m_port);
|
||||
}
|
||||
|
||||
void AddressableLED::SetSyncTime(units::microsecond_t syncTime) {
|
||||
int32_t status = 0;
|
||||
HAL_SetAddressableLEDSyncTime(m_handle, syncTime.to<int32_t>(), &status);
|
||||
FRC_CheckErrorStatus(status, "Port {}", m_port);
|
||||
}
|
||||
|
||||
void AddressableLED::Start() {
|
||||
int32_t status = 0;
|
||||
HAL_StartAddressableLEDOutput(m_handle, &status);
|
||||
FRC_CheckErrorStatus(status, "Port {}", m_port);
|
||||
}
|
||||
|
||||
void AddressableLED::Stop() {
|
||||
int32_t status = 0;
|
||||
HAL_StopAddressableLEDOutput(m_handle, &status);
|
||||
FRC_CheckErrorStatus(status, "Port {}", m_port);
|
||||
HAL_SetAddressableLEDData(
|
||||
start, ledData.size(),
|
||||
static_cast<HAL_AddressableLEDColorOrder>(colorOrder), ledData.data(),
|
||||
&status);
|
||||
FRC_CheckErrorStatus(status, "");
|
||||
}
|
||||
|
||||
void AddressableLED::LEDData::SetHSV(int h, int s, int v) {
|
||||
|
||||
@@ -9,108 +9,90 @@
|
||||
|
||||
#include <hal/simulation/AddressableLEDData.h>
|
||||
|
||||
#include "frc/AddressableLED.h"
|
||||
|
||||
using namespace frc;
|
||||
using namespace frc::sim;
|
||||
|
||||
AddressableLEDSim::AddressableLEDSim() : m_index{0} {}
|
||||
AddressableLEDSim::AddressableLEDSim(int channel) : m_channel{channel} {}
|
||||
|
||||
AddressableLEDSim::AddressableLEDSim(const AddressableLED& addressableLED)
|
||||
: m_index{0} {}
|
||||
|
||||
AddressableLEDSim AddressableLEDSim::CreateForChannel(int pwmChannel) {
|
||||
int index = HALSIM_FindAddressableLEDForChannel(pwmChannel);
|
||||
if (index < 0) {
|
||||
throw std::out_of_range("no addressable LED found for PWM channel");
|
||||
}
|
||||
return AddressableLEDSim{index};
|
||||
}
|
||||
|
||||
AddressableLEDSim AddressableLEDSim::CreateForIndex(int index) {
|
||||
return AddressableLEDSim{index};
|
||||
}
|
||||
: m_channel{addressableLED.GetChannel()} {}
|
||||
|
||||
std::unique_ptr<CallbackStore> AddressableLEDSim::RegisterInitializedCallback(
|
||||
NotifyCallback callback, bool initialNotify) {
|
||||
auto store = std::make_unique<CallbackStore>(
|
||||
m_index, -1, callback, &HALSIM_CancelAddressableLEDInitializedCallback);
|
||||
m_channel, -1, callback, &HALSIM_CancelAddressableLEDInitializedCallback);
|
||||
store->SetUid(HALSIM_RegisterAddressableLEDInitializedCallback(
|
||||
m_index, &CallbackStoreThunk, store.get(), initialNotify));
|
||||
m_channel, &CallbackStoreThunk, store.get(), initialNotify));
|
||||
return store;
|
||||
}
|
||||
|
||||
bool AddressableLEDSim::GetInitialized() const {
|
||||
return HALSIM_GetAddressableLEDInitialized(m_index);
|
||||
return HALSIM_GetAddressableLEDInitialized(m_channel);
|
||||
}
|
||||
|
||||
void AddressableLEDSim::SetInitialized(bool initialized) {
|
||||
HALSIM_SetAddressableLEDInitialized(m_index, initialized);
|
||||
HALSIM_SetAddressableLEDInitialized(m_channel, initialized);
|
||||
}
|
||||
|
||||
std::unique_ptr<CallbackStore> AddressableLEDSim::RegisterOutputPortCallback(
|
||||
std::unique_ptr<CallbackStore> AddressableLEDSim::RegisterStartCallback(
|
||||
NotifyCallback callback, bool initialNotify) {
|
||||
auto store = std::make_unique<CallbackStore>(
|
||||
m_index, -1, callback, &HALSIM_CancelAddressableLEDOutputPortCallback);
|
||||
store->SetUid(HALSIM_RegisterAddressableLEDOutputPortCallback(
|
||||
m_index, &CallbackStoreThunk, store.get(), initialNotify));
|
||||
m_channel, -1, callback, &HALSIM_CancelAddressableLEDStartCallback);
|
||||
store->SetUid(HALSIM_RegisterAddressableLEDStartCallback(
|
||||
m_channel, &CallbackStoreThunk, store.get(), initialNotify));
|
||||
return store;
|
||||
}
|
||||
|
||||
int AddressableLEDSim::GetOutputPort() const {
|
||||
return HALSIM_GetAddressableLEDOutputPort(m_index);
|
||||
int AddressableLEDSim::GetStart() const {
|
||||
return HALSIM_GetAddressableLEDStart(m_channel);
|
||||
}
|
||||
|
||||
void AddressableLEDSim::SetOutputPort(int outputPort) {
|
||||
HALSIM_SetAddressableLEDOutputPort(m_index, outputPort);
|
||||
void AddressableLEDSim::SetStart(int start) {
|
||||
HALSIM_SetAddressableLEDStart(m_channel, start);
|
||||
}
|
||||
|
||||
std::unique_ptr<CallbackStore> AddressableLEDSim::RegisterLengthCallback(
|
||||
NotifyCallback callback, bool initialNotify) {
|
||||
auto store = std::make_unique<CallbackStore>(
|
||||
m_index, -1, callback, &HALSIM_CancelAddressableLEDLengthCallback);
|
||||
m_channel, -1, callback, &HALSIM_CancelAddressableLEDLengthCallback);
|
||||
store->SetUid(HALSIM_RegisterAddressableLEDLengthCallback(
|
||||
m_index, &CallbackStoreThunk, store.get(), initialNotify));
|
||||
m_channel, &CallbackStoreThunk, store.get(), initialNotify));
|
||||
return store;
|
||||
}
|
||||
|
||||
int AddressableLEDSim::GetLength() const {
|
||||
return HALSIM_GetAddressableLEDLength(m_index);
|
||||
return HALSIM_GetAddressableLEDLength(m_channel);
|
||||
}
|
||||
|
||||
void AddressableLEDSim::SetLength(int length) {
|
||||
HALSIM_SetAddressableLEDLength(m_index, length);
|
||||
HALSIM_SetAddressableLEDLength(m_channel, length);
|
||||
}
|
||||
|
||||
std::unique_ptr<CallbackStore> AddressableLEDSim::RegisterRunningCallback(
|
||||
NotifyCallback callback, bool initialNotify) {
|
||||
auto store = std::make_unique<CallbackStore>(
|
||||
m_index, -1, callback, &HALSIM_CancelAddressableLEDRunningCallback);
|
||||
store->SetUid(HALSIM_RegisterAddressableLEDRunningCallback(
|
||||
m_index, &CallbackStoreThunk, store.get(), initialNotify));
|
||||
return store;
|
||||
int AddressableLEDSim::GetData(struct HAL_AddressableLEDData* data) const {
|
||||
return GetGlobalData(GetStart(), GetLength(), data);
|
||||
}
|
||||
|
||||
int AddressableLEDSim::GetRunning() const {
|
||||
return HALSIM_GetAddressableLEDRunning(m_index);
|
||||
}
|
||||
|
||||
void AddressableLEDSim::SetRunning(bool running) {
|
||||
HALSIM_SetAddressableLEDRunning(m_index, running);
|
||||
void AddressableLEDSim::SetData(struct HAL_AddressableLEDData* data) {
|
||||
SetGlobalData(GetStart(), GetLength(), data);
|
||||
}
|
||||
|
||||
std::unique_ptr<CallbackStore> AddressableLEDSim::RegisterDataCallback(
|
||||
ConstBufferCallback callback, bool initialNotify) {
|
||||
auto store = std::make_unique<CallbackStore>(
|
||||
m_index, -1, callback, &HALSIM_CancelAddressableLEDDataCallback);
|
||||
-1, callback, &HALSIM_CancelAddressableLEDDataCallback);
|
||||
store->SetUid(HALSIM_RegisterAddressableLEDDataCallback(
|
||||
m_index, &ConstBufferCallbackStoreThunk, store.get()));
|
||||
&ConstBufferCallbackStoreThunk, store.get()));
|
||||
return store;
|
||||
}
|
||||
|
||||
int AddressableLEDSim::GetData(struct HAL_AddressableLEDData* data) const {
|
||||
return HALSIM_GetAddressableLEDData(m_index, data);
|
||||
int AddressableLEDSim::GetGlobalData(int start, int length,
|
||||
struct HAL_AddressableLEDData* data) {
|
||||
return HALSIM_GetAddressableLEDData(start, length, data);
|
||||
}
|
||||
|
||||
void AddressableLEDSim::SetData(struct HAL_AddressableLEDData* data,
|
||||
int length) {
|
||||
HALSIM_SetAddressableLEDData(m_index, data, length);
|
||||
void AddressableLEDSim::SetGlobalData(int start, int length,
|
||||
struct HAL_AddressableLEDData* data) {
|
||||
HALSIM_SetAddressableLEDData(start, length, data);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
#include <hal/AddressableLED.h>
|
||||
#include <hal/AddressableLEDTypes.h>
|
||||
#include <hal/PWM.h>
|
||||
#include <hal/Types.h>
|
||||
#include <units/time.h>
|
||||
|
||||
@@ -21,15 +20,15 @@ namespace frc {
|
||||
/**
|
||||
* A class for driving addressable LEDs, such as WS2812B, WS2815, and NeoPixels.
|
||||
*
|
||||
* By default, the timing supports WS2812B and WS2815 LEDs, but is configurable
|
||||
* using SetBitTiming()
|
||||
*
|
||||
* Some LEDs use a different color order than the default GRB. The color order
|
||||
* is configurable using SetColorOrder().
|
||||
*
|
||||
* <p>Only 1 LED driver is currently supported by the roboRIO. However,
|
||||
* multiple LED strips can be connected in series and controlled from the
|
||||
* single driver.
|
||||
* Up to 1024 LEDs may be controlled in total across all AddressableLED
|
||||
* instances. A single global buffer is used for all instances. The start
|
||||
* position used for LED data for the output is set via SetStart() and the
|
||||
* length of the strip is set via SetLength(). Both of these default to zero, so
|
||||
* multiple instances will access the same pixel data unless SetStart() is
|
||||
* called to adjust the starting point.
|
||||
*/
|
||||
class AddressableLED {
|
||||
public:
|
||||
@@ -52,7 +51,6 @@ class AddressableLED {
|
||||
r = _r;
|
||||
g = _g;
|
||||
b = _b;
|
||||
padding = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,15 +99,22 @@ class AddressableLED {
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructs a new driver for a specific port.
|
||||
* Constructs a new driver for a specific channel.
|
||||
*
|
||||
* @param port the output port to use (Must be a PWM header)
|
||||
* @param channel the output channel to use
|
||||
*/
|
||||
explicit AddressableLED(int port);
|
||||
explicit AddressableLED(int channel);
|
||||
|
||||
AddressableLED(AddressableLED&&) = default;
|
||||
AddressableLED& operator=(AddressableLED&&) = default;
|
||||
|
||||
/**
|
||||
* Gets the channel for this addressable LED.
|
||||
*
|
||||
* @return channel
|
||||
*/
|
||||
int GetChannel() const { return m_channel; }
|
||||
|
||||
/**
|
||||
* Sets the color order for this AddressableLED. The default order is GRB.
|
||||
*
|
||||
@@ -119,79 +124,59 @@ class AddressableLED {
|
||||
*/
|
||||
void SetColorOrder(ColorOrder order);
|
||||
|
||||
/**
|
||||
* Sets the display start of the LED strip in the global buffer.
|
||||
*
|
||||
* @param start the strip start, in LEDs
|
||||
*/
|
||||
void SetStart(int start);
|
||||
|
||||
/**
|
||||
* Gets the display start of the LED strip in the global buffer.
|
||||
*
|
||||
* @return the strip start, in LEDs
|
||||
*/
|
||||
int GetStart() const { return m_start; }
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* <p>The max length is 5460 LEDs.
|
||||
*
|
||||
* @param length the strip length
|
||||
* @param length the strip length, in LEDs
|
||||
*/
|
||||
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.
|
||||
* Sets the LED output data. This will write to the global buffer starting at
|
||||
* the location set by SetStart() and up to the length set by SetLength().
|
||||
*
|
||||
* @param ledData the buffer to write
|
||||
*/
|
||||
void SetData(std::span<const 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.
|
||||
* Sets the LED output data. This will write to the global buffer starting at
|
||||
* the location set by SetStart() and up to the length set by SetLength().
|
||||
*
|
||||
* @param ledData the buffer to write
|
||||
*/
|
||||
void SetData(std::initializer_list<LEDData> ledData);
|
||||
|
||||
/**
|
||||
* Sets the bit timing.
|
||||
* Sets the LED output data at an arbitrary location in the global buffer.
|
||||
*
|
||||
* <p>By default, the driver is set up to drive WS2812B and WS2815, so nothing
|
||||
* needs to be set for those.
|
||||
*
|
||||
* @param highTime0 high time for 0 bit (default 400 ns)
|
||||
* @param lowTime0 low time for 0 bit (default 900 ns)
|
||||
* @param highTime1 high time for 1 bit (default 900 ns)
|
||||
* @param lowTime1 low time for 1 bit (default 600 ns)
|
||||
* @param start the start location, in LEDs
|
||||
* @param colorOrder the color order
|
||||
* @param ledData the buffer to write
|
||||
*/
|
||||
void SetBitTiming(units::nanosecond_t highTime0, units::nanosecond_t lowTime0,
|
||||
units::nanosecond_t highTime1,
|
||||
units::nanosecond_t lowTime1);
|
||||
|
||||
/**
|
||||
* Sets the sync time.
|
||||
*
|
||||
* <p>The sync time is the time to hold output so LEDs enable. Default set for
|
||||
* WS2812B and WS2815.
|
||||
*
|
||||
* @param syncTime the sync time (default 280us)
|
||||
*/
|
||||
void SetSyncTime(units::microsecond_t syncTime);
|
||||
|
||||
/**
|
||||
* Starts the output.
|
||||
*
|
||||
* <p>The output writes continuously.
|
||||
*/
|
||||
void Start();
|
||||
|
||||
/**
|
||||
* Stops the output.
|
||||
*/
|
||||
void Stop();
|
||||
static void SetGlobalData(int start, ColorOrder colorOrder,
|
||||
std::span<const LEDData> ledData);
|
||||
|
||||
private:
|
||||
hal::Handle<HAL_DigitalHandle, HAL_FreePWMPort> m_pwmHandle;
|
||||
hal::Handle<HAL_AddressableLEDHandle, HAL_FreeAddressableLED> m_handle;
|
||||
int m_port;
|
||||
int m_channel;
|
||||
int m_start{0};
|
||||
int m_length{0};
|
||||
ColorOrder m_colorOrder{kGRB};
|
||||
};
|
||||
|
||||
constexpr auto format_as(AddressableLED::ColorOrder order) {
|
||||
|
||||
@@ -22,9 +22,11 @@ namespace sim {
|
||||
class AddressableLEDSim {
|
||||
public:
|
||||
/**
|
||||
* Constructs for the first addressable LED.
|
||||
* Constructs an addressable LED for a specific channel.
|
||||
*
|
||||
* @param channel output channel
|
||||
*/
|
||||
AddressableLEDSim();
|
||||
explicit AddressableLEDSim(int channel);
|
||||
|
||||
/**
|
||||
* Constructs from an AddressableLED object.
|
||||
@@ -33,25 +35,6 @@ class AddressableLEDSim {
|
||||
*/
|
||||
explicit AddressableLEDSim(const AddressableLED& addressableLED);
|
||||
|
||||
/**
|
||||
* Creates an AddressableLEDSim for a PWM channel.
|
||||
*
|
||||
* @param pwmChannel PWM channel
|
||||
* @return Simulated object
|
||||
* @throws std::out_of_range if no AddressableLED is configured for that
|
||||
* channel
|
||||
*/
|
||||
static AddressableLEDSim CreateForChannel(int pwmChannel);
|
||||
|
||||
/**
|
||||
* Creates an AddressableLEDSim for a simulated index.
|
||||
* The index is incremented for each simulated AddressableLED.
|
||||
*
|
||||
* @param index simulator index
|
||||
* @return Simulated object
|
||||
*/
|
||||
static AddressableLEDSim CreateForIndex(int index);
|
||||
|
||||
/**
|
||||
* Register a callback on the Initialized property.
|
||||
*
|
||||
@@ -79,30 +62,30 @@ class AddressableLEDSim {
|
||||
void SetInitialized(bool initialized);
|
||||
|
||||
/**
|
||||
* Register a callback on the output port.
|
||||
* Register a callback on the start.
|
||||
*
|
||||
* @param callback the callback that will be called whenever the output port
|
||||
* @param callback the callback that will be called whenever the start
|
||||
* is changed
|
||||
* @param initialNotify if true, the callback will be run on the initial value
|
||||
* @return the CallbackStore object associated with this callback
|
||||
*/
|
||||
[[nodiscard]]
|
||||
std::unique_ptr<CallbackStore> RegisterOutputPortCallback(
|
||||
NotifyCallback callback, bool initialNotify);
|
||||
std::unique_ptr<CallbackStore> RegisterStartCallback(NotifyCallback callback,
|
||||
bool initialNotify);
|
||||
|
||||
/**
|
||||
* Get the output port.
|
||||
* Get the start.
|
||||
*
|
||||
* @return the output port
|
||||
* @return the start
|
||||
*/
|
||||
int GetOutputPort() const;
|
||||
int GetStart() const;
|
||||
|
||||
/**
|
||||
* Change the output port.
|
||||
* Change the start.
|
||||
*
|
||||
* @param outputPort the new output port
|
||||
* @param start the new start
|
||||
*/
|
||||
void SetOutputPort(int outputPort);
|
||||
void SetStart(int start);
|
||||
|
||||
/**
|
||||
* Register a callback on the length.
|
||||
@@ -130,44 +113,6 @@ class AddressableLEDSim {
|
||||
*/
|
||||
void SetLength(int length);
|
||||
|
||||
/**
|
||||
* Register a callback on whether the LEDs are running.
|
||||
*
|
||||
* @param callback the callback that will be called whenever the LED state is
|
||||
* changed
|
||||
* @param initialNotify if true, the callback will be run on the initial value
|
||||
* @return the CallbackStore object associated with this callback
|
||||
*/
|
||||
[[nodiscard]]
|
||||
std::unique_ptr<CallbackStore> RegisterRunningCallback(
|
||||
NotifyCallback callback, bool initialNotify);
|
||||
|
||||
/**
|
||||
* Check if the LEDs are running.
|
||||
*
|
||||
* @return true if they are
|
||||
*/
|
||||
int GetRunning() const;
|
||||
|
||||
/**
|
||||
* Change whether the LEDs are active.
|
||||
*
|
||||
* @param running the new value
|
||||
*/
|
||||
void SetRunning(bool running);
|
||||
|
||||
/**
|
||||
* Register a callback on the LED data.
|
||||
*
|
||||
* @param callback the callback that will be called whenever the LED data is
|
||||
* changed
|
||||
* @param initialNotify if true, the callback will be run on the initial value
|
||||
* @return the CallbackStore object associated with this callback
|
||||
*/
|
||||
[[nodiscard]]
|
||||
std::unique_ptr<CallbackStore> RegisterDataCallback(
|
||||
ConstBufferCallback callback, bool initialNotify);
|
||||
|
||||
/**
|
||||
* Get the LED data.
|
||||
*
|
||||
@@ -180,14 +125,44 @@ class AddressableLEDSim {
|
||||
* Change the LED data.
|
||||
*
|
||||
* @param data the new data
|
||||
* @param length the length of the LED data
|
||||
*/
|
||||
void SetData(struct HAL_AddressableLEDData* data, int length);
|
||||
void SetData(struct HAL_AddressableLEDData* data);
|
||||
|
||||
/**
|
||||
* Register a callback on the LED data.
|
||||
*
|
||||
* @param callback the callback that will be called whenever the LED data is
|
||||
* changed
|
||||
* @param initialNotify if true, the callback will be run on the initial value
|
||||
* @return the CallbackStore object associated with this callback
|
||||
*/
|
||||
[[nodiscard]]
|
||||
static std::unique_ptr<CallbackStore> RegisterDataCallback(
|
||||
ConstBufferCallback callback, bool initialNotify);
|
||||
|
||||
/**
|
||||
* Get the global LED data.
|
||||
*
|
||||
* @param start the start of the LED data
|
||||
* @param length the length of the LED data
|
||||
* @param data output parameter to fill with LED data
|
||||
* @return the length of the LED data
|
||||
*/
|
||||
static int GetGlobalData(int start, int length,
|
||||
struct HAL_AddressableLEDData* data);
|
||||
|
||||
/**
|
||||
* Change the global LED data.
|
||||
*
|
||||
* @param start the start of the LED data
|
||||
* @param length the length of the LED data
|
||||
* @param data the new data
|
||||
*/
|
||||
static void SetGlobalData(int start, int length,
|
||||
struct HAL_AddressableLEDData* data);
|
||||
|
||||
private:
|
||||
explicit AddressableLEDSim(int index) : m_index{index} {}
|
||||
|
||||
int m_index;
|
||||
int m_channel;
|
||||
};
|
||||
} // namespace sim
|
||||
} // namespace frc
|
||||
|
||||
@@ -1031,7 +1031,6 @@ void AssertIndexColor(std::span<AddressableLED::LEDData> data, int index,
|
||||
Color color) {
|
||||
frc::Color8Bit color8bit{color};
|
||||
|
||||
EXPECT_EQ(0, data[index].padding);
|
||||
EXPECT_EQ(color8bit.red, data[index].r & 0xFF);
|
||||
EXPECT_EQ(color8bit.green, data[index].g & 0xFF);
|
||||
EXPECT_EQ(color8bit.blue, data[index].b & 0xFF);
|
||||
|
||||
@@ -18,7 +18,7 @@ TEST(AddressableLEDSimTest, InitializationCallback) {
|
||||
HAL_Initialize(500, 0);
|
||||
|
||||
BooleanCallback callback;
|
||||
AddressableLEDSim sim;
|
||||
AddressableLEDSim sim{0};
|
||||
auto cb = sim.RegisterInitializedCallback(callback.GetCallback(), false);
|
||||
|
||||
EXPECT_FALSE(callback.WasTriggered());
|
||||
@@ -29,6 +29,26 @@ TEST(AddressableLEDSimTest, InitializationCallback) {
|
||||
EXPECT_TRUE(callback.GetLastValue());
|
||||
}
|
||||
|
||||
TEST(AddressableLEDSimTest, SetStart) {
|
||||
HAL_Initialize(500, 0);
|
||||
|
||||
AddressableLED led{0};
|
||||
AddressableLEDSim sim{led};
|
||||
IntCallback callback;
|
||||
|
||||
auto cb = sim.RegisterStartCallback(callback.GetCallback(), false);
|
||||
|
||||
EXPECT_EQ(0, sim.GetStart()); // Defaults to 0
|
||||
|
||||
std::array<AddressableLED::LEDData, 50> ledData;
|
||||
led.SetStart(1);
|
||||
led.SetData(ledData);
|
||||
|
||||
EXPECT_EQ(1, sim.GetStart());
|
||||
EXPECT_TRUE(callback.WasTriggered());
|
||||
EXPECT_EQ(1, callback.GetLastValue());
|
||||
}
|
||||
|
||||
TEST(AddressableLEDSimTest, SetLength) {
|
||||
HAL_Initialize(500, 0);
|
||||
|
||||
@@ -38,7 +58,7 @@ TEST(AddressableLEDSimTest, SetLength) {
|
||||
|
||||
auto cb = sim.RegisterLengthCallback(callback.GetCallback(), false);
|
||||
|
||||
EXPECT_EQ(1, sim.GetLength()); // Defaults to 1 led
|
||||
EXPECT_EQ(0, sim.GetLength()); // Defaults to 0 leds
|
||||
|
||||
std::array<AddressableLED::LEDData, 50> ledData;
|
||||
led.SetLength(ledData.max_size());
|
||||
@@ -49,51 +69,26 @@ TEST(AddressableLEDSimTest, SetLength) {
|
||||
EXPECT_EQ(50, callback.GetLastValue());
|
||||
}
|
||||
|
||||
TEST(AddressableLEDSimTest, SetRunning) {
|
||||
HAL_Initialize(500, 0);
|
||||
|
||||
AddressableLEDSim sim = AddressableLEDSim::CreateForIndex(0);
|
||||
BooleanCallback callback;
|
||||
auto cb = sim.RegisterRunningCallback(callback.GetCallback(), false);
|
||||
AddressableLED led{0};
|
||||
|
||||
EXPECT_FALSE(sim.GetRunning());
|
||||
|
||||
led.Start();
|
||||
EXPECT_TRUE(sim.GetRunning());
|
||||
EXPECT_TRUE(callback.WasTriggered());
|
||||
EXPECT_TRUE(callback.GetLastValue());
|
||||
|
||||
callback.Reset();
|
||||
led.Stop();
|
||||
EXPECT_FALSE(sim.GetRunning());
|
||||
EXPECT_TRUE(callback.WasTriggered());
|
||||
EXPECT_FALSE(callback.GetLastValue());
|
||||
}
|
||||
|
||||
TEST(AddressableLEDSimTest, SetData) {
|
||||
AddressableLED led{0};
|
||||
AddressableLEDSim sim = AddressableLEDSim::CreateForChannel(0);
|
||||
AddressableLEDSim sim{0};
|
||||
|
||||
bool callbackHit = false;
|
||||
std::array<AddressableLED::LEDData, 3> setData;
|
||||
auto cb = sim.RegisterDataCallback(
|
||||
[&](std::string_view, const unsigned char* buffer, unsigned int count) {
|
||||
ASSERT_EQ(count, 12u);
|
||||
ASSERT_EQ(count, 9u);
|
||||
EXPECT_EQ(0, buffer[0]);
|
||||
EXPECT_EQ(0, buffer[1]);
|
||||
EXPECT_EQ(255u, buffer[2]);
|
||||
|
||||
EXPECT_EQ(0, buffer[3]);
|
||||
EXPECT_EQ(255u, buffer[4]);
|
||||
EXPECT_EQ(0, buffer[5]);
|
||||
|
||||
EXPECT_EQ(0, buffer[4]);
|
||||
EXPECT_EQ(255u, buffer[5]);
|
||||
EXPECT_EQ(0, buffer[6]);
|
||||
EXPECT_EQ(255u, buffer[6]);
|
||||
EXPECT_EQ(0, buffer[7]);
|
||||
|
||||
EXPECT_EQ(255u, buffer[8]);
|
||||
EXPECT_EQ(0, buffer[9]);
|
||||
EXPECT_EQ(0, buffer[10]);
|
||||
EXPECT_EQ(0, buffer[11]);
|
||||
EXPECT_EQ(0, buffer[8]);
|
||||
|
||||
callbackHit = true;
|
||||
},
|
||||
@@ -115,17 +110,14 @@ TEST(AddressableLEDSimTest, SetData) {
|
||||
EXPECT_EQ(0xFF, simData[0].r);
|
||||
EXPECT_EQ(0x00, simData[0].g);
|
||||
EXPECT_EQ(0x00, simData[0].b);
|
||||
EXPECT_EQ(0x00, simData[0].padding);
|
||||
|
||||
EXPECT_EQ(0x00, simData[1].r);
|
||||
EXPECT_EQ(0xFF, simData[1].g);
|
||||
EXPECT_EQ(0x00, simData[1].b);
|
||||
EXPECT_EQ(0x00, simData[1].padding);
|
||||
|
||||
EXPECT_EQ(0x00, simData[2].r);
|
||||
EXPECT_EQ(0x00, simData[2].g);
|
||||
EXPECT_EQ(0xFF, simData[2].b);
|
||||
EXPECT_EQ(0x00, simData[2].padding);
|
||||
}
|
||||
|
||||
} // namespace frc::sim
|
||||
|
||||
@@ -37,5 +37,5 @@ TEST(SimInitializationTest, AllInitialize) {
|
||||
(void)rrsim;
|
||||
DutyCycleSim dcsim = DutyCycleSim::CreateForChannel(0);
|
||||
(void)dcsim;
|
||||
AddressableLEDSim adLED;
|
||||
AddressableLEDSim adLED{0};
|
||||
}
|
||||
|
||||
@@ -6,10 +6,8 @@
|
||||
|
||||
Robot::Robot() {
|
||||
// Default to a length of 60, start empty output
|
||||
// Length is expensive to set, so only set it once, then just update data
|
||||
m_led.SetLength(kLength);
|
||||
m_led.SetData(m_ledBuffer);
|
||||
m_led.Start();
|
||||
}
|
||||
|
||||
void Robot::RobotPeriodic() {
|
||||
|
||||
@@ -18,9 +18,8 @@ class Robot : public frc::TimedRobot {
|
||||
private:
|
||||
static constexpr int kLength = 60;
|
||||
|
||||
// PWM port 9
|
||||
// Must be a PWM header, not MXP or DIO
|
||||
frc::AddressableLED m_led{9};
|
||||
// SmartIO port 1
|
||||
frc::AddressableLED m_led{1};
|
||||
std::array<frc::AddressableLED::LEDData, kLength>
|
||||
m_ledBuffer; // Reuse the buffer
|
||||
|
||||
|
||||
@@ -6,19 +6,18 @@ package edu.wpi.first.wpilibj;
|
||||
|
||||
import edu.wpi.first.hal.AddressableLEDJNI;
|
||||
import edu.wpi.first.hal.HAL;
|
||||
import edu.wpi.first.hal.PWMJNI;
|
||||
|
||||
/**
|
||||
* A class for driving addressable LEDs, such as WS2812B, WS2815, and NeoPixels.
|
||||
*
|
||||
* <p>By default, the timing supports WS2812B and WS2815 LEDs, but is configurable using {@link
|
||||
* #setBitTiming(int, int, int, int)}
|
||||
*
|
||||
* <p>Some LEDs use a different color order than the default GRB. The color order is configurable
|
||||
* using {@link #setColorOrder(ColorOrder)}.
|
||||
*
|
||||
* <p>Only 1 LED driver is currently supported by the roboRIO. However, multiple LED strips can be
|
||||
* connected in series and controlled from the single driver.
|
||||
* <p>Up to 1024 LEDs may be controlled in total across all AddressableLED instances. A single
|
||||
* global buffer is used for all instances. The start position used for LED data for the output is
|
||||
* set via SetStart() and the length of the strip is set via SetLength(). Both of these default to
|
||||
* zero, so multiple instances will access the same pixel data unless SetStart() is called to adjust
|
||||
* the starting point.
|
||||
*/
|
||||
public class AddressableLED implements AutoCloseable {
|
||||
/** Order that color data is sent over the wire. */
|
||||
@@ -62,18 +61,21 @@ public class AddressableLED implements AutoCloseable {
|
||||
}
|
||||
}
|
||||
|
||||
private final int m_pwmHandle;
|
||||
private final int m_channel;
|
||||
private final int m_handle;
|
||||
private int m_start;
|
||||
private int m_length;
|
||||
private ColorOrder m_colorOrder = ColorOrder.kGRB;
|
||||
|
||||
/**
|
||||
* Constructs a new driver for a specific port.
|
||||
* Constructs a new driver for a specific channel.
|
||||
*
|
||||
* @param port the output port to use (Must be a PWM header, not on MXP)
|
||||
* @param channel the output channel to use
|
||||
*/
|
||||
public AddressableLED(int port) {
|
||||
m_pwmHandle = PWMJNI.initializePWMPort(port);
|
||||
m_handle = AddressableLEDJNI.initialize(m_pwmHandle);
|
||||
HAL.reportUsage("IO", port, "AddressableLED");
|
||||
public AddressableLED(int channel) {
|
||||
m_channel = channel;
|
||||
m_handle = AddressableLEDJNI.initialize(channel);
|
||||
HAL.reportUsage("IO", channel, "AddressableLED");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -81,9 +83,15 @@ public class AddressableLED implements AutoCloseable {
|
||||
if (m_handle != 0) {
|
||||
AddressableLEDJNI.free(m_handle);
|
||||
}
|
||||
if (m_pwmHandle != 0) {
|
||||
PWMJNI.freePWMPort(m_pwmHandle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the output channel.
|
||||
*
|
||||
* @return the output channel
|
||||
*/
|
||||
public int getChannel() {
|
||||
return m_channel;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,71 +102,63 @@ public class AddressableLED implements AutoCloseable {
|
||||
* @param order the color order
|
||||
*/
|
||||
public void setColorOrder(ColorOrder order) {
|
||||
AddressableLEDJNI.setColorOrder(m_handle, order.value);
|
||||
m_colorOrder = order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the display start of the LED strip in the global buffer.
|
||||
*
|
||||
* @param start the strip start, in LEDs
|
||||
*/
|
||||
public void setStart(int start) {
|
||||
m_start = start;
|
||||
AddressableLEDJNI.setStart(m_handle, start);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the display start of the LED strip in the global buffer.
|
||||
*
|
||||
* @return the strip start, in LEDs
|
||||
*/
|
||||
public int getStart() {
|
||||
return m_start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the length of the LED strip.
|
||||
*
|
||||
* <p>Calling this is an expensive call, so it's best to call it once, then just update data.
|
||||
*
|
||||
* <p>The max length is 5460 LEDs.
|
||||
*
|
||||
* @param length the strip length
|
||||
* @param length the strip length, in LEDs
|
||||
*/
|
||||
public void setLength(int length) {
|
||||
m_length = 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.
|
||||
* <p>This will write to the global buffer starting at the location set by setStart() and up to
|
||||
* the length set by setLength().
|
||||
*
|
||||
* @param buffer the buffer to write
|
||||
*/
|
||||
public void setData(AddressableLEDBuffer buffer) {
|
||||
AddressableLEDJNI.setData(m_handle, buffer.m_buffer);
|
||||
AddressableLEDJNI.setData(
|
||||
m_start,
|
||||
m_colorOrder.value,
|
||||
buffer.m_buffer,
|
||||
0,
|
||||
3 * Math.min(m_length, buffer.getLength()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bit timing.
|
||||
* Sets the LED output data at an arbitrary location in the global buffer.
|
||||
*
|
||||
* <p>By default, the driver is set up to drive WS2812B and WS2815, so nothing needs to be set for
|
||||
* those.
|
||||
*
|
||||
* @param highTime0 high time for 0 bit in nanoseconds (default 400 ns)
|
||||
* @param lowTime0 low time for 0 bit in nanoseconds (default 900 ns)
|
||||
* @param highTime1 high time for 1 bit in nanoseconds (default 900 ns)
|
||||
* @param lowTime1 low time for 1 bit in nanoseconds (default 600 ns)
|
||||
* @param start the start location, in LEDs
|
||||
* @param colorOrder the color order
|
||||
* @param buffer the buffer to write
|
||||
*/
|
||||
public void setBitTiming(int highTime0, int lowTime0, int highTime1, int lowTime1) {
|
||||
AddressableLEDJNI.setBitTiming(m_handle, highTime0, lowTime0, highTime1, lowTime1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the sync time.
|
||||
*
|
||||
* <p>The sync time is the time to hold output so LEDs enable. Default set for WS2812B and WS2815.
|
||||
*
|
||||
* @param syncTime the sync time in microseconds (default 280 μs)
|
||||
*/
|
||||
public void setSyncTime(int syncTime) {
|
||||
AddressableLEDJNI.setSyncTime(m_handle, syncTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the output.
|
||||
*
|
||||
* <p>The output writes continuously.
|
||||
*/
|
||||
public void start() {
|
||||
AddressableLEDJNI.start(m_handle);
|
||||
}
|
||||
|
||||
/** Stops the output. */
|
||||
public void stop() {
|
||||
AddressableLEDJNI.stop(m_handle);
|
||||
public static void setGlobalData(int start, ColorOrder colorOrder, AddressableLEDBuffer buffer) {
|
||||
AddressableLEDJNI.setData(start, colorOrder.value, buffer.m_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ public class AddressableLEDBuffer implements LEDReader, LEDWriter {
|
||||
* @param length The length of the buffer in pixels
|
||||
*/
|
||||
public AddressableLEDBuffer(int length) {
|
||||
m_buffer = new byte[length * 4];
|
||||
m_buffer = new byte[length * 3];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -27,10 +27,9 @@ public class AddressableLEDBuffer implements LEDReader, LEDWriter {
|
||||
*/
|
||||
@Override
|
||||
public void setRGB(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;
|
||||
m_buffer[index * 3] = (byte) b;
|
||||
m_buffer[(index * 3) + 1] = (byte) g;
|
||||
m_buffer[(index * 3) + 2] = (byte) r;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -40,7 +39,7 @@ public class AddressableLEDBuffer implements LEDReader, LEDWriter {
|
||||
*/
|
||||
@Override
|
||||
public int getLength() {
|
||||
return m_buffer.length / 4;
|
||||
return m_buffer.length / 3;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,7 +50,7 @@ public class AddressableLEDBuffer implements LEDReader, LEDWriter {
|
||||
*/
|
||||
@Override
|
||||
public int getRed(int index) {
|
||||
return m_buffer[index * 4 + 2] & 0xFF;
|
||||
return m_buffer[index * 3 + 2] & 0xFF;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,7 +61,7 @@ public class AddressableLEDBuffer implements LEDReader, LEDWriter {
|
||||
*/
|
||||
@Override
|
||||
public int getGreen(int index) {
|
||||
return m_buffer[index * 4 + 1] & 0xFF;
|
||||
return m_buffer[index * 3 + 1] & 0xFF;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -73,7 +72,7 @@ public class AddressableLEDBuffer implements LEDReader, LEDWriter {
|
||||
*/
|
||||
@Override
|
||||
public int getBlue(int index) {
|
||||
return m_buffer[index * 4] & 0xFF;
|
||||
return m_buffer[index * 3] & 0xFF;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,15 +8,18 @@ import edu.wpi.first.hal.simulation.AddressableLEDDataJNI;
|
||||
import edu.wpi.first.hal.simulation.ConstBufferCallback;
|
||||
import edu.wpi.first.hal.simulation.NotifyCallback;
|
||||
import edu.wpi.first.wpilibj.AddressableLED;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/** Class to control a simulated addressable LED. */
|
||||
public class AddressableLEDSim {
|
||||
private final int m_index;
|
||||
private final int m_channel;
|
||||
|
||||
/** Constructs for the first addressable LED. */
|
||||
public AddressableLEDSim() {
|
||||
m_index = 0;
|
||||
/**
|
||||
* Constructs an addressable LED for a specific channel.
|
||||
*
|
||||
* @param channel output channel
|
||||
*/
|
||||
public AddressableLEDSim(int channel) {
|
||||
m_channel = channel;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -26,38 +29,7 @@ public class AddressableLEDSim {
|
||||
*/
|
||||
@SuppressWarnings("PMD.UnusedFormalParameter")
|
||||
public AddressableLEDSim(AddressableLED addressableLED) {
|
||||
// there is only support for a single AddressableLED, so no lookup
|
||||
m_index = 0;
|
||||
}
|
||||
|
||||
private AddressableLEDSim(int index) {
|
||||
m_index = index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an AddressableLEDSim for a PWM channel.
|
||||
*
|
||||
* @param pwmChannel PWM channel
|
||||
* @return Simulated object
|
||||
* @throws NoSuchElementException if no AddressableLED is configured for that channel
|
||||
*/
|
||||
public static AddressableLEDSim createForChannel(int pwmChannel) {
|
||||
int index = AddressableLEDDataJNI.findForChannel(pwmChannel);
|
||||
if (index < 0) {
|
||||
throw new NoSuchElementException("no addressable LED found for PWM channel " + pwmChannel);
|
||||
}
|
||||
return new AddressableLEDSim(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an AddressableLEDSim for a simulated index. The index is incremented for each simulated
|
||||
* AddressableLED.
|
||||
*
|
||||
* @param index simulator index
|
||||
* @return Simulated object
|
||||
*/
|
||||
public static AddressableLEDSim createForIndex(int index) {
|
||||
return new AddressableLEDSim(index);
|
||||
m_channel = addressableLED.getChannel();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,8 +40,8 @@ public class AddressableLEDSim {
|
||||
* @return the {@link CallbackStore} object associated with this callback.
|
||||
*/
|
||||
public CallbackStore registerInitializedCallback(NotifyCallback callback, boolean initialNotify) {
|
||||
int uid = AddressableLEDDataJNI.registerInitializedCallback(m_index, callback, initialNotify);
|
||||
return new CallbackStore(m_index, uid, AddressableLEDDataJNI::cancelInitializedCallback);
|
||||
int uid = AddressableLEDDataJNI.registerInitializedCallback(m_channel, callback, initialNotify);
|
||||
return new CallbackStore(m_channel, uid, AddressableLEDDataJNI::cancelInitializedCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -78,7 +50,7 @@ public class AddressableLEDSim {
|
||||
* @return true if initialized
|
||||
*/
|
||||
public boolean getInitialized() {
|
||||
return AddressableLEDDataJNI.getInitialized(m_index);
|
||||
return AddressableLEDDataJNI.getInitialized(m_channel);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -87,37 +59,37 @@ public class AddressableLEDSim {
|
||||
* @param initialized the new value
|
||||
*/
|
||||
public void setInitialized(boolean initialized) {
|
||||
AddressableLEDDataJNI.setInitialized(m_index, initialized);
|
||||
AddressableLEDDataJNI.setInitialized(m_channel, initialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a callback on the output port.
|
||||
* Register a callback on the start.
|
||||
*
|
||||
* @param callback the callback that will be called whenever the output port is changed
|
||||
* @param callback the callback that will be called whenever the start is changed
|
||||
* @param initialNotify if true, the callback will be run on the initial value
|
||||
* @return the {@link CallbackStore} object associated with this callback.
|
||||
*/
|
||||
public CallbackStore registerOutputPortCallback(NotifyCallback callback, boolean initialNotify) {
|
||||
int uid = AddressableLEDDataJNI.registerOutputPortCallback(m_index, callback, initialNotify);
|
||||
return new CallbackStore(m_index, uid, AddressableLEDDataJNI::cancelOutputPortCallback);
|
||||
public CallbackStore registerStartCallback(NotifyCallback callback, boolean initialNotify) {
|
||||
int uid = AddressableLEDDataJNI.registerStartCallback(m_channel, callback, initialNotify);
|
||||
return new CallbackStore(m_channel, uid, AddressableLEDDataJNI::cancelStartCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the output port.
|
||||
* Get the start.
|
||||
*
|
||||
* @return the output port
|
||||
* @return the start
|
||||
*/
|
||||
public int getOutputPort() {
|
||||
return AddressableLEDDataJNI.getOutputPort(m_index);
|
||||
public int getStart() {
|
||||
return AddressableLEDDataJNI.getStart(m_channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the output port.
|
||||
* Change the start.
|
||||
*
|
||||
* @param outputPort the new output port
|
||||
* @param start the new start
|
||||
*/
|
||||
public void setOutputPort(int outputPort) {
|
||||
AddressableLEDDataJNI.setOutputPort(m_index, outputPort);
|
||||
public void setStart(int start) {
|
||||
AddressableLEDDataJNI.setStart(m_channel, start);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,8 +100,8 @@ public class AddressableLEDSim {
|
||||
* @return the {@link CallbackStore} object associated with this callback.
|
||||
*/
|
||||
public CallbackStore registerLengthCallback(NotifyCallback callback, boolean initialNotify) {
|
||||
int uid = AddressableLEDDataJNI.registerLengthCallback(m_index, callback, initialNotify);
|
||||
return new CallbackStore(m_index, uid, AddressableLEDDataJNI::cancelLengthCallback);
|
||||
int uid = AddressableLEDDataJNI.registerLengthCallback(m_channel, callback, initialNotify);
|
||||
return new CallbackStore(m_channel, uid, AddressableLEDDataJNI::cancelLengthCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,7 +110,7 @@ public class AddressableLEDSim {
|
||||
* @return the length
|
||||
*/
|
||||
public int getLength() {
|
||||
return AddressableLEDDataJNI.getLength(m_index);
|
||||
return AddressableLEDDataJNI.getLength(m_channel);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -147,37 +119,7 @@ public class AddressableLEDSim {
|
||||
* @param length the new value
|
||||
*/
|
||||
public void setLength(int length) {
|
||||
AddressableLEDDataJNI.setLength(m_index, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a callback on whether the LEDs are running.
|
||||
*
|
||||
* @param callback the callback that will be called whenever the LED state is changed
|
||||
* @param initialNotify if true, the callback will be run on the initial value
|
||||
* @return the {@link CallbackStore} object associated with this callback.
|
||||
*/
|
||||
public CallbackStore registerRunningCallback(NotifyCallback callback, boolean initialNotify) {
|
||||
int uid = AddressableLEDDataJNI.registerRunningCallback(m_index, callback, initialNotify);
|
||||
return new CallbackStore(m_index, uid, AddressableLEDDataJNI::cancelRunningCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the LEDs are running.
|
||||
*
|
||||
* @return true if they are
|
||||
*/
|
||||
public boolean getRunning() {
|
||||
return AddressableLEDDataJNI.getRunning(m_index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change whether the LEDs are active.
|
||||
*
|
||||
* @param running the new value
|
||||
*/
|
||||
public void setRunning(boolean running) {
|
||||
AddressableLEDDataJNI.setRunning(m_index, running);
|
||||
AddressableLEDDataJNI.setLength(m_channel, length);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -186,9 +128,9 @@ public class AddressableLEDSim {
|
||||
* @param callback the callback that will be called whenever the LED data is changed
|
||||
* @return the {@link CallbackStore} object associated with this callback.
|
||||
*/
|
||||
public CallbackStore registerDataCallback(ConstBufferCallback callback) {
|
||||
int uid = AddressableLEDDataJNI.registerDataCallback(m_index, callback);
|
||||
return new CallbackStore(m_index, uid, AddressableLEDDataJNI::cancelDataCallback);
|
||||
public static CallbackStore registerDataCallback(ConstBufferCallback callback) {
|
||||
int uid = AddressableLEDDataJNI.registerDataCallback(callback);
|
||||
return new CallbackStore(uid, AddressableLEDDataJNI::cancelDataCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -197,7 +139,7 @@ public class AddressableLEDSim {
|
||||
* @return the LED data
|
||||
*/
|
||||
public byte[] getData() {
|
||||
return AddressableLEDDataJNI.getData(m_index);
|
||||
return getGlobalData(getStart(), getLength());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -206,11 +148,32 @@ public class AddressableLEDSim {
|
||||
* @param data the new data
|
||||
*/
|
||||
public void setData(byte[] data) {
|
||||
AddressableLEDDataJNI.setData(m_index, data);
|
||||
setGlobalData(getStart(), data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the global LED data.
|
||||
*
|
||||
* @param start start, in LEDs
|
||||
* @param length length, in LEDs
|
||||
* @return the LED data
|
||||
*/
|
||||
public static byte[] getGlobalData(int start, int length) {
|
||||
return AddressableLEDDataJNI.getData(start, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the global LED data.
|
||||
*
|
||||
* @param start start, in LEDs
|
||||
* @param data the new data
|
||||
*/
|
||||
public static void setGlobalData(int start, byte[] data) {
|
||||
AddressableLEDDataJNI.setData(start, data);
|
||||
}
|
||||
|
||||
/** Reset all simulation data for this LED object. */
|
||||
public void resetData() {
|
||||
AddressableLEDDataJNI.resetData(m_index);
|
||||
AddressableLEDDataJNI.resetData(m_channel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ class AddressableLEDSimTest {
|
||||
@Test
|
||||
void testInitialization() {
|
||||
HAL.initialize(500, 0);
|
||||
AddressableLEDSim sim = new AddressableLEDSim();
|
||||
AddressableLEDSim sim = new AddressableLEDSim(0);
|
||||
assertFalse(sim.getInitialized());
|
||||
|
||||
BooleanCallback initializedCallback = new BooleanCallback();
|
||||
@@ -36,11 +36,11 @@ class AddressableLEDSimTest {
|
||||
|
||||
@Test
|
||||
void testLength() {
|
||||
AddressableLEDSim sim = new AddressableLEDSim();
|
||||
AddressableLEDSim sim = new AddressableLEDSim(0);
|
||||
IntCallback callback = new IntCallback();
|
||||
try (CallbackStore cb = sim.registerLengthCallback(callback, false);
|
||||
AddressableLED led = new AddressableLED(0)) {
|
||||
assertEquals(1, sim.getLength()); // Defaults to 1 led
|
||||
assertEquals(0, sim.getLength()); // Defaults to 0 leds
|
||||
|
||||
AddressableLEDBuffer ledData = new AddressableLEDBuffer(50);
|
||||
led.setLength(ledData.getLength());
|
||||
@@ -52,37 +52,14 @@ class AddressableLEDSimTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSetRunning() {
|
||||
AddressableLEDSim sim = AddressableLEDSim.createForIndex(0);
|
||||
BooleanCallback callback = new BooleanCallback();
|
||||
try (CallbackStore cb = sim.registerRunningCallback(callback, false);
|
||||
AddressableLED led = new AddressableLED(0)) {
|
||||
assertFalse(sim.getRunning());
|
||||
|
||||
led.start();
|
||||
assertTrue(sim.getRunning());
|
||||
assertTrue(callback.wasTriggered());
|
||||
assertTrue(callback.getSetValue());
|
||||
|
||||
callback.reset();
|
||||
led.stop();
|
||||
assertFalse(sim.getRunning());
|
||||
assertTrue(callback.wasTriggered());
|
||||
assertFalse(callback.getSetValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSetData() {
|
||||
AddressableLEDSim sim = new AddressableLEDSim();
|
||||
AddressableLEDSim sim = new AddressableLEDSim(0);
|
||||
BufferCallback callback = new BufferCallback();
|
||||
|
||||
try (AddressableLED led = new AddressableLED(0);
|
||||
CallbackStore cb = sim.registerDataCallback(callback)) {
|
||||
assertFalse(sim.getRunning());
|
||||
|
||||
assertEquals(1, sim.getLength()); // Defaults to 1 led
|
||||
CallbackStore cb = AddressableLEDSim.registerDataCallback(callback)) {
|
||||
assertEquals(0, sim.getLength()); // Defaults to 0 leds
|
||||
|
||||
AddressableLEDBuffer ledData = new AddressableLEDBuffer(3);
|
||||
led.setLength(ledData.getLength());
|
||||
@@ -94,22 +71,19 @@ class AddressableLEDSimTest {
|
||||
|
||||
byte[] data = sim.getData();
|
||||
System.out.println(Arrays.toString(data));
|
||||
assertEquals(12, data.length);
|
||||
assertEquals(9, data.length);
|
||||
|
||||
assertEquals((byte) 0, data[0]);
|
||||
assertEquals((byte) 0, data[1]);
|
||||
assertEquals((byte) 255, data[2]);
|
||||
|
||||
assertEquals((byte) 0, data[3]);
|
||||
assertEquals((byte) 255, data[4]);
|
||||
assertEquals((byte) 0, data[5]);
|
||||
|
||||
assertEquals((byte) 0, data[4]);
|
||||
assertEquals((byte) 255, data[5]);
|
||||
assertEquals((byte) 0, data[6]);
|
||||
assertEquals((byte) 255, data[6]);
|
||||
assertEquals((byte) 0, data[7]);
|
||||
|
||||
assertEquals((byte) 255, data[8]);
|
||||
assertEquals((byte) 0, data[9]);
|
||||
assertEquals((byte) 0, data[10]);
|
||||
assertEquals((byte) 0, data[11]);
|
||||
assertEquals((byte) 0, data[8]);
|
||||
|
||||
assertTrue(callback.wasTriggered());
|
||||
data = callback.getSetValue();
|
||||
@@ -117,17 +91,14 @@ class AddressableLEDSimTest {
|
||||
assertEquals((byte) 0, data[0]);
|
||||
assertEquals((byte) 0, data[1]);
|
||||
assertEquals((byte) 255, data[2]);
|
||||
|
||||
assertEquals((byte) 0, data[3]);
|
||||
assertEquals((byte) 255, data[4]);
|
||||
assertEquals((byte) 0, data[5]);
|
||||
|
||||
assertEquals((byte) 0, data[4]);
|
||||
assertEquals((byte) 255, data[5]);
|
||||
assertEquals((byte) 0, data[6]);
|
||||
assertEquals((byte) 255, data[6]);
|
||||
assertEquals((byte) 0, data[7]);
|
||||
|
||||
assertEquals((byte) 255, data[8]);
|
||||
assertEquals((byte) 0, data[9]);
|
||||
assertEquals((byte) 0, data[10]);
|
||||
assertEquals((byte) 0, data[11]);
|
||||
assertEquals((byte) 0, data[8]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,19 +31,16 @@ public class Robot extends TimedRobot {
|
||||
|
||||
/** Called once at the beginning of the robot program. */
|
||||
public Robot() {
|
||||
// PWM port 9
|
||||
// Must be a PWM header, not MXP or DIO
|
||||
m_led = new AddressableLED(9);
|
||||
// SmartIO port 1
|
||||
m_led = new AddressableLED(1);
|
||||
|
||||
// Reuse buffer
|
||||
// Default to a length of 60, start empty output
|
||||
// Length is expensive to set, so only set it once, then just update data
|
||||
// Default to a length of 60
|
||||
m_ledBuffer = new AddressableLEDBuffer(60);
|
||||
m_led.setLength(m_ledBuffer.getLength());
|
||||
|
||||
// Set the data
|
||||
m_led.setData(m_ledBuffer);
|
||||
m_led.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user