diff --git a/glass/src/lib/native/cpp/hardware/LEDDisplay.cpp b/glass/src/lib/native/cpp/hardware/LEDDisplay.cpp index 8e02be30a4..f7e099cd9a 100644 --- a/glass/src/lib/native/cpp/hardware/LEDDisplay.cpp +++ b/glass/src/lib/native/cpp/hardware/LEDDisplay.cpp @@ -25,7 +25,6 @@ void glass::DisplayLEDDisplay(LEDDisplayModel* model, int index) { wpi::SmallVector 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(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; diff --git a/glass/src/lib/native/cpp/hardware/PWM.cpp b/glass/src/lib/native/cpp/hardware/PWM.cpp index 6f58fbaff0..6c132f9bf0 100644 --- a/glass/src/lib/native/cpp/hardware/PWM.cpp +++ b/glass/src/lib/native/cpp/hardware/PWM.cpp @@ -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); } diff --git a/glass/src/lib/native/include/glass/hardware/LEDDisplay.h b/glass/src/lib/native/include/glass/hardware/LEDDisplay.h index 3aee6ae0f0..f582b80b1b 100644 --- a/glass/src/lib/native/include/glass/hardware/LEDDisplay.h +++ b/glass/src/lib/native/include/glass/hardware/LEDDisplay.h @@ -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 GetData(wpi::SmallVectorImpl& buf) = 0; }; diff --git a/glass/src/lib/native/include/glass/hardware/PWM.h b/glass/src/lib/native/include/glass/hardware/PWM.h index 184d45a133..cd9ecf9b6e 100644 --- a/glass/src/lib/native/include/glass/hardware/PWM.h +++ b/glass/src/lib/native/include/glass/hardware/PWM.h @@ -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; diff --git a/hal/src/main/java/edu/wpi/first/hal/AddressableLEDJNI.java b/hal/src/main/java/edu/wpi/first/hal/AddressableLEDJNI.java index 1294a7562a..25ae0c4e5e 100644 --- a/hal/src/main/java/edu/wpi/first/hal/AddressableLEDJNI.java +++ b/hal/src/main/java/edu/wpi/first/hal/AddressableLEDJNI.java @@ -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. * - *

This will take effect on the next call to {@link #setData(int, byte[])}. + *

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

The max length is 5460 LEDs. + *

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

If the output is enabled, this will start writing the next data cycle. It is safe to call, - * even while output is enabled. + *

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

By default, the driver is set up to drive WS2812B and WS2815, so nothing needs to be set for - * those. + *

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

The sync time is the time to hold output so LEDs enable. Default set for WS2812B and WS2815. + *

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

The output writes continuously. + *

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" + *

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() {} diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/AddressableLEDDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/simulation/AddressableLEDDataJNI.java index b1465352cb..4aa57a7c29 100644 --- a/hal/src/main/java/edu/wpi/first/hal/simulation/AddressableLEDDataJNI.java +++ b/hal/src/main/java/edu/wpi/first/hal/simulation/AddressableLEDDataJNI.java @@ -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() {} } diff --git a/hal/src/main/native/cpp/jni/AddressableLEDJNI.cpp b/hal/src/main/native/cpp/jni/AddressableLEDJNI.cpp index e7459a2b86..59fb111102 100644 --- a/hal/src/main/native/cpp/jni/AddressableLEDJNI.cpp +++ b/hal/src/main/native/cpp/jni/AddressableLEDJNI.cpp @@ -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(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(handle), - static_cast(colorOrder), &status); + HAL_SetAddressableLEDStart(static_cast(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 cdata{env, data}; + if (static_cast(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 jArrRef{env, arr}; - HAL_WriteAddressableLEDData( - static_cast(handle), - reinterpret_cast(jArrRef.data()), - jArrRef.size() / 4, &status); - CheckStatus(env, status); + HAL_SetAddressableLEDData( + outStart, rawdata.size() / 3, + static_cast(colorOrder), + reinterpret_cast(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 cdata{env, data, static_cast(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(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(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(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(handle), - &status); - CheckStatus(env, status); + HAL_SetAddressableLEDData( + outStart, rawdata.size() / 3, + static_cast(colorOrder), + reinterpret_cast(rawdata.data()), &status); } } // extern "C" diff --git a/hal/src/main/native/cpp/jni/HALUtil.cpp b/hal/src/main/native/cpp/jni/HALUtil.cpp index cca5bf41cb..4884f0ae79 100644 --- a/hal/src/main/native/cpp/jni/HALUtil.cpp +++ b/hal/src/main/native/cpp/jni/HALUtil.cpp @@ -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; diff --git a/hal/src/main/native/cpp/jni/HALUtil.h b/hal/src/main/native/cpp/jni/HALUtil.h index d8470a2683..b34a2780cc 100644 --- a/hal/src/main/native/cpp/jni/HALUtil.h +++ b/hal/src/main/native/cpp/jni/HALUtil.h @@ -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); diff --git a/hal/src/main/native/cpp/jni/simulation/AddressableLEDDataJNI.cpp b/hal/src/main/native/cpp/jni/simulation/AddressableLEDDataJNI.cpp index 00335b67be..91dcdf088d 100644 --- a/hal/src/main/native/cpp/jni/simulation/AddressableLEDDataJNI.cpp +++ b/hal/src/main/native/cpp/jni/simulation/AddressableLEDDataJNI.cpp @@ -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_kAddressableLEDMaxLength); - int32_t length = HALSIM_GetAddressableLEDData(index, data.get()); + length = HALSIM_GetAddressableLEDData(start, length, data.get()); return MakeJByteArray( - env, std::span(reinterpret_cast(data.get()), length * 4)); + env, std::span(reinterpret_cast(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 jArrRef{env, arr}; auto arrRef = jArrRef.array(); HALSIM_SetAddressableLEDData( - index, reinterpret_cast(arrRef.data()), - arrRef.size() / 4); + start, arrRef.size() / 3, + reinterpret_cast(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" diff --git a/hal/src/main/native/include/hal/AddressableLED.h b/hal/src/main/native/include/hal/AddressableLED.h index c220795138..9458b6e52c 100644 --- a/hal/src/main/native/include/hal/AddressableLED.h +++ b/hal/src/main/native/include/hal/AddressableLED.h @@ -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. + * + *

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

The max length is 5460 LEDs. + *

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

If the output is enabled, this will start writing the next data cycle. - * It is safe to call, even while output is enabled. + *

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

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

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

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" diff --git a/hal/src/main/native/include/hal/AddressableLEDTypes.h b/hal/src/main/native/include/hal/AddressableLEDTypes.h index 4dad3683c8..86d505fc0e 100644 --- a/hal/src/main/native/include/hal/AddressableLEDTypes.h +++ b/hal/src/main/native/include/hal/AddressableLEDTypes.h @@ -7,15 +7,14 @@ #include #include -/** 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; }; /** diff --git a/hal/src/main/native/include/hal/simulation/AddressableLEDData.h b/hal/src/main/native/include/hal/simulation/AddressableLEDData.h index d828e5c8e6..287ece975b 100644 --- a/hal/src/main/native/include/hal/simulation/AddressableLEDData.h +++ b/hal/src/main/native/include/hal/simulation/AddressableLEDData.h @@ -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, diff --git a/hal/src/main/native/sim/AddressableLED.cpp b/hal/src/main/native/sim/AddressableLED.cpp index 1682be48c4..9c6654a56a 100644 --- a/hal/src/main/native/sim/AddressableLED.cpp +++ b/hal/src/main/native/sim/AddressableLED.cpp @@ -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* ledHandles; - namespace hal::init { -void InitializeAddressableLED() { - static LimitedHandleResource - 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(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" diff --git a/hal/src/main/native/sim/PortsInternal.h b/hal/src/main/native/sim/PortsInternal.h index 0ade7a25aa..3e1d5668ce 100644 --- a/hal/src/main/native/sim/PortsInternal.h +++ b/hal/src/main/native/sim/PortsInternal.h @@ -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; diff --git a/hal/src/main/native/sim/mockdata/AddressableLEDData.cpp b/hal/src/main/native/sim/mockdata/AddressableLEDData.cpp index 0945ec930a..2cd3bef3e7 100644 --- a/hal/src/main/native/sim/mockdata/AddressableLEDData.cpp +++ b/hal/src/main/native/sim/mockdata/AddressableLEDData.cpp @@ -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(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" diff --git a/hal/src/main/native/sim/mockdata/AddressableLEDDataInternal.h b/hal/src/main/native/sim/mockdata/AddressableLEDDataInternal.h index 3382eedd9c..648b7d5c8d 100644 --- a/hal/src/main/native/sim/mockdata/AddressableLEDDataInternal.h +++ b/hal/src/main/native/sim/mockdata/AddressableLEDDataInternal.h @@ -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 initialized{ + false}; + SimDataValue start{0}; + SimDataValue 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 initialized{ - false}; - SimDataValue outputPort{-1}; - SimDataValue length{1}; - SimDataValue 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 data; - - void ResetData(); }; -extern AddressableLEDData* SimAddressableLEDData; +extern AddressableLEDDataBuffer* SimAddressableLEDDataBuffer; } // namespace hal diff --git a/hal/src/main/native/systemcore/AddressableLED.cpp b/hal/src/main/native/systemcore/AddressableLED.cpp index cd31e46b52..13c1a1e194 100644 --- a/hal/src/main/native/systemcore/AddressableLED.cpp +++ b/hal/src/main/native/systemcore/AddressableLED.cpp @@ -4,85 +4,152 @@ #include "hal/AddressableLED.h" +#include + +#include #include #include +#include #include +#include +#include #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" diff --git a/hal/src/main/native/systemcore/PortsInternal.h b/hal/src/main/native/systemcore/PortsInternal.h index 6c56740d46..5600d88bb2 100644 --- a/hal/src/main/native/systemcore/PortsInternal.h +++ b/hal/src/main/native/systemcore/PortsInternal.h @@ -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; diff --git a/hal/src/main/native/systemcore/SmartIo.cpp b/hal/src/main/native/systemcore/SmartIo.cpp index 8c993c9b0c..f47251c901 100644 --- a/hal/src/main/native/systemcore/SmartIo.cpp +++ b/hal/src/main/native/systemcore/SmartIo.cpp @@ -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 diff --git a/hal/src/main/native/systemcore/SmartIo.h b/hal/src/main/native/systemcore/SmartIo.h index 368950ca24..bd21f933fa 100644 --- a/hal/src/main/native/systemcore/SmartIo.h +++ b/hal/src/main/native/systemcore/SmartIo.h @@ -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* diff --git a/hal/src/main/native/systemcore/mockdata/AddressableLEDData.cpp b/hal/src/main/native/systemcore/mockdata/AddressableLEDData.cpp index a1d7011945..e27e74ef61 100644 --- a/hal/src/main/native/systemcore/mockdata/AddressableLEDData.cpp +++ b/hal/src/main/native/systemcore/mockdata/AddressableLEDData.cpp @@ -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) diff --git a/simulation/halsim_gui/src/main/native/cpp/AddressableLEDGui.cpp b/simulation/halsim_gui/src/main/native/cpp/AddressableLEDGui.cpp index d7049362c8..b9611dbbe2 100644 --- a/simulation/halsim_gui/src/main/native/cpp/AddressableLEDGui.cpp +++ b/simulation/halsim_gui/src/main/native/cpp/AddressableLEDGui.cpp @@ -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 GetData(wpi::SmallVectorImpl&) 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(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 func) + wpi::function_ref func) override; private: @@ -83,7 +83,7 @@ bool AddressableLEDsModel::Exists() { } void AddressableLEDsModel::ForEachLEDDisplay( - wpi::function_ref func) { + wpi::function_ref func) { for (int i = 0; i < static_cast(m_models.size()); ++i) { if (m_models[i]) { func(*m_models[i], i); diff --git a/simulation/halsim_gui/src/main/native/cpp/PWMSimGui.cpp b/simulation/halsim_gui/src/main/native/cpp/PWMSimGui.cpp index dec443169f..5d8a358dba 100644 --- a/simulation/halsim_gui/src/main/native/cpp/PWMSimGui.cpp +++ b/simulation/halsim_gui/src/main/native/cpp/PWMSimGui.cpp @@ -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(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( diff --git a/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_AddressableLED.cpp b/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_AddressableLED.cpp index 78629a3dbd..e310eb742f 100644 --- a/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_AddressableLED.cpp +++ b/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_AddressableLED.cpp @@ -31,12 +31,10 @@ HALSimWSProviderAddressableLED::~HALSimWSProviderAddressableLED() { void HALSimWSProviderAddressableLED::RegisterCallbacks() { m_initCbKey = REGISTER(Initialized, "(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 diff --git a/simulation/halsim_ws_core/src/main/native/include/WSProvider_AddressableLED.h b/simulation/halsim_ws_core/src/main/native/include/WSProvider_AddressableLED.h index 3970774214..b4f2795e24 100644 --- a/simulation/halsim_ws_core/src/main/native/include/WSProvider_AddressableLED.h +++ b/simulation/halsim_ws_core/src/main/native/include/WSProvider_AddressableLED.h @@ -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 diff --git a/wpilibc/src/main/native/cpp/AddressableLED.cpp b/wpilibc/src/main/native/cpp/AddressableLED.cpp index b437eb2f2e..f626ef89c4 100644 --- a/wpilibc/src/main/native/cpp/AddressableLED.cpp +++ b/wpilibc/src/main/native/cpp/AddressableLED.cpp @@ -4,6 +4,8 @@ #include "frc/AddressableLED.h" +#include + #include #include #include @@ -12,39 +14,39 @@ #include #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(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 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(m_length), ledData.size()), + static_cast(m_colorOrder), ledData.data(), + &status); + FRC_CheckErrorStatus(status, "Port {}", m_channel); } void AddressableLED::SetData(std::initializer_list 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 ledData) { int32_t status = 0; - HAL_SetAddressableLEDBitTiming( - m_handle, highTime0.to(), lowTime0.to(), - highTime1.to(), lowTime1.to(), &status); - FRC_CheckErrorStatus(status, "Port {}", m_port); -} - -void AddressableLED::SetSyncTime(units::microsecond_t syncTime) { - int32_t status = 0; - HAL_SetAddressableLEDSyncTime(m_handle, syncTime.to(), &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(colorOrder), ledData.data(), + &status); + FRC_CheckErrorStatus(status, ""); } void AddressableLED::LEDData::SetHSV(int h, int s, int v) { diff --git a/wpilibc/src/main/native/cpp/simulation/AddressableLEDSim.cpp b/wpilibc/src/main/native/cpp/simulation/AddressableLEDSim.cpp index 0448437349..434eac5488 100644 --- a/wpilibc/src/main/native/cpp/simulation/AddressableLEDSim.cpp +++ b/wpilibc/src/main/native/cpp/simulation/AddressableLEDSim.cpp @@ -9,108 +9,90 @@ #include +#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 AddressableLEDSim::RegisterInitializedCallback( NotifyCallback callback, bool initialNotify) { auto store = std::make_unique( - 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 AddressableLEDSim::RegisterOutputPortCallback( +std::unique_ptr AddressableLEDSim::RegisterStartCallback( NotifyCallback callback, bool initialNotify) { auto store = std::make_unique( - 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 AddressableLEDSim::RegisterLengthCallback( NotifyCallback callback, bool initialNotify) { auto store = std::make_unique( - 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 AddressableLEDSim::RegisterRunningCallback( - NotifyCallback callback, bool initialNotify) { - auto store = std::make_unique( - 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 AddressableLEDSim::RegisterDataCallback( ConstBufferCallback callback, bool initialNotify) { auto store = std::make_unique( - 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); } diff --git a/wpilibc/src/main/native/include/frc/AddressableLED.h b/wpilibc/src/main/native/include/frc/AddressableLED.h index c4aa7e9b4a..db54d108b5 100644 --- a/wpilibc/src/main/native/include/frc/AddressableLED.h +++ b/wpilibc/src/main/native/include/frc/AddressableLED.h @@ -9,7 +9,6 @@ #include #include -#include #include #include @@ -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(). * - *

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

Calling this is an expensive call, so its best to call it once, then - * just update data. - * - *

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

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 ledData); /** - * Sets the led output data. - * - *

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); /** - * Sets the bit timing. + * Sets the LED output data at an arbitrary location in the global buffer. * - *

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

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

The output writes continuously. - */ - void Start(); - - /** - * Stops the output. - */ - void Stop(); + static void SetGlobalData(int start, ColorOrder colorOrder, + std::span ledData); private: - hal::Handle m_pwmHandle; hal::Handle 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) { diff --git a/wpilibc/src/main/native/include/frc/simulation/AddressableLEDSim.h b/wpilibc/src/main/native/include/frc/simulation/AddressableLEDSim.h index 2a5fcae89f..18fbe9b874 100644 --- a/wpilibc/src/main/native/include/frc/simulation/AddressableLEDSim.h +++ b/wpilibc/src/main/native/include/frc/simulation/AddressableLEDSim.h @@ -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 RegisterOutputPortCallback( - NotifyCallback callback, bool initialNotify); + std::unique_ptr 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 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 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 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 diff --git a/wpilibc/src/test/native/cpp/LEDPatternTest.cpp b/wpilibc/src/test/native/cpp/LEDPatternTest.cpp index 467b4bbd81..8dc6d68cae 100644 --- a/wpilibc/src/test/native/cpp/LEDPatternTest.cpp +++ b/wpilibc/src/test/native/cpp/LEDPatternTest.cpp @@ -1031,7 +1031,6 @@ void AssertIndexColor(std::span 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); diff --git a/wpilibc/src/test/native/cpp/simulation/AddressableLEDSimTest.cpp b/wpilibc/src/test/native/cpp/simulation/AddressableLEDSimTest.cpp index 6907cf6f52..378561d57d 100644 --- a/wpilibc/src/test/native/cpp/simulation/AddressableLEDSimTest.cpp +++ b/wpilibc/src/test/native/cpp/simulation/AddressableLEDSimTest.cpp @@ -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 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 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 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 diff --git a/wpilibc/src/test/native/cpp/simulation/SimInitializationTest.cpp b/wpilibc/src/test/native/cpp/simulation/SimInitializationTest.cpp index 29e175bde1..e3e83d54ea 100644 --- a/wpilibc/src/test/native/cpp/simulation/SimInitializationTest.cpp +++ b/wpilibc/src/test/native/cpp/simulation/SimInitializationTest.cpp @@ -37,5 +37,5 @@ TEST(SimInitializationTest, AllInitialize) { (void)rrsim; DutyCycleSim dcsim = DutyCycleSim::CreateForChannel(0); (void)dcsim; - AddressableLEDSim adLED; + AddressableLEDSim adLED{0}; } diff --git a/wpilibcExamples/src/main/cpp/examples/AddressableLED/cpp/Robot.cpp b/wpilibcExamples/src/main/cpp/examples/AddressableLED/cpp/Robot.cpp index 70808ab473..796a8457e0 100644 --- a/wpilibcExamples/src/main/cpp/examples/AddressableLED/cpp/Robot.cpp +++ b/wpilibcExamples/src/main/cpp/examples/AddressableLED/cpp/Robot.cpp @@ -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() { diff --git a/wpilibcExamples/src/main/cpp/examples/AddressableLED/include/Robot.h b/wpilibcExamples/src/main/cpp/examples/AddressableLED/include/Robot.h index 9f87d16060..dd9bc81505 100644 --- a/wpilibcExamples/src/main/cpp/examples/AddressableLED/include/Robot.h +++ b/wpilibcExamples/src/main/cpp/examples/AddressableLED/include/Robot.h @@ -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 m_ledBuffer; // Reuse the buffer diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/AddressableLED.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/AddressableLED.java index 3e786783ef..ad83f5390b 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/AddressableLED.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/AddressableLED.java @@ -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. * - *

By default, the timing supports WS2812B and WS2815 LEDs, but is configurable using {@link - * #setBitTiming(int, int, int, int)} - * *

Some LEDs use a different color order than the default GRB. The color order is configurable * using {@link #setColorOrder(ColorOrder)}. * - *

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

Calling this is an expensive call, so it's best to call it once, then just update data. - * - *

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

If the output is enabled, this will start writing the next data cycle. It is safe to call, - * even while output is enabled. + *

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

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

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

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); } } diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/AddressableLEDBuffer.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/AddressableLEDBuffer.java index 28bbc4b4c5..a726f46745 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/AddressableLEDBuffer.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/AddressableLEDBuffer.java @@ -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; } /** diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/AddressableLEDSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/AddressableLEDSim.java index 83ef08e73f..83f8931ee0 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/AddressableLEDSim.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/AddressableLEDSim.java @@ -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); } } diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/AddressableLEDSimTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/AddressableLEDSimTest.java index 4ddadf1481..52a7d70736 100644 --- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/AddressableLEDSimTest.java +++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/AddressableLEDSimTest.java @@ -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]); } } } diff --git a/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/examples/addressableled/Robot.java b/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/examples/addressableled/Robot.java index a698f33392..1f01f4a590 100644 --- a/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/examples/addressableled/Robot.java +++ b/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/examples/addressableled/Robot.java @@ -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